@superpanel-sdk/runtime 0.2.3 → 0.7.0
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/README.md +30 -10
- package/dist/builder/codegen/emit.d.ts +25 -12
- package/dist/builder/codegen/emit.js +339 -78
- package/dist/builder/codegen/generate.d.ts +21 -2
- package/dist/builder/codegen/generate.js +147 -34
- package/dist/builder/company-import-graph.d.ts +2 -0
- package/dist/builder/company-import-graph.js +40 -8
- package/dist/builder/company-imports.d.ts +29 -0
- package/dist/builder/company-imports.js +122 -0
- package/dist/builder/compile/compile-sequence.d.ts +61 -8
- package/dist/builder/compile/compile-sequence.js +334 -80
- package/dist/builder/compile/function-code.d.ts +19 -3
- package/dist/builder/compile/function-code.js +123 -45
- package/dist/builder/compile/registry.d.ts +7 -3
- package/dist/builder/compile/registry.js +30 -27
- package/dist/builder/errors.d.ts +9 -0
- package/dist/builder/errors.js +17 -0
- package/dist/builder/function-params.d.ts +10 -0
- package/dist/builder/function-params.js +203 -0
- package/dist/builder/load.d.ts +70 -10
- package/dist/builder/load.js +258 -67
- package/dist/builder/paths.d.ts +9 -1
- package/dist/builder/paths.js +32 -2
- package/dist/builder/schedules.d.ts +25 -0
- package/dist/builder/schedules.js +101 -0
- package/dist/builder/slot-schema-validation.d.ts +4 -0
- package/dist/builder/slot-schema-validation.js +10 -0
- package/dist/builder/typecheck.d.ts +8 -0
- package/dist/builder/typecheck.js +102 -0
- package/dist/builder/types.d.ts +127 -19
- package/dist/builder/types.js +21 -1
- package/dist/cli/auth/auth.d.ts +37 -0
- package/dist/cli/auth/auth.js +211 -0
- package/dist/cli/auth/backend-url.d.ts +5 -0
- package/dist/cli/auth/backend-url.js +25 -0
- package/dist/cli/auth/clipboard.d.ts +9 -0
- package/dist/cli/auth/clipboard.js +38 -0
- package/dist/cli/auth/http.d.ts +20 -0
- package/dist/cli/auth/http.js +27 -0
- package/dist/cli/auth/index.d.ts +10 -0
- package/dist/cli/auth/index.js +27 -0
- package/dist/cli/auth/progress.d.ts +12 -0
- package/dist/cli/auth/progress.js +15 -0
- package/dist/cli/auth/serve-login.d.ts +8 -0
- package/dist/cli/auth/serve-login.js +24 -0
- package/dist/cli/calls/index.d.ts +177 -0
- package/dist/cli/calls/index.js +96 -0
- package/dist/cli/compile/index.js +3 -0
- package/dist/cli/config.d.ts +10 -0
- package/dist/cli/config.js +52 -0
- package/dist/cli/debug/index.d.ts +31 -0
- package/dist/cli/debug/index.js +119 -0
- package/dist/cli/exec/index.d.ts +39 -0
- package/dist/cli/exec/index.js +138 -0
- package/dist/cli/exec/session.d.ts +48 -0
- package/dist/cli/exec/session.js +82 -0
- package/dist/cli/exec/trace.d.ts +18 -0
- package/dist/cli/exec/trace.js +52 -0
- package/dist/cli/index.js +112 -9
- package/dist/cli/logs/index.d.ts +47 -0
- package/dist/cli/logs/index.js +113 -0
- package/dist/cli/mobile/index.d.ts +12 -0
- package/dist/cli/mobile/index.js +405 -0
- package/dist/cli/serve/index.d.ts +109 -3
- package/dist/cli/serve/index.js +506 -118
- package/dist/cli/turns/index.d.ts +105 -0
- package/dist/cli/turns/index.js +128 -0
- package/dist/cli/turns/run.d.ts +13 -0
- package/dist/cli/turns/run.js +57 -0
- package/dist/cli/turns/shadow.d.ts +112 -0
- package/dist/cli/turns/shadow.js +54 -0
- package/dist/cli/type-gen/index.js +9 -9
- package/dist/compiler.d.ts +7 -0
- package/dist/compiler.js +7 -0
- package/dist/compute-host/compute-host.d.ts +14 -23
- package/dist/compute-host/compute-host.js +18 -30
- package/dist/compute-host/index.d.ts +2 -4
- package/dist/compute-host/index.js +1 -2
- package/dist/compute-host/source-compute-host.d.ts +10 -10
- package/dist/compute-host/source-compute-host.js +33 -40
- package/dist/core/case-orchestrator/contact-hours.d.ts +70 -0
- package/dist/core/case-orchestrator/contact-hours.js +127 -0
- package/dist/core/case-orchestrator/index.d.ts +3 -0
- package/dist/core/case-orchestrator/index.js +3 -0
- package/dist/core/case-orchestrator/render.d.ts +75 -0
- package/dist/core/case-orchestrator/render.js +244 -0
- package/dist/core/case-orchestrator/time.d.ts +11 -0
- package/dist/core/case-orchestrator/time.js +29 -0
- package/dist/core/case-orchestrator/types.d.ts +708 -0
- package/dist/core/case-orchestrator/types.js +42 -0
- package/dist/core/context/call.d.ts +291 -0
- package/dist/core/context/call.js +94 -0
- package/dist/core/context/channels.d.ts +60 -0
- package/dist/core/context/channels.js +35 -0
- package/dist/core/context/contact.d.ts +96 -6
- package/dist/core/context/contact.js +48 -2
- package/dist/core/context/email-message.d.ts +198 -0
- package/dist/core/context/email-message.js +86 -0
- package/dist/core/context/email.d.ts +109 -0
- package/dist/core/context/email.js +90 -0
- package/dist/core/context/exchanges.d.ts +167 -0
- package/dist/core/context/exchanges.js +81 -0
- package/dist/core/context/instances.d.ts +307 -0
- package/dist/core/context/instances.js +137 -0
- package/dist/core/context/kv.d.ts +113 -0
- package/dist/core/context/kv.js +60 -0
- package/dist/core/context/platform-registry.d.ts +544 -4
- package/dist/core/context/platform-registry.js +14 -2
- package/dist/core/context/platform.d.ts +2 -1
- package/dist/core/context/sms.d.ts +177 -0
- package/dist/core/context/sms.js +77 -0
- package/dist/core/context/types.d.ts +79 -48
- package/dist/core/context/types.js +1 -7
- package/dist/core/conversation/index.d.ts +85 -0
- package/dist/core/conversation/index.js +133 -0
- package/dist/core/functions/errors.d.ts +74 -0
- package/dist/core/functions/errors.js +26 -0
- package/dist/core/functions/events.d.ts +192 -0
- package/dist/core/functions/events.js +23 -0
- package/dist/core/functions/schedules.d.ts +50 -0
- package/dist/core/functions/schedules.js +20 -0
- package/dist/core/functions/types.d.ts +29 -73
- package/dist/core/functions/types.js +1 -4
- package/dist/core/office-hours/index.d.ts +39 -0
- package/dist/core/office-hours/index.js +187 -0
- package/dist/core/page/define.d.ts +904 -0
- package/dist/core/page/define.js +518 -0
- package/dist/core/page/envelope.d.ts +55 -0
- package/dist/core/page/envelope.js +4 -0
- package/dist/core/page/fns.d.ts +448 -0
- package/dist/core/page/fns.js +539 -0
- package/dist/core/page/memory-reader.d.ts +27 -0
- package/dist/core/page/memory-reader.js +299 -0
- package/dist/core/page/ops.d.ts +58 -0
- package/dist/core/page/ops.js +220 -0
- package/dist/core/page/page-host.d.ts +20 -0
- package/dist/core/page/page-host.js +57 -0
- package/dist/core/page/records-query.d.ts +234 -0
- package/dist/core/page/records-query.js +780 -0
- package/dist/core/page/render.d.ts +295 -0
- package/dist/core/page/render.js +1060 -0
- package/dist/core/page/sandbox.d.ts +85 -0
- package/dist/core/page/sandbox.js +357 -0
- package/dist/core/page/time-format.d.ts +46 -0
- package/dist/core/page/time-format.js +125 -0
- package/dist/core/page/timeline.d.ts +40 -0
- package/dist/core/page/timeline.js +2 -0
- package/dist/core/page/typed.d.ts +648 -0
- package/dist/core/page/typed.js +2 -0
- package/dist/core/page/workspace.d.ts +57 -0
- package/dist/core/page/workspace.js +266 -0
- package/dist/core/party/index.d.ts +3 -0
- package/dist/core/party/index.js +3 -0
- package/dist/core/party/schema.d.ts +208 -0
- package/dist/core/party/schema.js +113 -0
- package/dist/core/party/types.d.ts +35 -0
- package/dist/core/party/types.js +15 -0
- package/dist/core/sequence/define.d.ts +56 -0
- package/dist/core/sequence/define.js +10 -0
- package/dist/core/sequence/index.d.ts +63 -0
- package/dist/core/sequence/index.js +231 -0
- package/dist/core/slot/binding.d.ts +40 -0
- package/dist/core/slot/binding.js +2 -0
- package/dist/core/slot/company-metadata.d.ts +102 -0
- package/dist/core/slot/company-metadata.js +536 -0
- package/dist/core/slot/compile-schema.d.ts +19 -13
- package/dist/core/slot/compile-schema.js +51 -248
- package/dist/core/slot/contact-timezone.d.ts +110 -0
- package/dist/core/slot/contact-timezone.js +186 -0
- package/dist/core/slot/field.d.ts +2 -25
- package/dist/core/slot/field.js +0 -71
- package/dist/core/slot/id-ref.d.ts +17 -2
- package/dist/core/slot/id-ref.js +16 -8
- package/dist/core/slot/index.d.ts +12 -13
- package/dist/core/slot/index.js +11 -12
- package/dist/core/slot/naming.d.ts +15 -0
- package/dist/core/slot/naming.js +96 -0
- package/dist/core/slot/platform-fields.d.ts +119 -0
- package/dist/core/slot/platform-fields.js +121 -0
- package/dist/core/slot/ref.d.ts +16 -0
- package/dist/core/slot/ref.js +14 -0
- package/dist/core/slot/row.d.ts +2 -9
- package/dist/core/slot/row.js +13 -23
- package/dist/core/slot/schema-compat.d.ts +17 -0
- package/dist/core/slot/schema-compat.js +103 -0
- package/dist/core/slot/schema.d.ts +353 -76
- package/dist/core/slot/schema.js +163 -10
- package/dist/core/slot/types.d.ts +30 -103
- package/dist/core/slot/value.d.ts +28 -3
- package/dist/core/slot/value.js +93 -57
- package/dist/dev-overlay/protocol.d.ts +74 -8
- package/dist/fn-context/build-context.d.ts +3 -1
- package/dist/fn-context/build-context.js +26 -10
- package/dist/fn-context/fake/empty-api.js +9 -28
- package/dist/fn-context/fake/index.d.ts +13 -4
- package/dist/fn-context/fake/index.js +29 -2
- package/dist/fn-context/fn-params.d.ts +3 -0
- package/dist/fn-context/fn-params.js +10 -0
- package/dist/fn-context/index.d.ts +5 -5
- package/dist/fn-context/index.js +4 -4
- package/dist/fn-context/log.js +2 -2
- package/dist/fn-context/make-ctx.d.ts +11 -0
- package/dist/fn-context/make-ctx.js +20 -9
- package/dist/fn-context/rpc/case-orchestrator-tools.d.ts +32 -0
- package/dist/fn-context/rpc/case-orchestrator-tools.js +12 -0
- package/dist/fn-context/rpc/errors.d.ts +13 -0
- package/dist/fn-context/rpc/errors.js +22 -0
- package/dist/fn-context/rpc/index.d.ts +4 -2
- package/dist/fn-context/rpc/index.js +4 -2
- package/dist/fn-context/rpc/integration/index.d.ts +15 -5
- package/dist/fn-context/rpc/integration/index.js +1 -1
- package/dist/fn-context/rpc/integration/list-surfaces.d.ts +21 -0
- package/dist/fn-context/rpc/integration/{list-bindings.js → list-surfaces.js} +4 -4
- package/dist/fn-context/rpc/log.d.ts +11 -1
- package/dist/fn-context/rpc/platform.d.ts +13 -3
- package/dist/fn-context/rpc/platform.js +1 -1
- package/dist/fn-context/rpc/records.d.ts +85 -0
- package/dist/fn-context/rpc/records.js +24 -0
- package/dist/fn-context/rpc/trpc-client.d.ts +44 -2
- package/dist/fn-context/rpc/trpc-client.js +222 -12
- package/dist/fn-context/rpc/trpc-init.d.ts +21 -3
- package/dist/fn-context/rpc/trpc-init.js +10 -4
- package/dist/fn-context/rpc/trpc-router-factory.d.ts +111 -7
- package/dist/fn-context/rpc/trpc-router-factory.js +2 -0
- package/dist/fn-context/run-scope.d.ts +4 -0
- package/dist/fn-context/run-scope.js +9 -0
- package/dist/fn-context/types.d.ts +52 -5
- package/dist/index.d.ts +36 -46
- package/dist/index.js +30 -33
- package/dist/logger.d.ts +11 -0
- package/dist/logger.js +49 -0
- package/dist/platform.d.ts +75 -0
- package/dist/platform.js +57 -0
- package/dist/testing-compile-child.d.ts +2 -0
- package/dist/testing-compile-child.js +20 -0
- package/dist/testing.d.ts +368 -0
- package/dist/testing.js +439 -0
- package/dist/voice-service/actions.d.ts +50 -6
- package/dist/voice-service/index.d.ts +2 -0
- package/dist/voice-service/index.js +2 -0
- package/dist/voice-service/protocol.d.ts +604 -0
- package/dist/voice-service/protocol.js +67 -0
- package/dist/voice-service/types.d.ts +55 -8
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +11 -0
- package/package.json +38 -15
- package/dist/builder/compile/compile-agenda.d.ts +0 -15
- package/dist/builder/compile/compile-agenda.js +0 -64
- package/dist/builder/merge.d.ts +0 -4
- package/dist/builder/merge.js +0 -19
- package/dist/compute-host/read-only-cache.d.ts +0 -20
- package/dist/compute-host/read-only-cache.js +0 -61
- package/dist/core/context/db.d.ts +0 -69
- package/dist/core/context/db.js +0 -44
- package/dist/core/context/docusign.d.ts +0 -134
- package/dist/core/context/docusign.js +0 -108
- package/dist/core/context/filevine.d.ts +0 -323
- package/dist/core/context/filevine.js +0 -254
- package/dist/core/context/http.d.ts +0 -9
- package/dist/core/context/http.js +0 -4
- package/dist/core/context/hubspot.d.ts +0 -250
- package/dist/core/context/hubspot.js +0 -191
- package/dist/core/context/twilio.d.ts +0 -50
- package/dist/core/context/twilio.js +0 -42
- package/dist/core/functions/define/case-context.d.ts +0 -14
- package/dist/core/functions/define/case-context.js +0 -15
- package/dist/core/functions/define/compute.d.ts +0 -7
- package/dist/core/functions/define/compute.js +0 -17
- package/dist/core/functions/define/custom.d.ts +0 -4
- package/dist/core/functions/define/custom.js +0 -8
- package/dist/core/functions/define/system.d.ts +0 -7
- package/dist/core/functions/define/system.js +0 -12
- package/dist/core/functions/func-ref.d.ts +0 -16
- package/dist/core/functions/func-ref.js +0 -20
- package/dist/core/slot/deps.d.ts +0 -15
- package/dist/core/slot/deps.js +0 -88
- package/dist/core/slot/derived.d.ts +0 -32
- package/dist/core/slot/derived.js +0 -115
- package/dist/core/slot/platform-session-fields.d.ts +0 -38
- package/dist/core/slot/platform-session-fields.js +0 -48
- package/dist/core/slot/sf-schema.d.ts +0 -23
- package/dist/core/slot/sf-schema.js +0 -125
- package/dist/core/slot/sf-validate.d.ts +0 -14
- package/dist/core/slot/sf-validate.js +0 -132
- package/dist/core/slot/snapshot.d.ts +0 -18
- package/dist/core/slot/snapshot.js +0 -138
- package/dist/core/slot/write.d.ts +0 -48
- package/dist/core/slot/write.js +0 -426
- package/dist/core/stage/builders.d.ts +0 -54
- package/dist/core/stage/builders.js +0 -31
- package/dist/core/stage/condition.d.ts +0 -17
- package/dist/core/stage/condition.js +0 -198
- package/dist/core/stage/drive.d.ts +0 -43
- package/dist/core/stage/drive.js +0 -78
- package/dist/core/stage/finish-when.d.ts +0 -20
- package/dist/core/stage/finish-when.js +0 -82
- package/dist/core/stage/flatten.d.ts +0 -27
- package/dist/core/stage/flatten.js +0 -466
- package/dist/core/stage/index.d.ts +0 -15
- package/dist/core/stage/index.js +0 -13
- package/dist/core/stage/interrupts.d.ts +0 -28
- package/dist/core/stage/interrupts.js +0 -120
- package/dist/core/stage/ivr-fields.d.ts +0 -9
- package/dist/core/stage/ivr-fields.js +0 -75
- package/dist/core/stage/simulate.d.ts +0 -24
- package/dist/core/stage/simulate.js +0 -33
- package/dist/core/stage/transfer-fields.d.ts +0 -19
- package/dist/core/stage/transfer-fields.js +0 -129
- package/dist/core/stage/transfer-spec.d.ts +0 -48
- package/dist/core/stage/transfer-spec.js +0 -113
- package/dist/core/stage/types.d.ts +0 -208
- package/dist/core/stage/types.js +0 -2
- package/dist/core/stage/validate.d.ts +0 -11
- package/dist/core/stage/validate.js +0 -330
- package/dist/core/stage/walk.d.ts +0 -39
- package/dist/core/stage/walk.js +0 -119
- package/dist/fn-context/rpc/integration/list-bindings.d.ts +0 -21
- package/dist/fn-context/system-args.d.ts +0 -6
- package/dist/fn-context/system-args.js +0 -14
|
@@ -1,35 +1,65 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
export function defineSystemFunc(main, options) {
|
|
15
|
-
return { kind: 'system', main, ...options };
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { companyRepoRoot } from '../company-import-graph.js';
|
|
6
|
+
import { RUNTIME_PACKAGE, companyImportError, packageRootOf, realPath, resolvedIssue, specifierIssue, } from '../company-imports.js';
|
|
7
|
+
/**
|
|
8
|
+
* A module of this runtime as a bundle takes it: `<name>.js` next to this module in the published
|
|
9
|
+
* package, `<name>.ts` in the source tree.
|
|
10
|
+
*/
|
|
11
|
+
function runtimeModule(name) {
|
|
12
|
+
const base = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../${name}`);
|
|
13
|
+
return existsSync(`${base}.js`) ? `${base}.js` : `${base}.ts`;
|
|
16
14
|
}
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
/** The bundle's entry: the compile's own code next to the company module, importing it. */
|
|
16
|
+
const ENTRY_FILE = 'superpanel-function-entry.ts';
|
|
17
|
+
/** Marks a resolve the plugin asked for itself, so it does not check its own request. */
|
|
18
|
+
const CHECKED = Symbol('company import checked');
|
|
19
|
+
/** Whether `file` is the company's own code: in the repository, outside its dependencies, not the compile's entry. */
|
|
20
|
+
function companyFileCheck(repoRoot, entryFile) {
|
|
21
|
+
const root = realPath(repoRoot);
|
|
22
|
+
return (file) => {
|
|
23
|
+
// The entry is the compile's own (it picks the export and the page's `pageEntry`), not the company's.
|
|
24
|
+
if (!path.isAbsolute(file) || file === entryFile)
|
|
25
|
+
return false;
|
|
26
|
+
const relative = path.relative(root, realPath(file));
|
|
27
|
+
return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative) && !relative.split(path.sep).includes('node_modules');
|
|
28
|
+
};
|
|
19
29
|
}
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Checks every import a company file makes (company-imports.ts) and bundles `@superpanel-sdk/runtime` as
|
|
32
|
+
* this runtime's own company API (`src/index.ts`): a code string carries the helpers of the runtime that
|
|
33
|
+
* compiled it, whichever copy the repository would resolve, and keeps of them only what it uses.
|
|
34
|
+
*/
|
|
35
|
+
function companyImportsPlugin(repoRoot, isCompanyFile) {
|
|
22
36
|
return {
|
|
23
|
-
name: 'superpanel-
|
|
37
|
+
name: 'superpanel-company-imports',
|
|
24
38
|
setup(build) {
|
|
25
|
-
build.onResolve({ filter:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
40
|
+
if (args.pluginData === CHECKED || !isCompanyFile(args.importer))
|
|
41
|
+
return undefined;
|
|
42
|
+
const refuse = (issue) => ({
|
|
43
|
+
errors: [{ text: companyImportError(args.importer, repoRoot, issue).message }],
|
|
44
|
+
});
|
|
45
|
+
const issue = specifierIssue(args.path);
|
|
46
|
+
if (issue)
|
|
47
|
+
return refuse(issue);
|
|
48
|
+
if (args.path === RUNTIME_PACKAGE)
|
|
49
|
+
return { path: runtimeModule('index') };
|
|
50
|
+
const resolved = await build.resolve(args.path, {
|
|
51
|
+
kind: args.kind,
|
|
52
|
+
importer: args.importer,
|
|
53
|
+
resolveDir: args.resolveDir,
|
|
54
|
+
pluginData: CHECKED,
|
|
55
|
+
});
|
|
56
|
+
if (resolved.errors.length > 0)
|
|
57
|
+
return { errors: resolved.errors };
|
|
58
|
+
const resolvedProblem = resolvedIssue(args.path, resolved.path, repoRoot);
|
|
59
|
+
if (resolvedProblem)
|
|
60
|
+
return refuse(resolvedProblem);
|
|
61
|
+
return { path: resolved.path, namespace: resolved.namespace, sideEffects: resolved.sideEffects, suffix: resolved.suffix };
|
|
62
|
+
});
|
|
33
63
|
},
|
|
34
64
|
};
|
|
35
65
|
}
|
|
@@ -47,13 +77,8 @@ export async function compileFunctionCode(fn) {
|
|
|
47
77
|
logLevel: 'silent',
|
|
48
78
|
});
|
|
49
79
|
const text = result.code.trim();
|
|
50
|
-
if (text.includes('@superpanel-sdk/runtime')
|
|
51
|
-
|
|
52
|
-
text.includes('defineCustomFunc') ||
|
|
53
|
-
text.includes('defineBoolComputeFunc') ||
|
|
54
|
-
text.includes('defineSystemFunc') ||
|
|
55
|
-
text.includes('defineCaseContext')) {
|
|
56
|
-
throw new Error('compiled function code still references define* / @superpanel-sdk/runtime');
|
|
80
|
+
if (text.includes('@superpanel-sdk/runtime')) {
|
|
81
|
+
throw new Error('compiled function code still references @superpanel-sdk/runtime');
|
|
57
82
|
}
|
|
58
83
|
const m = /^export\s+default\s*/.exec(text);
|
|
59
84
|
if (!m) {
|
|
@@ -61,40 +86,93 @@ export async function compileFunctionCode(fn) {
|
|
|
61
86
|
}
|
|
62
87
|
return text.slice(m[0].length).replace(/;?\s*$/, '');
|
|
63
88
|
}
|
|
64
|
-
|
|
89
|
+
/** The wrapper around the bundle: the code is one expression, and starts on line 2 (an evaluator's `(` shifts no frame). */
|
|
90
|
+
const BUNDLE_HEAD = '(()=>{';
|
|
91
|
+
const BUNDLE_TAIL = ';return __superpanel_function.default})()';
|
|
92
|
+
async function compileModuleSelection(modulePath, selection, imports = '') {
|
|
93
|
+
// The compile bundles inside its import graph; a caller outside one (a test) bundles within the module's package.
|
|
94
|
+
// Its real path: the map's sources are relative to it, as esbuild resolves files through symlinks.
|
|
95
|
+
const repoRoot = realPath(companyRepoRoot() ?? packageRootOf(modulePath));
|
|
96
|
+
const entryFile = path.join(realPath(path.dirname(modulePath)), ENTRY_FILE);
|
|
97
|
+
const isCompanyFile = companyFileCheck(repoRoot, entryFile);
|
|
65
98
|
const result = await esbuild.build({
|
|
66
99
|
stdin: {
|
|
67
100
|
contents: `import * as mod from ${JSON.stringify(modulePath)};
|
|
101
|
+
${imports}
|
|
68
102
|
const selected = ${selection};
|
|
69
103
|
export default selected;`,
|
|
70
|
-
resolveDir: path.dirname(
|
|
71
|
-
sourcefile:
|
|
104
|
+
resolveDir: path.dirname(entryFile),
|
|
105
|
+
sourcefile: ENTRY_FILE,
|
|
72
106
|
loader: 'ts',
|
|
73
107
|
},
|
|
108
|
+
absWorkingDir: repoRoot,
|
|
74
109
|
bundle: true,
|
|
75
110
|
write: false,
|
|
111
|
+
outfile: 'superpanel-function.js',
|
|
76
112
|
platform: 'neutral',
|
|
77
113
|
format: 'iife',
|
|
78
114
|
globalName: '__superpanel_function',
|
|
79
115
|
target: 'es2022',
|
|
80
116
|
minify: true,
|
|
117
|
+
// Functions keep their own names: a stack frame's name is the running function's, which a source
|
|
118
|
+
// map cannot give back (its `names` say what each renamed identifier was, not which function a
|
|
119
|
+
// position is in). The company Worker's own bundle keeps them too (`keep_names`).
|
|
120
|
+
keepNames: true,
|
|
81
121
|
logLevel: 'silent',
|
|
82
|
-
|
|
122
|
+
banner: { js: BUNDLE_HEAD },
|
|
123
|
+
footer: { js: BUNDLE_TAIL },
|
|
124
|
+
sourcemap: 'external',
|
|
125
|
+
sourcesContent: false,
|
|
126
|
+
plugins: [companyImportsPlugin(repoRoot, isCompanyFile)],
|
|
83
127
|
});
|
|
84
|
-
const
|
|
85
|
-
|
|
128
|
+
const code = result.outputFiles.find((file) => file.path.endsWith('.js'))?.text.trim();
|
|
129
|
+
const map = result.outputFiles.find((file) => file.path.endsWith('.js.map'))?.text;
|
|
130
|
+
if (!code || !map) {
|
|
86
131
|
throw new Error(`Failed to compile function module ${modulePath}`);
|
|
87
132
|
}
|
|
88
|
-
return
|
|
133
|
+
return { code, map: companySourceMap(JSON.parse(map), repoRoot, isCompanyFile) };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The map as the platform keeps it: the company's files by their path from the repository root, every
|
|
137
|
+
* other source `null` (no platform paths, and smaller), and only what a stack lookup reads.
|
|
138
|
+
*/
|
|
139
|
+
function companySourceMap(map, repoRoot, isCompanyFile) {
|
|
140
|
+
return {
|
|
141
|
+
version: 3,
|
|
142
|
+
sources: map.sources.map((source) => (source !== null && isCompanyFile(path.resolve(repoRoot, source)) ? source : null)),
|
|
143
|
+
names: map.names,
|
|
144
|
+
mappings: map.mappings,
|
|
145
|
+
};
|
|
89
146
|
}
|
|
90
147
|
/** Bundle one registered function with module-local helpers and constants. */
|
|
91
148
|
export function compileFunctionModuleCode(modulePath, functionName) {
|
|
92
149
|
const registry = `(mod.functions ?? mod.default?.functions ?? mod.default)`;
|
|
93
|
-
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(functionName)}]
|
|
150
|
+
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(functionName)}]`);
|
|
151
|
+
}
|
|
152
|
+
/** Bundle one event handler (a plain function under the `events` export) with module-local helpers. */
|
|
153
|
+
export function compileEventModuleCode(modulePath, eventName) {
|
|
154
|
+
const registry = `(mod.events ?? mod.default?.events ?? mod.default)`;
|
|
155
|
+
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(eventName)}]`);
|
|
94
156
|
}
|
|
95
|
-
/** Bundle
|
|
96
|
-
export function
|
|
97
|
-
const
|
|
98
|
-
return compileModuleSelection(modulePath,
|
|
157
|
+
/** Bundle one job's `run` of a `schedules.ts` (25 §6.4) with module-local helpers. */
|
|
158
|
+
export function compileScheduleModuleCode(modulePath, scheduleName) {
|
|
159
|
+
const registry = `(mod.schedules ?? mod.default?.schedules ?? mod.default)`;
|
|
160
|
+
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(scheduleName)}].run`);
|
|
161
|
+
}
|
|
162
|
+
/** Bundle a module's named export (a function) with its helpers. */
|
|
163
|
+
export function compileExportModuleCode(modulePath, exportName) {
|
|
164
|
+
return compileModuleSelection(modulePath, `(mod[${JSON.stringify(exportName)}] ?? mod.default)`);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Bundle a sequence's page script (`context.page.ts`, 15 §10.2) with its helpers, and its page actions
|
|
168
|
+
* (`actions.ts`, 76 §2.11) when it has them: the result evaluates to `pageEntry(module, actions)`, which
|
|
169
|
+
* renders the page or runs one of its actions (`core/page/define.ts`).
|
|
170
|
+
*/
|
|
171
|
+
export function compilePageModuleCode(modulePath, actionsPath = null) {
|
|
172
|
+
const imports = [
|
|
173
|
+
`import { pageEntry } from ${JSON.stringify(runtimeModule('core/page/define'))};`,
|
|
174
|
+
...(actionsPath ? [`import * as actionsModule from ${JSON.stringify(actionsPath)};`] : []),
|
|
175
|
+
].join('\n');
|
|
176
|
+
return compileModuleSelection(modulePath, actionsPath ? 'pageEntry(mod, actionsModule)' : 'pageEntry(mod, null)', imports);
|
|
99
177
|
}
|
|
100
178
|
//# sourceMappingURL=function-code.js.map
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type AnyEventHandlers } from '../../core/functions/events.js';
|
|
2
|
+
import type { FuncMap, FunctionRegistry } from '../../core/functions/types.js';
|
|
3
|
+
import type { FunctionSourceMap } from '../types.js';
|
|
2
4
|
export type BuildRegistryOptions = {
|
|
3
5
|
/** When false, skip esbuild and omit `code` (local serve overlay). Default true. */
|
|
4
6
|
includeCode?: boolean;
|
|
5
7
|
/** Source module used to bundle module-local helpers and constants. */
|
|
6
8
|
modulePath?: string;
|
|
9
|
+
/** Receives each function's source map by name (a module's bundle only): kept out of the registry. */
|
|
10
|
+
sourceMaps?: Record<string, FunctionSourceMap>;
|
|
7
11
|
};
|
|
8
12
|
/**
|
|
9
13
|
* Project author FuncMap → JSON-safe registry.
|
|
10
14
|
* Published builds include per-function compiled `code`; overlay omits it.
|
|
11
15
|
*/
|
|
12
16
|
export declare function toFunctionRegistry(functions: FuncMap, options?: BuildRegistryOptions): Promise<FunctionRegistry>;
|
|
13
|
-
/**
|
|
14
|
-
export declare function
|
|
17
|
+
/** Project the company `events` export → JSON-safe registry: each handler by its event's name. */
|
|
18
|
+
export declare function toEventRegistry(events: AnyEventHandlers, options?: BuildRegistryOptions): Promise<FunctionRegistry>;
|
|
15
19
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isSystemEventName } from '../../core/functions/events.js';
|
|
2
|
+
import { compileEventModuleCode, compileFunctionCode, compileFunctionModuleCode } from './function-code.js';
|
|
3
|
+
/** The bundle's code; its map goes to `sourceMaps`. */
|
|
4
|
+
function keepMap(name, compiled, sourceMaps) {
|
|
5
|
+
if (sourceMaps)
|
|
6
|
+
sourceMaps[name] = compiled.map;
|
|
7
|
+
return compiled.code;
|
|
8
|
+
}
|
|
3
9
|
function withCode(entry, code) {
|
|
4
10
|
if (code === undefined)
|
|
5
11
|
return entry;
|
|
@@ -12,37 +18,34 @@ function withCode(entry, code) {
|
|
|
12
18
|
export async function toFunctionRegistry(functions, options = {}) {
|
|
13
19
|
const includeCode = options.includeCode ?? true;
|
|
14
20
|
const out = {};
|
|
15
|
-
for (const [name,
|
|
21
|
+
for (const [name, fn] of Object.entries(functions)) {
|
|
16
22
|
const code = includeCode
|
|
17
23
|
? options.modulePath
|
|
18
|
-
? await compileFunctionModuleCode(options.modulePath, name)
|
|
19
|
-
: await compileFunctionCode(
|
|
24
|
+
? keepMap(name, await compileFunctionModuleCode(options.modulePath, name), options.sourceMaps)
|
|
25
|
+
: await compileFunctionCode(fn)
|
|
20
26
|
: undefined;
|
|
21
|
-
|
|
22
|
-
if (def.kind === 'custom') {
|
|
23
|
-
entry = withCode({ kind: 'custom', writes: [] }, code);
|
|
24
|
-
}
|
|
25
|
-
else if (def.kind === 'system') {
|
|
26
|
-
entry = withCode({ kind: 'system' }, code);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
entry = withCode({ kind: def.kind }, code);
|
|
30
|
-
}
|
|
31
|
-
out[name] = entry;
|
|
27
|
+
out[name] = withCode({}, code);
|
|
32
28
|
}
|
|
33
29
|
return out;
|
|
34
30
|
}
|
|
35
|
-
/**
|
|
36
|
-
export async function
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
/** Project the company `events` export → JSON-safe registry: each handler by its event's name. */
|
|
32
|
+
export async function toEventRegistry(events, options = {}) {
|
|
33
|
+
const includeCode = options.includeCode ?? true;
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const [name, handler] of Object.entries(events)) {
|
|
36
|
+
if (!isSystemEventName(name)) {
|
|
37
|
+
throw new Error(`events: '${name}' is not a platform event`);
|
|
38
|
+
}
|
|
39
|
+
if (typeof handler !== 'function') {
|
|
40
|
+
throw new Error(`events: handler for '${name}' must be a function`);
|
|
41
|
+
}
|
|
42
|
+
const code = includeCode
|
|
43
|
+
? options.modulePath
|
|
44
|
+
? keepMap(name, await compileEventModuleCode(options.modulePath, name), options.sourceMaps)
|
|
45
|
+
: await compileFunctionCode(handler)
|
|
46
|
+
: undefined;
|
|
47
|
+
out[name] = withCode({}, code);
|
|
42
48
|
}
|
|
43
|
-
|
|
44
|
-
? await compileCaseContextViewModuleCode(options.modulePath)
|
|
45
|
-
: await compileFunctionCode(fn);
|
|
46
|
-
return { kind: 'caseContextView', code };
|
|
49
|
+
return out;
|
|
47
50
|
}
|
|
48
51
|
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FuncMap } from '../core/functions/types.js';
|
|
2
|
+
/** The repository root's `errors.ts`, loaded: its `onError`, what serve runs. `null` without the file. */
|
|
3
|
+
export type LoadedOnError = {
|
|
4
|
+
path: string;
|
|
5
|
+
functions: FuncMap;
|
|
6
|
+
};
|
|
7
|
+
/** Load and check the repository root's `errors.ts` (67 §5): it exports `onError`, a function. */
|
|
8
|
+
export declare function loadOnError(repoRoot: string): Promise<LoadedOnError | null>;
|
|
9
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { pathToFileURL } from 'node:url';
|
|
2
|
+
import { ERRORS_MODULE, ON_ERROR_FUNCTION } from '../core/functions/errors.js';
|
|
3
|
+
import { companyImportGraphHref } from './company-import-graph.js';
|
|
4
|
+
import { findTsModule } from './paths.js';
|
|
5
|
+
/** Load and check the repository root's `errors.ts` (67 §5): it exports `onError`, a function. */
|
|
6
|
+
export async function loadOnError(repoRoot) {
|
|
7
|
+
const modulePath = findTsModule(repoRoot, ERRORS_MODULE);
|
|
8
|
+
if (!modulePath)
|
|
9
|
+
return null;
|
|
10
|
+
const mod = (await import(companyImportGraphHref(pathToFileURL(modulePath).href)));
|
|
11
|
+
const onError = mod[ON_ERROR_FUNCTION] ?? mod.default;
|
|
12
|
+
if (typeof onError !== 'function') {
|
|
13
|
+
throw new Error(`${ERRORS_MODULE}.ts: export const ${ON_ERROR_FUNCTION}: OnError = async (ctx, { error }) => { … } (67 §5)`);
|
|
14
|
+
}
|
|
15
|
+
return { path: modulePath, functions: { [ON_ERROR_FUNCTION]: onError } };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ActionParameters } from '../core/page/define.js';
|
|
2
|
+
export declare class FunctionParamsError extends Error {
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* The parameters of every function in `exportName` of `modulePath`, by its key. A function with no
|
|
6
|
+
* second parameter takes none (`{ type: 'object', properties: {} }`). A `define*` result (no call
|
|
7
|
+
* signature) is left out: it declares its own.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readFunctionParameters(modulePath: string, exportName: string): Record<string, ActionParameters>;
|
|
10
|
+
//# sourceMappingURL=function-params.d.ts.map
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { API, SignatureKind, SymbolFlags, TypeFlags, } from 'typescript/unstable/sync';
|
|
4
|
+
/**
|
|
5
|
+
* A function's parameters from its TypeScript type (38 §2.4): the builder reads the second parameter of
|
|
6
|
+
* each function in a registry export (`functions`, `actions` of `actions.ts`) as the pinned TypeScript's checker
|
|
7
|
+
* sees it, expanded, and writes what the AI sees of it. Whatever falls outside the types below is the
|
|
8
|
+
* author's mistake, said with the type to use instead.
|
|
9
|
+
*/
|
|
10
|
+
/** The marks `Id<T>` and the format types carry (`core/page/typed.ts`), as the checker names them. */
|
|
11
|
+
const ID_MARK = /^__@ID_BRAND@/;
|
|
12
|
+
const FORMAT_MARK = /^__@FORMAT_BRAND@/;
|
|
13
|
+
const FORMATS = new Set(['date', 'datetime', 'time', 'phone', 'email']);
|
|
14
|
+
const PARAMETER_TYPES = "string, number, boolean, literals ('a' | 'b'), Id<'table'>, IsoDate, IsoDateTime, TimeOfDay, Phone, Email, ContactSchedule, a list or an object";
|
|
15
|
+
export class FunctionParamsError extends Error {
|
|
16
|
+
}
|
|
17
|
+
/** The repository's `tsconfig.json`: the nearest one above the module. */
|
|
18
|
+
function tsconfigOf(modulePath) {
|
|
19
|
+
for (let dir = path.dirname(modulePath);; dir = path.dirname(dir)) {
|
|
20
|
+
const candidate = path.join(dir, 'tsconfig.json');
|
|
21
|
+
if (existsSync(candidate))
|
|
22
|
+
return candidate;
|
|
23
|
+
if (path.dirname(dir) === dir)
|
|
24
|
+
throw new FunctionParamsError(`${modulePath}: no tsconfig.json above it`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The parameters of every function in `exportName` of `modulePath`, by its key. A function with no
|
|
29
|
+
* second parameter takes none (`{ type: 'object', properties: {} }`). A `define*` result (no call
|
|
30
|
+
* signature) is left out: it declares its own.
|
|
31
|
+
*/
|
|
32
|
+
export function readFunctionParameters(modulePath, exportName) {
|
|
33
|
+
const tsconfig = tsconfigOf(modulePath);
|
|
34
|
+
const api = new API({ cwd: path.dirname(tsconfig) });
|
|
35
|
+
try {
|
|
36
|
+
const snapshot = api.updateSnapshot({ openProjects: [tsconfig] });
|
|
37
|
+
const project = snapshot.getDefaultProjectForFile(modulePath) ?? snapshot.getProject(tsconfig);
|
|
38
|
+
const source = project?.program.getSourceFile(modulePath);
|
|
39
|
+
if (!project || !source)
|
|
40
|
+
throw new FunctionParamsError(`${modulePath}: not part of ${tsconfig}'s program`);
|
|
41
|
+
const { checker } = project;
|
|
42
|
+
const moduleSymbol = checker.getSymbolAtLocation(source);
|
|
43
|
+
const exported = moduleSymbol
|
|
44
|
+
? checker.getExportsOfModule(moduleSymbol).find((s) => s.name === exportName)
|
|
45
|
+
: undefined;
|
|
46
|
+
if (!exported)
|
|
47
|
+
return {};
|
|
48
|
+
const registry = checker.getTypeOfSymbol(exported);
|
|
49
|
+
if (!registry)
|
|
50
|
+
return {};
|
|
51
|
+
const where = path.basename(modulePath);
|
|
52
|
+
const out = {};
|
|
53
|
+
for (const entry of checker.getPropertiesOfType(registry)) {
|
|
54
|
+
// JavaScript keeps this name for an object's prototype: as a key it is easily not the object's own.
|
|
55
|
+
if (entry.name === '__proto__')
|
|
56
|
+
throw new FunctionParamsError(`${path.basename(modulePath)}: ${exportName}.__proto__: pick another name`);
|
|
57
|
+
const type = checker.getTypeOfSymbol(entry);
|
|
58
|
+
if (!type)
|
|
59
|
+
continue;
|
|
60
|
+
const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
|
|
61
|
+
if (signatures.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
const label = `${where}: ${exportName}.${entry.name}`;
|
|
64
|
+
if (signatures.length > 1)
|
|
65
|
+
throw new FunctionParamsError(`${label} is overloaded: a function has one signature, (ctx, args)`);
|
|
66
|
+
const signature = signatures[0];
|
|
67
|
+
// `(...args)` hides how many it takes and which is args: the builder could not show the AI what to fill.
|
|
68
|
+
if (signature.hasRestParameter)
|
|
69
|
+
throw new FunctionParamsError(`${label} takes a rest parameter: a function takes (ctx, args), args one object`);
|
|
70
|
+
const params = signature.getParameters();
|
|
71
|
+
if (params.length > 2)
|
|
72
|
+
throw new FunctionParamsError(`${label} takes ${params.length} parameters: a function takes (ctx, args), args one object`);
|
|
73
|
+
if (params.length < 2) {
|
|
74
|
+
out[entry.name] = { type: 'object', properties: {} };
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const argsType = checker.getParameterType(signature, 1);
|
|
78
|
+
if (!argsType)
|
|
79
|
+
throw new FunctionParamsError(`${label}: the type checker cannot read its args`);
|
|
80
|
+
const optional = params[1].flags & SymbolFlags.Optional ||
|
|
81
|
+
(argsType.isUnionType() && argsType.getTypes().some((t) => t.flags & TypeFlags.Undefined));
|
|
82
|
+
if (optional)
|
|
83
|
+
throw new FunctionParamsError(`${label}: args must be one object parameter, not optional`);
|
|
84
|
+
const top = objectParam(checker, argsType, `${label}(args)`);
|
|
85
|
+
out[entry.name] = {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: top.properties,
|
|
88
|
+
...(top.required?.length ? { required: top.required } : {}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
api.close();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** A union's members without `undefined` (an optional parameter's); any other type alone. */
|
|
98
|
+
function withoutUndefined(type) {
|
|
99
|
+
return (type.isUnionType() ? type.getTypes() : [type]).filter((t) => !(t.flags & TypeFlags.Undefined));
|
|
100
|
+
}
|
|
101
|
+
function isPlainObject(checker, type) {
|
|
102
|
+
return (type.isObjectType() &&
|
|
103
|
+
!checker.isArrayType(type) &&
|
|
104
|
+
checker.getSignaturesOfType(type, SignatureKind.Call).length === 0);
|
|
105
|
+
}
|
|
106
|
+
function objectParam(checker, type, where) {
|
|
107
|
+
if (!isPlainObject(checker, type) &&
|
|
108
|
+
!(type.isIntersectionType() && type.getTypes().every((t) => isPlainObject(checker, t)))) {
|
|
109
|
+
throw new FunctionParamsError(`${where}: not an object of named parameters`);
|
|
110
|
+
}
|
|
111
|
+
if (checker.getIndexInfosOfType(type).length > 0)
|
|
112
|
+
throw new FunctionParamsError(`${where} has an index signature (Record<string, …>): name each parameter`);
|
|
113
|
+
const properties = {};
|
|
114
|
+
const required = [];
|
|
115
|
+
for (const prop of checker.getPropertiesOfType(type)) {
|
|
116
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
117
|
+
if (!propType)
|
|
118
|
+
throw new FunctionParamsError(`${where}.${prop.name}: the type checker cannot read it`);
|
|
119
|
+
// A row inside an object or a list is the page's to prefill: the page refuses it where the AI would choose (35 §2).
|
|
120
|
+
const optional = (prop.flags & SymbolFlags.Optional) !== 0;
|
|
121
|
+
// One way to say optional, the one the AI reads (76 §2.14): `name?: T`. `name: T | undefined` is
|
|
122
|
+
// optional to the type checker and required here; the page's `doNow()` check and the AI would disagree.
|
|
123
|
+
if (!optional && (propType.isUnionType() ? propType.getTypes() : [propType]).some((t) => t.flags & TypeFlags.Undefined)) {
|
|
124
|
+
throw new FunctionParamsError(`${where}.${prop.name}: T | undefined: write an optional parameter as ${prop.name}?: T`);
|
|
125
|
+
}
|
|
126
|
+
properties[prop.name] = valueParam(checker, propType, `${where}.${prop.name}`);
|
|
127
|
+
if (!optional)
|
|
128
|
+
required.push(prop.name);
|
|
129
|
+
}
|
|
130
|
+
return { type: 'object', properties, ...(required.length ? { required } : {}) };
|
|
131
|
+
}
|
|
132
|
+
function valueParam(checker, type, where) {
|
|
133
|
+
const members = withoutUndefined(type);
|
|
134
|
+
if (members.some((t) => t.flags & TypeFlags.Null))
|
|
135
|
+
throw new FunctionParamsError(`${where}: null is not a value the AI fills: make the parameter optional (name?: T)`);
|
|
136
|
+
if (members.length === 0)
|
|
137
|
+
throw new FunctionParamsError(`${where}: no type`);
|
|
138
|
+
// A union of literals: what the AI may choose among; `boolean` is `true | false`.
|
|
139
|
+
if (members.length > 1 || members[0].isLiteralType()) {
|
|
140
|
+
if (members.every((t) => t.flags & TypeFlags.BooleanLiteral))
|
|
141
|
+
return { type: 'boolean' };
|
|
142
|
+
if (members.every((t) => t.isStringLiteralType()))
|
|
143
|
+
return { type: 'string', enum: members.map((t) => t.value) };
|
|
144
|
+
if (members.every((t) => t.isNumberLiteralType()))
|
|
145
|
+
return { type: 'number', enum: members.map((t) => t.value) };
|
|
146
|
+
if (members.length > 1)
|
|
147
|
+
throw new FunctionParamsError(`${where} mixes types: use one of ${PARAMETER_TYPES}`);
|
|
148
|
+
}
|
|
149
|
+
const only = members[0];
|
|
150
|
+
// A contact's hours (25 §3): the runtime's `ContactSchedule`, checked as the field's value is.
|
|
151
|
+
if (only.getAliasSymbol()?.name === 'ContactSchedule')
|
|
152
|
+
return { type: 'contact_schedule' };
|
|
153
|
+
if (only.flags & (TypeFlags.Any | TypeFlags.Unknown))
|
|
154
|
+
throw new FunctionParamsError(`${where}: any / unknown says nothing: use one of ${PARAMETER_TYPES}`);
|
|
155
|
+
if (only.flags & TypeFlags.String)
|
|
156
|
+
return { type: 'string' };
|
|
157
|
+
if (only.flags & TypeFlags.Number)
|
|
158
|
+
return { type: 'number' };
|
|
159
|
+
if (only.flags & TypeFlags.Boolean)
|
|
160
|
+
return { type: 'boolean' };
|
|
161
|
+
if (only.isIntersectionType()) {
|
|
162
|
+
const marked = markOf(checker, only);
|
|
163
|
+
if (marked)
|
|
164
|
+
return marked;
|
|
165
|
+
if (only.getTypes().every((t) => isPlainObject(checker, t)))
|
|
166
|
+
return objectParam(checker, only, where);
|
|
167
|
+
throw new FunctionParamsError(`${where} is not a parameter type: use one of ${PARAMETER_TYPES}`);
|
|
168
|
+
}
|
|
169
|
+
if (checker.isArrayType(only)) {
|
|
170
|
+
const item = only.isTypeReference() ? checker.getTypeArguments(only)[0] : undefined;
|
|
171
|
+
if (!item)
|
|
172
|
+
throw new FunctionParamsError(`${where}: a list of what?`);
|
|
173
|
+
return { type: 'array', items: valueParam(checker, item, `${where}[]`) };
|
|
174
|
+
}
|
|
175
|
+
if (only.isObjectType()) {
|
|
176
|
+
if (checker.getSignaturesOfType(only, SignatureKind.Call).length > 0)
|
|
177
|
+
throw new FunctionParamsError(`${where}: a function is not a value the AI fills`);
|
|
178
|
+
return objectParam(checker, only, where);
|
|
179
|
+
}
|
|
180
|
+
throw new FunctionParamsError(`${where} is not a parameter type: use one of ${PARAMETER_TYPES}`);
|
|
181
|
+
}
|
|
182
|
+
/** `Id<'table'>` → a row of `table`; a format type → its format. Null when the intersection carries neither mark. */
|
|
183
|
+
function markOf(checker, type) {
|
|
184
|
+
if (!type.getTypes().some((t) => t.flags & TypeFlags.String))
|
|
185
|
+
return null;
|
|
186
|
+
for (const prop of checker.getPropertiesOfType(type)) {
|
|
187
|
+
const name = String(prop.escapedName);
|
|
188
|
+
const isId = ID_MARK.test(name);
|
|
189
|
+
if (!isId && !FORMAT_MARK.test(name))
|
|
190
|
+
continue;
|
|
191
|
+
const value = literalOf(checker, prop);
|
|
192
|
+
if (isId)
|
|
193
|
+
return value ? { type: 'ref', table: value } : null;
|
|
194
|
+
return value && FORMATS.has(value) ? { type: value } : null;
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
function literalOf(checker, prop) {
|
|
199
|
+
const type = checker.getTypeOfSymbol(prop);
|
|
200
|
+
const literal = type ? withoutUndefined(type).find((t) => t.isStringLiteralType()) : undefined;
|
|
201
|
+
return literal ? literal.value : null;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=function-params.js.map
|
package/dist/builder/load.d.ts
CHANGED
|
@@ -1,22 +1,82 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
4
|
-
|
|
1
|
+
import { type CompanyResolve, type Resolve } from '../core/party/types.js';
|
|
2
|
+
import { type AnyEventHandlers, type WebhookHandler } from '../core/functions/events.js';
|
|
3
|
+
import type { FuncMap, PlainFn } from '../core/functions/types.js';
|
|
4
|
+
import { type OfficeHours } from '../core/office-hours/index.js';
|
|
5
|
+
import { type CompanySchema, type SessionSchema } from '../core/slot/schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* A sequence's leftover `slots.ts` (or `slots/index.ts`): the sequence layer has no schema any more
|
|
8
|
+
* (15 §10.17 第 1 条). Its tables and fields are the company's; how a cell is filled is the page's
|
|
9
|
+
* `$extraction`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assertNoSlotsModule(sequenceDir: string, sequenceId: string): void;
|
|
12
|
+
/** Sequence ids: the directories under `sequences/` with an `index.ts` (`defineSequence`). */
|
|
5
13
|
export declare function listSequenceIds(repoRoot: string): string[];
|
|
6
14
|
export declare function loadCompanySchema(schemaPath: string): Promise<CompanySchema>;
|
|
7
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The company's session fields from `schema/session.ts` (or `schema/session/index.ts`), its
|
|
17
|
+
* `sessionSchema` export (11-remove-sequence-schema §3.1). No file: sessions have no fields.
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadSessionSchema(repoRoot: string): Promise<SessionSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Sequence office hours from `sequences/<id>/office-hours.ts`. Missing file is `null` (always open).
|
|
22
|
+
* A present file that does not export a valid `officeHours` fails compile.
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadOfficeHours(sequenceDir: string): Promise<OfficeHours | null>;
|
|
8
25
|
/**
|
|
9
26
|
* Load sequence `functions` map from functions.ts or functions/index.ts.
|
|
10
27
|
* Accepts named `functions` or default export FuncMap.
|
|
11
28
|
*/
|
|
12
29
|
export declare function loadSequenceFunctions(functionsPath: string): Promise<FuncMap>;
|
|
13
30
|
/**
|
|
14
|
-
* Load optional `
|
|
31
|
+
* Load optional sequence `events` map from events.ts / events/index.ts.
|
|
32
|
+
* Keys must be platform event names; values are plain handler functions.
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadSequenceEvents(eventsPath: string): Promise<AnyEventHandlers>;
|
|
35
|
+
/**
|
|
36
|
+
* The channels `context.page.ts` has a page function for (17b §9.1). Read from the compiled page code in
|
|
37
|
+
* a context of its own, as the platform runs it: importing the page module here would register its
|
|
38
|
+
* actions in this process, and a second compile would find them named twice. `persona` and `faq` are
|
|
39
|
+
* called when a conversation starts (24 §4), not here.
|
|
40
|
+
*/
|
|
41
|
+
export declare function loadPageChannels(pageCode: string, sequenceId: string): string[];
|
|
42
|
+
/**
|
|
43
|
+
* What the compiled page code says of itself as it loads: its channels, and the page actions it
|
|
44
|
+
* registered (76 §2.11), read in a context of its own as `loadPageChannels` does.
|
|
45
|
+
*/
|
|
46
|
+
export declare function loadPageModule(pageCode: string, sequenceId: string): {
|
|
47
|
+
channels: string[];
|
|
48
|
+
actions: string[];
|
|
49
|
+
};
|
|
50
|
+
/** The Case Orchestrator from orchestrator.ts / orchestrator/index.ts: `orchestrator`, or the default export. */
|
|
51
|
+
export declare function loadSequenceCaseOrchestrator(caseOrchestratorPath: string): Promise<PlainFn>;
|
|
52
|
+
/** A sequence's `resolve`: `(ctx, conversation)`. */
|
|
53
|
+
export declare function loadSequenceResolver(resolvePath: string): Promise<Resolve>;
|
|
54
|
+
/** The company `resolve` (§18.2), a function of the company part (22 §5): `(ctx, conversation)`. */
|
|
55
|
+
export declare function loadCompanyResolver(resolvePath: string): Promise<CompanyResolve>;
|
|
56
|
+
/** The module of the company's webhooks (22 §9) at the repository root. */
|
|
57
|
+
export declare const WEBHOOK_MODULE = "webhook";
|
|
58
|
+
/** `received` of `webhook.ts`, a function of the company part: `(ctx, { event })`. */
|
|
59
|
+
export declare function loadCompanyWebhook(webhookPath: string): Promise<WebhookHandler>;
|
|
60
|
+
export declare function isPlatformName(name: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* A leftover root `channels.ts` (or `channels/index.ts`): webhook URLs are made and named on the
|
|
63
|
+
* Webhooks page now, like phone numbers, and code refers to them by name only.
|
|
64
|
+
*/
|
|
65
|
+
export declare function assertNoChannelsModule(repoRoot: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* `sequences/<id>/index.ts` default export (`defineSequence({ subject })`): the sequence's business
|
|
68
|
+
* root. Without the file or the declaration, `subject` is undefined and the compile reports it.
|
|
15
69
|
*/
|
|
16
|
-
export declare function
|
|
70
|
+
export declare function loadSequenceDefinition(sequenceDir: string): Promise<{
|
|
71
|
+
subject: unknown;
|
|
72
|
+
label: unknown;
|
|
73
|
+
}>;
|
|
17
74
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
75
|
+
* `sequences/<id>/variables.ts` (14-sequence-instance §4.4): `variables` (from `defineVariables`) and
|
|
76
|
+
* the optional `experiments`. Both undefined without the file.
|
|
20
77
|
*/
|
|
21
|
-
export declare function
|
|
78
|
+
export declare function loadSequenceVariables(sequenceDir: string): Promise<{
|
|
79
|
+
variables: unknown;
|
|
80
|
+
experiments: unknown;
|
|
81
|
+
}>;
|
|
22
82
|
//# sourceMappingURL=load.d.ts.map
|