feat: simplify SOP to immediate-effect configuration

This commit is contained in:
Eric 1549169735@qq.com
2026-08-18 16:27:02 +08:00
parent c5ab886b70
commit 8de48fb05e
150 changed files with 6764 additions and 1626 deletions

121
sdk/dist/index.d.ts vendored Normal file
View File

@@ -0,0 +1,121 @@
export type ScenarioInput = Record<string, unknown>;
export type OutputField = {
key: string;
name: string;
type: string;
source: string;
value: unknown;
};
export type ResultField = {
key: string;
name: string;
type: string;
required?: boolean;
options?: unknown[];
fields?: ResultField[];
items?: Omit<ResultField, 'key' | 'name'>;
};
export type ResultSchema = {
fields: ResultField[];
};
export type NodeField = {
key: string;
name: string;
type: string;
required: boolean;
options: unknown[];
validation: Record<string, unknown>;
};
export type PresentationField = {
key: string;
label: string;
kind: 'text' | 'image';
value: unknown;
};
export type NodePresentation = {
summary: PresentationField[];
items: Array<{
fields: PresentationField[];
}>;
opening?: {
title: string;
content: string;
};
};
export type KnowledgeCollectionOption = {
value: string;
label: string;
parents?: string[];
suggested?: boolean;
};
export type KnowledgeCollectionStep = {
field_key: string;
name: string;
required: boolean;
multiple: boolean;
from_field?: string;
options: KnowledgeCollectionOption[];
};
export type KnowledgeCollection = {
context_fields: NodeField[];
context_title?: string;
context_hint?: string;
selection_title?: string;
selection_hint?: string;
steps: KnowledgeCollectionStep[];
};
export type NodeView = {
node_key: string;
type: string;
title: string;
content: string;
fields?: NodeField[];
presentation?: NodePresentation;
outputs?: unknown[];
collection?: KnowledgeCollection;
};
export type ScenarioState = {
run_id: number;
external_ref: string;
status: string;
final_result?: Record<string, unknown> | null;
result_schema: ResultSchema;
session_token?: string;
node: NodeView;
outputs: OutputField[];
};
export type SDKEvent = 'ready' | 'node_change' | 'form_submit' | 'finish' | 'error';
export type CreateOptions = {
baseURL?: string;
publicKey: string;
scenarioKey: string;
sopId?: number;
input?: ScenarioInput;
initialValues?: ScenarioInput;
externalRef?: string;
};
export type FinishOptions = {
result?: string;
finalResult?: Record<string, unknown> | null;
};
export declare class SalesScenario {
private readonly options;
private token;
private state?;
private handlers;
constructor(options: CreateOptions);
start(): Promise<ScenarioState>;
getState(): ScenarioState;
getCurrentNode(): Promise<ScenarioState>;
submit(values: ScenarioInput): Promise<ScenarioState>;
next(): Promise<ScenarioState>;
finish(options?: FinishOptions): Promise<ScenarioState>;
reset(): Promise<ScenarioState>;
destroy(): void;
on(event: SDKEvent, handler: (payload: unknown) => void): () => boolean;
private update;
private setState;
private emit;
private request;
}
export declare function create(options: CreateOptions): SalesScenario;

104
sdk/dist/index.iife.js vendored Normal file
View File

