@superpanel-sdk/runtime 0.5.0 → 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 +3 -3
- package/dist/builder/codegen/emit.d.ts +5 -10
- package/dist/builder/codegen/emit.js +100 -106
- package/dist/builder/codegen/generate.d.ts +3 -5
- package/dist/builder/codegen/generate.js +13 -32
- package/dist/builder/company-imports.d.ts +5 -0
- package/dist/builder/company-imports.js +9 -1
- package/dist/builder/compile/compile-sequence.d.ts +13 -11
- package/dist/builder/compile/compile-sequence.js +135 -83
- package/dist/builder/compile/function-code.d.ts +15 -9
- package/dist/builder/compile/function-code.js +59 -29
- package/dist/builder/compile/registry.d.ts +4 -4
- package/dist/builder/compile/registry.js +14 -12
- 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 +17 -17
- package/dist/builder/load.js +27 -25
- package/dist/builder/paths.d.ts +6 -1
- package/dist/builder/paths.js +16 -2
- package/dist/builder/schedules.d.ts +9 -7
- package/dist/builder/schedules.js +20 -21
- package/dist/builder/typecheck.d.ts +1 -1
- package/dist/builder/typecheck.js +3 -6
- package/dist/builder/types.d.ts +41 -5
- package/dist/builder/types.js +19 -0
- package/dist/cli/calls/index.d.ts +177 -0
- package/dist/cli/calls/index.js +96 -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 +84 -1
- 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 +40 -4
- package/dist/cli/serve/index.js +167 -28
- 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 +0 -1
- package/dist/compute-host/compute-host.d.ts +5 -6
- package/dist/compute-host/compute-host.js +4 -13
- package/dist/compute-host/source-compute-host.d.ts +5 -7
- package/dist/compute-host/source-compute-host.js +12 -33
- package/dist/core/case-orchestrator/contact-hours.d.ts +26 -6
- package/dist/core/case-orchestrator/contact-hours.js +27 -8
- package/dist/core/case-orchestrator/index.d.ts +1 -4
- package/dist/core/case-orchestrator/index.js +1 -4
- package/dist/core/case-orchestrator/render.d.ts +1 -1
- package/dist/core/case-orchestrator/render.js +15 -10
- package/dist/core/case-orchestrator/types.d.ts +83 -128
- package/dist/core/case-orchestrator/types.js +0 -4
- package/dist/core/context/email-message.d.ts +40 -1
- package/dist/core/context/email-message.js +27 -0
- package/dist/core/context/email.d.ts +13 -1
- package/dist/core/context/email.js +2 -3
- package/dist/core/context/exchanges.d.ts +25 -0
- package/dist/core/context/exchanges.js +25 -7
- package/dist/core/context/instances.d.ts +31 -2
- package/dist/core/context/instances.js +18 -4
- package/dist/core/context/platform-registry.d.ts +35 -0
- package/dist/core/context/sms.d.ts +30 -0
- package/dist/core/context/sms.js +20 -0
- package/dist/core/context/types.d.ts +29 -1
- package/dist/core/conversation/index.d.ts +58 -4
- package/dist/core/conversation/index.js +123 -4
- package/dist/core/functions/errors.d.ts +74 -0
- package/dist/core/functions/errors.js +26 -0
- package/dist/core/functions/events.d.ts +23 -78
- package/dist/core/functions/events.js +8 -17
- package/dist/core/functions/schedules.d.ts +9 -10
- package/dist/core/functions/schedules.js +2 -2
- package/dist/core/functions/types.d.ts +17 -72
- package/dist/core/functions/types.js +1 -9
- package/dist/core/page/define.d.ts +230 -160
- package/dist/core/page/define.js +145 -104
- 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/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 +67 -25
- package/dist/core/page/render.js +492 -272
- 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 +27 -0
- package/dist/core/page/time-format.js +84 -0
- package/dist/core/page/typed.d.ts +165 -159
- package/dist/core/page/workspace.d.ts +25 -1
- package/dist/core/page/workspace.js +48 -13
- package/dist/core/party/schema.d.ts +74 -3
- package/dist/core/party/schema.js +39 -6
- package/dist/core/party/types.d.ts +8 -13
- package/dist/core/sequence/define.d.ts +1 -2
- package/dist/core/slot/company-metadata.d.ts +11 -22
- package/dist/core/slot/company-metadata.js +12 -39
- package/dist/core/slot/compile-schema.js +6 -6
- package/dist/core/slot/field.d.ts +1 -2
- package/dist/core/slot/field.js +0 -2
- package/dist/core/slot/index.d.ts +3 -3
- package/dist/core/slot/index.js +3 -3
- package/dist/core/slot/naming.d.ts +1 -1
- package/dist/core/slot/naming.js +1 -1
- package/dist/core/slot/platform-fields.d.ts +4 -4
- package/dist/core/slot/platform-fields.js +5 -5
- package/dist/core/slot/schema-compat.d.ts +8 -7
- package/dist/core/slot/schema-compat.js +22 -31
- package/dist/core/slot/schema.d.ts +3 -59
- package/dist/core/slot/schema.js +0 -15
- package/dist/core/slot/types.d.ts +4 -10
- package/dist/core/slot/value.d.ts +2 -0
- package/dist/core/slot/value.js +6 -2
- package/dist/dev-overlay/protocol.d.ts +38 -5
- package/dist/fn-context/build-context.js +10 -4
- package/dist/fn-context/fake/index.d.ts +2 -0
- package/dist/fn-context/fake/index.js +5 -3
- package/dist/fn-context/fn-params.d.ts +2 -5
- package/dist/fn-context/fn-params.js +6 -9
- package/dist/fn-context/index.d.ts +1 -1
- package/dist/fn-context/make-ctx.js +5 -4
- package/dist/fn-context/rpc/case-orchestrator-tools.d.ts +11 -3
- package/dist/fn-context/rpc/case-orchestrator-tools.js +0 -1
- 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 +1 -1
- package/dist/fn-context/rpc/index.js +1 -1
- package/dist/fn-context/rpc/integration/index.d.ts +11 -1
- package/dist/fn-context/rpc/log.d.ts +11 -1
- package/dist/fn-context/rpc/platform.d.ts +11 -1
- package/dist/fn-context/rpc/records.d.ts +13 -6
- package/dist/fn-context/rpc/records.js +2 -4
- package/dist/fn-context/rpc/trpc-client.d.ts +42 -0
- package/dist/fn-context/rpc/trpc-client.js +151 -22
- package/dist/fn-context/rpc/trpc-init.d.ts +19 -1
- package/dist/fn-context/rpc/trpc-init.js +10 -4
- package/dist/fn-context/rpc/trpc-router-factory.d.ts +66 -8
- package/dist/fn-context/run-scope.js +1 -1
- package/dist/fn-context/types.d.ts +20 -6
- package/dist/index.d.ts +11 -12
- package/dist/index.js +5 -8
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +8 -0
- package/dist/platform.d.ts +32 -33
- package/dist/platform.js +23 -22
- 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 +12 -35
- 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 +16 -6
- package/dist/worker.d.ts +2 -1
- package/dist/worker.js +2 -1
- package/package.json +20 -16
- package/dist/core/case-orchestrator/follow-ups.d.ts +0 -31
- package/dist/core/case-orchestrator/follow-ups.js +0 -103
- package/dist/core/case-orchestrator/tools.d.ts +0 -29
- package/dist/core/case-orchestrator/tools.js +0 -31
- package/dist/core/case-orchestrator/validate.d.ts +0 -11
- package/dist/core/case-orchestrator/validate.js +0 -63
- package/dist/core/functions/define/bind.d.ts +0 -25
- package/dist/core/functions/define/bind.js +0 -14
- package/dist/core/functions/define/case.d.ts +0 -9
- package/dist/core/functions/define/case.js +0 -13
- package/dist/core/functions/define/events.d.ts +0 -20
- package/dist/core/functions/define/events.js +0 -21
- package/dist/core/functions/define/no-case.d.ts +0 -4
- package/dist/core/functions/define/no-case.js +0 -9
- package/dist/core/functions/func-ref.d.ts +0 -25
- package/dist/core/functions/func-ref.js +0 -20
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CompiledSlotSchema } from '../../core/slot/types.js';
|
|
2
|
-
import type
|
|
3
|
-
import type { CompanyPart, RuntimePackageSource, SequenceBuild } from '../types.js';
|
|
2
|
+
import { type CompanyPart, type RuntimePackageSource, type SequenceBuild, type SourceMaps } from '../types.js';
|
|
4
3
|
/** SequenceBuild cache key. Bump when compiled `code` shape changes. */
|
|
5
4
|
export declare function runtimePackageVersion(): string;
|
|
6
5
|
export declare function runtimePackageSource(repoRoot: string): RuntimePackageSource;
|
|
@@ -18,19 +17,19 @@ export type CompileSequenceResult = {
|
|
|
18
17
|
build: SequenceBuild;
|
|
19
18
|
/** The company schema the build runs against (28 §2): what the company part of the build carries. */
|
|
20
19
|
schema: CompiledSlotSchema;
|
|
21
|
-
|
|
20
|
+
/** Where the build's code came from in the company's files, by `functionKey`: kept apart from the build. */
|
|
21
|
+
sourceMaps: SourceMaps;
|
|
22
22
|
wrote: boolean;
|
|
23
23
|
};
|
|
24
|
-
export type CompileSequenceBuildResult = Omit<CompileSequenceResult, 'companyMetadata'>;
|
|
25
|
-
export declare function compileCompanyMetadataFromRepo(repoRoot: string): Promise<CompiledCompanyMetadata>;
|
|
26
24
|
export declare function compileSequence(repoRoot: string, sequenceId: string, options?: CompileSequenceOptions): Promise<CompileSequenceResult>;
|
|
27
|
-
export declare function compileSequenceBuild(repoRoot: string, sequenceId: string, options?: CompileSequenceOptions): Promise<
|
|
25
|
+
export declare function compileSequenceBuild(repoRoot: string, sequenceId: string, options?: CompileSequenceOptions): Promise<CompileSequenceResult>;
|
|
28
26
|
export declare function compileAll(repoRoot: string, options?: CompileSequenceOptions & {
|
|
29
27
|
sequenceIds?: string[];
|
|
30
28
|
}): Promise<CompileSequenceResult[]>;
|
|
31
29
|
/**
|
|
32
30
|
* The company part of the company build (22 §5): the root `resolve.ts` as `companyResolve`, the root
|
|
33
|
-
* `webhook.ts` as `webhook.received`, the root `schedules.ts` as `schedule.<name>` (25 §6.4),
|
|
31
|
+
* `webhook.ts` as `webhook.received`, the root `schedules.ts` as `schedule.<name>` (25 §6.4), the root
|
|
32
|
+
* `errors.ts` as `onError` (67 §5), and the
|
|
34
33
|
* company schema with no subject. An error in it fails the
|
|
35
34
|
* whole compile.
|
|
36
35
|
*/
|
|
@@ -56,6 +55,8 @@ export type CompileRepoEvent = {
|
|
|
56
55
|
export type CompileRepoSequenceResult = {
|
|
57
56
|
ok: true;
|
|
58
57
|
build: SequenceBuild;
|
|
58
|
+
/** Where its code came from in the company's files, by `functionKey` (kept apart from the build). */
|
|
59
|
+
sourceMaps: SourceMaps;
|
|
59
60
|
} | {
|
|
60
61
|
ok: false;
|
|
61
62
|
error: string;
|
|
@@ -68,13 +69,14 @@ export type CompileRepoOptions = {
|
|
|
68
69
|
onEvent?: (event: CompileRepoEvent) => void;
|
|
69
70
|
};
|
|
70
71
|
/**
|
|
71
|
-
* Compile company
|
|
72
|
-
* repository. A sequence error is collected; a company schema error or a type error
|
|
73
|
-
* call, a type error with the tsc output as its message.
|
|
72
|
+
* Compile the company part (its schema first) once, then every named sequence in this process, then
|
|
73
|
+
* type-check the repository. A sequence error is collected; a company schema error or a type error
|
|
74
|
+
* rejects the whole call, a type error with the tsc output as its message.
|
|
74
75
|
*/
|
|
75
76
|
export declare function compileRepo(repoRoot: string, options: CompileRepoOptions): Promise<{
|
|
76
|
-
companyMetadata: CompiledCompanyMetadata;
|
|
77
77
|
company: CompanyPart;
|
|
78
|
+
/** The company functions' source maps, by `functionKey` (kept apart from the build). */
|
|
79
|
+
companySourceMaps: SourceMaps;
|
|
78
80
|
sequences: Record<string, CompileRepoSequenceResult>;
|
|
79
81
|
}>;
|
|
80
82
|
//# sourceMappingURL=compile-sequence.d.ts.map
|
|
@@ -2,19 +2,24 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { compileSlotSchema } from '../../core/slot/compile-schema.js';
|
|
5
|
-
import {
|
|
5
|
+
import { subjectTableIssues } from '../../core/slot/company-metadata.js';
|
|
6
6
|
import { ensureCompanyStub, ensureStub } from '../codegen/generate.js';
|
|
7
7
|
import { withCompanyImportGraph } from '../company-import-graph.js';
|
|
8
|
-
import {
|
|
8
|
+
import { ORCHESTRATOR_FUNCTION, } from '../../core/case-orchestrator/types.js';
|
|
9
9
|
import { COMPANY_RESOLVE_FUNCTION, RESOLVE_FUNCTION, RESOLVE_MODULE } from '../../core/party/types.js';
|
|
10
10
|
import { compileVariables } from '../../core/sequence/index.js';
|
|
11
11
|
import { WEBHOOK_RECEIVED_FUNCTION } from '../../core/functions/events.js';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { SCHEDULES_MODULE } from '../../core/functions/schedules.js';
|
|
13
|
+
import { isPlatformName, listSequenceIds, loadCompanySchema, loadCompanyWebhook, WEBHOOK_MODULE, loadOfficeHours, loadSequenceCaseOrchestrator, loadSequenceEvents, loadSequenceFunctions, loadSequenceDefinition, loadCompanyResolver, loadSequenceResolver, loadSequenceVariables, loadPageModule, loadSessionSchema, assertNoSlotsModule, assertNoChannelsModule, } from '../load.js';
|
|
14
|
+
import { findTsModule, requireCompanyResolveModule, requirePagePath, requireResolveModule, resolveTsModule } from '../paths.js';
|
|
14
15
|
import { fatalSlotSchemaIssues } from '../slot-schema-validation.js';
|
|
16
|
+
import { readFunctionParameters } from '../function-params.js';
|
|
15
17
|
import { typecheckRepo } from '../typecheck.js';
|
|
18
|
+
import { COMPANY_SCOPE, CONTEXT_PAGE_FUNCTION, functionKey, } from '../types.js';
|
|
16
19
|
import { compileExportModuleCode, compilePageModuleCode } from './function-code.js';
|
|
17
|
-
import {
|
|
20
|
+
import { loadSchedules, scheduleRegistry } from '../schedules.js';
|
|
21
|
+
import { loadOnError } from '../errors.js';
|
|
22
|
+
import { ERRORS_MODULE, ON_ERROR_FUNCTION } from '../../core/functions/errors.js';
|
|
18
23
|
import { toEventRegistry, toFunctionRegistry } from './registry.js';
|
|
19
24
|
/** SequenceBuild cache key. Bump when compiled `code` shape changes. */
|
|
20
25
|
export function runtimePackageVersion() {
|
|
@@ -41,23 +46,20 @@ async function loadCompanySchemas(repoRoot) {
|
|
|
41
46
|
const schemaPath = resolveTsModule(repoRoot, 'schema', `No company schema found. Expected schema.ts or schema/index.ts under ${repoRoot}`);
|
|
42
47
|
return { company: await loadCompanySchema(schemaPath), session: await loadSessionSchema(repoRoot) };
|
|
43
48
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
/** The company schema, compiled; a schema error throws, with every issue in the message. */
|
|
50
|
+
function compileCompanySlotSchema({ company, session }) {
|
|
51
|
+
const { schema, validation } = compileSlotSchema(company, { session });
|
|
52
|
+
if (!validation.ok) {
|
|
53
|
+
const fatal = fatalSlotSchemaIssues(validation.issues);
|
|
54
|
+
if (fatal.length > 0)
|
|
55
|
+
throw new Error(fatal.map((issue) => issue.message).join('; '));
|
|
50
56
|
}
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
export async function compileCompanyMetadataFromRepo(repoRoot) {
|
|
54
|
-
return withCompanyImportGraph(repoRoot, async () => compileMetadata(await loadCompanySchemas(repoRoot)));
|
|
57
|
+
return schema;
|
|
55
58
|
}
|
|
56
59
|
export async function compileSequence(repoRoot, sequenceId, options = {}) {
|
|
57
60
|
return withCompanyImportGraph(repoRoot, async () => {
|
|
58
|
-
const result = await compileSequenceInGraph(repoRoot, sequenceId, options);
|
|
59
|
-
|
|
60
|
-
return { ...build, companyMetadata: compileMetadata(schemas) };
|
|
61
|
+
const { schemas: _, ...result } = await compileSequenceInGraph(repoRoot, sequenceId, options);
|
|
62
|
+
return result;
|
|
61
63
|
});
|
|
62
64
|
}
|
|
63
65
|
export async function compileSequenceBuild(repoRoot, sequenceId, options = {}) {
|
|
@@ -73,17 +75,15 @@ async function compileSequenceInGraph(repoRoot, sequenceId, options) {
|
|
|
73
75
|
}
|
|
74
76
|
const sequenceDir = path.join(repoRoot, 'sequences', sequenceId);
|
|
75
77
|
assertNoSlotsModule(sequenceDir, sequenceId);
|
|
78
|
+
// `functions/index.ts` (or `functions.ts`) is optional: without it the sequence has no functions (76 §5.5).
|
|
76
79
|
const functionsPath = findTsModule(sequenceDir, 'functions');
|
|
77
|
-
if (!functionsPath) {
|
|
78
|
-
throw new Error(`No sequence functions found. Expected sequences/${sequenceId}/functions.ts or sequences/${sequenceId}/functions/index.ts`);
|
|
79
|
-
}
|
|
80
80
|
// `__gen/` is gitignored in company repos, so a fresh checkout (server-side compile from a git
|
|
81
81
|
// archive) has no `__gen/index.ts` — which functions.ts / events.ts import at runtime. Write the
|
|
82
82
|
// missing generated files first; existing ones are left untouched.
|
|
83
83
|
ensureStub(repoRoot, sequenceId);
|
|
84
84
|
const schemas = await loadCompanySchemas(repoRoot);
|
|
85
85
|
const { company, session } = schemas;
|
|
86
|
-
const authored = await loadSequenceFunctions(functionsPath);
|
|
86
|
+
const authored = functionsPath ? await loadSequenceFunctions(functionsPath) : {};
|
|
87
87
|
// The conversation follows the page (17b): what to do next is worked out from it, not from an agenda.
|
|
88
88
|
for (const removed of ['agenda', 'agendas']) {
|
|
89
89
|
if (findTsModule(sequenceDir, removed)) {
|
|
@@ -91,19 +91,26 @@ async function compileSequenceInGraph(repoRoot, sequenceId, options) {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
const caseOrchestratorPath = findTsModule(sequenceDir, 'orchestrator');
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
throw new Error(`functions must not define '${reserved}'; it is the Case Orchestrator's, from orchestrator.ts`);
|
|
97
|
-
}
|
|
94
|
+
if (Object.hasOwn(authored, ORCHESTRATOR_FUNCTION)) {
|
|
95
|
+
throw new Error(`functions must not define '${ORCHESTRATOR_FUNCTION}'; it is the Case Orchestrator's, from orchestrator.ts`);
|
|
98
96
|
}
|
|
99
97
|
for (const reserved of [RESOLVE_FUNCTION, COMPANY_RESOLVE_FUNCTION]) {
|
|
100
98
|
if (Object.hasOwn(authored, reserved)) {
|
|
101
99
|
throw new Error(`functions must not define '${reserved}'; it is a resolver in ${RESOLVE_MODULE}.ts`);
|
|
102
100
|
}
|
|
103
101
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
// The page script is known by this name among the sequence's functions (`functionKey`).
|
|
103
|
+
if (Object.hasOwn(authored, CONTEXT_PAGE_FUNCTION)) {
|
|
104
|
+
throw new Error(`functions must not define '${CONTEXT_PAGE_FUNCTION}'; it is the page script's name (context.page.ts)`);
|
|
105
|
+
}
|
|
106
|
+
// Recurring jobs are the company's only (25 §6.4): the repository root's schedules.ts.
|
|
107
|
+
if (findTsModule(sequenceDir, SCHEDULES_MODULE)) {
|
|
108
|
+
throw new Error(`sequences/${sequenceId}/${SCHEDULES_MODULE}.ts is not supported: recurring jobs go in the repository root's ${SCHEDULES_MODULE}.ts (import the sequence's functions from there) (25 §6.4)`);
|
|
109
|
+
}
|
|
110
|
+
// onError is the company's only (67 §5): the repository root's errors.ts.
|
|
111
|
+
if (findTsModule(sequenceDir, ERRORS_MODULE)) {
|
|
112
|
+
throw new Error(`sequences/${sequenceId}/${ERRORS_MODULE}.ts is not supported: onError goes in the repository root's ${ERRORS_MODULE}.ts (67 §5)`);
|
|
113
|
+
}
|
|
107
114
|
if (findTsModule(sequenceDir, 'party')) {
|
|
108
115
|
throw new Error(`sequences/${sequenceId}/party.ts is no longer supported: export ${RESOLVE_FUNCTION} from sequences/${sequenceId}/${RESOLVE_MODULE}.ts`);
|
|
109
116
|
}
|
|
@@ -113,12 +120,7 @@ async function compileSequenceInGraph(repoRoot, sequenceId, options) {
|
|
|
113
120
|
const functions = {
|
|
114
121
|
...authored,
|
|
115
122
|
[RESOLVE_FUNCTION]: resolver,
|
|
116
|
-
...(caseOrchestratorFn
|
|
117
|
-
? {
|
|
118
|
-
[ORCHESTRATOR_FUNCTION]: { kind: 'orchestrator', main: caseOrchestratorFn.orchestrator },
|
|
119
|
-
[ORCHESTRATOR_CONTACTS_FUNCTION]: { kind: 'orchestrator', main: caseOrchestratorFn.contacts },
|
|
120
|
-
}
|
|
121
|
-
: {}),
|
|
123
|
+
...(caseOrchestratorFn ? { [ORCHESTRATOR_FUNCTION]: caseOrchestratorFn } : {}),
|
|
122
124
|
};
|
|
123
125
|
const eventsPath = findTsModule(sequenceDir, 'events');
|
|
124
126
|
const events = eventsPath ? await loadSequenceEvents(eventsPath) : {};
|
|
@@ -131,10 +133,9 @@ async function compileSequenceInGraph(repoRoot, sequenceId, options) {
|
|
|
131
133
|
throw new Error(`sequences/${sequenceId}/view.ts is no longer supported: the Orchestrator reads with ctx.api.db, and names who a Run may contact with contacts in orchestrator.ts`);
|
|
132
134
|
}
|
|
133
135
|
// The conversation's page is the page script, always (15 §10.2): no default page.
|
|
134
|
-
const pagePath =
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
136
|
+
const pagePath = requirePagePath(sequenceDir, sequenceId);
|
|
137
|
+
// The page's actions (76 §2.11): `actions.ts`, optional, like `functions/`.
|
|
138
|
+
const actionsPath = findTsModule(sequenceDir, 'actions') ?? null;
|
|
138
139
|
// The FAQ is the page's (24 §7): `faq` in definePage, called when the conversation starts.
|
|
139
140
|
if (findTsModule(sequenceDir, 'knowledge')) {
|
|
140
141
|
throw new Error(`sequences/${sequenceId}/knowledge.ts is no longer supported: return the FAQ from definePage({ faq: (ctx) => [...] }) in context.page.ts (24 §7)`);
|
|
@@ -160,22 +161,22 @@ async function compileSequenceInGraph(repoRoot, sequenceId, options) {
|
|
|
160
161
|
if (findTsModule(sequenceDir, 'load')) {
|
|
161
162
|
throw new Error(`sequences/${sequenceId}/load.ts: declarative load is no longer supported; read with db in context.page.ts`);
|
|
162
163
|
}
|
|
163
|
-
const orchestrator = caseOrchestratorFn
|
|
164
|
-
? { fn: ORCHESTRATOR_FUNCTION, contactsFn: ORCHESTRATOR_CONTACTS_FUNCTION }
|
|
165
|
-
: null;
|
|
164
|
+
const orchestrator = caseOrchestratorFn ? { fn: ORCHESTRATOR_FUNCTION } : null;
|
|
166
165
|
const includeCode = options.includeCode ?? true;
|
|
167
|
-
const
|
|
168
|
-
|
|
166
|
+
const functionMaps = {};
|
|
167
|
+
const [functionsRegistry, resolveCompiled, caseOrchestratorCompiled, eventsRegistry, page,] = await Promise.all([
|
|
168
|
+
toFunctionRegistry(authored, { includeCode, ...(functionsPath ? { modulePath: functionsPath } : {}), sourceMaps: functionMaps }),
|
|
169
169
|
includeCode ? compileExportModuleCode(resolvePath, RESOLVE_FUNCTION) : Promise.resolve(undefined),
|
|
170
170
|
caseOrchestratorPath && includeCode
|
|
171
171
|
? compileExportModuleCode(caseOrchestratorPath, ORCHESTRATOR_FUNCTION)
|
|
172
172
|
: Promise.resolve(undefined),
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
compilePageModuleCode(pagePath),
|
|
176
|
-
schedules ? scheduleRegistry(schedules, includeCode) : Promise.resolve({}),
|
|
173
|
+
toEventRegistry(events, { includeCode, modulePath: eventsPath, sourceMaps: functionMaps }),
|
|
174
|
+
compilePageModuleCode(pagePath, actionsPath),
|
|
177
175
|
]);
|
|
178
|
-
const
|
|
176
|
+
const resolveCode = codeKeepingMap(RESOLVE_FUNCTION, resolveCompiled, functionMaps);
|
|
177
|
+
const caseOrchestratorCode = codeKeepingMap(ORCHESTRATOR_FUNCTION, caseOrchestratorCompiled, functionMaps);
|
|
178
|
+
const pageCode = page.code;
|
|
179
|
+
const { channels, actions: actionNames } = loadPageModule(pageCode, sequenceId);
|
|
179
180
|
const runtimeVersion = runtimePackageVersion();
|
|
180
181
|
const build = {
|
|
181
182
|
sequenceId,
|
|
@@ -188,31 +189,39 @@ async function compileSequenceInGraph(repoRoot, sequenceId, options) {
|
|
|
188
189
|
experiments: variables.experiments,
|
|
189
190
|
functions: {
|
|
190
191
|
...functionsRegistry,
|
|
191
|
-
[RESOLVE_FUNCTION]: resolveCode === undefined ? {
|
|
192
|
-
...(caseOrchestratorPath
|
|
193
|
-
? {
|
|
194
|
-
[ORCHESTRATOR_FUNCTION]: caseOrchestratorCode === undefined
|
|
195
|
-
? { kind: 'orchestrator' }
|
|
196
|
-
: { kind: 'orchestrator', code: caseOrchestratorCode },
|
|
197
|
-
[ORCHESTRATOR_CONTACTS_FUNCTION]: caseOrchestratorContactsCode === undefined
|
|
198
|
-
? { kind: 'orchestrator' }
|
|
199
|
-
: { kind: 'orchestrator', code: caseOrchestratorContactsCode },
|
|
200
|
-
}
|
|
201
|
-
: {}),
|
|
202
|
-
...schedulesRegistry,
|
|
192
|
+
[RESOLVE_FUNCTION]: resolveCode === undefined ? {} : { code: resolveCode },
|
|
193
|
+
...(caseOrchestratorPath ? { [ORCHESTRATOR_FUNCTION]: caseOrchestratorCode === undefined ? {} : { code: caseOrchestratorCode } } : {}),
|
|
203
194
|
},
|
|
204
195
|
events: eventsRegistry,
|
|
205
196
|
officeHours: await loadOfficeHours(sequenceDir),
|
|
206
197
|
orchestrator,
|
|
207
|
-
contextPage: { code: pageCode, channels },
|
|
208
|
-
...(schedules ? { schedules: schedules.manifest } : {}),
|
|
198
|
+
contextPage: { code: pageCode, channels, ...functionParameters(authored, functionsPath), ...actionParameters(actionsPath, actionNames, sequenceId) },
|
|
209
199
|
};
|
|
210
200
|
const outPath = sequenceBuildPath(repoRoot, sequenceId);
|
|
211
201
|
if (!options.dryRun) {
|
|
212
202
|
mkdirSync(path.dirname(outPath), { recursive: true });
|
|
213
203
|
writeFileSync(outPath, `${JSON.stringify(build, null, 2)}\n`, 'utf8');
|
|
214
204
|
}
|
|
215
|
-
return {
|
|
205
|
+
return {
|
|
206
|
+
sequenceId,
|
|
207
|
+
outPath,
|
|
208
|
+
build,
|
|
209
|
+
schema,
|
|
210
|
+
schemas,
|
|
211
|
+
sourceMaps: keyedMaps(sequenceId, { ...functionMaps, [CONTEXT_PAGE_FUNCTION]: page.map }),
|
|
212
|
+
wrote: !options.dryRun,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/** Maps by name in `scope`, keyed as the platform knows the code: its {@link functionKey}. */
|
|
216
|
+
function keyedMaps(scope, byName) {
|
|
217
|
+
return Object.fromEntries(Object.entries(byName).map(([name, map]) => [functionKey(scope, name), map]));
|
|
218
|
+
}
|
|
219
|
+
/** A compiled function's code, its map kept in `maps` by the function's name; nothing when not compiled. */
|
|
220
|
+
function codeKeepingMap(name, compiled, maps) {
|
|
221
|
+
if (!compiled)
|
|
222
|
+
return undefined;
|
|
223
|
+
maps[name] = compiled.map;
|
|
224
|
+
return compiled.code;
|
|
216
225
|
}
|
|
217
226
|
export async function compileAll(repoRoot, options = {}) {
|
|
218
227
|
return withCompanyImportGraph(repoRoot, async () => {
|
|
@@ -220,52 +229,65 @@ export async function compileAll(repoRoot, options = {}) {
|
|
|
220
229
|
if (ids.length === 0) {
|
|
221
230
|
throw new Error(`No sequences found under ${path.join(repoRoot, 'sequences')} (a sequence is a directory with index.ts)`);
|
|
222
231
|
}
|
|
223
|
-
|
|
232
|
+
compileCompanySlotSchema(await loadCompanySchemas(repoRoot));
|
|
224
233
|
const results = [];
|
|
225
234
|
for (const sequenceId of ids) {
|
|
226
235
|
const { schemas: _, ...result } = await compileSequenceInGraph(repoRoot, sequenceId, options);
|
|
227
|
-
results.push(
|
|
236
|
+
results.push(result);
|
|
228
237
|
}
|
|
229
238
|
return results;
|
|
230
239
|
});
|
|
231
240
|
}
|
|
232
241
|
/**
|
|
233
242
|
* The company part of the company build (22 §5): the root `resolve.ts` as `companyResolve`, the root
|
|
234
|
-
* `webhook.ts` as `webhook.received`, the root `schedules.ts` as `schedule.<name>` (25 §6.4),
|
|
243
|
+
* `webhook.ts` as `webhook.received`, the root `schedules.ts` as `schedule.<name>` (25 §6.4), the root
|
|
244
|
+
* `errors.ts` as `onError` (67 §5), and the
|
|
235
245
|
* company schema with no subject. An error in it fails the
|
|
236
246
|
* whole compile.
|
|
237
247
|
*/
|
|
238
248
|
export async function compileCompanyPart(repoRoot, options = {}) {
|
|
249
|
+
return (await compileCompanyPartWithMaps(repoRoot, options)).part;
|
|
250
|
+
}
|
|
251
|
+
/** {@link compileCompanyPart}, with the source maps of its functions by `functionKey` (kept apart from the build). */
|
|
252
|
+
async function compileCompanyPartWithMaps(repoRoot, options) {
|
|
239
253
|
return withCompanyImportGraph(repoRoot, async () => {
|
|
240
254
|
const includeCode = options.includeCode ?? true;
|
|
241
255
|
// `resolve.ts` and `webhook.ts` import the root `__gen/`, which a fresh checkout does not have.
|
|
242
256
|
ensureCompanyStub(repoRoot);
|
|
243
|
-
|
|
257
|
+
// The schema first: an error in it fails the compile before any company code loads.
|
|
258
|
+
const schema = compileCompanySlotSchema(await loadCompanySchemas(repoRoot));
|
|
244
259
|
const companyResolvePath = requireCompanyResolveModule(repoRoot);
|
|
245
260
|
await loadCompanyResolver(companyResolvePath);
|
|
246
261
|
assertNoChannelsModule(repoRoot);
|
|
247
262
|
const webhookPath = findTsModule(repoRoot, WEBHOOK_MODULE);
|
|
248
263
|
if (webhookPath)
|
|
249
264
|
await loadCompanyWebhook(webhookPath);
|
|
250
|
-
const schedules = await loadSchedules(repoRoot
|
|
251
|
-
const
|
|
265
|
+
const schedules = await loadSchedules(repoRoot);
|
|
266
|
+
const onError = await loadOnError(repoRoot);
|
|
267
|
+
const sourceMaps = {};
|
|
268
|
+
const [resolveCompiled, webhookCompiled, schedulesRegistry, onErrorCompiled] = await Promise.all([
|
|
252
269
|
includeCode ? compileExportModuleCode(companyResolvePath, RESOLVE_FUNCTION) : Promise.resolve(undefined),
|
|
253
270
|
includeCode && webhookPath ? compileExportModuleCode(webhookPath, 'received') : Promise.resolve(undefined),
|
|
254
|
-
schedules ? scheduleRegistry(schedules, includeCode) : Promise.resolve({}),
|
|
271
|
+
schedules ? scheduleRegistry(schedules, includeCode, sourceMaps) : Promise.resolve({}),
|
|
272
|
+
includeCode && onError ? compileExportModuleCode(onError.path, ON_ERROR_FUNCTION) : Promise.resolve(undefined),
|
|
255
273
|
]);
|
|
256
|
-
const entry = (
|
|
257
|
-
|
|
258
|
-
|
|
274
|
+
const entry = (name, compiled) => {
|
|
275
|
+
const code = codeKeepingMap(name, compiled, sourceMaps);
|
|
276
|
+
return code === undefined ? {} : { code };
|
|
277
|
+
};
|
|
278
|
+
const part = {
|
|
259
279
|
functions: {
|
|
260
|
-
[COMPANY_RESOLVE_FUNCTION]: entry(
|
|
261
|
-
...(webhookPath ? { [WEBHOOK_RECEIVED_FUNCTION]: entry(
|
|
280
|
+
[COMPANY_RESOLVE_FUNCTION]: entry(COMPANY_RESOLVE_FUNCTION, resolveCompiled),
|
|
281
|
+
...(webhookPath ? { [WEBHOOK_RECEIVED_FUNCTION]: entry(WEBHOOK_RECEIVED_FUNCTION, webhookCompiled) } : {}),
|
|
262
282
|
...schedulesRegistry,
|
|
283
|
+
...(onError ? { [ON_ERROR_FUNCTION]: entry(ON_ERROR_FUNCTION, onErrorCompiled) } : {}),
|
|
263
284
|
},
|
|
264
285
|
...(schedules ? { schedules: schedules.manifest } : {}),
|
|
265
286
|
schema,
|
|
266
287
|
runtimeVersion: runtimePackageVersion(),
|
|
267
288
|
runtimeSource: options.runtimeSource ?? runtimePackageSource(repoRoot),
|
|
268
289
|
};
|
|
290
|
+
return { part, sourceMaps: keyedMaps(COMPANY_SCOPE, sourceMaps) };
|
|
269
291
|
});
|
|
270
292
|
}
|
|
271
293
|
export const COMPILE_CONCURRENCY = 4;
|
|
@@ -298,15 +320,17 @@ async function mapPool(items, limit, run) {
|
|
|
298
320
|
await Promise.all(workers);
|
|
299
321
|
}
|
|
300
322
|
/**
|
|
301
|
-
* Compile company
|
|
302
|
-
* repository. A sequence error is collected; a company schema error or a type error
|
|
303
|
-
* call, a type error with the tsc output as its message.
|
|
323
|
+
* Compile the company part (its schema first) once, then every named sequence in this process, then
|
|
324
|
+
* type-check the repository. A sequence error is collected; a company schema error or a type error
|
|
325
|
+
* rejects the whole call, a type error with the tsc output as its message.
|
|
304
326
|
*/
|
|
305
327
|
export async function compileRepo(repoRoot, options) {
|
|
306
328
|
return withCompanyImportGraph(repoRoot, async () => {
|
|
307
|
-
const companyMetadata = compileMetadata(await loadCompanySchemas(repoRoot));
|
|
308
329
|
const runtimeSource = options.runtimeSource ?? runtimePackageSource(repoRoot);
|
|
309
|
-
const company = await
|
|
330
|
+
const { part: company, sourceMaps: companySourceMaps } = await compileCompanyPartWithMaps(repoRoot, {
|
|
331
|
+
includeCode: true,
|
|
332
|
+
runtimeSource,
|
|
333
|
+
});
|
|
310
334
|
options.onEvent?.({
|
|
311
335
|
type: 'log',
|
|
312
336
|
text: `Repo build runtime: ${runtimePackageVersion()} (${runtimeSource})`,
|
|
@@ -322,7 +346,7 @@ export async function compileRepo(repoRoot, options) {
|
|
|
322
346
|
runtimeSource,
|
|
323
347
|
includeCode: true,
|
|
324
348
|
}), timeoutMs, `compile timed out after ${Math.round(timeoutMs / 60_000)} minutes`);
|
|
325
|
-
sequences[sequenceId] = { ok: true, build: result.build };
|
|
349
|
+
sequences[sequenceId] = { ok: true, build: result.build, sourceMaps: result.sourceMaps };
|
|
326
350
|
options.onEvent?.({ type: 'log', sequence: sequenceId, text: `Compiled ${sequenceId}` });
|
|
327
351
|
options.onEvent?.({ type: 'sequence-finished', sequence: sequenceId, ok: true });
|
|
328
352
|
}
|
|
@@ -336,7 +360,35 @@ export async function compileRepo(repoRoot, options) {
|
|
|
336
360
|
if (Object.values(sequences).every((outcome) => outcome.ok)) {
|
|
337
361
|
await typecheckRepo(repoRoot, (text) => options.onEvent?.({ type: 'log', text }));
|
|
338
362
|
}
|
|
339
|
-
return {
|
|
363
|
+
return { company, companySourceMaps, sequences };
|
|
340
364
|
});
|
|
341
365
|
}
|
|
366
|
+
/** The page actions' parameters, from their `args` types (76 §2.11): `actions` of `actions.ts`, as functions' are read; nothing without. */
|
|
367
|
+
function actionParameters(actionsPath, names, sequenceId) {
|
|
368
|
+
if (!actionsPath || names.length === 0)
|
|
369
|
+
return {};
|
|
370
|
+
const typed = readFunctionParameters(actionsPath, 'actions');
|
|
371
|
+
const out = {};
|
|
372
|
+
for (const name of names) {
|
|
373
|
+
const parameters = Object.hasOwn(typed, name) ? typed[name] : undefined;
|
|
374
|
+
if (!parameters)
|
|
375
|
+
throw new Error(`sequences/${sequenceId}/${path.basename(actionsPath)}: actions.${name}: the type checker does not see it as a function`);
|
|
376
|
+
out[name] = { parameters };
|
|
377
|
+
}
|
|
378
|
+
return { actions: out };
|
|
379
|
+
}
|
|
380
|
+
/** The functions' parameters, from their `args` types (38 §2.4), for the page's function buttons; nothing without functions. */
|
|
381
|
+
function functionParameters(functions, functionsPath) {
|
|
382
|
+
if (!functionsPath || Object.keys(functions).length === 0)
|
|
383
|
+
return {};
|
|
384
|
+
const typed = readFunctionParameters(functionsPath, 'functions');
|
|
385
|
+
const out = {};
|
|
386
|
+
for (const name of Object.keys(functions)) {
|
|
387
|
+
const parameters = Object.hasOwn(typed, name) ? typed[name] : undefined;
|
|
388
|
+
if (!parameters)
|
|
389
|
+
throw new Error(`${functionsPath}: functions.${name}: the type checker does not see it as a function`);
|
|
390
|
+
out[name] = { parameters };
|
|
391
|
+
}
|
|
392
|
+
return { functions: out };
|
|
393
|
+
}
|
|
342
394
|
//# sourceMappingURL=compile-sequence.js.map
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
+
import type { FunctionSourceMap } from '../types.js';
|
|
1
2
|
/**
|
|
2
3
|
* Compile a single function implementation to a standalone JS expression string
|
|
3
4
|
* suitable for QuickJS `eval` / registry `code` fields (minified).
|
|
4
5
|
*/
|
|
5
6
|
export declare function compileFunctionCode(fn: (...args: never[]) => unknown): Promise<string>;
|
|
7
|
+
/** A function's or page script's compiled code, and where its positions were in the company's files. */
|
|
8
|
+
export type CompiledModule = {
|
|
9
|
+
code: string;
|
|
10
|
+
map: FunctionSourceMap;
|
|
11
|
+
};
|
|
6
12
|
/** Bundle one registered function with module-local helpers and constants. */
|
|
7
|
-
export declare function compileFunctionModuleCode(modulePath: string, functionName: string): Promise<
|
|
13
|
+
export declare function compileFunctionModuleCode(modulePath: string, functionName: string): Promise<CompiledModule>;
|
|
8
14
|
/** Bundle one event handler (a plain function under the `events` export) with module-local helpers. */
|
|
9
|
-
export declare function compileEventModuleCode(modulePath: string, eventName: string): Promise<
|
|
15
|
+
export declare function compileEventModuleCode(modulePath: string, eventName: string): Promise<CompiledModule>;
|
|
10
16
|
/** Bundle one job's `run` of a `schedules.ts` (25 §6.4) with module-local helpers. */
|
|
11
|
-
export declare function compileScheduleModuleCode(modulePath: string, scheduleName: string): Promise<
|
|
12
|
-
/** Bundle a module's named export (a
|
|
13
|
-
export declare function compileExportModuleCode(modulePath: string, exportName: string): Promise<
|
|
17
|
+
export declare function compileScheduleModuleCode(modulePath: string, scheduleName: string): Promise<CompiledModule>;
|
|
18
|
+
/** Bundle a module's named export (a function) with its helpers. */
|
|
19
|
+
export declare function compileExportModuleCode(modulePath: string, exportName: string): Promise<CompiledModule>;
|
|
14
20
|
/**
|
|
15
|
-
* Bundle a sequence's page script (`context.page.ts`, 15 §10.2) with its helpers and
|
|
16
|
-
* the result evaluates to `pageEntry(module)`, which
|
|
17
|
-
* (`core/page/define.ts`).
|
|
21
|
+
* Bundle a sequence's page script (`context.page.ts`, 15 §10.2) with its helpers, and its page actions
|
|
22
|
+
* (`actions.ts`, 76 §2.11) when it has them: the result evaluates to `pageEntry(module, actions)`, which
|
|
23
|
+
* renders the page or runs one of its actions (`core/page/define.ts`).
|
|
18
24
|
*/
|
|
19
|
-
export declare function compilePageModuleCode(modulePath: string): Promise<
|
|
25
|
+
export declare function compilePageModuleCode(modulePath: string, actionsPath?: string | null): Promise<CompiledModule>;
|
|
20
26
|
//# sourceMappingURL=function-code.d.ts.map
|
|
@@ -16,20 +16,23 @@ function runtimeModule(name) {
|
|
|
16
16
|
const ENTRY_FILE = 'superpanel-function-entry.ts';
|
|
17
17
|
/** Marks a resolve the plugin asked for itself, so it does not check its own request. */
|
|
18
18
|
const CHECKED = Symbol('company import checked');
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
* this runtime's own company API (`src/index.ts`): a code string carries the helpers of the runtime that
|
|
22
|
-
* compiled it, whichever copy the repository would resolve, and keeps of them only what it uses.
|
|
23
|
-
*/
|
|
24
|
-
function companyImportsPlugin(repoRoot, entryFile) {
|
|
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) {
|
|
25
21
|
const root = realPath(repoRoot);
|
|
26
|
-
|
|
22
|
+
return (file) => {
|
|
27
23
|
// The entry is the compile's own (it picks the export and the page's `pageEntry`), not the company's.
|
|
28
24
|
if (!path.isAbsolute(file) || file === entryFile)
|
|
29
25
|
return false;
|
|
30
26
|
const relative = path.relative(root, realPath(file));
|
|
31
27
|
return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative) && !relative.split(path.sep).includes('node_modules');
|
|
32
28
|
};
|
|
29
|
+
}
|
|
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) {
|
|
33
36
|
return {
|
|
34
37
|
name: 'superpanel-company-imports',
|
|
35
38
|
setup(build) {
|
|
@@ -74,12 +77,8 @@ export async function compileFunctionCode(fn) {
|
|
|
74
77
|
logLevel: 'silent',
|
|
75
78
|
});
|
|
76
79
|
const text = result.code.trim();
|
|
77
|
-
if (text.includes('@superpanel-sdk/runtime')
|
|
78
|
-
|
|
79
|
-
text.includes('defineNoCaseFunc') ||
|
|
80
|
-
text.includes('defineEvents') ||
|
|
81
|
-
text.includes('bindDefines')) {
|
|
82
|
-
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');
|
|
83
82
|
}
|
|
84
83
|
const m = /^export\s+default\s*/.exec(text);
|
|
85
84
|
if (!m) {
|
|
@@ -87,40 +86,68 @@ export async function compileFunctionCode(fn) {
|
|
|
87
86
|
}
|
|
88
87
|
return text.slice(m[0].length).replace(/;?\s*$/, '');
|
|
89
88
|
}
|
|
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})()';
|
|
90
92
|
async function compileModuleSelection(modulePath, selection, imports = '') {
|
|
91
93
|
// The compile bundles inside its import graph; a caller outside one (a test) bundles within the module's package.
|
|
92
|
-
|
|
93
|
-
const
|
|
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);
|
|
94
98
|
const result = await esbuild.build({
|
|
95
99
|
stdin: {
|
|
96
100
|
contents: `import * as mod from ${JSON.stringify(modulePath)};
|
|
97
101
|
${imports}
|
|
98
102
|
const selected = ${selection};
|
|
99
103
|
export default selected;`,
|
|
100
|
-
resolveDir: path.dirname(
|
|
104
|
+
resolveDir: path.dirname(entryFile),
|
|
101
105
|
sourcefile: ENTRY_FILE,
|
|
102
106
|
loader: 'ts',
|
|
103
107
|
},
|
|
108
|
+
absWorkingDir: repoRoot,
|
|
104
109
|
bundle: true,
|
|
105
110
|
write: false,
|
|
111
|
+
outfile: 'superpanel-function.js',
|
|
106
112
|
platform: 'neutral',
|
|
107
113
|
format: 'iife',
|
|
108
114
|
globalName: '__superpanel_function',
|
|
109
115
|
target: 'es2022',
|
|
110
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,
|
|
111
121
|
logLevel: 'silent',
|
|
112
|
-
|
|
122
|
+
banner: { js: BUNDLE_HEAD },
|
|
123
|
+
footer: { js: BUNDLE_TAIL },
|
|
124
|
+
sourcemap: 'external',
|
|
125
|
+
sourcesContent: false,
|
|
126
|
+
plugins: [companyImportsPlugin(repoRoot, isCompanyFile)],
|
|
113
127
|
});
|
|
114
|
-
const
|
|
115
|
-
|
|
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) {
|
|
116
131
|
throw new Error(`Failed to compile function module ${modulePath}`);
|
|
117
132
|
}
|
|
118
|
-
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
|
+
};
|
|
119
146
|
}
|
|
120
147
|
/** Bundle one registered function with module-local helpers and constants. */
|
|
121
148
|
export function compileFunctionModuleCode(modulePath, functionName) {
|
|
122
149
|
const registry = `(mod.functions ?? mod.default?.functions ?? mod.default)`;
|
|
123
|
-
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(functionName)}]
|
|
150
|
+
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(functionName)}]`);
|
|
124
151
|
}
|
|
125
152
|
/** Bundle one event handler (a plain function under the `events` export) with module-local helpers. */
|
|
126
153
|
export function compileEventModuleCode(modulePath, eventName) {
|
|
@@ -132,17 +159,20 @@ export function compileScheduleModuleCode(modulePath, scheduleName) {
|
|
|
132
159
|
const registry = `(mod.schedules ?? mod.default?.schedules ?? mod.default)`;
|
|
133
160
|
return compileModuleSelection(modulePath, `${registry}[${JSON.stringify(scheduleName)}].run`);
|
|
134
161
|
}
|
|
135
|
-
/** Bundle a module's named export (a
|
|
162
|
+
/** Bundle a module's named export (a function) with its helpers. */
|
|
136
163
|
export function compileExportModuleCode(modulePath, exportName) {
|
|
137
|
-
|
|
138
|
-
return compileModuleSelection(modulePath, `(${entry}.main ?? ${entry})`);
|
|
164
|
+
return compileModuleSelection(modulePath, `(mod[${JSON.stringify(exportName)}] ?? mod.default)`);
|
|
139
165
|
}
|
|
140
166
|
/**
|
|
141
|
-
* Bundle a sequence's page script (`context.page.ts`, 15 §10.2) with its helpers and
|
|
142
|
-
* the result evaluates to `pageEntry(module)`, which
|
|
143
|
-
* (`core/page/define.ts`).
|
|
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`).
|
|
144
170
|
*/
|
|
145
|
-
export function compilePageModuleCode(modulePath) {
|
|
146
|
-
|
|
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);
|
|
147
177
|
}
|
|
148
178
|
//# sourceMappingURL=function-code.js.map
|