feat: simplify SOP to immediate-effect configuration
This commit is contained in:
37
sdk/src/index.ts
Normal file
37
sdk/src/index.ts
Normal 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)}
|
||||
Reference in New Issue
Block a user