@@ -0,0 +1,104 @@
"use strict";
var IqudooSalesScenario = (() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
SalesScenario: () => SalesScenario,
create: () => create
});
var SalesScenario = class {
constructor(options) {
this.options = options;
}
options;
token = "";
state;
handlers = /* @__PURE__ */ new Map();
async start() {
const state = await this.request(`/public/scenarios/${encodeURIComponent(this.options.scenarioKey)}/runs`, { method: "POST", body: JSON.stringify({ public_key: this.options.publicKey, sop_id: this.options.sopId, input: this.options.input || {}, initial_values: this.options.initialValues || {}, external_ref: this.options.externalRef || "" }) });
if (state.session_token) this.token = state.session_token;
this.setState(state);
this.emit("ready", state);
return state;
}
getState() {
if (!this.state) throw new Error("SDK has not started");
return this.state;
}
async getCurrentNode() {
return this.update(`/public/runs/${this.getState().run_id}/current`);
}
async submit(values) {
const state = await this.update(`/public/runs/${this.getState().run_id}/submit`, { method: "POST", body: JSON.stringify({ node_key: this.getState().node.node_key, answers: values }) });
this.emit("form_submit", { values, state });
return state;
}
async next() {
return this.update(`/public/runs/${this.getState().run_id}/next`, { method: "POST" });
}
async finish(options = {}) {
const state = await this.update(`/public/runs/${this.getState().run_id}/finish`, { method: "POST", body: JSON.stringify({ result: options.result || "", final_result: options.finalResult ?? null }) });
this.emit("finish", state);
return state;
}
async reset() {
return this.update(`/public/runs/${this.getState().run_id}/reset`, { method: "POST" });
}
destroy() {
this.handlers.clear();
this.token = "";
this.state = void 0;
}
on(event, handler) {
const handlers = this.handlers.get(event) || /* @__PURE__ */ new Set();
handlers.add(handler);
this.handlers.set(event, handlers);
return () => handlers.delete(handler);
}
async update(path, init = {}) {
const state = await this.request(path, init);
this.setState(state);
return state;
}
setState(state) {
this.state = state;
this.emit("node_change", state.node);
}
emit(event, payload) {
this.handlers.get(event)?.forEach((handler) => handler(payload));
}
async request(path, init) {
try {
const response = await fetch(`${(this.options.baseURL || "").replace(/\/$/, "")}${path}`, { ...init, headers: { "Content-Type": "application/json", ...this.token ? { Authorization: `Bearer ${this.token}` } : {} } });
const body = await response.json();
if (!response.ok) throw new Error(body.message || `Request failed: ${response.status}`);
return body.data || body;
} catch (error) {
this.emit("error", error);
throw error;
}
}
};
function create(options) {
return new SalesScenario(options);
}
return __toCommonJS(index_exports);
})();

35
sdk/dist/index.js vendored Normal file
View File

@@ -0,0 +1,35 @@
export class SalesScenario {
options;
token = '';
state;
handlers = new Map();
constructor(options) {
this.options = options;
}
async start() { const state = await this.request(`/public/scenarios/${encodeURIComponent(this.options.scenarioKey)}/runs`, { method: 'POST', body: JSON.stringify({ public_key: this.options.publicKey, sop_id: this.options.sopId, input: this.options.input || {}, initial_values: this.options.initialValues || {}, external_ref: this.options.externalRef || '' }) }); if (state.session_token)
this.token = state.session_token; this.setState(state); this.emit('ready', state); return state; }
getState() { if (!this.state)
throw new Error('SDK has not started'); return this.state; }
async getCurrentNode() { return this.update(`/public/runs/${this.getState().run_id}/current`); }
async submit(values) { const state = await this.update(`/public/runs/${this.getState().run_id}/submit`, { method: 'POST', body: JSON.stringify({ node_key: this.getState().node.node_key, answers: values }) }); this.emit('form_submit', { values, state }); return state; }
async next() { return this.update(`/public/runs/${this.getState().run_id}/next`, { method: 'POST' }); }
async finish(options = {}) { const state = await this.update(`/public/runs/${this.getState().run_id}/finish`, { method: 'POST', body: JSON.stringify({ result: options.result || '', final_result: options.finalResult ?? null }) }); this.emit('finish', state); return state; }
async reset() { return this.update(`/public/runs/${this.getState().run_id}/reset`, { method: 'POST' }); }
destroy() { this.handlers.clear(); this.token = ''; this.state = undefined; }
on(event, handler) { const handlers = this.handlers.get(event) || new Set(); handlers.add(handler); this.handlers.set(event, handlers); return () => handlers.delete(handler); }
async update(path, init = {}) { const state = await this.request(path, init); this.setState(state); return state; }
setState(state) { this.state = state; this.emit('node_change', state.node); }
emit(event, payload) { this.handlers.get(event)?.forEach(handler => handler(payload)); }
async request(path, init) { try {
const response = await fetch(`${(this.options.baseURL || '').replace(/\/$/, '')}${path}`, { ...init, headers: { 'Content-Type': 'application/json', ...(this.token ? { Authorization: `Bearer ${this.token}` } : {}) } });
const body = await response.json();
if (!response.ok)
throw new Error(body.message || `Request failed: ${response.status}`);
return (body.data || body);
}
catch (error) {
this.emit('error', error);
throw error;
} }
}
export function create(options) { return new SalesScenario(options); }

