primitive-admin 1.0.54 → 1.0.56

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 (110) hide show
  1. package/assets/skill/skills/primitive-platform/SKILL.md +230 -2
  2. package/dist/bin/primitive.js +3 -1
  3. package/dist/bin/primitive.js.map +1 -1
  4. package/dist/src/commands/apps.js +54 -2
  5. package/dist/src/commands/apps.js.map +1 -1
  6. package/dist/src/commands/database-types.js +4 -4
  7. package/dist/src/commands/database-types.js.map +1 -1
  8. package/dist/src/commands/databases.js +35 -14
  9. package/dist/src/commands/databases.js.map +1 -1
  10. package/dist/src/commands/documents.js +77 -0
  11. package/dist/src/commands/documents.js.map +1 -1
  12. package/dist/src/commands/guides.d.ts +15 -12
  13. package/dist/src/commands/guides.js +22 -15
  14. package/dist/src/commands/guides.js.map +1 -1
  15. package/dist/src/commands/metadata.js +48 -3
  16. package/dist/src/commands/metadata.js.map +1 -1
  17. package/dist/src/commands/scripts.d.ts +18 -0
  18. package/dist/src/commands/scripts.js +59 -5
  19. package/dist/src/commands/scripts.js.map +1 -1
  20. package/dist/src/commands/settings.d.ts +15 -0
  21. package/dist/src/commands/settings.js +102 -0
  22. package/dist/src/commands/settings.js.map +1 -0
  23. package/dist/src/commands/sync-app-settings.d.ts +115 -0
  24. package/dist/src/commands/sync-app-settings.js +379 -0
  25. package/dist/src/commands/sync-app-settings.js.map +1 -0
  26. package/dist/src/commands/sync.d.ts +134 -19
  27. package/dist/src/commands/sync.js +1949 -600
  28. package/dist/src/commands/sync.js.map +1 -1
  29. package/dist/src/commands/workflows.js +54 -15
  30. package/dist/src/commands/workflows.js.map +1 -1
  31. package/dist/src/lib/api-client.d.ts +29 -1
  32. package/dist/src/lib/api-client.js +31 -2
  33. package/dist/src/lib/api-client.js.map +1 -1
  34. package/dist/src/lib/app-settings-descriptor.d.ts +108 -0
  35. package/dist/src/lib/app-settings-descriptor.js +254 -0
  36. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  37. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +36 -0
  38. package/dist/src/lib/codegen-shared/generatedFiles.js +67 -10
  39. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
  40. package/dist/src/lib/codegen-shared/prettierStable.d.ts +262 -0
  41. package/dist/src/lib/codegen-shared/prettierStable.js +610 -0
  42. package/dist/src/lib/codegen-shared/prettierStable.js.map +1 -0
  43. package/dist/src/lib/db-codegen/dbGenerator.d.ts +11 -83
  44. package/dist/src/lib/db-codegen/dbGenerator.js +96 -556
  45. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
  46. package/dist/src/lib/db-codegen/dbNaming.d.ts +20 -7
  47. package/dist/src/lib/db-codegen/dbNaming.js +31 -13
  48. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
  49. package/dist/src/lib/db-codegen/dbTemplates.d.ts +70 -4
  50. package/dist/src/lib/db-codegen/dbTemplates.js +244 -70
  51. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
  52. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +13 -22
  53. package/dist/src/lib/db-codegen/dbTsTypes.js +33 -28
  54. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -1
  55. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  56. package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
  57. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  58. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +112 -0
  59. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +211 -0
  60. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  61. package/dist/src/lib/generated-allowlist.js +7 -0
  62. package/dist/src/lib/generated-allowlist.js.map +1 -1
  63. package/dist/src/lib/platform-owned.d.ts +37 -0
  64. package/dist/src/lib/platform-owned.js +46 -0
  65. package/dist/src/lib/platform-owned.js.map +1 -0
  66. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +100 -0
  67. package/dist/src/lib/swift-codegen/dbGenerator.js +682 -0
  68. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  69. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  70. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  71. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  72. package/dist/src/lib/swift-codegen/generator.d.ts +85 -0
  73. package/dist/src/lib/swift-codegen/generator.js +266 -0
  74. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  75. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
  76. package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
  77. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  78. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +90 -0
  79. package/dist/src/lib/swift-codegen/siblingSymbols.js +152 -0
  80. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -0
  81. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  82. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  83. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  84. package/dist/src/lib/sync-resource-types.d.ts +437 -0
  85. package/dist/src/lib/sync-resource-types.js +781 -0
  86. package/dist/src/lib/sync-resource-types.js.map +1 -0
  87. package/dist/src/lib/template.d.ts +1 -1
  88. package/dist/src/lib/template.js +6 -3
  89. package/dist/src/lib/template.js.map +1 -1
  90. package/dist/src/lib/toml-metadata-config.js +18 -0
  91. package/dist/src/lib/toml-metadata-config.js.map +1 -1
  92. package/dist/src/lib/workflow-apply.js +12 -2
  93. package/dist/src/lib/workflow-apply.js.map +1 -1
  94. package/dist/src/lib/workflow-codegen/generator.d.ts +27 -5
  95. package/dist/src/lib/workflow-codegen/generator.js +214 -68
  96. package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
  97. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +83 -0
  98. package/dist/src/lib/workflow-codegen/invokerIR.js +71 -0
  99. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  100. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +17 -1
  101. package/dist/src/lib/workflow-codegen/schemaToTs.js +59 -38
  102. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -1
  103. package/dist/src/lib/workflow-payload.d.ts +19 -0
  104. package/dist/src/lib/workflow-payload.js +21 -0
  105. package/dist/src/lib/workflow-payload.js.map +1 -1
  106. package/dist/src/lib/workflow-toml-validator.d.ts +30 -0
  107. package/dist/src/lib/workflow-toml-validator.js +206 -0
  108. package/dist/src/lib/workflow-toml-validator.js.map +1 -1
  109. package/dist/src/types/index.d.ts +1 -0
  110. package/package.json +5 -2
