primitive-admin 1.1.0-alpha.43 → 1.1.0-alpha.45

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 (79) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/primitive.js +0 -0
  3. package/dist/src/commands/blob-buckets.js +20 -7
  4. package/dist/src/commands/blob-buckets.js.map +1 -1
  5. package/dist/src/commands/catalog.js +3 -3
  6. package/dist/src/commands/catalog.js.map +1 -1
  7. package/dist/src/commands/databases.js +3 -3
  8. package/dist/src/commands/databases.js.map +1 -1
  9. package/dist/src/commands/guides.d.ts +86 -0
  10. package/dist/src/commands/guides.js +222 -41
  11. package/dist/src/commands/guides.js.map +1 -1
  12. package/dist/src/commands/integrations.js +2 -2
  13. package/dist/src/commands/integrations.js.map +1 -1
  14. package/dist/src/commands/prompts.js +2 -2
  15. package/dist/src/commands/prompts.js.map +1 -1
  16. package/dist/src/commands/sync.d.ts +23 -3
  17. package/dist/src/commands/sync.js +370 -121
  18. package/dist/src/commands/sync.js.map +1 -1
  19. package/dist/src/commands/workflows.js +191 -26
  20. package/dist/src/commands/workflows.js.map +1 -1
  21. package/dist/src/lib/api-client.d.ts +1 -0
  22. package/dist/src/lib/api-client.js +4 -0
  23. package/dist/src/lib/api-client.js.map +1 -1
  24. package/dist/src/lib/block-layout.js +5 -5
  25. package/dist/src/lib/block-layout.js.map +1 -1
  26. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +61 -0
  27. package/dist/src/lib/codegen-shared/generatedFiles.js +127 -0
  28. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
  29. package/dist/src/lib/config-toml.d.ts +10 -0
  30. package/dist/src/lib/config-toml.js +42 -0
  31. package/dist/src/lib/config-toml.js.map +1 -0
  32. package/dist/src/lib/constants.d.ts +9 -0
  33. package/dist/src/lib/constants.js +9 -0
  34. package/dist/src/lib/constants.js.map +1 -1
  35. package/dist/src/lib/db-codegen/dbGenerator.d.ts +35 -7
  36. package/dist/src/lib/db-codegen/dbGenerator.js +384 -125
  37. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
  38. package/dist/src/lib/db-codegen/dbNaming.d.ts +29 -0
  39. package/dist/src/lib/db-codegen/dbNaming.js +58 -0
  40. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
  41. package/dist/src/lib/db-codegen/dbTemplates.d.ts +114 -5
  42. package/dist/src/lib/db-codegen/dbTemplates.js +163 -16
  43. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
  44. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +7 -3
  45. package/dist/src/lib/db-codegen/dbTsTypes.js +23 -1
  46. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -1
  47. package/dist/src/lib/generated-allowlist.js +14 -0
  48. package/dist/src/lib/generated-allowlist.js.map +1 -1
  49. package/dist/src/lib/init-config.js +2 -2
  50. package/dist/src/lib/init-config.js.map +1 -1
  51. package/dist/src/lib/toml-database-config.d.ts +10 -39
  52. package/dist/src/lib/toml-database-config.js +16 -82
  53. package/dist/src/lib/toml-database-config.js.map +1 -1
  54. package/dist/src/lib/toml-metadata-config.d.ts +1 -1
  55. package/dist/src/lib/toml-metadata-config.js +3 -3
  56. package/dist/src/lib/toml-metadata-config.js.map +1 -1
  57. package/dist/src/lib/toml-native-form.d.ts +46 -0
  58. package/dist/src/lib/toml-native-form.js +78 -0
  59. package/dist/src/lib/toml-native-form.js.map +1 -0
  60. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +96 -0
  61. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +112 -0
  62. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
  63. package/dist/src/lib/workflow-codegen/generator.d.ts +70 -0
  64. package/dist/src/lib/workflow-codegen/generator.js +186 -0
  65. package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
  66. package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
  67. package/dist/src/lib/workflow-codegen/naming.js +81 -0
  68. package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
  69. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +55 -0
  70. package/dist/src/lib/workflow-codegen/schemaToTs.js +237 -0
  71. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
  72. package/dist/src/lib/workflow-fragments.js +3 -3
  73. package/dist/src/lib/workflow-fragments.js.map +1 -1
  74. package/dist/src/lib/workflow-toml-validator.d.ts +1 -1
  75. package/dist/src/lib/workflow-toml-validator.js +1 -1
  76. package/dist/src/validators.d.ts +4 -3
  77. package/dist/src/validators.js +6 -5
  78. package/dist/src/validators.js.map +1 -1
  79. package/package.json +5 -3
