@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.
Files changed (189) hide show
  1. package/README.md +3 -3
  2. package/dist/builder/codegen/emit.d.ts +5 -10
  3. package/dist/builder/codegen/emit.js +100 -106
  4. package/dist/builder/codegen/generate.d.ts +3 -5
  5. package/dist/builder/codegen/generate.js +13 -32
  6. package/dist/builder/company-imports.d.ts +5 -0
  7. package/dist/builder/company-imports.js +9 -1
  8. package/dist/builder/compile/compile-sequence.d.ts +13 -11
  9. package/dist/builder/compile/compile-sequence.js +135 -83
  10. package/dist/builder/compile/function-code.d.ts +15 -9
  11. package/dist/builder/compile/function-code.js +59 -29
  12. package/dist/builder/compile/registry.d.ts +4 -4
  13. package/dist/builder/compile/registry.js +14 -12
  14. package/dist/builder/errors.d.ts +9 -0
  15. package/dist/builder/errors.js +17 -0
  16. package/dist/builder/function-params.d.ts +10 -0
  17. package/dist/builder/function-params.js +203 -0
  18. package/dist/builder/load.d.ts +17 -17
  19. package/dist/builder/load.js +27 -25
  20. package/dist/builder/paths.d.ts +6 -1
  21. package/dist/builder/paths.js +16 -2
  22. package/dist/builder/schedules.d.ts +9 -7
  23. package/dist/builder/schedules.js +20 -21
  24. package/dist/builder/typecheck.d.ts +1 -1
  25. package/dist/builder/typecheck.js +3 -6
  26. package/dist/builder/types.d.ts +41 -5
  27. package/dist/builder/types.js +19 -0
  28. package/dist/cli/calls/index.d.ts +177 -0
  29. package/dist/cli/calls/index.js +96 -0
  30. package/dist/cli/debug/index.d.ts +31 -0
  31. package/dist/cli/debug/index.js +119 -0
  32. package/dist/cli/exec/index.d.ts +39 -0
  33. package/dist/cli/exec/index.js +138 -0
  34. package/dist/cli/exec/session.d.ts +48 -0
  35. package/dist/cli/exec/session.js +82 -0
  36. package/dist/cli/exec/trace.d.ts +18 -0
  37. package/dist/cli/exec/trace.js +52 -0
  38. package/dist/cli/index.js +84 -1
  39. package/dist/cli/logs/index.d.ts +47 -0
  40. package/dist/cli/logs/index.js +113 -0
  41. package/dist/cli/mobile/index.d.ts +12 -0
  42. package/dist/cli/mobile/index.js +405 -0
  43. package/dist/cli/serve/index.d.ts +40 -4
  44. package/dist/cli/serve/index.js +167 -28
  45. package/dist/cli/turns/index.d.ts +105 -0
  46. package/dist/cli/turns/index.js +128 -0
  47. package/dist/cli/turns/run.d.ts +13 -0
  48. package/dist/cli/turns/run.js +57 -0
  49. package/dist/cli/turns/shadow.d.ts +112 -0
  50. package/dist/cli/turns/shadow.js +54 -0
  51. package/dist/cli/type-gen/index.js +0 -1
  52. package/dist/compute-host/compute-host.d.ts +5 -6
  53. package/dist/compute-host/compute-host.js +4 -13
  54. package/dist/compute-host/source-compute-host.d.ts +5 -7
  55. package/dist/compute-host/source-compute-host.js +12 -33
  56. package/dist/core/case-orchestrator/contact-hours.d.ts +26 -6
  57. package/dist/core/case-orchestrator/contact-hours.js +27 -8
  58. package/dist/core/case-orchestrator/index.d.ts +1 -4
  59. package/dist/core/case-orchestrator/index.js +1 -4
  60. package/dist/core/case-orchestrator/render.d.ts +1 -1
  61. package/dist/core/case-orchestrator/render.js +15 -10
  62. package/dist/core/case-orchestrator/types.d.ts +83 -128
  63. package/dist/core/case-orchestrator/types.js +0 -4
  64. package/dist/core/context/email-message.d.ts +40 -1
  65. package/dist/core/context/email-message.js +27 -0
  66. package/dist/core/context/email.d.ts +13 -1
  67. package/dist/core/context/email.js +2 -3
  68. package/dist/core/context/exchanges.d.ts +25 -0
  69. package/dist/core/context/exchanges.js +25 -7
  70. package/dist/core/context/instances.d.ts +31 -2
  71. package/dist/core/context/instances.js +18 -4
  72. package/dist/core/context/platform-registry.d.ts +35 -0
  73. package/dist/core/context/sms.d.ts +30 -0
  74. package/dist/core/context/sms.js +20 -0
  75. package/dist/core/context/types.d.ts +29 -1
  76. package/dist/core/conversation/index.d.ts +58 -4
  77. package/dist/core/conversation/index.js +123 -4
  78. package/dist/core/functions/errors.d.ts +74 -0
  79. package/dist/core/functions/errors.js +26 -0
  80. package/dist/core/functions/events.d.ts +23 -78
  81. package/dist/core/functions/events.js +8 -17
  82. package/dist/core/functions/schedules.d.ts +9 -10
  83. package/dist/core/functions/schedules.js +2 -2
  84. package/dist/core/functions/types.d.ts +17 -72
  85. package/dist/core/functions/types.js +1 -9
  86. package/dist/core/page/define.d.ts +230 -160
  87. package/dist/core/page/define.js +145 -104
  88. package/dist/core/page/envelope.d.ts +55 -0
  89. package/dist/core/page/envelope.js +4 -0
  90. package/dist/core/page/fns.d.ts +448 -0
  91. package/dist/core/page/fns.js +539 -0
  92. package/dist/core/page/memory-reader.d.ts +27 -0
  93. package/dist/core/page/memory-reader.js +299 -0
  94. package/dist/core/page/page-host.d.ts +20 -0
  95. package/dist/core/page/page-host.js +57 -0
  96. package/dist/core/page/records-query.d.ts +234 -0
  97. package/dist/core/page/records-query.js +780 -0
  98. package/dist/core/page/render.d.ts +67 -25
  99. package/dist/core/page/render.js +492 -272
  100. package/dist/core/page/sandbox.d.ts +85 -0
  101. package/dist/core/page/sandbox.js +357 -0
  102. package/dist/core/page/time-format.d.ts +27 -0
  103. package/dist/core/page/time-format.js +84 -0
  104. package/dist/core/page/typed.d.ts +165 -159
  105. package/dist/core/page/workspace.d.ts +25 -1
  106. package/dist/core/page/workspace.js +48 -13
  107. package/dist/core/party/schema.d.ts +74 -3
  108. package/dist/core/party/schema.js +39 -6
  109. package/dist/core/party/types.d.ts +8 -13
  110. package/dist/core/sequence/define.d.ts +1 -2
  111. package/dist/core/slot/company-metadata.d.ts +11 -22
  112. package/dist/core/slot/company-metadata.js +12 -39
  113. package/dist/core/slot/compile-schema.js +6 -6
  114. package/dist/core/slot/field.d.ts +1 -2
  115. package/dist/core/slot/field.js +0 -2
  116. package/dist/core/slot/index.d.ts +3 -3
  117. package/dist/core/slot/index.js +3 -3
  118. package/dist/core/slot/naming.d.ts +1 -1
  119. package/dist/core/slot/naming.js +1 -1
  120. package/dist/core/slot/platform-fields.d.ts +4 -4
  121. package/dist/core/slot/platform-fields.js +5 -5
  122. package/dist/core/slot/schema-compat.d.ts +8 -7
  123. package/dist/core/slot/schema-compat.js +22 -31
  124. package/dist/core/slot/schema.d.ts +3 -59
  125. package/dist/core/slot/schema.js +0 -15
  126. package/dist/core/slot/types.d.ts +4 -10
  127. package/dist/core/slot/value.d.ts +2 -0
  128. package/dist/core/slot/value.js +6 -2
  129. package/dist/dev-overlay/protocol.d.ts +38 -5
  130. package/dist/fn-context/build-context.js +10 -4
  131. package/dist/fn-context/fake/index.d.ts +2 -0
  132. package/dist/fn-context/fake/index.js +5 -3
  133. package/dist/fn-context/fn-params.d.ts +2 -5
  134. package/dist/fn-context/fn-params.js +6 -9
  135. package/dist/fn-context/index.d.ts +1 -1
  136. package/dist/fn-context/make-ctx.js +5 -4
  137. package/dist/fn-context/rpc/case-orchestrator-tools.d.ts +11 -3
  138. package/dist/fn-context/rpc/case-orchestrator-tools.js +0 -1
  139. package/dist/fn-context/rpc/errors.d.ts +13 -0
  140. package/dist/fn-context/rpc/errors.js +22 -0
  141. package/dist/fn-context/rpc/index.d.ts +1 -1
  142. package/dist/fn-context/rpc/index.js +1 -1
  143. package/dist/fn-context/rpc/integration/index.d.ts +11 -1
  144. package/dist/fn-context/rpc/log.d.ts +11 -1
  145. package/dist/fn-context/rpc/platform.d.ts +11 -1
  146. package/dist/fn-context/rpc/records.d.ts +13 -6
  147. package/dist/fn-context/rpc/records.js +2 -4
  148. package/dist/fn-context/rpc/trpc-client.d.ts +42 -0
  149. package/dist/fn-context/rpc/trpc-client.js +151 -22
  150. package/dist/fn-context/rpc/trpc-init.d.ts +19 -1
  151. package/dist/fn-context/rpc/trpc-init.js +10 -4
  152. package/dist/fn-context/rpc/trpc-router-factory.d.ts +66 -8
  153. package/dist/fn-context/run-scope.js +1 -1
  154. package/dist/fn-context/types.d.ts +20 -6
  155. package/dist/index.d.ts +11 -12
  156. package/dist/index.js +5 -8
  157. package/dist/logger.d.ts +4 -0
  158. package/dist/logger.js +8 -0
  159. package/dist/platform.d.ts +32 -33
  160. package/dist/platform.js +23 -22
  161. package/dist/testing-compile-child.d.ts +2 -0
  162. package/dist/testing-compile-child.js +20 -0
  163. package/dist/testing.d.ts +368 -0
  164. package/dist/testing.js +439 -0
  165. package/dist/voice-service/actions.d.ts +12 -35
  166. package/dist/voice-service/index.d.ts +2 -0
  167. package/dist/voice-service/index.js +2 -0
  168. package/dist/voice-service/protocol.d.ts +604 -0
  169. package/dist/voice-service/protocol.js +67 -0
  170. package/dist/voice-service/types.d.ts +16 -6
  171. package/dist/worker.d.ts +2 -1
  172. package/dist/worker.js +2 -1
  173. package/package.json +20 -16
  174. package/dist/core/case-orchestrator/follow-ups.d.ts +0 -31
  175. package/dist/core/case-orchestrator/follow-ups.js +0 -103
  176. package/dist/core/case-orchestrator/tools.d.ts +0 -29
  177. package/dist/core/case-orchestrator/tools.js +0 -31
  178. package/dist/core/case-orchestrator/validate.d.ts +0 -11
  179. package/dist/core/case-orchestrator/validate.js +0 -63
  180. package/dist/core/functions/define/bind.d.ts +0 -25
  181. package/dist/core/functions/define/bind.js +0 -14
  182. package/dist/core/functions/define/case.d.ts +0 -9
  183. package/dist/core/functions/define/case.js +0 -13
  184. package/dist/core/functions/define/events.d.ts +0 -20
  185. package/dist/core/functions/define/events.js +0 -21
  186. package/dist/core/functions/define/no-case.d.ts +0 -4
  187. package/dist/core/functions/define/no-case.js +0 -9
  188. package/dist/core/functions/func-ref.d.ts +0 -25
  189. 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 { CompiledCompanyMetadata } from '../../core/slot/schema.js';
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
- companyMetadata: CompiledCompanyMetadata;
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<CompileSequenceBuildResult>;
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), and the
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 metadata once, then every named sequence in this process, then type-check the
72
- * repository. A sequence error is collected; a company schema error or a type error rejects the whole
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 { compileCompanyMetadata, subjectTableIssues } from '../../core/slot/company-metadata.js';
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 { ORCHESTRATOR_CONTACTS_FUNCTION, ORCHESTRATOR_FUNCTION, } from '../../core/case-orchestrator/types.js';
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 { isPlatformName, listSequenceIds, loadCompanySchema, loadCompanyWebhook, WEBHOOK_MODULE, loadOfficeHours, loadSequenceCaseOrchestrator, loadSequenceEvents, loadSequenceFunctions, loadSequenceDefinition, loadCompanyResolver, loadSequenceResolver, loadSequenceVariables, loadPageChannels, loadSessionSchema, assertNoSlotsModule, assertNoChannelsModule, } from '../load.js';
13
- import { findTsModule, requireCompanyResolveModule, requireResolveModule, resolveTsModule } from '../paths.js';
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 { assertNoScheduleNames, loadSchedules, scheduleRegistry } from '../schedules.js';
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
- function compileMetadata({ company, session }) {
45
- const result = compileCompanyMetadata(company, session);
46
- if (!result.validation.ok || !result.metadata) {
47
- throw new Error(result.validation.ok
48
- ? 'invalid company metadata'
49
- : result.validation.issues.map((issue) => issue.message).join('; '));
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 result.metadata;
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
- const { schemas, ...build } = result;
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
- for (const reserved of [ORCHESTRATOR_FUNCTION, ORCHESTRATOR_CONTACTS_FUNCTION]) {
95
- if (Object.hasOwn(authored, reserved)) {
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
- assertNoScheduleNames(Object.keys(authored), `sequences/${sequenceId}/functions`);
105
- // The sequence's recurring jobs (25 §6.4): `schedule.<name>` functions, timed by `schedules`.
106
- const schedules = await loadSchedules(sequenceDir, `sequences/${sequenceId}/schedules.ts`);
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 = findTsModule(sequenceDir, 'context.page');
135
- if (!pagePath) {
136
- throw new Error(`sequences/${sequenceId}: context.page.ts is required (the conversation's page, 15 §10.2)`);
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 [functionsRegistry, resolveCode, caseOrchestratorCode, caseOrchestratorContactsCode, eventsRegistry, pageCode, schedulesRegistry,] = await Promise.all([
168
- toFunctionRegistry(authored, { includeCode, modulePath: functionsPath }),
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
- caseOrchestratorPath && includeCode ? compileExportModuleCode(caseOrchestratorPath, 'contacts') : Promise.resolve(undefined),
174
- toEventRegistry(events, { includeCode, modulePath: eventsPath }),
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 channels = loadPageChannels(pageCode, sequenceId);
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 ? { kind: 'noCase' } : { kind: 'noCase', code: resolveCode },
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 { sequenceId, outPath, build, schema, schemas, wrote: !options.dryRun };
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
- const companyMetadata = compileMetadata(await loadCompanySchemas(repoRoot));
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({ ...result, companyMetadata });
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), and the
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
- const { company, session } = await loadCompanySchemas(repoRoot);
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, 'schedules.ts');
251
- const [resolveCode, webhookCode, schedulesRegistry] = await Promise.all([
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 = (code) => (code === undefined ? { kind: 'noCase' } : { kind: 'noCase', code });
257
- const { schema } = compileSlotSchema(company, { session });
258
- return {
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(resolveCode),
261
- ...(webhookPath ? { [WEBHOOK_RECEIVED_FUNCTION]: entry(webhookCode) } : {}),
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 metadata once, then every named sequence in this process, then type-check the
302
- * repository. A sequence error is collected; a company schema error or a type error rejects the whole
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 compileCompanyPart(repoRoot, { includeCode: true, runtimeSource });
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 { companyMetadata, company, sequences };
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<string>;
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<string>;
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<string>;
12
- /** Bundle a module's named export (a plain function, or a `define*` result's `main`) with its helpers. */
13
- export declare function compileExportModuleCode(modulePath: string, exportName: string): Promise<string>;
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 the page module:
16
- * the result evaluates to `pageEntry(module)`, which renders the page or runs one of its actions
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<string>;
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
- * Checks every import a company file makes (company-imports.ts) and bundles `@superpanel-sdk/runtime` as
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
- const isCompanyFile = (file) => {
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
- text.includes('defineCaseFunc') ||
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
- const repoRoot = companyRepoRoot() ?? packageRootOf(modulePath);
93
- const entryFile = path.join(path.dirname(modulePath), ENTRY_FILE);
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(modulePath),
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
- plugins: [companyImportsPlugin(repoRoot, entryFile)],
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 output = result.outputFiles[0]?.text.trim();
115
- if (!output) {
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 `(()=>{${output};return __superpanel_function.default})()`;
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)}].main`);
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 plain function, or a `define*` result's `main`) with its helpers. */
162
+ /** Bundle a module's named export (a function) with its helpers. */
136
163
  export function compileExportModuleCode(modulePath, exportName) {
137
- const entry = `(mod[${JSON.stringify(exportName)}] ?? mod.default)`;
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 the page module:
142
- * the result evaluates to `pageEntry(module)`, which renders the page or runs one of its actions
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
- return compileModuleSelection(modulePath, 'pageEntry(mod)', `import { pageEntry } from ${JSON.stringify(runtimeModule('core/page/define'))};`);
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