@@ -16,11 +16,24 @@
16
16
  * `schema-validation` descriptor) so the generated types match runtime
17
17
  * validation exactly. A malformed schema throws (fail-and-exit).
18
18
  * - `.runSync` is emitted only for `syncCallable: true` workflows (the server
19
- * rejects run-sync otherwise); `.start` and `.getStatus` for every
20
- * non-reserved workflow (the typed async path, issue #1512 — async-only
21
- * workflows are exactly the ones that need a typed `getStatus`). No
22
- * `.terminate` member is emitted (the factory stays a start/status helper;
23
- * typed termination is available via the client's explicit `terminate<O>`).
19
+ * rejects run-sync otherwise); `.start`, `.getStatus`, and `.terminate` for
20
+ * every non-reserved workflow (the typed async path, issue #1512 —
21
+ * async-only workflows are exactly the ones that need a typed `getStatus` /
22
+ * `terminate`). `.terminate` binds `<Key>Output` (a terminated run can carry
23
+ * partial output); issue #1543 added the member, reversing #1512's
24
+ * start/status-only decision.
25
+ * - `.define` is emitted only for an apply-mode workflow
26
+ * (`requiresClientApply !== false`, the server's default). It binds
27
+ * `<Key>Output` so the `onApply` handler's `output` is the workflow's real
28
+ * output type rather than `any` (issue #1543, on top of #1542's
29
+ * `define<O>` / `WorkflowDefineOptions<O>` generics). `getPendingApplies`
30
+ * gets no member — #1542 made it a concrete `PendingApply[]` with no output
31
+ * to bind, and it is scoped to a document rather than a workflow.
32
+ * - `.cronTriggers.{create,update}` bind `<Key>Input` to the trigger's
33
+ * `rootInput` and pin `workflowKey`, so a cron helper can't be redirected at
34
+ * another workflow (issue #1543). `rootInput` is `Partial<<Key>Input>` for
35
+ * an object-shaped input schema (an `inputMapping` may supply the rest) and
36
+ * the full `<Key>Input` otherwise.
24
37
  * - `input` is a REQUIRED option iff the schema rejects `{}` (the client's
25
38
  * `input ?? {}` fallback would fail validation); otherwise `input?`.
26
39
  * - The runtime call always passes the ORIGINAL key string; only identifiers
@@ -28,28 +41,28 @@
28
41
  * cannot override it.
29
42
  * - Disk lifecycle (write / `--check` / suffix-based cleanup) delegates to the
30
43
  * shared `writeOrCheckGeneratedFiles`, exactly like `databases codegen`.
44
+ *
45
+ * FORMATTING CONTRACT (#1565): the emitted TypeScript must be a fixed point of
46
+ * Prettier's DEFAULT config — `prettier --write` over a generated file must
47
+ * leave it byte-for-byte unchanged, because `--check` byte-compares. There is
48
+ * no Prettier dependency and no automated round-trip test to catch a
49
+ * regression, so any edit here that changes line shapes must be verified by
50
+ * hand (regenerate a representative output, run Prettier over it, confirm no
51
+ * diff). Wrap long constructs through `codegen-shared/prettierStable.ts` rather
52
+ * than hand-joining strings — see that file's header for the full contract.
31
53
  */
32
54
  import * as path from "path";
33
- import { parseConfigToml } from "../config-toml.js";
34
- import { safeJsonParse } from "../workflow-payload.js";
35
55
  import { writeOrCheckGeneratedFiles, } from "../codegen-shared/generatedFiles.js";
36
56
  import { fingerprintToml } from "../db-codegen/dbFingerprint.js";
37
- import { schemaToTsType, schemaRejectsEmptyObject } from "./schemaToTs.js";
57
+ import { atom, generic, indent, intersection, objectType, printType, renderArrowCall, renderArrowProperty, renderParenList, renderTypeAlias, tsStringLiteral, union, } from "../codegen-shared/prettierStable.js";
58
+ import { schemaToTypeNode } from "./schemaToTs.js";
38
59
  import { describeSchema } from "./generated-schema-descriptor.js";
60
+ import { describeWorkflowInvoker } from "./invokerIR.js";
39
61
  import { workflowInputTypeName, workflowOutputTypeName, workflowFactoryName, } from "./naming.js";
40
- /** Prefix marking a platform-owned workflow key (mirrors the server's
41
- * `INTERNAL_WORKFLOW_KEY_PREFIX`; inlined because the CLI cannot import from
42
- * `src/`). Such workflows are never client-invocable and are skipped. */
43
- const INTERNAL_WORKFLOW_KEY_PREFIX = "__internal.";
44
62
  /** Suffix identifying a generated file (shared with `databases codegen`). */
45
63
  export const GENERATED_FILE_SUFFIX = ".generated.ts";
46
64
  /** The client package the generated file imports its types from. */
47
65
  const CLIENT_PACKAGE = "js-bao-wss-client";
48
- /** True for a platform-owned workflow key. */
49
- function isReservedKey(key) {
50
- return (typeof key === "string" &&
51
- key.trim().toLowerCase().startsWith(INTERNAL_WORKFLOW_KEY_PREFIX));
52
- }
53
66
  /**
54
67
  * Render a top-level `<Name>Input`/`<Name>Output` declaration. An absent schema
55
68
  * → `unknown`. A plain object type → an `interface`; anything else → a `type`
@@ -62,80 +75,108 @@ function isReservedKey(key) {
62
75
  */
63
76
  function renderTypeDecl(name, schema) {
64
77
  if (schema === undefined) {
65
- return `export type ${name} = unknown;`;
78
+ // Through `renderTypeAlias`, not hand-joined: a long enough workflow key
79
+ // pushes `export type <Key>Output = unknown;` past the print width, and
80
+ // Prettier then moves the `unknown` below the `=` (#1565).
81
+ return renderTypeAlias(name, atom("unknown"));
66
82
  }
67
- const expr = schemaToTsType(schema, 0);
68
- if (expr.startsWith("{") && !describeSchema(schema).oneOf) {
69
- return `export interface ${name} ${expr}`;
83
+ const node = schemaToTypeNode(schema);
84
+ if (node.kind === "block" && !describeSchema(schema).oneOf) {
85
+ return `export interface ${name} ${printType(node, 0, 0)}`;
70
86
  }
71
- return `export type ${name} = ${expr};`;
87
+ return renderTypeAlias(name, node);
72
88
  }
73
89
  /**
74
90
  * Parse a single workflow TOML into the data the emitter needs. Throws on
75
91
  * malformed schema JSON (fail-and-exit) — the honest `unknown` fallback is for
76
92
  * valid-but-untypeable schemas only. Returns null for a reserved workflow.
93
+ *
94
+ * The operation metadata (key, `syncCallable`, required-vs-optional `input`,
95
+ * parsed schemas) comes from the SHARED `describeWorkflowInvoker` IR so the TS
96
+ * and Swift invokers can never disagree (#1547 binding item 5). Only the
97
+ * TS-specific naming + type-declaration rendering happens here.
77
98
  */
78
99
  function parseWorkflow(input) {
79
100
  // #1464 removed `@iarna/toml`; #1446 makes `sync pull` emit schemas as native
80
101
  // TOML tables (incl. mixed-type enums like `enum = ["ok", 1]`, TOML 1.0). The
81
- // `parseConfigToml` facade parses both. `safeJsonParse` still owns the
82
- // string-vs-inline-table schema handling.
83
- const data = parseConfigToml(input.tomlContent);
84
- const workflow = data?.workflow ?? {};
85
- const key = typeof workflow.key === "string" && workflow.key.length > 0
86
- ? workflow.key
87
- : input.fileStem;
88
- if (isReservedKey(key))
89
- return null;
90
- // safeJsonParse throws on invalid JSON in a schema string — let it bubble.
91
- const inputSchema = safeJsonParse(workflow.inputSchema);
92
- const outputSchema = safeJsonParse(workflow.outputSchema);
93
- const inputTypeName = workflowInputTypeName(key);
94
- const outputTypeName = workflowOutputTypeName(key);
102
+ // shared IR uses `parseConfigToml` + `safeJsonParse` under the hood.
103
+ const ir = describeWorkflowInvoker({
104
+ fileStem: input.fileStem,
105
+ tomlContent: input.tomlContent,
106
+ });
107
+ if (!ir)
108
+ return null; // reserved workflow
109
+ const inputTypeName = workflowInputTypeName(ir.key);
110
+ const outputTypeName = workflowOutputTypeName(ir.key);
95
111
  return {
96
- key,
97
- syncCallable: workflow.syncCallable === true,
112
+ key: ir.key,
113
+ syncCallable: ir.syncCallable,
98
114
  inputTypeName,
99
115
  outputTypeName,
100
- factoryName: workflowFactoryName(key),
101
- inputDecl: renderTypeDecl(inputTypeName, inputSchema),
102
- outputDecl: renderTypeDecl(outputTypeName, outputSchema),
103
- // `input` is required iff the schema rejects the client's `{}` fallback.
104
- // A schema-less workflow (`undefined`) accepts anything → optional.
105
- inputRequired: inputSchema !== undefined && schemaRejectsEmptyObject(inputSchema),
116
+ factoryName: workflowFactoryName(ir.key),
117
+ inputDecl: renderTypeDecl(inputTypeName, ir.inputSchema),
118
+ outputDecl: renderTypeDecl(outputTypeName, ir.outputSchema),
119
+ inputRequired: ir.inputRequired,
120
+ // Object-shaped only when the schema declares exactly `type: "object"`
121
+ // the one case where `Partial<<Key>Input>` is a sound cron `rootInput`
122
+ // type. Schema-less / union / scalar / array → not object-shaped.
123
+ inputIsObjectShaped: ir.inputSchema !== undefined &&
124
+ describeSchema(ir.inputSchema).singularType === "object",
125
+ requiresClientApply: ir.requiresClientApply,
106
126
  };
107
127
  }
108
- /** Render the typed invoker factory for one workflow. */
128
+ /**
129
+ * Render the typed invoker factory for one workflow.
130
+ *
131
+ * Every line shape here is emitted the way Prettier's default config would
132
+ * print it (#1565) — see `codegen-shared/prettierStable.ts`. `runSync`/`start`
133
+ * always break their parameter list: the shortest possible
134
+ * `opts: {…} & Omit<…>` parameter is already wider than the 80-column budget,
135
+ * so there is no width decision to make there.
136
+ */
109
137
  function renderFactory(wf) {
110
- const keyLiteral = JSON.stringify(wf.key);
138
+ const keyLiteral = tsStringLiteral(wf.key);
111
139
  const inputMember = wf.inputRequired
112
140
  ? `input: ${wf.inputTypeName}`
113
141
  : `input?: ${wf.inputTypeName}`;
114
142
  const lines = [
115
- `export function ${wf.factoryName}(client: JsBaoClient) {`,
143
+ renderParenList(`export function ${wf.factoryName}`, ["client: JsBaoClient"], " {", 0),
116
144
  ` return {`,
117
145
  ];
146
+ // `opts: { input: X } & Omit<<Options>, "workflowKey" | "input">` — the
147
+ // intersection breaks inside the `Omit<...>` when it overflows.
148
+ const optsParam = (optionsTypeName) => {
149
+ const node = intersection([
150
+ objectType([inputMember]),
151
+ generic("Omit", [
152
+ atom(optionsTypeName),
153
+ union([atom(`"workflowKey"`), atom(`"input"`)]),
154
+ ]),
155
+ ]);
156
+ const head = `${indent(3)}opts: `;
157
+ return `${head}${printType(node, head.length, 3, 1)},`;
158
+ };
118
159
  // Spread `opts` FIRST, then set `workflowKey` LAST, so the factory's intended
119
160
  // key always wins. `Omit<..., "workflowKey">` only rejects an excess
120
161
  // `workflowKey` on object literals; a caller passing an options *variable*
121
162
  // carrying an extra `workflowKey` (or any untyped JS caller) would otherwise
122
163
  // override the key and invoke the wrong workflow if the spread came last.
164
+ const invocation = (method, typeArgs, optionsTypeName) => renderArrowCall({
165
+ head: [
166
+ `${indent(2)}${method}: (`,
167
+ optsParam(optionsTypeName),
168
+ `${indent(2)}) =>`,
169
+ ].join("\n"),
170
+ callee: generic(`client.workflows.${method}`, typeArgs.map(atom)),
171
+ leadingArgs: [],
172
+ objectMembers: ["...opts", { key: "workflowKey", value: keyLiteral }],
173
+ level: 3,
174
+ tail: ",",
175
+ });
123
176
  if (wf.syncCallable) {
124
- lines.push(` runSync: (\n` +
125
- ` opts: { ${inputMember} } & Omit<RunSyncWorkflowOptions, "workflowKey" | "input">\n` +
126
- ` ) =>\n` +
127
- ` client.workflows.runSync<${wf.inputTypeName}, ${wf.outputTypeName}>({\n` +
128
- ` ...opts,\n` +
129
- ` workflowKey: ${keyLiteral},\n` +
130
- ` }),`);
177
+ lines.push(invocation("runSync", [wf.inputTypeName, wf.outputTypeName], "RunSyncWorkflowOptions"));
131
178
  }
132
- lines.push(` start: (\n` +
133
- ` opts: { ${inputMember} } & Omit<StartWorkflowOptions, "workflowKey" | "input">\n` +
134
- ` ) =>\n` +
135
- ` client.workflows.start<${wf.inputTypeName}>({\n` +
136
- ` ...opts,\n` +
137
- ` workflowKey: ${keyLiteral},\n` +
138
- ` }),`);
179
+ lines.push(invocation("start", [wf.inputTypeName], "StartWorkflowOptions"));
139
180
  // Typed status fetch (#1512), emitted for EVERY non-reserved workflow — not
140
181
  // gated on `syncCallable`, since async-only workflows are exactly the ones
141
182
  // that need a typed `status.output`. `output` is bound to `<Key>Output` from
@@ -144,11 +185,107 @@ function renderFactory(wf) {
144
185
  // it — you cannot fetch a run's status without knowing which run). Same
145
186
  // spread-first / key-last ordering so an untyped caller cannot override the
146
187
  // key and read the wrong workflow's status.
147
- lines.push(` getStatus: (opts: Omit<GetWorkflowStatusOptions, "workflowKey">) =>\n` +
148
- ` client.workflows.getStatus<${wf.outputTypeName}>({\n` +
149
- ` ...opts,\n` +
150
- ` workflowKey: ${keyLiteral},\n` +
151
- ` }),`);
188
+ //
189
+ // Its `opts` parameter carries no generated names, so it always fits on one
190
+ // line — unlike start/runSync above.
191
+ lines.push(renderArrowCall({
192
+ head: `${indent(2)}getStatus: (opts: Omit<GetWorkflowStatusOptions, "workflowKey">) =>`,
193
+ callee: generic("client.workflows.getStatus", [atom(wf.outputTypeName)]),
194
+ leadingArgs: [],
195
+ objectMembers: ["...opts", { key: "workflowKey", value: keyLiteral }],
196
+ level: 3,
197
+ tail: ",",
198
+ }));
199
+ // Typed termination (#1543), emitted for EVERY non-reserved workflow — any
200
+ // run can be terminated. `output` is bound to `<Key>Output` (a terminated run
201
+ // can carry partial output), same schema-less → `unknown` rule as getStatus.
202
+ // `runKey` stays required. Same spread-first / key-last ordering so an untyped
203
+ // caller cannot override the key and terminate the wrong workflow's run. This
204
+ // member reverses #1512's start/status-only decision.
205
+ lines.push(renderArrowProperty({
206
+ level: 2,
207
+ key: "terminate",
208
+ params: [`opts: Omit<TerminateWorkflowOptions, "workflowKey">`],
209
+ signatureTail: " =>",
210
+ callee: generic("client.workflows.terminate", [atom(wf.outputTypeName)]),
211
+ leadingArgs: [],
212
+ objectMembers: ["...opts", { key: "workflowKey", value: keyLiteral }],
213
+ tail: ",",
214
+ }));
215
+ // Typed apply handler (#1543 Phase 2), emitted ONLY for an apply-mode
216
+ // workflow (`requiresClientApply !== false` — the same default the server
217
+ // uses to decide a completed run needs a client apply). `WorkflowDefineOptions<O>`
218
+ // and `WorkflowApplyHandler<O>` come from #1542; binding `<Key>Output` here
219
+ // makes the `onApply` callback's `output` the workflow's real output type
220
+ // instead of `any`. The key is passed as a positional argument, so there is
221
+ // no spread a caller could use to override it.
222
+ //
223
+ // No `getPendingApplies` member: #1542 shipped it as a concrete
224
+ // `PendingApply[]` (the server element carries no `output`, so there is no
225
+ // output generic to bind), and the call is scoped to a DOCUMENT rather than
226
+ // a workflow — a per-workflow member would bind nothing and would wrongly
227
+ // suggest the result only covers this workflow.
228
+ if (wf.requiresClientApply) {
229
+ lines.push(renderArrowProperty({
230
+ level: 2,
231
+ key: "define",
232
+ params: [`options: WorkflowDefineOptions<${wf.outputTypeName}>`],
233
+ signatureTail: " =>",
234
+ callee: generic("client.workflows.define", [atom(wf.outputTypeName)]),
235
+ leadingArgs: [keyLiteral, "options"],
236
+ tail: ",",
237
+ }));
238
+ }
239
+ // Typed cron-trigger create/update (#1543), folded INTO the factory (not a
240
+ // separate export). The client's own `rootInput` generic (#1542) is bound to
241
+ // `<Key>Input`: `Partial<...>` for an object-shaped schema (an `inputMapping`
242
+ // may supply the rest), the full type otherwise. Binding the generic rather
243
+ // than restating the field keeps the caller-facing params in step with the
244
+ // client contract — notably `update` accepts `rootInput: null` to clear a
245
+ // stored root input, while `create` does not (the server rejects a null there
246
+ // with a 400). `workflowKey` is Omit-ted from the caller-facing params and
247
+ // pinned LAST so a caller can't redirect the trigger at another workflow.
248
+ // Nothing is spread after `workflowKey` — `rootInput` rides in via `...params`
249
+ // — preserving the key-last convention.
250
+ // `rootInput` is `Partial<<Key>Input>` for an object-shaped schema (an
251
+ // `inputMapping` may supply the rest) and the full `<Key>Input` otherwise.
252
+ // Built as a `TypeNode` so `printType` can break the nested type-argument
253
+ // lists Prettier opens up at long key lengths (e.g.
254
+ // `Omit<CreateCronTriggerParams<Partial<...>>, "workflowKey">`).
255
+ const rootInputNode = wf.inputIsObjectShaped
256
+ ? generic("Partial", [atom(wf.inputTypeName)])
257
+ : atom(wf.inputTypeName);
258
+ const cronParam = (paramsGeneric) => ({
259
+ name: "params",
260
+ type: generic("Omit", [
261
+ generic(paramsGeneric, [rootInputNode]),
262
+ atom(`"workflowKey"`),
263
+ ]),
264
+ });
265
+ lines.push([
266
+ ` cronTriggers: {`,
267
+ renderArrowProperty({
268
+ level: 3,
269
+ key: "create",
270
+ params: [cronParam("CreateCronTriggerParams")],
271
+ signatureTail: " =>",
272
+ callee: generic("client.cronTriggers.create", [rootInputNode]),
273
+ leadingArgs: [],
274
+ objectMembers: ["...params", { key: "workflowKey", value: keyLiteral }],
275
+ tail: ",",
276
+ }),
277
+ renderArrowProperty({
278
+ level: 3,
279
+ key: "update",
280
+ params: ["triggerId: string", cronParam("UpdateCronTriggerParams")],
281
+ signatureTail: " =>",
282
+ callee: generic("client.cronTriggers.update", [rootInputNode]),
283
+ leadingArgs: ["triggerId"],
284
+ objectMembers: ["...params", { key: "workflowKey", value: keyLiteral }],
285
+ tail: ",",
286
+ }),
287
+ ` },`,
288
+ ].join("\n"));
152
289
  lines.push(` };`, `}`);
153
290
  return lines.join("\n");
154
291
  }
@@ -163,15 +300,24 @@ export function renderWorkflowFile(input) {
163
300
  return null;
164
301
  const fingerprint = fingerprintToml(input.tomlContent);
165
302
  // Only import the option types actually referenced, so the generated file
166
- // compiles under a consumer's `noUnusedLocals`. `GetWorkflowStatusOptions` is
167
- // always referenced now every factory emits a `getStatus` member (#1512).
303
+ // compiles under a consumer's `noUnusedLocals`. `GetWorkflowStatusOptions`,
304
+ // `TerminateWorkflowOptions`, and the two cron-param types are always
305
+ // referenced now — every factory emits `getStatus`, `terminate` (#1512 /
306
+ // #1543), and `cronTriggers.{create,update}` (#1543).
168
307
  const imports = [
308
+ "CreateCronTriggerParams",
169
309
  "GetWorkflowStatusOptions",
170
310
  "JsBaoClient",
171
311
  "StartWorkflowOptions",
312
+ "TerminateWorkflowOptions",
313
+ "UpdateCronTriggerParams",
172
314
  ];
173
315
  if (wf.syncCallable)
174
316
  imports.push("RunSyncWorkflowOptions");
317
+ // Only an apply-mode workflow emits `define`, so its option type is imported
318
+ // only then — a non-apply-mode file would otherwise fail `noUnusedLocals`.
319
+ if (wf.requiresClientApply)
320
+ imports.push("WorkflowDefineOptions");
175
321
  imports.sort();
176
322
  const blocks = [];
177
323
  blocks.push([
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/lib/workflow-codegen/generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/lib/workflow-codegen/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Shared workflow-invoker IR (issue #1547, Phase 3).
3
+ *
4
+ * The typed invoker factory is generated on BOTH the TypeScript side
5
+ * (`workflow-codegen/generator.ts`) and the Swift side
6
+ * (`swift-codegen/generator.ts`). The maintainer decision (item 5, binding)
7
+ * requires that invoker generation reuse ONE description of the workflow's
8
+ * operation metadata — the runtime key, whether `runSync` is emitted
9
+ * (`syncCallable`), whether `input` is a required argument, and whether the
10
+ * workflow is apply-mode (`requiresClientApply`) — rather than each language
11
+ * renderer re-deriving it from the TOML. This module is that
12
+ * single source: both renderers call `describeWorkflowInvoker` and read the
13
+ * SAME `WorkflowInvokerIR`, so the two clients can never disagree on which
14
+ * operations a workflow exposes or whether its input is required.
15
+ *
16
+ * What stays language-specific (and is therefore NOT in the IR): the emitted
17
+ * identifiers (the TS and Swift base names come from different naming helpers)
18
+ * and the rendered type declarations. The IR carries only the parsed schemas +
19
+ * the neutral operation flags; each renderer turns the schemas into its own
20
+ * syntax.
21
+ */
22
+ import { INTERNAL_WORKFLOW_KEY_PREFIX } from "../platform-owned.js";
23
+ export { INTERNAL_WORKFLOW_KEY_PREFIX };
24
+ /** Raw inputs a renderer already has on hand for one workflow TOML. */
25
+ export interface WorkflowInvokerSource {
26
+ /** Source `.toml` filename stem (fallback key when `[workflow].key` is absent). */
27
+ fileStem: string;
28
+ /** Raw TOML content (already read from disk). */
29
+ tomlContent: string;
30
+ }
31
+ /**
32
+ * Language-neutral description of one workflow's invoker surface. Consumed by
33
+ * both the TS and Swift invoker renderers; neither reconstructs these decisions
34
+ * on its own.
35
+ */
36
+ export interface WorkflowInvokerIR {
37
+ /**
38
+ * The ORIGINAL workflow key. The runtime call always passes this verbatim —
39
+ * only emitted identifiers are sanitized (per language).
40
+ */
41
+ key: string;
42
+ /**
43
+ * Whether the workflow is sync-callable. `runSync` is emitted ONLY when this
44
+ * is true (the server rejects run-sync for non-sync-callable workflows), on
45
+ * both clients.
46
+ */
47
+ syncCallable: boolean;
48
+ /**
49
+ * Whether `input` is a REQUIRED argument. True iff the input schema rejects
50
+ * the empty object `{}` (the client's `input ?? {}` fallback would then fail
51
+ * validation). A schema-less workflow accepts anything → optional. Computed
52
+ * ONCE here via `schemaRejectsEmptyObject`, shared with both renderers.
53
+ */
54
+ inputRequired: boolean;
55
+ /**
56
+ * Whether the workflow is apply-mode — its completed run waits for a client
57
+ * to apply the output. Mirrors the server's default: apply-mode unless the
58
+ * TOML sets `requiresClientApply = false` (`src/workflows/app-workflow.ts`).
59
+ * Only an apply-mode workflow gets a `define` member on the generated
60
+ * invoker (issue #1543). Parsed here, alongside `syncCallable`, so no
61
+ * renderer reparses the TOML for it.
62
+ */
63
+ requiresClientApply: boolean;
64
+ /** Parsed input schema, or `undefined` when absent. */
65
+ inputSchema: unknown;
66
+ /** Parsed output schema, or `undefined` when absent. */
67
+ outputSchema: unknown;
68
+ }
69
+ /**
70
+ * True for a platform-owned (reserved) workflow key. Thin alias over the shared
71
+ * `isPlatformOwnedWorkflowKey` (#1660) kept for existing callers of this name.
72
+ */
73
+ export declare function isReservedWorkflowKey(key: string): boolean;
74
+ /**
75
+ * Parse one workflow TOML into the shared invoker IR. Returns `null` for a
76
+ * reserved (`__internal.*`) workflow (no invoker is generated). Throws on
77
+ * malformed schema JSON (fail-and-exit) — the honest `undefined`/`unknown`
78
+ * fallback is for valid-but-untypeable schemas only.
79
+ *
80
+ * This is the ONE place that reads `syncCallable` / `requiresClientApply` and
81
+ * computes required-vs-optional `input`; both language generators call it.
82
+ */
83
+ export declare function describeWorkflowInvoker(source: WorkflowInvokerSource): WorkflowInvokerIR | null;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Shared workflow-invoker IR (issue #1547, Phase 3).
3
+ *
4
+ * The typed invoker factory is generated on BOTH the TypeScript side
5
+ * (`workflow-codegen/generator.ts`) and the Swift side
6
+ * (`swift-codegen/generator.ts`). The maintainer decision (item 5, binding)
7
+ * requires that invoker generation reuse ONE description of the workflow's
8
+ * operation metadata — the runtime key, whether `runSync` is emitted
9
+ * (`syncCallable`), whether `input` is a required argument, and whether the
10
+ * workflow is apply-mode (`requiresClientApply`) — rather than each language
11
+ * renderer re-deriving it from the TOML. This module is that
12
+ * single source: both renderers call `describeWorkflowInvoker` and read the
13
+ * SAME `WorkflowInvokerIR`, so the two clients can never disagree on which
14
+ * operations a workflow exposes or whether its input is required.
15
+ *
16
+ * What stays language-specific (and is therefore NOT in the IR): the emitted
17
+ * identifiers (the TS and Swift base names come from different naming helpers)
18
+ * and the rendered type declarations. The IR carries only the parsed schemas +
19
+ * the neutral operation flags; each renderer turns the schemas into its own
20
+ * syntax.
21
+ */
22
+ import { parseConfigToml } from "../config-toml.js";
23
+ import { safeJsonParse } from "../workflow-payload.js";
24
+ import { schemaRejectsEmptyObject } from "./schemaToTs.js";
25
+ import { INTERNAL_WORKFLOW_KEY_PREFIX, isPlatformOwnedWorkflowKey, } from "../platform-owned.js";
26
+ // Re-export so existing importers of these codegen symbols keep working; the
27
+ // single source of truth is now `../platform-owned.js` (#1660), shared with the
28
+ // `sync` pull/diff/push filters so codegen and sync can never drift.
29
+ export { INTERNAL_WORKFLOW_KEY_PREFIX };
30
+ /**
31
+ * True for a platform-owned (reserved) workflow key. Thin alias over the shared
32
+ * `isPlatformOwnedWorkflowKey` (#1660) kept for existing callers of this name.
33
+ */
34
+ export function isReservedWorkflowKey(key) {
35
+ return isPlatformOwnedWorkflowKey(key);
36
+ }
37
+ /**
38
+ * Parse one workflow TOML into the shared invoker IR. Returns `null` for a
39
+ * reserved (`__internal.*`) workflow (no invoker is generated). Throws on
40
+ * malformed schema JSON (fail-and-exit) — the honest `undefined`/`unknown`
41
+ * fallback is for valid-but-untypeable schemas only.
42
+ *
43
+ * This is the ONE place that reads `syncCallable` / `requiresClientApply` and
44
+ * computes required-vs-optional `input`; both language generators call it.
45
+ */
46
+ export function describeWorkflowInvoker(source) {
47
+ const data = parseConfigToml(source.tomlContent);
48
+ const workflow = data?.workflow ?? {};
49
+ const key = typeof workflow.key === "string" && workflow.key.length > 0
50
+ ? workflow.key
51
+ : source.fileStem;
52
+ if (isReservedWorkflowKey(key))
53
+ return null;
54
+ // safeJsonParse throws on invalid JSON in a schema string — let it bubble.
55
+ const inputSchema = safeJsonParse(workflow.inputSchema);
56
+ const outputSchema = safeJsonParse(workflow.outputSchema);
57
+ return {
58
+ key,
59
+ syncCallable: workflow.syncCallable === true,
60
+ // `input` is required iff the schema rejects the client's `{}` fallback.
61
+ // A schema-less workflow (`undefined`) accepts anything → optional.
62
+ inputRequired: inputSchema !== undefined && schemaRejectsEmptyObject(inputSchema),
63
+ // Apply-mode unless explicitly disabled — the same `!== false` default the
64
+ // server applies when it decides whether a completed run needs a client
65
+ // apply. An absent key means apply-mode.
66
+ requiresClientApply: workflow.requiresClientApply !== false,
67
+ inputSchema,
68
+ outputSchema,
69
+ };
70
+ }
71
+ //# sourceMappingURL=invokerIR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invokerIR.js","sourceRoot":"","sources":["../../../../src/lib/workflow-codegen/invokerIR.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,6EAA6E;AAC7E,gFAAgF;AAChF,qEAAqE;AACrE,OAAO,EAAE,4BAA4B,EAAE,CAAC;AAiDxC;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,0BAA0B,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAA6B;IAE7B,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,CAAQ,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;IACtC,MAAM,GAAG,GACP,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;QACzD,CAAC,CAAC,QAAQ,CAAC,GAAG;QACd,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAEtB,IAAI,qBAAqB,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5C,2EAA2E;IAC3E,MAAM,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAE1D,OAAO;QACL,GAAG;QACH,YAAY,EAAE,QAAQ,CAAC,YAAY,KAAK,IAAI;QAC5C,yEAAyE;QACzE,oEAAoE;QACpE,aAAa,EACX,WAAW,KAAK,SAAS,IAAI,wBAAwB,CAAC,WAAW,CAAC;QACpE,2EAA2E;QAC3E,wEAAwE;QACxE,yCAAyC;QACzC,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB,KAAK,KAAK;QAC3D,WAAW;QACX,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -38,13 +38,29 @@
38
38
  * Errors are NOT swallowed here — a malformed schema fails upstream at parse
39
39
  * time, and a defective tagged union throws — this walker otherwise returns
40
40
  * `unknown` for anything it does not recognize.
41
+ *
42
+ * FORMATTING CONTRACT (#1565): the types emitted here must be a fixed point of
43
+ * Prettier's DEFAULT config, since `workflows codegen --check` byte-compares
44
+ * the emission against disk. Long unions therefore render through
45
+ * `codegen-shared/prettierStable.ts` (which reproduces Prettier's width
46
+ * decision) instead of being joined with `" | "`. There is no Prettier
47
+ * dependency and no automated round-trip test, so verify any change to these
48
+ * shapes by hand — see that module's header.
41
49
  */
50
+ import { type TypeNode } from "../codegen-shared/prettierStable.js";
42
51
  /**
43
52
  * Convert a parsed JSON Schema node to a TypeScript type expression. Object
44
53
  * types render multi-line (2-space indent per level); everything else renders
45
- * on a single line. `indent` is the current indentation depth.
54
+ * on a single line unless it is too wide for Prettier's default print width
55
+ * (#1565). `indent` is the current indentation depth.
46
56
  */
47
57
  export declare function schemaToTsType(schema: any, indent?: number): string;
58
+ /**
59
+ * `schemaToTsType` as a wrappable node — the emitters print it at the position
60
+ * it actually occupies so long unions/objects wrap exactly as Prettier would
61
+ * (#1565). See `codegen-shared/prettierStable.ts`.
62
+ */
63
+ export declare function schemaToTypeNode(schema: any): TypeNode;
48
64
  /**
49
65
  * True when the schema REJECTS an empty object `{}` — i.e. the client's
50
66
  * `rootInput: options.input ?? {}` fallback would fail validation, so `input`