@@ -0,0 +1,96 @@
1
+ /**
2
+ * GENERATED FILE — DO NOT EDIT BY HAND.
3
+ *
4
+ * Vendored byte-for-byte from the canonical server module
5
+ * `src/workflows/schema-descriptor.ts` — the SAME interpretation the server
6
+ * validator (`validateValue`) enforces. The CLI cannot import server `src/`
7
+ * at runtime, so `workflows codegen`'s type converter imports this committed
8
+ * copy instead.
9
+ *
10
+ * Regenerate with:
11
+ * node cli/scripts/gen-workflow-schema-descriptor.mjs (runs at CLI prebuild)
12
+ *
13
+ * A CI freshness guard
14
+ * (`cli/scripts/gen-workflow-schema-descriptor.mjs --check`, also asserted by
15
+ * `cli/tests/unit/workflow-codegen-descriptor-drift-guard.test.ts`) fails if
16
+ * this committed copy does not match the source — see issue #1442 / #998.
17
+ */
18
+ /**
19
+ * Canonical interpretation of the JSON-Schema subset the workflow platform
20
+ * supports (issue #1442).
21
+ *
22
+ * The server validator (`validateValue` in `schema-validation.ts`) and the CLI
23
+ * `workflows codegen` type converter (`workflow-codegen/schemaToTs.ts`) must
24
+ * agree EXACTLY on how a workflow `inputSchema`/`outputSchema` is interpreted —
25
+ * otherwise a generated `<Key>Input` type promises a shape the runtime does not
26
+ * enforce (or rejects a value the runtime accepts). Previously the converter
27
+ * re-derived those interpretation decisions by hand, which drifts from the
28
+ * validator over time.
29
+ *
30
+ * This module is the single source of that interpretation. Both consumers read
31
+ * from `describeSchema` + `isType`:
32
+ *
33
+ * - the type gate is checked before `enum` (a value failing `type` is
34
+ * rejected before `enum` is consulted);
35
+ * - a type UNION (`type: ["string","null"]`) never descends into
36
+ * `properties`/`items` — only the exact string types `"object"`/`"array"`
37
+ * do;
38
+ * - `integer` means `Number.isInteger`;
39
+ * - `additionalProperties` only closes an object; it is not a nested schema.
40
+ *
41
+ * It is deliberately dependency-free (no imports) so the CLI can vendor a
42
+ * byte-for-byte copy as a committed artifact via
43
+ * `cli/scripts/gen-workflow-schema-descriptor.mjs` (the #998 gen-allowlist
44
+ * pattern). A drift-guard test runs that generator in `--check` mode, so a
45
+ * change here that isn't regenerated into the CLI artifact fails CI. The CLI
46
+ * never imports server `src/` at runtime — only the build-time generator reads
47
+ * this file.
48
+ */
49
+ /** Does a value satisfy a JSON-schema `type` name? `integer` = `Number.isInteger`. */
50
+ export declare function isType(value: any, type: string): boolean;
51
+ /**
52
+ * The interpretation of a single schema node, normalized so both the validator
53
+ * and the type converter can consume it without re-reading raw schema fields.
54
+ */
55
+ export interface SchemaDescriptor {
56
+ /** True when `schema.type` is an array (a type union). */
57
+ isUnion: boolean;
58
+ /** `schema.type` when it is a single string; null for a union or absent type. */
59
+ singularType: string | null;
60
+ /**
61
+ * The declared type(s) normalized to an array. An array `type` is kept as-is;
62
+ * a single string becomes a one-element array; an absent/falsy type is `[]`
63
+ * (no type gate). Matches the validator's `allowedTypes` normalization.
64
+ */
65
+ types: string[];
66
+ /** The `enum` array when present, else null. */
67
+ enumValues: any[] | null;
68
+ /**
69
+ * Object descent info — non-null ONLY when `schema.type` is exactly the
70
+ * string `"object"` AND `properties` is a declared object (matching the
71
+ * validator's `schema.type === "object" && schema.properties` descent gate).
72
+ * A type UNION containing `"object"` never descends.
73
+ */
74
+ object: {
75
+ /** The raw `properties` map (child schemas). May be empty `{}`. */
76
+ properties: Record<string, any>;
77
+ /** The raw `required` list (unfiltered, as the validator reads it). */
78
+ required: any[];
79
+ /** True when `additionalProperties === false` (a closed object). */
80
+ additionalPropertiesClosed: boolean;
81
+ } | null;
82
+ /**
83
+ * Array descent info — non-null ONLY when `schema.type` is exactly the string
84
+ * `"array"` AND `items` is present (matching the validator's
85
+ * `schema.type === "array" && schema.items` descent gate).
86
+ */
87
+ array: {
88
+ /** The raw `items` schema (may be a tuple array the validator no-ops on). */
89
+ items: any;
90
+ } | null;
91
+ }
92
+ /**
93
+ * Interpret a parsed schema node. A non-object schema (null, array, scalar)
94
+ * enforces nothing → the empty descriptor.
95
+ */
96
+ export declare function describeSchema(schema: any): SchemaDescriptor;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * GENERATED FILE — DO NOT EDIT BY HAND.
3
+ *
4
+ * Vendored byte-for-byte from the canonical server module
5
+ * `src/workflows/schema-descriptor.ts` — the SAME interpretation the server
6
+ * validator (`validateValue`) enforces. The CLI cannot import server `src/`
7
+ * at runtime, so `workflows codegen`'s type converter imports this committed
8
+ * copy instead.
9
+ *
10
+ * Regenerate with:
11
+ * node cli/scripts/gen-workflow-schema-descriptor.mjs (runs at CLI prebuild)
12
+ *
13
+ * A CI freshness guard
14
+ * (`cli/scripts/gen-workflow-schema-descriptor.mjs --check`, also asserted by
15
+ * `cli/tests/unit/workflow-codegen-descriptor-drift-guard.test.ts`) fails if
16
+ * this committed copy does not match the source — see issue #1442 / #998.
17
+ */
18
+ /**
19
+ * Canonical interpretation of the JSON-Schema subset the workflow platform
20
+ * supports (issue #1442).
21
+ *
22
+ * The server validator (`validateValue` in `schema-validation.ts`) and the CLI
23
+ * `workflows codegen` type converter (`workflow-codegen/schemaToTs.ts`) must
24
+ * agree EXACTLY on how a workflow `inputSchema`/`outputSchema` is interpreted —
25
+ * otherwise a generated `<Key>Input` type promises a shape the runtime does not
26
+ * enforce (or rejects a value the runtime accepts). Previously the converter
27
+ * re-derived those interpretation decisions by hand, which drifts from the
28
+ * validator over time.
29
+ *
30
+ * This module is the single source of that interpretation. Both consumers read
31
+ * from `describeSchema` + `isType`:
32
+ *
33
+ * - the type gate is checked before `enum` (a value failing `type` is
34
+ * rejected before `enum` is consulted);
35
+ * - a type UNION (`type: ["string","null"]`) never descends into
36
+ * `properties`/`items` — only the exact string types `"object"`/`"array"`
37
+ * do;
38
+ * - `integer` means `Number.isInteger`;
39
+ * - `additionalProperties` only closes an object; it is not a nested schema.
40
+ *
41
+ * It is deliberately dependency-free (no imports) so the CLI can vendor a
42
+ * byte-for-byte copy as a committed artifact via
43
+ * `cli/scripts/gen-workflow-schema-descriptor.mjs` (the #998 gen-allowlist
44
+ * pattern). A drift-guard test runs that generator in `--check` mode, so a
45
+ * change here that isn't regenerated into the CLI artifact fails CI. The CLI
46
+ * never imports server `src/` at runtime — only the build-time generator reads
47
+ * this file.
48
+ */
49
+ /** Does a value satisfy a JSON-schema `type` name? `integer` = `Number.isInteger`. */
50
+ export function isType(value, type) {
51
+ if (type === "array")
52
+ return Array.isArray(value);
53
+ if (type === "object")
54
+ return !!value && typeof value === "object" && !Array.isArray(value);
55
+ if (type === "string")
56
+ return typeof value === "string";
57
+ if (type === "number")
58
+ return typeof value === "number" && !Number.isNaN(value);
59
+ if (type === "integer")
60
+ return Number.isInteger(value);
61
+ if (type === "boolean")
62
+ return typeof value === "boolean";
63
+ if (type === "null")
64
+ return value === null;
65
+ // Unknown type name: nothing to enforce, so treat as a match (the validator
66
+ // must not reject a value against a keyword it does not model).
67
+ return true;
68
+ }
69
+ const EMPTY_DESCRIPTOR = {
70
+ isUnion: false,
71
+ singularType: null,
72
+ types: [],
73
+ enumValues: null,
74
+ object: null,
75
+ array: null,
76
+ };
77
+ /**
78
+ * Interpret a parsed schema node. A non-object schema (null, array, scalar)
79
+ * enforces nothing → the empty descriptor.
80
+ */
81
+ export function describeSchema(schema) {
82
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
83
+ return EMPTY_DESCRIPTOR;
84
+ }
85
+ const typeSpec = schema.type;
86
+ const isUnion = Array.isArray(typeSpec);
87
+ const singularType = typeof typeSpec === "string" ? typeSpec : null;
88
+ // Mirror the validator's normalization exactly: an array stays an array; a
89
+ // truthy non-array becomes `[typeSpec]`; anything falsy is `[]`.
90
+ const types = isUnion ? typeSpec : typeSpec ? [typeSpec] : [];
91
+ const enumValues = Array.isArray(schema.enum)
92
+ ? schema.enum
93
+ : null;
94
+ const props = schema.properties;
95
+ const object = singularType === "object" &&
96
+ props &&
97
+ typeof props === "object" &&
98
+ !Array.isArray(props)
99
+ ? {
100
+ properties: props,
101
+ required: Array.isArray(schema.required)
102
+ ? schema.required
103
+ : [],
104
+ additionalPropertiesClosed: schema.additionalProperties === false,
105
+ }
106
+ : null;
107
+ const array = singularType === "array" && schema.items
108
+ ? { items: schema.items }
109
+ : null;
110
+ return { isUnion, singularType, types, enumValues, object, array };
111
+ }
112
+ //# sourceMappingURL=generated-schema-descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generated-schema-descriptor.js","sourceRoot":"","sources":["../../../../src/lib/workflow-codegen/generated-schema-descriptor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * `workflows codegen` orchestrator (issue #1442).
3
+ *
4
+ * Reads synced workflow TOMLs (`.primitive/sync/<env>/<appId>/workflows/*.toml`)
5
+ * and emits ONE generated file per workflow —
6
+ * `workflows/generated/<key>.generated.ts` — each containing the workflow's
7
+ * `<Key>Input`/`<Key>Output` types plus a typed `<key>(client)` invoker factory
8
+ * returning `{ runSync?, start }`. This mirrors `databases codegen`'s per-type
9
+ * `<Type>.generated.ts` layout (#1441's `<type>Ops`): per-file artifacts keep
10
+ * team merges conflict-free and let a `[workflow-key]` filter regenerate exactly
11
+ * one file.
12
+ *
13
+ * Design decisions (see the plan of record on #1442, post-pivot):
14
+ * - Schemas are interpreted through the SHARED descriptor
15
+ * (`generated-schema-descriptor.ts`, a vendored copy of the server's
16
+ * `schema-validation` descriptor) so the generated types match runtime
17
+ * validation exactly. A malformed schema throws (fail-and-exit).
18
+ * - `.runSync` is emitted only for `syncCallable: true` workflows (the server
19
+ * rejects run-sync otherwise); `.start` for every non-reserved workflow.
20
+ * - `input` is a REQUIRED option iff the schema rejects `{}` (the client's
21
+ * `input ?? {}` fallback would fail validation); otherwise `input?`.
22
+ * - The runtime call always passes the ORIGINAL key string; only identifiers
23
+ * are sanitized. `workflowKey` is set AFTER spreading `opts`, so a caller
24
+ * cannot override it.
25
+ * - Disk lifecycle (write / `--check` / suffix-based cleanup) delegates to the
26
+ * shared `writeOrCheckGeneratedFiles`, exactly like `databases codegen`.
27
+ */
28
+ import { type WriteOrCheckResult } from "../codegen-shared/generatedFiles.js";
29
+ /** Suffix identifying a generated file (shared with `databases codegen`). */
30
+ export declare const GENERATED_FILE_SUFFIX = ".generated.ts";
31
+ export interface WorkflowCodegenInput {
32
+ /** Source `.toml` filename stem (fallback key when `[workflow].key` is absent). */
33
+ fileStem: string;
34
+ /** Path to the source `workflows/<key>.toml` file. */
35
+ tomlPath: string;
36
+ /** Raw TOML content (already read from disk). */
37
+ tomlContent: string;
38
+ }
39
+ export interface GenerateWorkflowTypesOptions {
40
+ inputs: WorkflowCodegenInput[];
41
+ /** Directory where the `<key>.generated.ts` files are written. */
42
+ outputDir: string;
43
+ /** `--check`: compare against disk, do not write. */
44
+ check?: boolean;
45
+ /**
46
+ * Set when the run was filtered to a single workflow key (the
47
+ * `primitive workflows codegen <key>` argument). The `inputs` set is then
48
+ * PARTIAL — it does not represent the full set of owned generated files — so
49
+ * stale-output cleanup (and `--check` stale detection) is scoped to the
50
+ * filtered workflow's own file and must NOT touch / flag sibling workflows'
51
+ * `*.generated.ts` files. The unfiltered "generate all" run leaves this unset
52
+ * and keeps full orphan cleanup. Mirrors `databases codegen`'s `singleType`.
53
+ */
54
+ singleWorkflow?: boolean;
55
+ }
56
+ /**
57
+ * Render the full `<key>.generated.ts` content for a single workflow TOML input.
58
+ * Returns null for a reserved (`__internal.*`) workflow. Pure — exported so
59
+ * tests can assert on the string directly.
60
+ */
61
+ export declare function renderWorkflowFile(input: WorkflowCodegenInput): {
62
+ key: string;
63
+ content: string;
64
+ } | null;
65
+ /**
66
+ * Run workflow codegen end-to-end. One `<key>.generated.ts` per workflow;
67
+ * delegates the disk lifecycle to the shared writer/checker, exactly like
68
+ * `databases codegen`.
69
+ */
70
+ export declare function generateWorkflowTypes(options: GenerateWorkflowTypesOptions): Promise<WriteOrCheckResult>;
@@ -0,0 +1,186 @@
1
+ /**
2
+ * `workflows codegen` orchestrator (issue #1442).
3
+ *
4
+ * Reads synced workflow TOMLs (`.primitive/sync/<env>/<appId>/workflows/*.toml`)
5
+ * and emits ONE generated file per workflow —
6
+ * `workflows/generated/<key>.generated.ts` — each containing the workflow's
7
+ * `<Key>Input`/`<Key>Output` types plus a typed `<key>(client)` invoker factory
8
+ * returning `{ runSync?, start }`. This mirrors `databases codegen`'s per-type
9
+ * `<Type>.generated.ts` layout (#1441's `<type>Ops`): per-file artifacts keep
10
+ * team merges conflict-free and let a `[workflow-key]` filter regenerate exactly
11
+ * one file.
12
+ *
13
+ * Design decisions (see the plan of record on #1442, post-pivot):
14
+ * - Schemas are interpreted through the SHARED descriptor
15
+ * (`generated-schema-descriptor.ts`, a vendored copy of the server's
16
+ * `schema-validation` descriptor) so the generated types match runtime
17
+ * validation exactly. A malformed schema throws (fail-and-exit).
18
+ * - `.runSync` is emitted only for `syncCallable: true` workflows (the server
19
+ * rejects run-sync otherwise); `.start` for every non-reserved workflow.
20
+ * - `input` is a REQUIRED option iff the schema rejects `{}` (the client's
21
+ * `input ?? {}` fallback would fail validation); otherwise `input?`.
22
+ * - The runtime call always passes the ORIGINAL key string; only identifiers
23
+ * are sanitized. `workflowKey` is set AFTER spreading `opts`, so a caller
24
+ * cannot override it.
25
+ * - Disk lifecycle (write / `--check` / suffix-based cleanup) delegates to the
26
+ * shared `writeOrCheckGeneratedFiles`, exactly like `databases codegen`.
27
+ */
28
+ import * as path from "path";
29
+ import { parseConfigToml } from "../config-toml.js";
30
+ import { safeJsonParse } from "../workflow-payload.js";
31
+ import { writeOrCheckGeneratedFiles, } from "../codegen-shared/generatedFiles.js";
32
+ import { fingerprintToml } from "../db-codegen/dbFingerprint.js";
33
+ import { schemaToTsType, schemaRejectsEmptyObject } from "./schemaToTs.js";
34
+ import { workflowInputTypeName, workflowOutputTypeName, workflowFactoryName, } from "./naming.js";
35
+ /** Prefix marking a platform-owned workflow key (mirrors the server's
36
+ * `INTERNAL_WORKFLOW_KEY_PREFIX`; inlined because the CLI cannot import from
37
+ * `src/`). Such workflows are never client-invocable and are skipped. */
38
+ const INTERNAL_WORKFLOW_KEY_PREFIX = "__internal.";
39
+ /** Suffix identifying a generated file (shared with `databases codegen`). */
40
+ export const GENERATED_FILE_SUFFIX = ".generated.ts";
41
+ /** The client package the generated file imports its types from. */
42
+ const CLIENT_PACKAGE = "js-bao-wss-client";
43
+ /** True for a platform-owned workflow key. */
44
+ function isReservedKey(key) {
45
+ return (typeof key === "string" &&
46
+ key.trim().toLowerCase().startsWith(INTERNAL_WORKFLOW_KEY_PREFIX));
47
+ }
48
+ /**
49
+ * Render a top-level `<Name>Input`/`<Name>Output` declaration. An absent schema
50
+ * → `unknown`. An object type → an `interface`; anything else → a `type` alias.
51
+ */
52
+ function renderTypeDecl(name, schema) {
53
+ if (schema === undefined) {
54
+ return `export type ${name} = unknown;`;
55
+ }
56
+ const expr = schemaToTsType(schema, 0);
57
+ if (expr.startsWith("{")) {
58
+ return `export interface ${name} ${expr}`;
59
+ }
60
+ return `export type ${name} = ${expr};`;
61
+ }
62
+ /**
63
+ * Parse a single workflow TOML into the data the emitter needs. Throws on
64
+ * malformed schema JSON (fail-and-exit) — the honest `unknown` fallback is for
65
+ * valid-but-untypeable schemas only. Returns null for a reserved workflow.
66
+ */
67
+ function parseWorkflow(input) {
68
+ // #1464 removed `@iarna/toml`; #1446 makes `sync pull` emit schemas as native
69
+ // TOML tables (incl. mixed-type enums like `enum = ["ok", 1]`, TOML 1.0). The
70
+ // `parseConfigToml` facade parses both. `safeJsonParse` still owns the
71
+ // string-vs-inline-table schema handling.
72
+ const data = parseConfigToml(input.tomlContent);
73
+ const workflow = data?.workflow ?? {};
74
+ const key = typeof workflow.key === "string" && workflow.key.length > 0
75
+ ? workflow.key
76
+ : input.fileStem;
77
+ if (isReservedKey(key))
78
+ return null;
79
+ // safeJsonParse throws on invalid JSON in a schema string — let it bubble.
80
+ const inputSchema = safeJsonParse(workflow.inputSchema);
81
+ const outputSchema = safeJsonParse(workflow.outputSchema);
82
+ const inputTypeName = workflowInputTypeName(key);
83
+ const outputTypeName = workflowOutputTypeName(key);
84
+ return {
85
+ key,
86
+ syncCallable: workflow.syncCallable === true,
87
+ inputTypeName,
88
+ outputTypeName,
89
+ factoryName: workflowFactoryName(key),
90
+ inputDecl: renderTypeDecl(inputTypeName, inputSchema),
91
+ outputDecl: renderTypeDecl(outputTypeName, outputSchema),
92
+ // `input` is required iff the schema rejects the client's `{}` fallback.
93
+ // A schema-less workflow (`undefined`) accepts anything → optional.
94
+ inputRequired: inputSchema !== undefined && schemaRejectsEmptyObject(inputSchema),
95
+ };
96
+ }
97
+ /** Render the typed invoker factory for one workflow. */
98
+ function renderFactory(wf) {
99
+ const keyLiteral = JSON.stringify(wf.key);
100
+ const inputMember = wf.inputRequired
101
+ ? `input: ${wf.inputTypeName}`
102
+ : `input?: ${wf.inputTypeName}`;
103
+ const lines = [
104
+ `export function ${wf.factoryName}(client: JsBaoClient) {`,
105
+ ` return {`,
106
+ ];
107
+ // Spread `opts` FIRST, then set `workflowKey` LAST, so the factory's intended
108
+ // key always wins. `Omit<..., "workflowKey">` only rejects an excess
109
+ // `workflowKey` on object literals; a caller passing an options *variable*
110
+ // carrying an extra `workflowKey` (or any untyped JS caller) would otherwise
111
+ // override the key and invoke the wrong workflow if the spread came last.
112
+ if (wf.syncCallable) {
113
+ lines.push(` runSync: (\n` +
114
+ ` opts: { ${inputMember} } & Omit<RunSyncWorkflowOptions, "workflowKey" | "input">\n` +
115
+ ` ) =>\n` +
116
+ ` client.workflows.runSync<${wf.inputTypeName}, ${wf.outputTypeName}>({\n` +
117
+ ` ...opts,\n` +
118
+ ` workflowKey: ${keyLiteral},\n` +
119
+ ` }),`);
120
+ }
121
+ lines.push(` start: (\n` +
122
+ ` opts: { ${inputMember} } & Omit<StartWorkflowOptions, "workflowKey" | "input">\n` +
123
+ ` ) =>\n` +
124
+ ` client.workflows.start<${wf.inputTypeName}>({\n` +
125
+ ` ...opts,\n` +
126
+ ` workflowKey: ${keyLiteral},\n` +
127
+ ` }),`);
128
+ lines.push(` };`, `}`);
129
+ return lines.join("\n");
130
+ }
131
+ /**
132
+ * Render the full `<key>.generated.ts` content for a single workflow TOML input.
133
+ * Returns null for a reserved (`__internal.*`) workflow. Pure — exported so
134
+ * tests can assert on the string directly.
135
+ */
136
+ export function renderWorkflowFile(input) {
137
+ const wf = parseWorkflow(input);
138
+ if (!wf)
139
+ return null;
140
+ const fingerprint = fingerprintToml(input.tomlContent);
141
+ // Only import the option types actually referenced, so the generated file
142
+ // compiles under a consumer's `noUnusedLocals`.
143
+ const imports = ["JsBaoClient", "StartWorkflowOptions"];
144
+ if (wf.syncCallable)
145
+ imports.push("RunSyncWorkflowOptions");
146
+ imports.sort();
147
+ const blocks = [];
148
+ blocks.push([
149
+ `// AUTO-GENERATED FROM workflows/${wf.key}.toml — DO NOT EDIT.`,
150
+ "// Run `primitive workflows codegen` to regenerate.",
151
+ `// fingerprint: ${fingerprint}`,
152
+ ].join("\n"));
153
+ blocks.push(`import type {\n${imports
154
+ .map((i) => ` ${i},`)
155
+ .join("\n")}\n} from "${CLIENT_PACKAGE}";`);
156
+ blocks.push(wf.inputDecl);
157
+ blocks.push(wf.outputDecl);
158
+ blocks.push(renderFactory(wf));
159
+ return { key: wf.key, content: blocks.join("\n\n") + "\n" };
160
+ }
161
+ /**
162
+ * Run workflow codegen end-to-end. One `<key>.generated.ts` per workflow;
163
+ * delegates the disk lifecycle to the shared writer/checker, exactly like
164
+ * `databases codegen`.
165
+ */
166
+ export async function generateWorkflowTypes(options) {
167
+ const outAbs = path.resolve(options.outputDir);
168
+ const filesToWrite = new Map();
169
+ for (const input of options.inputs) {
170
+ const rendered = renderWorkflowFile(input);
171
+ if (!rendered)
172
+ continue; // reserved workflow — no file
173
+ const filePath = path.join(outAbs, `${rendered.key}${GENERATED_FILE_SUFFIX}`);
174
+ filesToWrite.set(filePath, rendered.content);
175
+ }
176
+ return await writeOrCheckGeneratedFiles({
177
+ outputDir: outAbs,
178
+ filesToWrite,
179
+ check: options.check,
180
+ // A single-workflow filter run owns only a subset of the generated files,
181
+ // so orphan cleanup / stale detection must be scoped to the filtered file.
182
+ fullOwnership: options.singleWorkflow !== true,
183
+ generatedSuffix: GENERATED_FILE_SUFFIX,
184
+ });
185
+ }
186
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/lib/workflow-codegen/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Identifier-naming helpers for `workflows codegen` (issue #1442).
3
+ *
4
+ * Workflow keys resolve case-insensitively server-side and may contain
5
+ * characters that aren't valid TS identifiers (`.`, `-`). Only the emitted
6
+ * identifiers are sanitized — the runtime call always passes the ORIGINAL key
7
+ * string.
8
+ *
9
+ * Type names: `pascalCase(key) + "Input" | "Output"` (reuses `pascalCase` from
10
+ * the database codegen so the two commands share one PascalCase rule).
11
+ * Factory property: a camelCase form of the key.
12
+ */
13
+ /**
14
+ * `create-checkout-session` / `createCheckoutSession` → `CreateCheckoutSession`.
15
+ * A digit-leading key (`123-job` → `_123Job`) is prefixed with `_` so the
16
+ * emitted type name is a valid TS identifier.
17
+ */
18
+ export declare function workflowTypeBaseName(key: string): string;
19
+ /** PascalCase base + `Input` (e.g. `CreateCheckoutSessionInput`). */
20
+ export declare function workflowInputTypeName(key: string): string;
21
+ /** PascalCase base + `Output` (e.g. `CreateCheckoutSessionOutput`). */
22
+ export declare function workflowOutputTypeName(key: string): string;
23
+ /**
24
+ * camelCase factory function name for a workflow key: PascalCase, then lowercase
25
+ * the first character (`create-checkout-session` → `createCheckoutSession`,
26
+ * `refresh-sheet` → `refreshSheet`). Used as the top-level exported factory
27
+ * function name in the per-workflow generated file, so it must be a legal
28
+ * function identifier: a digit-leading key (`123-job` → `_123Job`) is
29
+ * underscore-prefixed, and a key that lands on a JS reserved word (`delete`,
30
+ * `new`, `import`) is underscore-suffixed (`delete_`). Only the emitted
31
+ * identifier changes; the runtime call still passes the ORIGINAL key string.
32
+ */
33
+ export declare function workflowFactoryName(key: string): string;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Identifier-naming helpers for `workflows codegen` (issue #1442).
3
+ *
4
+ * Workflow keys resolve case-insensitively server-side and may contain
5
+ * characters that aren't valid TS identifiers (`.`, `-`). Only the emitted
6
+ * identifiers are sanitized — the runtime call always passes the ORIGINAL key
7
+ * string.
8
+ *
9
+ * Type names: `pascalCase(key) + "Input" | "Output"` (reuses `pascalCase` from
10
+ * the database codegen so the two commands share one PascalCase rule).
11
+ * Factory property: a camelCase form of the key.
12
+ */
13
+ import { pascalCase } from "../db-codegen/dbNaming.js";
14
+ /**
15
+ * Ensure an identifier is a valid TS identifier start. The server accepts
16
+ * workflow keys matching `^[a-z0-9][a-z0-9-_]{2,}$`, so a digit-leading key
17
+ * like `123-job` PascalCases to `123Job` — not a legal TS type name or
18
+ * unquoted object property, since identifiers can't start with a digit.
19
+ * Prefix an underscore in that case (`123Job` → `_123Job`). Only the emitted
20
+ * identifier changes; the runtime call still passes the ORIGINAL key string.
21
+ */
22
+ function ensureValidIdentifierStart(name) {
23
+ const first = name.charAt(0);
24
+ if (first >= "0" && first <= "9") {
25
+ return `_${name}`;
26
+ }
27
+ return name;
28
+ }
29
+ /**
30
+ * `create-checkout-session` / `createCheckoutSession` → `CreateCheckoutSession`.
31
+ * A digit-leading key (`123-job` → `_123Job`) is prefixed with `_` so the
32
+ * emitted type name is a valid TS identifier.
33
+ */
34
+ export function workflowTypeBaseName(key) {
35
+ return ensureValidIdentifierStart(pascalCase(key));
36
+ }
37
+ /** PascalCase base + `Input` (e.g. `CreateCheckoutSessionInput`). */
38
+ export function workflowInputTypeName(key) {
39
+ return `${workflowTypeBaseName(key)}Input`;
40
+ }
41
+ /** PascalCase base + `Output` (e.g. `CreateCheckoutSessionOutput`). */
42
+ export function workflowOutputTypeName(key) {
43
+ return `${workflowTypeBaseName(key)}Output`;
44
+ }
45
+ /**
46
+ * Reserved words that cannot be used as a bare `function <name>` declaration.
47
+ * The per-workflow factory is now a top-level exported function (not an
48
+ * object-literal property), so a key that camelCases to one of these must be
49
+ * escaped or `export function delete(client) {}` is a syntax error. Covers ES
50
+ * reserved words plus the strict-mode/future set — a workflow key resolves case
51
+ * -insensitively and matches `^[a-z0-9][a-z0-9-_]{2,}$`, so only the lowercase
52
+ * single-word forms can actually collide.
53
+ */
54
+ const RESERVED_WORDS = new Set([
55
+ "break", "case", "catch", "class", "const", "continue", "debugger",
56
+ "default", "delete", "do", "else", "enum", "export", "extends", "false",
57
+ "finally", "for", "function", "if", "import", "in", "instanceof", "new",
58
+ "null", "return", "super", "switch", "this", "throw", "true", "try",
59
+ "typeof", "var", "void", "while", "with", "yield", "let", "static",
60
+ "implements", "interface", "package", "private", "protected", "public",
61
+ "await",
62
+ ]);
63
+ /**
64
+ * camelCase factory function name for a workflow key: PascalCase, then lowercase
65
+ * the first character (`create-checkout-session` → `createCheckoutSession`,
66
+ * `refresh-sheet` → `refreshSheet`). Used as the top-level exported factory
67
+ * function name in the per-workflow generated file, so it must be a legal
68
+ * function identifier: a digit-leading key (`123-job` → `_123Job`) is
69
+ * underscore-prefixed, and a key that lands on a JS reserved word (`delete`,
70
+ * `new`, `import`) is underscore-suffixed (`delete_`). Only the emitted
71
+ * identifier changes; the runtime call still passes the ORIGINAL key string.
72
+ */
73
+ export function workflowFactoryName(key) {
74
+ const pascal = pascalCase(key);
75
+ if (pascal.length === 0)
76
+ return pascal;
77
+ const camel = pascal.charAt(0).toLowerCase() + pascal.slice(1);
78
+ const safeStart = ensureValidIdentifierStart(camel);
79
+ return RESERVED_WORDS.has(safeStart) ? `${safeStart}_` : safeStart;
80
+ }
81
+ //# sourceMappingURL=naming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.js","sourceRoot":"","sources":["../../../../src/lib/workflow-codegen/naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD;;;;;;;GAOG;AACH,SAAS,0BAA0B,CAAC,IAAY;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QACjC,OAAO,IAAI,IAAI,EAAE,CAAC;IACpB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAO,0BAA0B,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7C,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU;IAClE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO;IACvE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK;IACvE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK;IACnE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ;IAClE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ;IACtE,OAAO;CACR,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IACpD,OAAO,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * JSON-Schema → TypeScript converter for `workflows codegen` (issue #1442).
3
+ *
4
+ * Workflow `inputSchema`/`outputSchema` are real JSON Schema. This converter
5
+ * types only the subset the server's validator descends into — and it reads
6
+ * that interpretation from the SAME descriptor the server validator consumes,
7
+ * vendored into the CLI as `generated-schema-descriptor.ts` (a byte copy of
8
+ * `src/workflows/schema-descriptor.ts`, kept fresh by
9
+ * `cli/scripts/gen-workflow-schema-descriptor.mjs` + its drift guard). So the
10
+ * generated type and the runtime validation can never disagree on:
11
+ *
12
+ * - `type` single scalar (`string`/`number`/`integer`/`boolean`/`null`) →
13
+ * the mapped TS scalar.
14
+ * - `type` array-union — only when every member is a scalar/`null` → a TS
15
+ * union. A union that contains `object` or `array` renders `unknown`,
16
+ * because the server only walks `properties`/`items` for the bare string
17
+ * `"object"`/`"array"` — a union is never descended, so a precise-looking
18
+ * type would over-promise.
19
+ * - `enum` → a scalar-literal union, intersected with the declared `type`
20
+ * first (the server gates on `type` before checking `enum`).
21
+ * - `type: "object"` with `properties` → a nested object type; `required[]`
22
+ * drives `name:` vs `name?:`. An OPEN object (no `additionalProperties:
23
+ * false`) also emits `[key: string]: unknown` so extra keys the runtime
24
+ * validator accepts don't hit TS excess-property errors; a CLOSED object
25
+ * (`additionalProperties: false`) omits the index signature.
26
+ * - `type: "array"` with `items` → `T[]`.
27
+ *
28
+ * Everything the server ignores (`$ref`, `oneOf`/`anyOf`/`allOf`, `format`,
29
+ * `patternProperties`, numeric constraints, tuple `items`) renders `unknown`.
30
+ *
31
+ * Errors are NOT swallowed here — a malformed schema fails upstream at parse
32
+ * time; this walker only sees an already-parsed schema and returns `unknown`
33
+ * for anything it does not recognize.
34
+ */
35
+ /**
36
+ * Convert a parsed JSON Schema node to a TypeScript type expression. Object
37
+ * types render multi-line (2-space indent per level); everything else renders
38
+ * on a single line. `indent` is the current indentation depth.
39
+ */
40
+ export declare function schemaToTsType(schema: any, indent?: number): string;
41
+ /**
42
+ * True when the schema REJECTS an empty object `{}` — i.e. the client's
43
+ * `rootInput: options.input ?? {}` fallback would fail validation, so `input`
44
+ * must be a compile-time-required option (issue #1442, P4). Derived from the
45
+ * shared descriptor so it matches the server validator exactly:
46
+ *
47
+ * - a declared top-level `type` that `{}` does not satisfy (anything but
48
+ * `object`, e.g. `string`/`array`, or a union with no `object` arm);
49
+ * - a top-level `enum` (a fresh `{}` is never an enum member);
50
+ * - `type: "object"` with a non-empty `required[]` (a missing required key).
51
+ *
52
+ * An all-optional object schema, or a schema with no top-level constraints,
53
+ * accepts `{}` → `input` is optional.
54
+ */
55
+ export declare function schemaRejectsEmptyObject(schema: any): boolean;