@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,19 +1,19 @@
1
1
  import { type AnyEventHandlers } from '../../core/functions/events.js';
2
2
  import type { FuncMap, FunctionRegistry } from '../../core/functions/types.js';
3
+ import type { FunctionSourceMap } from '../types.js';
3
4
  export type BuildRegistryOptions = {
4
5
  /** When false, skip esbuild and omit `code` (local serve overlay). Default true. */
5
6
  includeCode?: boolean;
6
7
  /** Source module used to bundle module-local helpers and constants. */
7
8
  modulePath?: string;
9
+ /** Receives each function's source map by name (a module's bundle only): kept out of the registry. */
10
+ sourceMaps?: Record<string, FunctionSourceMap>;
8
11
  };
9
12
  /**
10
13
  * Project author FuncMap → JSON-safe registry.
11
14
  * Published builds include per-function compiled `code`; overlay omits it.
12
15
  */
13
16
  export declare function toFunctionRegistry(functions: FuncMap, options?: BuildRegistryOptions): Promise<FunctionRegistry>;
14
- /**
15
- * Project the company `events` export → JSON-safe registry. The kind of each
16
- * handler is fixed by the platform event table (`case` / `noCase`), not by the author.
17
- */
17
+ /** Project the company `events` export → JSON-safe registry: each handler by its event's name. */
18
18
  export declare function toEventRegistry(events: AnyEventHandlers, options?: BuildRegistryOptions): Promise<FunctionRegistry>;
19
19
  //# sourceMappingURL=registry.d.ts.map
@@ -1,5 +1,11 @@
1
- import { isSystemEventName, systemEventKind } from '../../core/functions/events.js';
1
+ import { isSystemEventName } from '../../core/functions/events.js';
2
2
  import { compileEventModuleCode, compileFunctionCode, compileFunctionModuleCode } from './function-code.js';