514
sdk/package-lock.json generated Normal file
View File

@@ -0,0 +1,514 @@
{
"name": "@iqudoo/sales-scenario-sdk",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@iqudoo/sales-scenario-sdk",
"version": "0.1.0",
"devDependencies": {
"esbuild": "^0.28.2",
"typescript": "5.9.3"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.28.2",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.28.2.tgz",
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.2",
"@esbuild/android-arm": "0.28.2",
"@esbuild/android-arm64": "0.28.2",
"@esbuild/android-x64": "0.28.2",
"@esbuild/darwin-arm64": "0.28.2",
"@esbuild/darwin-x64": "0.28.2",
"@esbuild/freebsd-arm64": "0.28.2",
"@esbuild/freebsd-x64": "0.28.2",
"@esbuild/linux-arm": "0.28.2",
"@esbuild/linux-arm64": "0.28.2",
"@esbuild/linux-ia32": "0.28.2",
"@esbuild/linux-loong64": "0.28.2",
"@esbuild/linux-mips64el": "0.28.2",
"@esbuild/linux-ppc64": "0.28.2",
"@esbuild/linux-riscv64": "0.28.2",
"@esbuild/linux-s390x": "0.28.2",
"@esbuild/linux-x64": "0.28.2",
"@esbuild/netbsd-arm64": "0.28.2",
"@esbuild/netbsd-x64": "0.28.2",
"@esbuild/openbsd-arm64": "0.28.2",
"@esbuild/openbsd-x64": "0.28.2",
"@esbuild/openharmony-arm64": "0.28.2",
"@esbuild/sunos-x64": "0.28.2",
"@esbuild/win32-arm64": "0.28.2",
"@esbuild/win32-ia32": "0.28.2",
"@esbuild/win32-x64": "0.28.2"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
}
}
}

23
sdk/package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "@iqudoo/sales-scenario-sdk",
"version": "0.1.0",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --format=iife --global-name=IqudooSalesScenario --outfile=dist/index.iife.js",
"build:esm": "tsc -p tsconfig.json",
"build:iife": "esbuild src/index.ts --bundle --format=iife --global-name=IqudooSalesScenario --outfile=dist/index.iife.js"
},
"devDependencies": {
"esbuild": "^0.28.2",
"typescript": "5.9.3"
}
}

37
sdk/src/index.ts Normal file
View File

