@superpanel-sdk/runtime 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builder/compile/compile-agenda.js +9 -4
- package/dist/cli/serve/index.js +60 -12
- package/dist/compute-host/index.d.ts +2 -0
- package/dist/compute-host/index.js +1 -0
- package/dist/compute-host/read-only-cache.d.ts +20 -0
- package/dist/compute-host/read-only-cache.js +61 -0
- package/dist/compute-host/source-compute-host.js +7 -2
- package/dist/core/context/types.d.ts +19 -1
- package/dist/core/functions/define/custom.d.ts +1 -1
- package/dist/core/functions/types.d.ts +4 -4
- package/dist/core/slot/index.d.ts +1 -1
- package/dist/core/slot/index.js +1 -1
- package/dist/core/slot/types.d.ts +2 -0
- package/dist/core/slot/write.d.ts +8 -1
- package/dist/core/slot/write.js +145 -38
- package/dist/core/stage/builders.d.ts +23 -5
- package/dist/core/stage/builders.js +3 -0
- package/dist/core/stage/drive.d.ts +1 -1
- package/dist/core/stage/drive.js +9 -8
- package/dist/core/stage/flatten.js +13 -11
- package/dist/core/stage/index.d.ts +8 -4
- package/dist/core/stage/index.js +5 -2
- package/dist/core/stage/interrupts.d.ts +28 -0
- package/dist/core/stage/interrupts.js +120 -0
- package/dist/core/stage/ivr-fields.d.ts +9 -0
- package/dist/core/stage/ivr-fields.js +75 -0
- package/dist/core/stage/transfer-fields.d.ts +6 -1
- package/dist/core/stage/transfer-fields.js +44 -3
- package/dist/core/stage/transfer-spec.d.ts +48 -0
- package/dist/core/stage/transfer-spec.js +113 -0
- package/dist/core/stage/types.d.ts +45 -14
- package/dist/core/stage/validate.js +105 -1
- package/dist/core/stage/walk.d.ts +5 -0
- package/dist/core/stage/walk.js +33 -10
- package/dist/fn-context/rpc/trpc-client.js +3 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/voice-service/types.d.ts +3 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toEffectiveSchema } from '../../core/slot/compile-schema.js';
|
|
2
|
-
import { collectTransferBlocks, fatalAgendaIssues, flattenAgendaPlacements, flattenAgendaTree, isAgendaTree, isSequenceAgendas, normalizeSequenceAgendas, registerTransferSessionFields, validateCompiledAgenda, } from '../../core/stage/index.js';
|
|
2
|
+
import { collectIvrBlocks, collectTransferBlocks, collectTransferInterruptHeaders, fatalAgendaIssues, flattenAgendaPlacements, flattenAgendaTree, isAgendaTree, isSequenceAgendas, normalizeSequenceAgendas, registerIvrSessionFields, registerTransferSessionFields, validateCompiledAgenda, } from '../../core/stage/index.js';
|
|
3
3
|
function asAgendaTrees(raw) {
|
|
4
4
|
if (isAgendaTree(raw))
|
|
5
5
|
return [raw];
|
|
@@ -27,8 +27,11 @@ export function compileSequenceAgendas(schema, raw, options = {}) {
|
|
|
27
27
|
}
|
|
28
28
|
const trees = asAgendaTrees(raw);
|
|
29
29
|
if (trees) {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
30
|
+
const nodes = trees.flatMap((tree) => tree.tree);
|
|
31
|
+
const transferIds = collectTransferBlocks({}, nodes).map((block) => block.id);
|
|
32
|
+
const withTransfer = registerIvrSessionFields(registerTransferSessionFields(schema, transferIds, {
|
|
33
|
+
lastResult: collectTransferInterruptHeaders(trees.map((tree) => tree.header)),
|
|
34
|
+
}), collectIvrBlocks({}, nodes).map((block) => block.id));
|
|
32
35
|
const compiled = {};
|
|
33
36
|
for (const tree of trees) {
|
|
34
37
|
compiled[tree.id] = compileOneFlat(tree.id, tree.header, flattenAgendaTree(tree.tree, { functions: options.functions }), withTransfer, options.functions, issues);
|
|
@@ -48,7 +51,9 @@ export function compileSequenceAgendas(schema, raw, options = {}) {
|
|
|
48
51
|
return { schema, effectiveSchema: toEffectiveSchema(schema), agendas: {}, issues };
|
|
49
52
|
}
|
|
50
53
|
const transferIds = collectTransferBlocks(agendasInput.blocks).map((block) => block.id);
|
|
51
|
-
const withTransfer = registerTransferSessionFields(schema, transferIds
|
|
54
|
+
const withTransfer = registerIvrSessionFields(registerTransferSessionFields(schema, transferIds, {
|
|
55
|
+
lastResult: collectTransferInterruptHeaders(Object.values(agendasInput.agendas).map((config) => config.header)),
|
|
56
|
+
}), collectIvrBlocks(agendasInput.blocks).map((block) => block.id));
|
|
52
57
|
const compiled = {};
|
|
53
58
|
for (const [agendaId, config] of Object.entries(agendasInput.agendas)) {
|
|
54
59
|
compiled[agendaId] = compileOneFlat(agendaId, config.header, flattenAgendaPlacements(config.placements, agendasInput.blocks, { functions: options.functions }), withTransfer, options.functions, issues);
|
package/dist/cli/serve/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { withCompanyImportGraph } from '../../builder/company-import-graph.js';
|
|
|
5
5
|
import { findTsModule } from '../../builder/paths.js';
|
|
6
6
|
import { listSequenceIds, loadSequenceCaseContextView, loadSequenceFunctions } from '../../builder/load.js';
|
|
7
7
|
import { createSourceComputeHost } from '../../compute-host/source-compute-host.js';
|
|
8
|
+
import { formatRuntimeVersion } from '../../fn-context/rpc/request-id.js';
|
|
8
9
|
import { encodeOverlayMessage, OVERLAY_REPLACED_CLOSE_CODE, parseOverlayMessage, } from '../../dev-overlay/protocol.js';
|
|
9
10
|
const DEFAULT_BACKEND_URL = 'http://127.0.0.1:8100';
|
|
10
11
|
function env(name) {
|
|
@@ -27,6 +28,20 @@ export function overlayWebSocketUrl(raw) {
|
|
|
27
28
|
url.hash = '';
|
|
28
29
|
return url.toString();
|
|
29
30
|
}
|
|
31
|
+
function overlayRpcUrl(raw) {
|
|
32
|
+
const url = new URL(raw);
|
|
33
|
+
if (url.protocol === 'ws:')
|
|
34
|
+
url.protocol = 'http:';
|
|
35
|
+
else if (url.protocol === 'wss:')
|
|
36
|
+
url.protocol = 'https:';
|
|
37
|
+
else if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
38
|
+
throw new Error(`unsupported backend url: ${raw}`);
|
|
39
|
+
}
|
|
40
|
+
url.pathname = `${url.pathname.replace(/\/$/, '')}/trpc`;
|
|
41
|
+
url.search = '';
|
|
42
|
+
url.hash = '';
|
|
43
|
+
return url.toString();
|
|
44
|
+
}
|
|
30
45
|
/** `sequences/<id>/…` → sequence id */
|
|
31
46
|
function sequenceIdFromPath(repoRoot, file) {
|
|
32
47
|
const rel = path.relative(repoRoot, file);
|
|
@@ -73,13 +88,19 @@ function send(ws, message) {
|
|
|
73
88
|
function logField(label, value) {
|
|
74
89
|
console.log(` ${label.padEnd(10)} ${value}`);
|
|
75
90
|
}
|
|
76
|
-
async function handleExecute(loaded, message) {
|
|
91
|
+
async function handleExecute(loaded, message, rpcUrl) {
|
|
92
|
+
const data = message.data
|
|
93
|
+
? {
|
|
94
|
+
...message.data,
|
|
95
|
+
config: { ...message.data.config, backendUrl: rpcUrl },
|
|
96
|
+
}
|
|
97
|
+
: undefined;
|
|
77
98
|
const host = createSourceComputeHost({
|
|
78
99
|
functions: loaded.functions,
|
|
79
100
|
caseContextView: loaded.view,
|
|
80
|
-
data:
|
|
101
|
+
data: data,
|
|
81
102
|
runToken: message.runToken,
|
|
82
|
-
runtimeVersion: loaded.build.
|
|
103
|
+
runtimeVersion: loaded.build.engineVersion,
|
|
83
104
|
runtimeSource: loaded.build.runtimeSource ?? 'npm',
|
|
84
105
|
getRequestId: () => message.logRequestId,
|
|
85
106
|
getTags: () => message.logTags,
|
|
@@ -101,14 +122,36 @@ function pushOverlays(ws, sequences) {
|
|
|
101
122
|
});
|
|
102
123
|
}
|
|
103
124
|
}
|
|
125
|
+
function closeDetail(event) {
|
|
126
|
+
return event.reason ? `${event.code} ${event.reason}` : String(event.code);
|
|
127
|
+
}
|
|
104
128
|
function waitOpen(ws) {
|
|
105
129
|
return new Promise((resolve, reject) => {
|
|
106
130
|
if (ws.readyState === WebSocket.OPEN) {
|
|
107
131
|
resolve();
|
|
108
132
|
return;
|
|
109
133
|
}
|
|
110
|
-
|
|
111
|
-
|
|
134
|
+
let settled = false;
|
|
135
|
+
const finish = (fn) => {
|
|
136
|
+
if (settled)
|
|
137
|
+
return;
|
|
138
|
+
settled = true;
|
|
139
|
+
cleanup();
|
|
140
|
+
fn();
|
|
141
|
+
};
|
|
142
|
+
const onOpen = () => finish(() => resolve());
|
|
143
|
+
const onClose = (event) => finish(() => reject(new Error(`websocket closed ${closeDetail(event)}`)));
|
|
144
|
+
const onError = () => {
|
|
145
|
+
setTimeout(() => finish(() => reject(new Error('websocket error'))), 250);
|
|
146
|
+
};
|
|
147
|
+
const cleanup = () => {
|
|
148
|
+
ws.removeEventListener('open', onOpen);
|
|
149
|
+
ws.removeEventListener('close', onClose);
|
|
150
|
+
ws.removeEventListener('error', onError);
|
|
151
|
+
};
|
|
152
|
+
ws.addEventListener('open', onOpen);
|
|
153
|
+
ws.addEventListener('close', onClose);
|
|
154
|
+
ws.addEventListener('error', onError);
|
|
112
155
|
});
|
|
113
156
|
}
|
|
114
157
|
class OverlayReplacedError extends Error {
|
|
@@ -146,7 +189,7 @@ function waitAuthOk(ws) {
|
|
|
146
189
|
cleanup();
|
|
147
190
|
reject(event.code === OVERLAY_REPLACED_CLOSE_CODE
|
|
148
191
|
? new OverlayReplacedError()
|
|
149
|
-
: new Error(
|
|
192
|
+
: new Error(`websocket closed before auth.ok ${closeDetail(event)}`));
|
|
150
193
|
};
|
|
151
194
|
const cleanup = () => {
|
|
152
195
|
ws.removeEventListener('message', onMessage);
|
|
@@ -156,7 +199,7 @@ function waitAuthOk(ws) {
|
|
|
156
199
|
ws.addEventListener('close', onClose);
|
|
157
200
|
});
|
|
158
201
|
}
|
|
159
|
-
function attachExecuteHandler(ws, sequences) {
|
|
202
|
+
function attachExecuteHandler(ws, sequences, rpcUrl) {
|
|
160
203
|
ws.addEventListener('message', (event) => {
|
|
161
204
|
void (async () => {
|
|
162
205
|
let message;
|
|
@@ -185,7 +228,7 @@ function attachExecuteHandler(ws, sequences) {
|
|
|
185
228
|
const started = Date.now();
|
|
186
229
|
console.log(`execute ${call}`);
|
|
187
230
|
try {
|
|
188
|
-
const result = await handleExecute(loaded, message);
|
|
231
|
+
const result = await handleExecute(loaded, message, rpcUrl);
|
|
189
232
|
console.log(`execute ${call} ok ${Date.now() - started}ms`);
|
|
190
233
|
send(ws, { type: 'execute.result', requestId: message.requestId, ok: true, result });
|
|
191
234
|
}
|
|
@@ -205,7 +248,7 @@ function attachExecuteHandler(ws, sequences) {
|
|
|
205
248
|
function waitSessionEnd(ws) {
|
|
206
249
|
return new Promise((resolve) => {
|
|
207
250
|
if (ws.readyState === WebSocket.CLOSED) {
|
|
208
|
-
resolve('closed');
|
|
251
|
+
resolve({ closed: 'already closed' });
|
|
209
252
|
return;
|
|
210
253
|
}
|
|
211
254
|
const onMessage = (event) => {
|
|
@@ -222,7 +265,7 @@ function waitSessionEnd(ws) {
|
|
|
222
265
|
};
|
|
223
266
|
const onClose = (event) => {
|
|
224
267
|
cleanup();
|
|
225
|
-
resolve(event.code === OVERLAY_REPLACED_CLOSE_CODE ? 'replaced' :
|
|
268
|
+
resolve(event.code === OVERLAY_REPLACED_CLOSE_CODE ? 'replaced' : { closed: closeDetail(event) });
|
|
226
269
|
};
|
|
227
270
|
const cleanup = () => {
|
|
228
271
|
ws.removeEventListener('message', onMessage);
|
|
@@ -241,6 +284,7 @@ export async function runServe(repoRoot, options = {}) {
|
|
|
241
284
|
throw new Error('SUPERPANEL_SDK_API_KEY or --api-key is required');
|
|
242
285
|
const backendUrl = options.url ?? env('SUPERPANEL_SDK_BACKEND_URL') ?? DEFAULT_BACKEND_URL;
|
|
243
286
|
const url = overlayWebSocketUrl(backendUrl);
|
|
287
|
+
const rpcUrl = overlayRpcUrl(backendUrl);
|
|
244
288
|
const sequenceIds = options.sequenceIds ?? listSequenceIds(repoRoot);
|
|
245
289
|
if (sequenceIds.length === 0) {
|
|
246
290
|
throw new Error(`No sequences with slots found under ${path.join(repoRoot, 'sequences')}`);
|
|
@@ -249,9 +293,13 @@ export async function runServe(repoRoot, options = {}) {
|
|
|
249
293
|
const sequences = await loadSequences(repoRoot, sequenceIds, generation);
|
|
250
294
|
let socket = null;
|
|
251
295
|
const names = [...sequences.keys()];
|
|
296
|
+
const firstBuild = sequences.values().next().value?.build;
|
|
252
297
|
console.log('Local overlay');
|
|
253
298
|
logField('company', companyId);
|
|
254
299
|
logField('sequences', names.join(', '));
|
|
300
|
+
if (firstBuild) {
|
|
301
|
+
logField('runtime', formatRuntimeVersion(firstBuild.engineVersion, firstBuild.runtimeSource ?? 'npm'));
|
|
302
|
+
}
|
|
255
303
|
logField('backend', backendUrl);
|
|
256
304
|
logField('websocket', url);
|
|
257
305
|
let timer;
|
|
@@ -328,14 +376,14 @@ export async function runServe(repoRoot, options = {}) {
|
|
|
328
376
|
names: [...sequences.keys()],
|
|
329
377
|
});
|
|
330
378
|
await authOk;
|
|
331
|
-
attachExecuteHandler(ws, sequences);
|
|
379
|
+
attachExecuteHandler(ws, sequences, rpcUrl);
|
|
332
380
|
pushOverlays(ws, sequences);
|
|
333
381
|
delayMs = 500;
|
|
334
382
|
console.log(`connected overlay ${url}`);
|
|
335
383
|
const end = await waitSessionEnd(ws);
|
|
336
384
|
if (end === 'replaced')
|
|
337
385
|
throw new OverlayReplacedError();
|
|
338
|
-
console.log(
|
|
386
|
+
console.log(`disconnected retrying ${end.closed}`);
|
|
339
387
|
}
|
|
340
388
|
catch (error) {
|
|
341
389
|
if (error instanceof OverlayReplacedError)
|
|
@@ -2,4 +2,6 @@ export { createLocalComputeHost, resolveComputeHost } from './compute-host.js';
|
|
|
2
2
|
export type { ComputeFnMap, ComputeHost, ComputeHostOrFns, LocalComputeHostOptions } from './compute-host.js';
|
|
3
3
|
export { createSourceComputeHost } from './source-compute-host.js';
|
|
4
4
|
export type { SourceComputeHost, SourceComputeHostOptions } from './source-compute-host.js';
|
|
5
|
+
export { readOnlyComputeNames, withReadOnlyComputeCache } from './read-only-cache.js';
|
|
6
|
+
export type { ReadOnlyComputeCacheOptions } from './read-only-cache.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { createLocalComputeHost, resolveComputeHost } from './compute-host.js';
|
|
2
2
|
export { createSourceComputeHost } from './source-compute-host.js';
|
|
3
|
+
export { readOnlyComputeNames, withReadOnlyComputeCache } from './read-only-cache.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ComputeHost } from './compute-host.js';
|
|
2
|
+
/** Names safe to cache: `caseContextView` plus every compute / boolCompute. */
|
|
3
|
+
export declare function readOnlyComputeNames(functions?: Record<string, {
|
|
4
|
+
kind: string;
|
|
5
|
+
}>): Set<string>;
|
|
6
|
+
export type ReadOnlyComputeCacheOptions = {
|
|
7
|
+
/** Defaults to `caseContextView` only. Pass {@link readOnlyComputeNames} for compute / boolCompute too. */
|
|
8
|
+
readOnly?: Iterable<string> | ((name: string) => boolean);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Cache read-only `execute` results by function name + the single input object.
|
|
12
|
+
* Calls with extra args bypass the cache so a shared snapshot cannot alias
|
|
13
|
+
* two different argument lists.
|
|
14
|
+
*
|
|
15
|
+
* Do not wrap a host used by derived recompute: that path mutates one snapshot
|
|
16
|
+
* in place between `compute` calls. Stage walk / when-eval is safe (new snapshot
|
|
17
|
+
* after writes).
|
|
18
|
+
*/
|
|
19
|
+
export declare function withReadOnlyComputeCache(host: ComputeHost, options?: ReadOnlyComputeCacheOptions): ComputeHost;
|
|
20
|
+
//# sourceMappingURL=read-only-cache.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const READ_ONLY_KINDS = new Set(['compute', 'boolCompute', 'caseContextView']);
|
|
2
|
+
/** Names safe to cache: `caseContextView` plus every compute / boolCompute. */
|
|
3
|
+
export function readOnlyComputeNames(functions) {
|
|
4
|
+
const names = new Set(['caseContextView']);
|
|
5
|
+
if (!functions)
|
|
6
|
+
return names;
|
|
7
|
+
for (const [name, entry] of Object.entries(functions)) {
|
|
8
|
+
if (READ_ONLY_KINDS.has(entry.kind))
|
|
9
|
+
names.add(name);
|
|
10
|
+
}
|
|
11
|
+
return names;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Cache read-only `execute` results by function name + the single input object.
|
|
15
|
+
* Calls with extra args bypass the cache so a shared snapshot cannot alias
|
|
16
|
+
* two different argument lists.
|
|
17
|
+
*
|
|
18
|
+
* Do not wrap a host used by derived recompute: that path mutates one snapshot
|
|
19
|
+
* in place between `compute` calls. Stage walk / when-eval is safe (new snapshot
|
|
20
|
+
* after writes).
|
|
21
|
+
*/
|
|
22
|
+
export function withReadOnlyComputeCache(host, options) {
|
|
23
|
+
const allow = resolveAllow(options?.readOnly);
|
|
24
|
+
const cache = new WeakMap();
|
|
25
|
+
return {
|
|
26
|
+
async execute(name, args = []) {
|
|
27
|
+
const input = args[0];
|
|
28
|
+
if (!allow(name) || args.length !== 1 || input == null || typeof input !== 'object') {
|
|
29
|
+
return host.execute(name, args);
|
|
30
|
+
}
|
|
31
|
+
let byName = cache.get(input);
|
|
32
|
+
if (!byName) {
|
|
33
|
+
byName = new Map();
|
|
34
|
+
cache.set(input, byName);
|
|
35
|
+
}
|
|
36
|
+
const hit = byName.get(name);
|
|
37
|
+
if (hit)
|
|
38
|
+
return hit;
|
|
39
|
+
const pending = host.execute(name, args);
|
|
40
|
+
byName.set(name, pending);
|
|
41
|
+
try {
|
|
42
|
+
return await pending;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (byName.get(name) === pending)
|
|
46
|
+
byName.delete(name);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
dispose() {
|
|
51
|
+
host.dispose();
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function resolveAllow(readOnly) {
|
|
56
|
+
if (typeof readOnly === 'function')
|
|
57
|
+
return readOnly;
|
|
58
|
+
const names = new Set(readOnly ?? ['caseContextView']);
|
|
59
|
+
return (name) => names.has(name);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=read-only-cache.js.map
|
|
@@ -49,11 +49,16 @@ export function createSourceComputeHost(options) {
|
|
|
49
49
|
const caseContext = viewFn(requireSlots(name, args));
|
|
50
50
|
const ctx = await systemContext();
|
|
51
51
|
const fn = def.main;
|
|
52
|
-
return fn(caseContext, ctx);
|
|
52
|
+
return fn(caseContext, { ...ctx, params: args[1] ?? {} });
|
|
53
53
|
}
|
|
54
54
|
const params = resolveSystemFnParams(args);
|
|
55
|
+
const contextStarted = Date.now();
|
|
55
56
|
const ctx = await systemContext();
|
|
56
|
-
|
|
57
|
+
console.log(`[source timing] ${name} context ${Date.now() - contextStarted}ms`);
|
|
58
|
+
const functionStarted = Date.now();
|
|
59
|
+
const result = await def.main({ ...ctx, params });
|
|
60
|
+
console.log(`[source timing] ${name} function ${Date.now() - functionStarted}ms`);
|
|
61
|
+
return result;
|
|
57
62
|
},
|
|
58
63
|
dispose() { },
|
|
59
64
|
};
|
|
@@ -19,7 +19,25 @@ export type Slots = Record<string, unknown>;
|
|
|
19
19
|
* With `view.ts`, use `CaseContextOf<typeof caseContextView>` from that module.
|
|
20
20
|
*/
|
|
21
21
|
export type CaseContext = Record<string, unknown>;
|
|
22
|
-
|
|
22
|
+
/** Flat writes for single-row tables, or the current-bound row of an entity table. */
|
|
23
|
+
export type FieldWrites = Record<FieldPath, unknown>;
|
|
24
|
+
/** Address one row of a multi-row table (`children`, `contact`, custom arrays). */
|
|
25
|
+
export type RowWrite = {
|
|
26
|
+
table: string;
|
|
27
|
+
rowId: string;
|
|
28
|
+
values: Record<string, unknown>;
|
|
29
|
+
};
|
|
30
|
+
/** Mix flat field writes with explicit row writes in one return. */
|
|
31
|
+
export type StructuredWrites = {
|
|
32
|
+
fields?: FieldWrites;
|
|
33
|
+
rows?: RowWrite[];
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Function / platform write payload.
|
|
37
|
+
* Flat `{ '表.字段': 值 }` for single-row (or current-party) fields;
|
|
38
|
+
* `{ table, rowId, values }` to write a specific multi-row.
|
|
39
|
+
*/
|
|
40
|
+
export type Writes = FieldWrites | RowWrite | StructuredWrites;
|
|
23
41
|
export type Logger = {
|
|
24
42
|
info: (message: string, extra?: Record<string, unknown>) => void;
|
|
25
43
|
warn: (message: string, extra?: Record<string, unknown>) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CustomFn, DefinedFunc, FuncOptions } from '../types.js';
|
|
2
2
|
import type { CaseContext } from '../../context/types.js';
|
|
3
|
-
export declare function defineCustomFunc<S = CaseContext>(main: CustomFn<S>, options?: FuncOptions): DefinedFunc;
|
|
3
|
+
export declare function defineCustomFunc<S = CaseContext, P extends object = object>(main: CustomFn<S, P>, options?: FuncOptions): DefinedFunc;
|
|
4
4
|
//# sourceMappingURL=custom.d.ts.map
|
|
@@ -6,16 +6,16 @@ export type FuncOptions = {
|
|
|
6
6
|
};
|
|
7
7
|
/** First arg is CaseContext (or Slots when the sequence has no view). */
|
|
8
8
|
export type ComputeFn<S = CaseContext, R = unknown> = (caseContext: S) => R | Promise<R>;
|
|
9
|
-
export type
|
|
9
|
+
export type FunctionCtx<Params extends object> = SystemContext & {
|
|
10
|
+
params: Params;
|
|
11
|
+
};
|
|
12
|
+
export type CustomFn<S = CaseContext, P extends object = object> = (caseContext: S, ctx: FunctionCtx<P>) => Promise<Writes | null>;
|
|
10
13
|
/** Inbound webhook request payload. */
|
|
11
14
|
export type WebHookFunctionParams = {
|
|
12
15
|
headers: Record<string, string | string[] | undefined>;
|
|
13
16
|
body: unknown;
|
|
14
17
|
rawBody?: string;
|
|
15
18
|
};
|
|
16
|
-
export type FunctionCtx<Params extends object> = SystemContext & {
|
|
17
|
-
params: Params;
|
|
18
|
-
};
|
|
19
19
|
export type FunctionCall<Params extends object, Return> = (ctx: FunctionCtx<Params>) => Promise<Return>;
|
|
20
20
|
export type WebHookFunction = FunctionCall<WebHookFunctionParams, void>;
|
|
21
21
|
export type GetFirstMessageParams<S = CaseContext> = {
|
|
@@ -9,7 +9,7 @@ export { isValidDataTypeValue, validateExtractedField, validateBareValue } from
|
|
|
9
9
|
export { buildSlotFillingJsonSchema, buildFieldCatalog, type SfSchemaOptions } from './sf-schema.js';
|
|
10
10
|
export { validateSlotFillingOutput, type ValidateSlotFillingOptions } from './sf-validate.js';
|
|
11
11
|
export { snapshotFrom, cloneSnapshot, getSingleField, getSnapshotTable, type SnapshotSeed } from './snapshot.js';
|
|
12
|
-
export { applyFieldPatch, applyWrites, applySlotFilling, markAskedUnknown, type ApplySlotFillingOptions, type FieldPatchInput, } from './write.js';
|
|
12
|
+
export { applyFieldPatch, applyWrites, applySlotFilling, markAskedUnknown, isRowWrite, isStructuredWrites, normalizeWrites, type ApplySlotFillingOptions, type FieldPatchInput, } from './write.js';
|
|
13
13
|
export type { ComputeFnMap, ComputeHost, ComputeHostOrFns, LocalComputeHostOptions, RecomputeOptions, } from './derived.js';
|
|
14
14
|
export { createLocalComputeHost, createSourceComputeHost, resolveComputeHost, recomputeDerived, applyFieldPatchAndRecompute, applyWritesAndRecompute, applySlotFillingAndRecompute, } from './derived.js';
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/slot/index.js
CHANGED
|
@@ -9,6 +9,6 @@ export { isValidDataTypeValue, validateExtractedField, validateBareValue } from
|
|
|
9
9
|
export { buildSlotFillingJsonSchema, buildFieldCatalog } from './sf-schema.js';
|
|
10
10
|
export { validateSlotFillingOutput } from './sf-validate.js';
|
|
11
11
|
export { snapshotFrom, cloneSnapshot, getSingleField, getSnapshotTable } from './snapshot.js';
|
|
12
|
-
export { applyFieldPatch, applyWrites, applySlotFilling, markAskedUnknown, } from './write.js';
|
|
12
|
+
export { applyFieldPatch, applyWrites, applySlotFilling, markAskedUnknown, isRowWrite, isStructuredWrites, normalizeWrites, } from './write.js';
|
|
13
13
|
export { createLocalComputeHost, createSourceComputeHost, resolveComputeHost, recomputeDerived, applyFieldPatchAndRecompute, applyWritesAndRecompute, applySlotFillingAndRecompute, } from './derived.js';
|
|
14
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import type { FieldState, Writes } from '../context/types.js';
|
|
1
|
+
import type { FieldState, FieldWrites, RowWrite, StructuredWrites, Writes } from '../context/types.js';
|
|
2
2
|
import type { FieldPath } from './path.js';
|
|
3
3
|
import type { ApplyWritesOptions, ApplyWritesResult, CompiledSlotSchema, RuntimeSlotsSnapshot, SlotFillingOutput, UpdatedBy } from './types.js';
|
|
4
|
+
export declare function isRowWrite(value: unknown): value is RowWrite;
|
|
5
|
+
export declare function isStructuredWrites(value: unknown): value is StructuredWrites;
|
|
6
|
+
export declare function normalizeWrites(writes: Writes | null | undefined): {
|
|
7
|
+
fields: FieldWrites;
|
|
8
|
+
rows: RowWrite[];
|
|
9
|
+
} | null;
|
|
4
10
|
/**
|
|
5
11
|
* Apply bare Writes (function / human / import / platform) onto a snapshot.
|
|
6
12
|
* Validates type/enum and write permissions. Detects C5 changes and appends history.
|
|
13
|
+
* Multi-row tables: pass `{ table, rowId, values }` (or `rows` on StructuredWrites).
|
|
7
14
|
*/
|
|
8
15
|
export declare function applyWrites(schema: CompiledSlotSchema, snapshot: RuntimeSlotsSnapshot, writes: Writes | null | undefined, options: ApplyWritesOptions): ApplyWritesResult;
|
|
9
16
|
export type FieldPatchInput = {
|