3
+ /** The bundle's code; its map goes to `sourceMaps`. */
4
+ function keepMap(name, compiled, sourceMaps) {
5
+ if (sourceMaps)
6
+ sourceMaps[name] = compiled.map;
7
+ return compiled.code;
8
+ }
3
9
  function withCode(entry, code) {
4
10
  if (code === undefined)
5
11
  return entry;
@@ -12,21 +18,17 @@ function withCode(entry, code) {
12
18
  export async function toFunctionRegistry(functions, options = {}) {
13
19
  const includeCode = options.includeCode ?? true;
14
20
  const out = {};
15
- for (const [name, def] of Object.entries(functions)) {
21
+ for (const [name, fn] of Object.entries(functions)) {
16
22
  const code = includeCode
17
23
  ? options.modulePath
18
- ? await compileFunctionModuleCode(options.modulePath, name)
19
- : await compileFunctionCode(def.main)
24
+ ? keepMap(name, await compileFunctionModuleCode(options.modulePath, name), options.sourceMaps)
25
+ : await compileFunctionCode(fn)
20
26
  : undefined;
21
- const entry = withCode({ kind: def.kind }, code);
22
- out[name] = entry;
27
+ out[name] = withCode({}, code);
23
28
  }
24
29
  return out;
25
30
  }
26
- /**
27
- * Project the company `events` export → JSON-safe registry. The kind of each
28
- * handler is fixed by the platform event table (`case` / `noCase`), not by the author.
29
- */
31
+ /** Project the company `events` export → JSON-safe registry: each handler by its event's name. */
30
32
  export async function toEventRegistry(events, options = {}) {
31
33
  const includeCode = options.includeCode ?? true;
32
34
  const out = {};
@@ -39,10 +41,10 @@ export async function toEventRegistry(events, options = {}) {
39
41
  }
40
42
  const code = includeCode
41
43
  ? options.modulePath
42
- ? await compileEventModuleCode(options.modulePath, name)
44
+ ? keepMap(name, await compileEventModuleCode(options.modulePath, name), options.sourceMaps)
43
45
  : await compileFunctionCode(handler)
44
46
  : undefined;
45
- out[name] = withCode({ kind: systemEventKind(name) }, code);
47
+ out[name] = withCode({}, code);
46
48
  }
47
49
  return out;
48
50
  }
@@ -0,0 +1,9 @@
1
+ import type { FuncMap } from '../core/functions/types.js';
2
+ /** The repository root's `errors.ts`, loaded: its `onError`, what serve runs. `null` without the file. */
3
+ export type LoadedOnError = {
4
+ path: string;
5
+ functions: FuncMap;
6
+ };
7
+ /** Load and check the repository root's `errors.ts` (67 §5): it exports `onError`, a function. */
8
+ export declare function loadOnError(repoRoot: string): Promise<LoadedOnError | null>;
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { ERRORS_MODULE, ON_ERROR_FUNCTION } from '../core/functions/errors.js';
3
+ import { companyImportGraphHref } from './company-import-graph.js';
4
+ import { findTsModule } from './paths.js';
5
+ /** Load and check the repository root's `errors.ts` (67 §5): it exports `onError`, a function. */
6
+ export async function loadOnError(repoRoot) {
7
+ const modulePath = findTsModule(repoRoot, ERRORS_MODULE);
8
+ if (!modulePath)
9
+ return null;
10
+ const mod = (await import(companyImportGraphHref(pathToFileURL(modulePath).href)));
11
+ const onError = mod[ON_ERROR_FUNCTION] ?? mod.default;
12
+ if (typeof onError !== 'function') {
13
+ throw new Error(`${ERRORS_MODULE}.ts: export const ${ON_ERROR_FUNCTION}: OnError = async (ctx, { error }) => { … } (67 §5)`);
14
+ }
15
+ return { path: modulePath, functions: { [ON_ERROR_FUNCTION]: onError } };
16
+ }
17
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,10 @@
1
+ import type { ActionParameters } from '../core/page/define.js';
2
+ export declare class FunctionParamsError extends Error {
3
+ }
4
+ /**
5
+ * The parameters of every function in `exportName` of `modulePath`, by its key. A function with no
6
+ * second parameter takes none (`{ type: 'object', properties: {} }`). A `define*` result (no call
7
+ * signature) is left out: it declares its own.
8
+ */
9
+ export declare function readFunctionParameters(modulePath: string, exportName: string): Record<string, ActionParameters>;
10
+ //# sourceMappingURL=function-params.d.ts.map
@@ -0,0 +1,203 @@
1
+ import { existsSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { API, SignatureKind, SymbolFlags, TypeFlags, } from 'typescript/unstable/sync';
4
+ /**
5
+ * A function's parameters from its TypeScript type (38 §2.4): the builder reads the second parameter of
6
+ * each function in a registry export (`functions`, `actions` of `actions.ts`) as the pinned TypeScript's checker
7
+ * sees it, expanded, and writes what the AI sees of it. Whatever falls outside the types below is the
8
+ * author's mistake, said with the type to use instead.
9
+ */
10
+ /** The marks `Id<T>` and the format types carry (`core/page/typed.ts`), as the checker names them. */
11
+ const ID_MARK = /^__@ID_BRAND@/;
12
+ const FORMAT_MARK = /^__@FORMAT_BRAND@/;
13
+ const FORMATS = new Set(['date', 'datetime', 'time', 'phone', 'email']);
14
+ const PARAMETER_TYPES = "string, number, boolean, literals ('a' | 'b'), Id<'table'>, IsoDate, IsoDateTime, TimeOfDay, Phone, Email, ContactSchedule, a list or an object";
15
+ export class FunctionParamsError extends Error {
16
+ }
17
+ /** The repository's `tsconfig.json`: the nearest one above the module. */
18
+ function tsconfigOf(modulePath) {
19
+ for (let dir = path.dirname(modulePath);; dir = path.dirname(dir)) {
20
+ const candidate = path.join(dir, 'tsconfig.json');
21
+ if (existsSync(candidate))
22
+ return candidate;
23
+ if (path.dirname(dir) === dir)
24
+ throw new FunctionParamsError(`${modulePath}: no tsconfig.json above it`);
25
+ }
26
+ }
27
+ /**
28
+ * The parameters of every function in `exportName` of `modulePath`, by its key. A function with no
29
+ * second parameter takes none (`{ type: 'object', properties: {} }`). A `define*` result (no call
30
+ * signature) is left out: it declares its own.
31
+ */
32
+ export function readFunctionParameters(modulePath, exportName) {
33
+ const tsconfig = tsconfigOf(modulePath);
34
+ const api = new API({ cwd: path.dirname(tsconfig) });
35
+ try {
36
+ const snapshot = api.updateSnapshot({ openProjects: [tsconfig] });
37
+ const project = snapshot.getDefaultProjectForFile(modulePath) ?? snapshot.getProject(tsconfig);
38
+ const source = project?.program.getSourceFile(modulePath);
39
+ if (!project || !source)
40
+ throw new FunctionParamsError(`${modulePath}: not part of ${tsconfig}'s program`);
41
+ const { checker } = project;
42
+ const moduleSymbol = checker.getSymbolAtLocation(source);
43
+ const exported = moduleSymbol
44
+ ? checker.getExportsOfModule(moduleSymbol).find((s) => s.name === exportName)
45
+ : undefined;
46
+ if (!exported)
47
+ return {};
48
+ const registry = checker.getTypeOfSymbol(exported);
49
+ if (!registry)
50
+ return {};
51
+ const where = path.basename(modulePath);
52
+ const out = {};
53
+ for (const entry of checker.getPropertiesOfType(registry)) {
54
+ // JavaScript keeps this name for an object's prototype: as a key it is easily not the object's own.
55
+ if (entry.name === '__proto__')
56
+ throw new FunctionParamsError(`${path.basename(modulePath)}: ${exportName}.__proto__: pick another name`);
57
+ const type = checker.getTypeOfSymbol(entry);
58
+ if (!type)
59
+ continue;
60
+ const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
61
+ if (signatures.length === 0)
62
+ continue;
63
+ const label = `${where}: ${exportName}.${entry.name}`;
64
+ if (signatures.length > 1)
65
+ throw new FunctionParamsError(`${label} is overloaded: a function has one signature, (ctx, args)`);
66
+ const signature = signatures[0];
67
+ // `(...args)` hides how many it takes and which is args: the builder could not show the AI what to fill.
68
+ if (signature.hasRestParameter)
69
+ throw new FunctionParamsError(`${label} takes a rest parameter: a function takes (ctx, args), args one object`);
70
+ const params = signature.getParameters();
71
+ if (params.length > 2)
72
+ throw new FunctionParamsError(`${label} takes ${params.length} parameters: a function takes (ctx, args), args one object`);
73
+ if (params.length < 2) {
74
+ out[entry.name] = { type: 'object', properties: {} };
75
+ continue;
76
+ }
77
+ const argsType = checker.getParameterType(signature, 1);
78
+ if (!argsType)
79
+ throw new FunctionParamsError(`${label}: the type checker cannot read its args`);
80
+ const optional = params[1].flags & SymbolFlags.Optional ||
81
+ (argsType.isUnionType() && argsType.getTypes().some((t) => t.flags & TypeFlags.Undefined));
82
+ if (optional)
83
+ throw new FunctionParamsError(`${label}: args must be one object parameter, not optional`);
84
+ const top = objectParam(checker, argsType, `${label}(args)`);
85
+ out[entry.name] = {
86
+ type: 'object',
87
+ properties: top.properties,
88
+ ...(top.required?.length ? { required: top.required } : {}),
89
+ };
90
+ }
91
+ return out;
92
+ }
93
+ finally {
94
+ api.close();
95
+ }
96
+ }
97
+ /** A union's members without `undefined` (an optional parameter's); any other type alone. */
98
+ function withoutUndefined(type) {
99
+ return (type.isUnionType() ? type.getTypes() : [type]).filter((t) => !(t.flags & TypeFlags.Undefined));
100
+ }
101
+ function isPlainObject(checker, type) {
102
+ return (type.isObjectType() &&
103
+ !checker.isArrayType(type) &&
104
+ checker.getSignaturesOfType(type, SignatureKind.Call).length === 0);
105
+ }
106
+ function objectParam(checker, type, where) {
107
+ if (!isPlainObject(checker, type) &&
108
+ !(type.isIntersectionType() && type.getTypes().every((t) => isPlainObject(checker, t)))) {
109
+ throw new FunctionParamsError(`${where}: not an object of named parameters`);
110
+ }
111
+ if (checker.getIndexInfosOfType(type).length > 0)
112
+ throw new FunctionParamsError(`${where} has an index signature (Record<string, …>): name each parameter`);
113
+ const properties = {};
114
+ const required = [];
115
+ for (const prop of checker.getPropertiesOfType(type)) {
116
+ const propType = checker.getTypeOfSymbol(prop);
117
+ if (!propType)
118
+ throw new FunctionParamsError(`${where}.${prop.name}: the type checker cannot read it`);
119
+ // A row inside an object or a list is the page's to prefill: the page refuses it where the AI would choose (35 §2).
120
+ const optional = (prop.flags & SymbolFlags.Optional) !== 0;
121
+ // One way to say optional, the one the AI reads (76 §2.14): `name?: T`. `name: T | undefined` is
122
+ // optional to the type checker and required here; the page's `doNow()` check and the AI would disagree.
123
+ if (!optional && (propType.isUnionType() ? propType.getTypes() : [propType]).some((t) => t.flags & TypeFlags.Undefined)) {
124
+ throw new FunctionParamsError(`${where}.${prop.name}: T | undefined: write an optional parameter as ${prop.name}?: T`);
125
+ }
126
+ properties[prop.name] = valueParam(checker, propType, `${where}.${prop.name}`);
127
+ if (!optional)
128
+ required.push(prop.name);
129
+ }
130
+ return { type: 'object', properties, ...(required.length ? { required } : {}) };
131
+ }
132
+ function valueParam(checker, type, where) {
133
+ const members = withoutUndefined(type);
134
+ if (members.some((t) => t.flags & TypeFlags.Null))
135
+ throw new FunctionParamsError(`${where}: null is not a value the AI fills: make the parameter optional (name?: T)`);
136
+ if (members.length === 0)
137
+ throw new FunctionParamsError(`${where}: no type`);
138
+ // A union of literals: what the AI may choose among; `boolean` is `true | false`.
139
+ if (members.length > 1 || members[0].isLiteralType()) {
140
+ if (members.every((t) => t.flags & TypeFlags.BooleanLiteral))
141
+ return { type: 'boolean' };
142
+ if (members.every((t) => t.isStringLiteralType()))
143
+ return { type: 'string', enum: members.map((t) => t.value) };
144
+ if (members.every((t) => t.isNumberLiteralType()))
145
+ return { type: 'number', enum: members.map((t) => t.value) };
146
+ if (members.length > 1)
147
+ throw new FunctionParamsError(`${where} mixes types: use one of ${PARAMETER_TYPES}`);
148
+ }
149
+ const only = members[0];
150
+ // A contact's hours (25 §3): the runtime's `ContactSchedule`, checked as the field's value is.
151
+ if (only.getAliasSymbol()?.name === 'ContactSchedule')
152
+ return { type: 'contact_schedule' };
153
+ if (only.flags & (TypeFlags.Any | TypeFlags.Unknown))
154
+ throw new FunctionParamsError(`${where}: any / unknown says nothing: use one of ${PARAMETER_TYPES}`);
155
+ if (only.flags & TypeFlags.String)
156
+ return { type: 'string' };
157
+ if (only.flags & TypeFlags.Number)
158
+ return { type: 'number' };
159
+ if (only.flags & TypeFlags.Boolean)
160
+ return { type: 'boolean' };
161
+ if (only.isIntersectionType()) {
162
+ const marked = markOf(checker, only);
163
+ if (marked)
164
+ return marked;
165
+ if (only.getTypes().every((t) => isPlainObject(checker, t)))
166
+ return objectParam(checker, only, where);
167
+ throw new FunctionParamsError(`${where} is not a parameter type: use one of ${PARAMETER_TYPES}`);
168
+ }
169
+ if (checker.isArrayType(only)) {
170
+ const item = only.isTypeReference() ? checker.getTypeArguments(only)[0] : undefined;
171
+ if (!item)
172
+ throw new FunctionParamsError(`${where}: a list of what?`);
173
+ return { type: 'array', items: valueParam(checker, item, `${where}[]`) };
174
+ }
175
+ if (only.isObjectType()) {
176
+ if (checker.getSignaturesOfType(only, SignatureKind.Call).length > 0)
177
+ throw new FunctionParamsError(`${where}: a function is not a value the AI fills`);
178
+ return objectParam(checker, only, where);
179
+ }
180
+ throw new FunctionParamsError(`${where} is not a parameter type: use one of ${PARAMETER_TYPES}`);
181
+ }
182
+ /** `Id<'table'>` → a row of `table`; a format type → its format. Null when the intersection carries neither mark. */
183
+ function markOf(checker, type) {
184
+ if (!type.getTypes().some((t) => t.flags & TypeFlags.String))
185
+ return null;
186
+ for (const prop of checker.getPropertiesOfType(type)) {
187
+ const name = String(prop.escapedName);
188
+ const isId = ID_MARK.test(name);
189
+ if (!isId && !FORMAT_MARK.test(name))
190
+ continue;
191
+ const value = literalOf(checker, prop);
192
+ if (isId)
193
+ return value ? { type: 'ref', table: value } : null;
194
+ return value && FORMATS.has(value) ? { type: value } : null;
195
+ }
196
+ return null;
197
+ }
198
+ function literalOf(checker, prop) {
199
+ const type = checker.getTypeOfSymbol(prop);
200
+ const literal = type ? withoutUndefined(type).find((t) => t.isStringLiteralType()) : undefined;
201
+ return literal ? literal.value : null;
202
+ }
203
+ //# sourceMappingURL=function-params.js.map
@@ -1,6 +1,6 @@
1
- import type { CompanyResolveInput, CompanyResolveResult, ResolveInput, ResolveResult } from '../core/party/schema.js';
2
- import { type AnyEventHandlers, type WebhookEvent, type WebhookOutcome } from '../core/functions/events.js';
3
- import type { DefinedNoCaseFunc, FuncMap } from '../core/functions/types.js';
1
+ import { type CompanyResolve, type Resolve } from '../core/party/types.js';
2
+ import { type AnyEventHandlers, type WebhookHandler } from '../core/functions/events.js';
3
+ import type { FuncMap, PlainFn } from '../core/functions/types.js';
4
4
  import { type OfficeHours } from '../core/office-hours/index.js';
5
5
  import { type CompanySchema, type SessionSchema } from '../core/slot/schema.js';
6
6
  /**
@@ -40,23 +40,23 @@ export declare function loadSequenceEvents(eventsPath: string): Promise<AnyEvent
40
40
  */
41
41
  export declare function loadPageChannels(pageCode: string, sequenceId: string): string[];
42
42
  /**
43
- * The Case Orchestrator from orchestrator.ts / orchestrator/index.ts: the entry point (`orchestrator`, or
44
- * the default export) and `contacts`, whom a Run may contact (required: the platform runs it first).
43
+ * What the compiled page code says of itself as it loads: its channels, and the page actions it
44
+ * registered (76 §2.11), read in a context of its own as `loadPageChannels` does.
45
45
  */
46
- export declare function loadSequenceCaseOrchestrator(caseOrchestratorPath: string): Promise<{
47
- orchestrator: (...args: never[]) => unknown;
48
- contacts: (...args: never[]) => unknown;
49
- }>;
50
- /** A sequence's `resolve`, registered as a `noCase` function. */
51
- export declare function loadSequenceResolver(resolvePath: string): Promise<DefinedNoCaseFunc<ResolveInput, ResolveResult>>;
52
- /** The company `resolve` (§18.2), registered as a `noCase` function of the company part (22 §5). */
53
- export declare function loadCompanyResolver(resolvePath: string): Promise<DefinedNoCaseFunc<CompanyResolveInput, CompanyResolveResult>>;
46
+ export declare function loadPageModule(pageCode: string, sequenceId: string): {
47
+ channels: string[];
48
+ actions: string[];
49
+ };
50
+ /** The Case Orchestrator from orchestrator.ts / orchestrator/index.ts: `orchestrator`, or the default export. */
51
+ export declare function loadSequenceCaseOrchestrator(caseOrchestratorPath: string): Promise<PlainFn>;
52
+ /** A sequence's `resolve`: `(ctx, conversation)`. */
53
+ export declare function loadSequenceResolver(resolvePath: string): Promise<Resolve>;
54
+ /** The company `resolve` (§18.2), a function of the company part (22 §5): `(ctx, conversation)`. */
55
+ export declare function loadCompanyResolver(resolvePath: string): Promise<CompanyResolve>;
54
56
  /** The module of the company's webhooks (22 §9) at the repository root. */
55
57
  export declare const WEBHOOK_MODULE = "webhook";
56
- /** `received` of `webhook.ts`, registered as a `noCase` function of the company part. */
57
- export declare function loadCompanyWebhook(webhookPath: string): Promise<DefinedNoCaseFunc<{
58
- event: WebhookEvent;
59
- }, WebhookOutcome>>;
58
+ /** `received` of `webhook.ts`, a function of the company part: `(ctx, { event })`. */
59
+ export declare function loadCompanyWebhook(webhookPath: string): Promise<WebhookHandler>;
60
60
  export declare function isPlatformName(name: string): boolean;
61
61
  /**
62
62
  * A leftover root `channels.ts` (or `channels/index.ts`): webhook URLs are made and named on the
@@ -19,18 +19,14 @@ function isFuncMap(value) {
19
19
  if (value == null || typeof value !== 'object' || Array.isArray(value)) {
20
20
  return false;
21
21
  }
22
- for (const entry of Object.values(value)) {
23
- if (entry == null || typeof entry !== 'object' || Array.isArray(entry)) {
24
- return false;
25
- }
26
- const kind = entry.kind;
27
- if (kind === 'compute' || kind === 'boolCompute') {
28
- // Compute functions only existed as derived fields' computeFn (13-data-model-v1 §21).
29
- throw new Error(`functions: ${kind} functions were removed with derived fields; compute it in context.page.ts instead`);
30
- }
31
- if (kind !== 'case' && kind !== 'noCase') {
32
- return false;
22
+ for (const [name, entry] of Object.entries(value)) {
23
+ if (typeof entry === 'function')
24
+ continue;
25
+ // A `defineCaseFunc(…)` / `defineNoCaseFunc(…)` result: functions are plain `(ctx, args)` now (38 §2.1).
26
+ if (entry != null && typeof entry === 'object' && 'main' in entry) {
27
+ throw new Error(`functions.${name}: write it as a plain function (ctx, args), its parameters its args type (docs 38; AGENTS.md, "Functions")`);
33
28
  }
29
+ return false;
34
30
  }
35
31
  return true;
36
32
  }
@@ -262,29 +258,35 @@ export async function loadSequenceEvents(eventsPath) {
262
258
  * called when a conversation starts (24 §4), not here.
263
259
  */
264
260
  export function loadPageChannels(pageCode, sequenceId) {
261
+ return loadPageModule(pageCode, sequenceId).channels;
262
+ }
263
+ /**
264
+ * What the compiled page code says of itself as it loads: its channels, and the page actions it
265
+ * registered (76 §2.11), read in a context of its own as `loadPageChannels` does.
266
+ */
267
+ export function loadPageModule(pageCode, sequenceId) {
265
268
  try {
266
269
  const entry = runInNewContext(pageCode);
270
+ const out = entry({ mode: 'channels' });
267
271
  // Copied out of the other context: its arrays are not this one's.
268
- return [...(entry({ mode: 'channels' }).channels ?? [])].map(String);
272
+ return { channels: [...(out.channels ?? [])].map(String), actions: [...(out.actions ?? [])].map(String) };
269
273
  }
270
274
  catch (error) {
271
275
  throw new Error(`sequences/${sequenceId}/context.page.ts: ${error instanceof Error ? error.message : String(error)}`);
272
276
  }
273
277
  }
274
- /**
275
- * The Case Orchestrator from orchestrator.ts / orchestrator/index.ts: the entry point (`orchestrator`, or
276
- * the default export) and `contacts`, whom a Run may contact (required: the platform runs it first).
277
- */
278
+ /** The Case Orchestrator from orchestrator.ts / orchestrator/index.ts: `orchestrator`, or the default export. */
278
279
  export async function loadSequenceCaseOrchestrator(caseOrchestratorPath) {
279
280
  const mod = await importModule(caseOrchestratorPath);
280
281
  const orchestrator = [mod[ORCHESTRATOR_FUNCTION], mod.default].find((value) => typeof value === 'function');
281
282
  if (!orchestrator) {
282
283
  throw new Error(`Could not find ${ORCHESTRATOR_FUNCTION} export (${ORCHESTRATOR_FUNCTION} | default) as a function in ${caseOrchestratorPath}`);
283
284
  }
284
- if (typeof mod.contacts !== 'function') {
285
- throw new Error(`${caseOrchestratorPath}: export contacts, whom a Run may contact: export const contacts: CaseOrchestratorContacts = async (c, ctx) => contactIds`);
285
+ // Whom a Run may contact is the Orchestrator's to read now (38 §2.8).
286
+ if (Object.hasOwn(mod, 'contacts')) {
287
+ throw new Error(`${caseOrchestratorPath}: contacts is no longer supported: delete it. The orchestrator reads whom to contact from the business data, and names them on an Agent request (contacts: [...])`);
286
288
  }
287
- return { orchestrator: orchestrator, contacts: mod.contacts };
289
+ return orchestrator;
288
290
  }
289
291
  /** A `resolve.ts` / `resolve/index.ts`: its exported function `resolve` (or the default export). */
290
292
  async function loadResolveExport(resolvePath) {
@@ -294,23 +296,23 @@ async function loadResolveExport(resolvePath) {
294
296
  return entry;
295
297
  throw new Error(`Could not find ${RESOLVE_FUNCTION} export (${RESOLVE_FUNCTION} | default) as a function in ${resolvePath}`);
296
298
  }
297
- /** A sequence's `resolve`, registered as a `noCase` function. */
299
+ /** A sequence's `resolve`: `(ctx, conversation)`. */
298
300
  export async function loadSequenceResolver(resolvePath) {
299
- return { kind: 'noCase', main: (await loadResolveExport(resolvePath)) };
301
+ return (await loadResolveExport(resolvePath));
300
302
  }
301
- /** The company `resolve` (§18.2), registered as a `noCase` function of the company part (22 §5). */
303
+ /** The company `resolve` (§18.2), a function of the company part (22 §5): `(ctx, conversation)`. */
302
304
  export async function loadCompanyResolver(resolvePath) {
303
- return { kind: 'noCase', main: (await loadResolveExport(resolvePath)) };
305
+ return (await loadResolveExport(resolvePath));
304
306
  }
305
307
  /** The module of the company's webhooks (22 §9) at the repository root. */
306
308
  export const WEBHOOK_MODULE = 'webhook';
307
- /** `received` of `webhook.ts`, registered as a `noCase` function of the company part. */
309
+ /** `received` of `webhook.ts`, a function of the company part: `(ctx, { event })`. */
308
310
  export async function loadCompanyWebhook(webhookPath) {
309
311
  const mod = await importModule(webhookPath);
310
312
  const entry = [mod.received, mod.default].find((value) => typeof value === 'function');
311
313
  if (!entry)
312
314
  throw new Error(`Could not find received export (received | default) as a function in ${webhookPath}`);
313
- return { kind: 'noCase', main: entry };
315
+ return entry;
314
316
  }
315
317
  /** A name the platform keeps (a sequence's directory, a webhook): letters, numbers and single hyphens. */
316
318
  const PLATFORM_NAME = /^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/;
@@ -1,8 +1,13 @@
1
1
  /**
2
- * A TS module may live as `<dir>/<name>.ts` or `<dir>/<name>/index.ts`.
2
+ * A TS module may live as `<dir>/<name>.ts` or `<dir>/<name>/index.ts`, or `.tsx` (a page in JSX, 31 §10).
3
3
  * File form is preferred when both exist.
4
4
  */
5
5
  export declare function tsModuleCandidates(dir: string, name: string): string[];
6
+ /**
7
+ * A sequence's page script (15 §10.2): `context.page.ts`, written with functions (76). A page in JSX
8
+ * (`context.page.tsx`, 31) is no longer one.
9
+ */
10
+ export declare function requirePagePath(sequenceDir: string, sequenceId: string): string;
6
11
  /** Return the first existing candidate, or `undefined` if none exist. */
7
12
  export declare function findTsModule(dir: string, name: string): string | undefined;
8
13
  /** Return the first existing candidate, or throw with `missingMessage`. */
@@ -2,11 +2,25 @@ import { existsSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { RESOLVE_FUNCTION, RESOLVE_MODULE } from '../core/party/types.js';
4
4
  /**
5
- * A TS module may live as `<dir>/<name>.ts` or `<dir>/<name>/index.ts`.
5
+ * A TS module may live as `<dir>/<name>.ts` or `<dir>/<name>/index.ts`, or `.tsx` (a page in JSX, 31 §10).
6
6
  * File form is preferred when both exist.
7
7
  */
8
8
  export function tsModuleCandidates(dir, name) {
9
- return [path.join(dir, `${name}.ts`), path.join(dir, name, 'index.ts')];
9
+ return [path.join(dir, `${name}.ts`), path.join(dir, `${name}.tsx`), path.join(dir, name, 'index.ts'), path.join(dir, name, 'index.tsx')];
10
+ }
11
+ /**
12
+ * A sequence's page script (15 §10.2): `context.page.ts`, written with functions (76). A page in JSX
13
+ * (`context.page.tsx`, 31) is no longer one.
14
+ */
15
+ export function requirePagePath(sequenceDir, sequenceId) {
16
+ const jsx = path.join(sequenceDir, 'context.page.tsx');
17
+ if (existsSync(jsx)) {
18
+ throw new Error(`sequences/${sequenceId}/context.page.tsx: a page is written with functions in context.page.ts (76), not JSX: page({ guide }, { name: block({ title }, { … }) }), button({ title, does, action: run(fn.x, { … }) })`);
19
+ }
20
+ const page = path.join(sequenceDir, 'context.page.ts');
21
+ if (!existsSync(page))
22
+ throw new Error(`sequences/${sequenceId}: context.page.ts is required (the conversation's page, 15 §10.2)`);
23
+ return page;
10
24
  }
11
25
  /** Return the first existing candidate, or `undefined` if none exist. */
12
26
  export function findTsModule(dir, name) {
@@ -1,5 +1,6 @@
1
1
  import { type ScheduleDefinition, type ScheduleManifest } from '../core/functions/schedules.js';
2
2
  import type { FuncMap, FunctionRegistry } from '../core/functions/types.js';
3
+ import type { FunctionSourceMap } from './types.js';
3
4
  /**
4
5
  * Why one job's `cron` / `timezone` cannot run, or `null`. The cron is read by the same parser the
5
6
  * worker's job scheduler uses (BullMQ's cron-parser); five fields only, so nothing runs every second.
@@ -10,14 +11,15 @@ export declare function parseSchedules(value: unknown, where: string): Record<st
10
11
  /** A directory's `schedules.ts`, loaded: what serve runs and what the build records. `null` without the file. */
11
12
  export type LoadedSchedules = {
12
13
  path: string;
13
- /** `schedule.<name>` → the job's `run`, as a `noCase` function. */
14
+ /** `schedule.<name>` → the job's `run`, a function `(ctx, { schedule })`. */
14
15
  functions: FuncMap;
15
16
  manifest: ScheduleManifest;
16
17
  };
17
- /** Load and check `<dir>/schedules.ts`; `where` names it in errors (`schedules.ts`, `sequences/pi/schedules.ts`). */
18
- export declare function loadSchedules(dir: string, where: string): Promise<LoadedSchedules | null>;
19
- /** The build's registry entries of the jobs: `schedule.<name>` (`code` left out on the serve overlay). */
20
- export declare function scheduleRegistry(loaded: LoadedSchedules, includeCode: boolean): Promise<FunctionRegistry>;
21
- /** Authored functions must leave `schedule.*` to `schedules.ts`. */
22
- export declare function assertNoScheduleNames(names: string[], where: string): void;
18
+ /** Load and check the repository root's `schedules.ts`, the company's only one (25 §6.4). */
19
+ export declare function loadSchedules(repoRoot: string): Promise<LoadedSchedules | null>;
20
+ /**
21
+ * The build's registry entries of the jobs: `schedule.<name>` (`code` left out on the serve overlay). Each
22
+ * compiled job's source map goes to `sourceMaps`, by the same name.
23
+ */
24
+ export declare function scheduleRegistry(loaded: LoadedSchedules, includeCode: boolean, sourceMaps?: Record<string, FunctionSourceMap>): Promise<FunctionRegistry>;
23
25
  //# sourceMappingURL=schedules.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { pathToFileURL } from 'node:url';
2
2
  import { CronExpressionParser } from 'cron-parser';
3
- import { SCHEDULE_FUNCTION_PREFIX, SCHEDULES_MODULE, scheduleFunctionName, } from '../core/functions/schedules.js';
3
+ import { SCHEDULES_MODULE, scheduleFunctionName, } from '../core/functions/schedules.js';
4
4
  import { compileScheduleModuleCode } from './compile/function-code.js';
5
5
  import { companyImportGraphHref } from './company-import-graph.js';
6
6
  import { findTsModule } from './paths.js';
@@ -68,35 +68,34 @@ async function importSchedules(modulePath, where) {
68
68
  const fromDefault = isPlainObject(mod.default) && Object.hasOwn(mod.default, 'schedules') ? mod.default.schedules : mod.default;
69
69
  return parseSchedules(mod.schedules ?? fromDefault, where);
70
70
  }
71
- /** Load and check `<dir>/schedules.ts`; `where` names it in errors (`schedules.ts`, `sequences/pi/schedules.ts`). */
72
- export async function loadSchedules(dir, where) {
73
- const modulePath = findTsModule(dir, SCHEDULES_MODULE);
71
+ /** Load and check the repository root's `schedules.ts`, the company's only one (25 §6.4). */
72
+ export async function loadSchedules(repoRoot) {
73
+ const modulePath = findTsModule(repoRoot, SCHEDULES_MODULE);
74
74
  if (!modulePath)
75
75
  return null;
76
- const schedules = await importSchedules(modulePath, where);
76
+ const schedules = await importSchedules(modulePath, `${SCHEDULES_MODULE}.ts`);
77
77
  const functions = {};
78
78
  const manifest = {};
79
79
  for (const [name, { cron, timezone, run }] of Object.entries(schedules)) {
80
- functions[scheduleFunctionName(name)] = { kind: 'noCase', main: run };
80
+ functions[scheduleFunctionName(name)] = run;
81
81
  manifest[name] = { cron: cron.trim(), timezone };
82
82
  }
83
83
  return { path: modulePath, functions, manifest };
84
84
  }
85
- /** The build's registry entries of the jobs: `schedule.<name>` (`code` left out on the serve overlay). */
86
- export async function scheduleRegistry(loaded, includeCode) {
87
- const entries = await Promise.all(Object.keys(loaded.manifest).map(async (name) => [
88
- scheduleFunctionName(name),
89
- includeCode
90
- ? { kind: 'noCase', code: await compileScheduleModuleCode(loaded.path, name) }
91
- : { kind: 'noCase' },
92
- ]));
85
+ /**
86
+ * The build's registry entries of the jobs: `schedule.<name>` (`code` left out on the serve overlay). Each
87
+ * compiled job's source map goes to `sourceMaps`, by the same name.
88
+ */
89
+ export async function scheduleRegistry(loaded, includeCode, sourceMaps) {
90
+ const entries = await Promise.all(Object.keys(loaded.manifest).map(async (name) => {
91
+ const fn = scheduleFunctionName(name);
92
+ if (!includeCode)
93
+ return [fn, {}];
94
+ const compiled = await compileScheduleModuleCode(loaded.path, name);
95
+ if (sourceMaps)
96
+ sourceMaps[fn] = compiled.map;
97
+ return [fn, { code: compiled.code }];
98
+ }));
93
99
  return Object.fromEntries(entries);
94
100
  }
95
- /** Authored functions must leave `schedule.*` to `schedules.ts`. */
96
- export function assertNoScheduleNames(names, where) {
97
- const taken = names.filter((name) => name.startsWith(SCHEDULE_FUNCTION_PREFIX));
98
- if (taken.length > 0) {
99
- throw new Error(`${where} must not define ${taken.map((n) => `'${n}'`).join(', ')}: ${SCHEDULE_FUNCTION_PREFIX}* names are the jobs of ${SCHEDULES_MODULE}.ts`);
100
- }
101
- }
102
101
  //# sourceMappingURL=schedules.js.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The repository's type check, as `pnpm typecheck` runs it locally: `type:gen`, then `tsc --noEmit`
2
+ * The repository's type check, as `npm run typecheck` runs it locally: `type:gen`, then `tsc --noEmit`
3
3
  * with the repo's own `tsconfig.json`. With no sequence it writes only the root `__gen` (the local
4
4
  * `type:gen` needs a sequence). The compile runs it itself, so a type error blocks a release in every
5
5
  * environment; the platform never calls the repo's `typecheck` script.