@@ -0,0 +1,37 @@
export type ScenarioInput = Record<string, unknown>
export type OutputField = { key:string; name:string; type:string; source:string; value:unknown }
export type ResultField = { key:string; name:string; type:string; required?:boolean; options?:unknown[]; fields?:ResultField[]; items?:Omit<ResultField,'key'|'name'> }
export type ResultSchema = { fields:ResultField[] }
export type NodeField = { key:string; name:string; type:string; required:boolean; options:unknown[]; validation:Record<string,unknown> }
export type PresentationField = { key:string; label:string; kind:'text'|'image'; value:unknown }
export type NodePresentation = { summary:PresentationField[]; items:Array<{fields:PresentationField[]}>; opening?:{title:string; content:string} }
export type KnowledgeCollectionOption = { value:string; label:string; parents?:string[]; suggested?:boolean }
export type KnowledgeCollectionStep = { field_key:string; name:string; required:boolean; multiple:boolean; from_field?:string; options:KnowledgeCollectionOption[] }
export type KnowledgeCollection = { context_fields:NodeField[]; context_title?:string; context_hint?:string; selection_title?:string; selection_hint?:string; steps:KnowledgeCollectionStep[] }
export type NodeView = { node_key:string; type:string; title:string; content:string; fields?:NodeField[]; presentation?:NodePresentation; outputs?:unknown[]; collection?:KnowledgeCollection }
export type ScenarioState = { run_id:number; external_ref:string; status:string; final_result?:Record<string, unknown>|null; result_schema:ResultSchema; session_token?:string; node:NodeView; outputs:OutputField[] }
export type SDKEvent = 'ready'|'node_change'|'form_submit'|'finish'|'error'
export type CreateOptions = { baseURL?:string; publicKey:string; scenarioKey:string; sopId?:number; input?:ScenarioInput; initialValues?:ScenarioInput; externalRef?:string }
export type FinishOptions = { result?:string; finalResult?:Record<string, unknown>|null }
export class SalesScenario {
private token=''
private state?:ScenarioState
private handlers=new Map<SDKEvent,Set<(payload:unknown)=>void>>()
constructor(private readonly options:CreateOptions){}
async start(){const state=await this.request<ScenarioState>(`/public/scenarios/${encodeURIComponent(this.options.scenarioKey)}/runs`,{method:'POST',body:JSON.stringify({public_key:this.options.publicKey,sop_id:this.options.sopId,input:this.options.input||{},initial_values:this.options.initialValues||{},external_ref:this.options.externalRef||''})});if(state.session_token)this.token=state.session_token;this.setState(state);this.emit('ready',state);return state}
getState(){if(!this.state)throw new Error('SDK has not started');return this.state}
async getCurrentNode(){return this.update(`/public/runs/${this.getState().run_id}/current`)}
async submit(values:ScenarioInput){const state=await this.update(`/public/runs/${this.getState().run_id}/submit`,{method:'POST',body:JSON.stringify({node_key:this.getState().node.node_key,answers:values})});this.emit('form_submit',{values,state});return state}
async next(){return this.update(`/public/runs/${this.getState().run_id}/next`,{method:'POST'})}
async finish(options:FinishOptions={}){const state=await this.update(`/public/runs/${this.getState().run_id}/finish`,{method:'POST',body:JSON.stringify({result:options.result||'',final_result:options.finalResult??null})});this.emit('finish',state);return state}
async reset(){return this.update(`/public/runs/${this.getState().run_id}/reset`,{method:'POST'})}
destroy(){this.handlers.clear();this.token='';this.state=undefined}
on(event:SDKEvent,handler:(payload:unknown)=>void){const handlers=this.handlers.get(event)||new Set();handlers.add(handler);this.handlers.set(event,handlers);return()=>handlers.delete(handler)}
private async update(path:string,init:RequestInit={}){const state=await this.request<ScenarioState>(path,init);this.setState(state);return state}
private setState(state:ScenarioState){this.state=state;this.emit('node_change',state.node)}
private emit(event:SDKEvent,payload:unknown){this.handlers.get(event)?.forEach(handler=>handler(payload))}
private async request<T>(path:string,init:RequestInit){try{const response=await fetch(`${(this.options.baseURL||'').replace(/\/$/,'')}${path}`,{...init,headers:{'Content-Type':'application/json',...(this.token?{Authorization:`Bearer ${this.token}`}:{})}});const body=await response.json();if(!response.ok)throw new Error(body.message||`Request failed: ${response.status}`);return (body.data||body) as T}catch(error){this.emit('error',error);throw error}}
}
export function create(options:CreateOptions){return new SalesScenario(options)}

13
sdk/tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Bundler",
"strict": true,
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"lib": ["ES2022", "DOM"]
},
"include": ["src/**/*.ts"]
}