primitive-admin 1.1.0-alpha.47 → 1.1.0-alpha.49

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 (74) hide show
  1. package/dist/bin/primitive.js +2 -0
  2. package/dist/bin/primitive.js.map +1 -1
  3. package/dist/src/commands/apps.js +54 -2
  4. package/dist/src/commands/apps.js.map +1 -1
  5. package/dist/src/commands/databases.js +31 -10
  6. package/dist/src/commands/databases.js.map +1 -1
  7. package/dist/src/commands/documents.js +77 -0
  8. package/dist/src/commands/documents.js.map +1 -1
  9. package/dist/src/commands/guides.d.ts +15 -12
  10. package/dist/src/commands/guides.js +22 -15
  11. package/dist/src/commands/guides.js.map +1 -1
  12. package/dist/src/commands/settings.d.ts +15 -0
  13. package/dist/src/commands/settings.js +102 -0
  14. package/dist/src/commands/settings.js.map +1 -0
  15. package/dist/src/commands/sync-app-settings.d.ts +105 -0
  16. package/dist/src/commands/sync-app-settings.js +339 -0
  17. package/dist/src/commands/sync-app-settings.js.map +1 -0
  18. package/dist/src/commands/sync.d.ts +34 -19
  19. package/dist/src/commands/sync.js +373 -200
  20. package/dist/src/commands/sync.js.map +1 -1
  21. package/dist/src/commands/workflows.js +32 -10
  22. package/dist/src/commands/workflows.js.map +1 -1
  23. package/dist/src/lib/api-client.d.ts +2 -0
  24. package/dist/src/lib/api-client.js +6 -0
  25. package/dist/src/lib/api-client.js.map +1 -1
  26. package/dist/src/lib/app-settings-descriptor.d.ts +108 -0
  27. package/dist/src/lib/app-settings-descriptor.js +250 -0
  28. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  29. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +15 -0
  30. package/dist/src/lib/codegen-shared/generatedFiles.js +27 -10
  31. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
  32. package/dist/src/lib/db-codegen/dbGenerator.d.ts +11 -83
  33. package/dist/src/lib/db-codegen/dbGenerator.js +93 -556
  34. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
  35. package/dist/src/lib/db-codegen/dbNaming.d.ts +15 -7
  36. package/dist/src/lib/db-codegen/dbNaming.js +25 -13
  37. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
  38. package/dist/src/lib/db-codegen/dbTemplates.d.ts +55 -4
  39. package/dist/src/lib/db-codegen/dbTemplates.js +169 -40
  40. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
  41. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  42. package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
  43. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  44. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +101 -0
  45. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +200 -0
  46. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  47. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +68 -0
  48. package/dist/src/lib/swift-codegen/dbGenerator.js +380 -0
  49. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  50. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  51. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  52. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  53. package/dist/src/lib/swift-codegen/generator.d.ts +84 -0
  54. package/dist/src/lib/swift-codegen/generator.js +178 -0
  55. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  56. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
  57. package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
  58. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  59. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  60. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  61. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  62. package/dist/src/lib/sync-resource-types.d.ts +225 -0
  63. package/dist/src/lib/sync-resource-types.js +394 -0
  64. package/dist/src/lib/sync-resource-types.js.map +1 -0
  65. package/dist/src/lib/template.d.ts +1 -1
  66. package/dist/src/lib/template.js +6 -3
  67. package/dist/src/lib/template.js.map +1 -1
  68. package/dist/src/lib/workflow-codegen/generator.d.ts +18 -5
  69. package/dist/src/lib/workflow-codegen/generator.js +116 -41
  70. package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
  71. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +85 -0
  72. package/dist/src/lib/workflow-codegen/invokerIR.js +71 -0
  73. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  74. package/package.json +4 -2
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Shared field descriptor for app-settings TOML sync (issue #1033).
3
+ *
4
+ * A single source of truth describing every app setting that round-trips
5
+ * through `app.toml`. It drives BOTH directions:
6
+ * - pull (`serializeAppSettingsToToml`): server settings -> `app.toml` object
7
+ * - push (`parseTomlToAppSettings`): `app.toml` object -> settings payload
8
+ *
9
+ * Driving serializer and parser from one table means the two can never drift
10
+ * apart, and a single drift test can assert the descriptor stays in step with
11
+ * the server's `GET /settings` response and `PUT /settings` allow-list. This
12
+ * generalizes the earlier hand-maintained `AUTH_BOOLEAN_KEYS` /
13
+ * `RECOGNIZED_AUTH_KEYS` pattern to every section, and fully replaces it.
14
+ *
15
+ * Design decisions of record (issue #1033):
16
+ * - `googleClientSecret` is a secret: never written to `app.toml` on pull, and
17
+ * a hard error (abort before any PUT) if hand-added on push. Non-secret
18
+ * `googleClientId` syncs normally.
19
+ * - `[cors]` is always emitted (the `mode` key is `emit: "always"`), even in
20
+ * universal mode. A one-time diff on the next pull for existing apps is
21
+ * acceptable.
22
+ * - `[invitations]` is an additive table for the member-invitation fields.
23
+ * - Legacy `passkeyRpId` / `passkeyRpName` are still writable server-side but
24
+ * excluded from TOML (superseded by `passkeyRpConfig` -> `[auth.passkeys]`).
25
+ * The coverage test classifies them as deprecated-writable exclusions, NOT
26
+ * computed/read-only.
27
+ * - Push type mismatches are field-named validation errors — no silent
28
+ * coercion of a mistyped TOML value.
29
+ */
30
+ /**
31
+ * Every field that round-trips through `app.toml`. 26 entries — the server's
32
+ * `PUT /settings` allow-list minus the two deprecated legacy passkey fields.
33
+ * `googleClientSecret` is present but flagged `secret` (excluded from TOML).
34
+ */
35
+ export const APP_SETTINGS_DESCRIPTOR = [
36
+ // ---- [app] --------------------------------------------------------------
37
+ { field: "name", section: "app", key: "name", type: "string", emit: "always" },
38
+ { field: "mode", section: "app", key: "mode", type: "string", emit: "always" },
39
+ { field: "baseUrl", section: "app", key: "baseUrl", type: "string", emit: "whenSet" },
40
+ { field: "waitlistEnabled", section: "app", key: "waitlistEnabled", type: "boolean", emit: "always" },
41
+ { field: "waitlistNotifyAdmins", section: "app", key: "waitlistNotifyAdmins", type: "boolean", emit: "always" },
42
+ { field: "allowedDomains", section: "app", key: "allowedDomains", type: "string[]", emit: "whenSet" },
43
+ { field: "testAccountBaseEmails", section: "app", key: "testAccountBaseEmails", type: "string[]", emit: "whenSet" },
44
+ // ---- [auth] -------------------------------------------------------------
45
+ { field: "googleOAuthEnabled", section: "auth", key: "googleOAuthEnabled", type: "boolean", emit: "whenSet" },
46
+ { field: "googleClientId", section: "auth", key: "googleClientId", type: "string", emit: "whenSet" },
47
+ // Secret — omitted on pull, hard error on push. See GOOGLE_CLIENT_SECRET_PUSH_ERROR.
48
+ { field: "googleClientSecret", section: "auth", key: "googleClientSecret", type: "string", emit: "whenSet", secret: true },
49
+ { field: "passkeyEnabled", section: "auth", key: "passkeyEnabled", type: "boolean", emit: "always" },
50
+ { field: "magicLinkEnabled", section: "auth", key: "magicLinkEnabled", type: "boolean", emit: "always" },
51
+ { field: "appleSignInEnabled", section: "auth", key: "appleSignInEnabled", type: "boolean", emit: "whenSet" },
52
+ { field: "otpEnabled", section: "auth", key: "otpEnabled", type: "boolean", emit: "whenSet" },
53
+ { field: "appleAudiences", section: "auth", key: "appleAudiences", type: "string[]", emit: "whenSet" },
54
+ { field: "redirectUris", section: "auth", key: "redirectUris", type: "string[]", emit: "whenSet" },
55
+ // passkeyRpConfig <-> [auth.passkeys] (nested object of rpId -> { name }).
56
+ { field: "passkeyRpConfig", section: "auth", key: "passkeys", type: "object", emit: "whenSet" },
57
+ // ---- [cors] -------------------------------------------------------------
58
+ // `mode` is `always` so the [cors] table is always emitted (decision 3).
59
+ { field: "corsMode", section: "cors", key: "mode", type: "string", emit: "always" },
60
+ { field: "corsAllowedOrigins", section: "cors", key: "allowedOrigins", type: "string[]", emit: "whenSet" },
61
+ { field: "corsAllowCredentials", section: "cors", key: "allowCredentials", type: "boolean", emit: "whenSet" },
62
+ { field: "corsAllowedMethods", section: "cors", key: "allowedMethods", type: "string[]", emit: "whenSet" },
63
+ { field: "corsAllowedHeaders", section: "cors", key: "allowedHeaders", type: "string[]", emit: "whenSet" },
64
+ { field: "corsExposedHeaders", section: "cors", key: "exposedHeaders", type: "string[]", emit: "whenSet" },
65
+ { field: "corsMaxAge", section: "cors", key: "maxAge", type: "number", emit: "whenSet" },
66
+ // ---- [invitations] ------------------------------------------------------
67
+ { field: "memberInvitationsEnabled", section: "invitations", key: "enabled", type: "boolean", emit: "always" },
68
+ { field: "memberInvitationLimit", section: "invitations", key: "limit", type: "number", emit: "always" },
69
+ ];
70
+ /** Section render order for a stable, diff-friendly `app.toml`. */
71
+ export const APP_SETTINGS_SECTIONS = [
72
+ "app",
73
+ "auth",
74
+ "cors",
75
+ "invitations",
76
+ ];
77
+ /**
78
+ * `GET /settings` keys that are computed/read-only and never sync (no server
79
+ * setter). The external coverage drift test classifies these here.
80
+ */
81
+ export const IGNORED_GET_KEYS = new Set([
82
+ "appId",
83
+ "hasGoogleAuth",
84
+ "hasAppleAuth",
85
+ "hasPasskey",
86
+ "createdAt",
87
+ "modifiedAt",
88
+ ]);
89
+ /**
90
+ * Fields that ARE still writable server-side (present in the `PUT /settings`
91
+ * allow-list) but are deliberately excluded from TOML because a newer field
92
+ * supersedes them. Kept distinct from `IGNORED_GET_KEYS` so the coverage test's
93
+ * "every allow-listed field is covered" claim stays true — these are excluded,
94
+ * not read-only. (Codex design-review concern #1.)
95
+ */
96
+ export const DEPRECATED_WRITABLE_EXCLUDED = new Set([
97
+ "passkeyRpId",
98
+ "passkeyRpName",
99
+ ]);
100
+ /** Push error for a hand-added `googleClientSecret` — points at a real command. */
101
+ export const GOOGLE_CLIENT_SECRET_PUSH_ERROR = 'app.toml must not contain a "googleClientSecret" key under [auth]. ' +
102
+ "Secrets are excluded from synced config by design. Remove the key, then set " +
103
+ "the secret with:\n primitive apps update <appId> --google-client-secret <secret>";
104
+ const DESCRIPTOR_BY_SECTION = (() => {
105
+ const m = new Map();
106
+ for (const d of APP_SETTINGS_DESCRIPTOR) {
107
+ const list = m.get(d.section) ?? [];
108
+ list.push(d);
109
+ m.set(d.section, list);
110
+ }
111
+ return m;
112
+ })();
113
+ /** Descriptor `field` names, for parity/coverage tests. */
114
+ export const DESCRIPTOR_FIELDS = new Set(APP_SETTINGS_DESCRIPTOR.map((d) => d.field));
115
+ function typeOfValue(value) {
116
+ if (value === null || value === undefined)
117
+ return "null";
118
+ if (typeof value === "boolean")
119
+ return "boolean";
120
+ if (typeof value === "number")
121
+ return "number";
122
+ if (typeof value === "string")
123
+ return "string";
124
+ if (Array.isArray(value))
125
+ return "string[]";
126
+ if (typeof value === "object")
127
+ return "object";
128
+ return "unknown";
129
+ }
130
+ /** True if a value should be omitted under `emit: "whenSet"`. */
131
+ function isEmptyForEmit(value, type) {
132
+ if (value === null || value === undefined)
133
+ return true;
134
+ if (type === "string")
135
+ return value === "";
136
+ if (type === "string[]")
137
+ return !Array.isArray(value) || value.length === 0;
138
+ if (type === "object")
139
+ return (typeof value !== "object" ||
140
+ value === null ||
141
+ Object.keys(value).length === 0);
142
+ return false; // booleans (false) and numbers (0) are meaningful, never empty
143
+ }
144
+ /**
145
+ * Validate a push value against its descriptor type. Returns an error string
146
+ * (field-named) on mismatch, or `null` when the value is acceptable. Arrays are
147
+ * checked element-by-element so a `["a", 1]` mistype is caught.
148
+ */
149
+ function typeError(descriptor, value) {
150
+ const actual = typeOfValue(value);
151
+ if (actual === "null")
152
+ return null; // null clears; server owns clear semantics
153
+ if (descriptor.type === "string[]") {
154
+ if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
155
+ return `[${descriptor.section}].${descriptor.key} must be an array of strings (got ${actual})`;
156
+ }
157
+ return null;
158
+ }
159
+ if (descriptor.type === "object") {
160
+ if (actual !== "object") {
161
+ return `[${descriptor.section}].${descriptor.key} must be a table (got ${actual})`;
162
+ }
163
+ return null;
164
+ }
165
+ if (actual !== descriptor.type) {
166
+ return `[${descriptor.section}].${descriptor.key} must be a ${descriptor.type} (got ${actual})`;
167
+ }
168
+ return null;
169
+ }
170
+ /**
171
+ * Build one `app.toml` section object from server settings (pull direction).
172
+ * Secret fields are never written. Applies each field's `emit` rule; a `null`
173
+ * value is always omitted (TOML cannot encode null).
174
+ */
175
+ export function serializeSection(settings, section) {
176
+ const out = {};
177
+ for (const d of DESCRIPTOR_BY_SECTION.get(section) ?? []) {
178
+ if (d.secret)
179
+ continue;
180
+ const value = settings[d.field];
181
+ if (value === null || value === undefined)
182
+ continue;
183
+ if (d.emit === "whenSet" && isEmptyForEmit(value, d.type))
184
+ continue;
185
+ out[d.key] = value;
186
+ }
187
+ return out;
188
+ }
189
+ /**
190
+ * Build the full `app.toml` data object (all sections) from server settings.
191
+ * Empty sections are omitted, though in practice every section has at least one
192
+ * `emit: "always"` key so all four are present.
193
+ */
194
+ export function serializeAppSettingsToToml(settings) {
195
+ const data = {};
196
+ for (const section of APP_SETTINGS_SECTIONS) {
197
+ const obj = serializeSection(settings, section);
198
+ if (Object.keys(obj).length > 0)
199
+ data[section] = obj;
200
+ }
201
+ return data;
202
+ }
203
+ /**
204
+ * Translate a parsed `app.toml` object into a `PUT /settings` payload (push
205
+ * direction). Only keys present in the TOML are forwarded — an omitted key
206
+ * never overwrites server state. Unknown keys warn; type mismatches and any
207
+ * secret key are hard errors that the caller must treat as abort-before-PUT.
208
+ *
209
+ * `isCrossAppPush` strips `name` so a cross-app push never overwrites the
210
+ * target app's name.
211
+ */
212
+ export function parseTomlToAppSettings(tomlData, options = {}) {
213
+ const settings = {};
214
+ const warnings = [];
215
+ const errors = [];
216
+ for (const section of APP_SETTINGS_SECTIONS) {
217
+ const sectionData = tomlData?.[section];
218
+ if (sectionData === undefined || sectionData === null)
219
+ continue;
220
+ if (typeof sectionData !== "object" || Array.isArray(sectionData)) {
221
+ errors.push(`[${section}] must be a table`);
222
+ continue;
223
+ }
224
+ const descriptors = DESCRIPTOR_BY_SECTION.get(section) ?? [];
225
+ const byKey = new Map(descriptors.map((d) => [d.key, d]));
226
+ for (const key of Object.keys(sectionData)) {
227
+ const d = byKey.get(key);
228
+ if (!d) {
229
+ warnings.push(`Unrecognized [${section}] key "${key}" in app.toml — ignored. ` +
230
+ `Recognized keys: ${descriptors.map((x) => x.key).join(", ")}.`);
231
+ continue;
232
+ }
233
+ if (d.secret) {
234
+ errors.push(GOOGLE_CLIENT_SECRET_PUSH_ERROR);
235
+ continue;
236
+ }
237
+ if (options.isCrossAppPush && d.field === "name")
238
+ continue;
239
+ const value = sectionData[key];
240
+ const err = typeError(d, value);
241
+ if (err) {
242
+ errors.push(err);
243
+ continue;
244
+ }
245
+ settings[d.field] = value;
246
+ }
247
+ }
248
+ return { settings, warnings, errors };
249
+ }
250
+ //# sourceMappingURL=app-settings-descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-settings-descriptor.js","sourceRoot":"","sources":["../../../src/lib/app-settings-descriptor.ts"],"names":[],"mappings":"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"}
@@ -52,6 +52,21 @@ export interface WriteOrCheckOptions {
52
52
  * reaches the other generator's files.
53
53
  */
54
54
  generatedSuffix?: string;
55
+ /**
56
+ * Optional banner prefix that further narrows ownership by file CONTENT.
57
+ * When set, a `<suffix>` file is only considered owned (for orphan cleanup /
58
+ * stale detection) if its contents also start with this prefix.
59
+ *
60
+ * The Swift path needs this: both `workflows codegen --lang swift` and the
61
+ * Swift model codegen (`swift-bao-codegen`) emit `.generated.swift` files and
62
+ * may share one output dir (a Sources dir in the consuming app). Suffix alone
63
+ * cannot tell them apart, so a suffix-only sweep would delete the other
64
+ * generator's files. Scoping by the emitted header banner keeps each
65
+ * generator's cleanup to its own files. The TS callers leave this unset —
66
+ * their default `generated/` dirs are single-generator, so suffix ownership
67
+ * is already unambiguous.
68
+ */
69
+ ownershipBanner?: string;
55
70
  }
56
71
  /**
57
72
  * Write (or `--check`) a set of rendered generated files, handling orphan
@@ -24,10 +24,10 @@ export async function writeOrCheckGeneratedFiles(options) {
24
24
  const outAbs = path.resolve(options.outputDir);
25
25
  const suffix = options.generatedSuffix ?? DEFAULT_GENERATED_SUFFIX;
26
26
  if (options.check === true) {
27
- return await runCheck(outAbs, options.filesToWrite, options.fullOwnership, suffix);
27
+ return await runCheck(outAbs, options.filesToWrite, options.fullOwnership, suffix, options.ownershipBanner);
28
28
  }
29
29
  await fsp.mkdir(outAbs, { recursive: true });
30
- const deletedFiles = await cleanupGeneratedOutputs(outAbs, options.filesToWrite, options.fullOwnership, suffix);
30
+ const deletedFiles = await cleanupGeneratedOutputs(outAbs, options.filesToWrite, options.fullOwnership, suffix, options.ownershipBanner);
31
31
  const writtenFiles = [];
32
32
  for (const [filePath, content] of options.filesToWrite) {
33
33
  await fsp.writeFile(filePath, content, "utf-8");
@@ -37,7 +37,7 @@ export async function writeOrCheckGeneratedFiles(options) {
37
37
  deletedFiles.sort();
38
38
  return { writtenFiles, deletedFiles, mismatches: [] };
39
39
  }
40
- async function runCheck(outAbs, filesToWrite, fullOwnership, suffix) {
40
+ async function runCheck(outAbs, filesToWrite, fullOwnership, suffix, ownershipBanner) {
41
41
  const mismatches = [];
42
42
  for (const [filePath, expected] of filesToWrite) {
43
43
  let actual;
@@ -64,7 +64,7 @@ async function runCheck(outAbs, filesToWrite, fullOwnership, suffix) {
64
64
  // owns a subset: `filesToWrite` is then partial, so sibling files aren't
65
65
  // "stale" — they just weren't in scope.
66
66
  if (fullOwnership && (await dirExists(outAbs))) {
67
- const onDisk = await listOwnedGeneratedFiles(outAbs, suffix);
67
+ const onDisk = await listOwnedGeneratedFiles(outAbs, suffix, ownershipBanner);
68
68
  const expectedPaths = new Set(filesToWrite.keys());
69
69
  for (const filePath of onDisk) {
70
70
  if (!expectedPaths.has(filePath)) {
@@ -78,13 +78,13 @@ async function runCheck(outAbs, filesToWrite, fullOwnership, suffix) {
78
78
  mismatches,
79
79
  };
80
80
  }
81
- async function cleanupGeneratedOutputs(outDir, filesToWrite, fullOwnership, suffix) {
81
+ async function cleanupGeneratedOutputs(outDir, filesToWrite, fullOwnership, suffix, ownershipBanner) {
82
82
  // A filtered run only owns a subset; `filesToWrite` does not represent the
83
83
  // full set of generated files, so skip orphan cleanup to avoid destroying
84
84
  // sibling files. Full cleanup only happens on the unfiltered run.
85
85
  if (!fullOwnership)
86
86
  return [];
87
- const onDisk = await listOwnedGeneratedFiles(outDir, suffix);
87
+ const onDisk = await listOwnedGeneratedFiles(outDir, suffix, ownershipBanner);
88
88
  const expectedPaths = new Set(filesToWrite.keys());
89
89
  const deleted = [];
90
90
  for (const filePath of onDisk) {
@@ -97,9 +97,11 @@ async function cleanupGeneratedOutputs(outDir, filesToWrite, fullOwnership, suff
97
97
  }
98
98
  /**
99
99
  * List only the generator-owned files in `outDir`, decided by the `suffix`
100
- * (`.generated.ts`). Hand-written files are never touched.
100
+ * (`.generated.ts`) and, when given, an `ownershipBanner` prefix on the file's
101
+ * content. Hand-written files — and files owned by a DIFFERENT generator that
102
+ * happen to share the suffix — are never touched.
101
103
  */
102
- async function listOwnedGeneratedFiles(outDir, suffix) {
104
+ async function listOwnedGeneratedFiles(outDir, suffix, ownershipBanner) {
103
105
  if (!(await dirExists(outDir)))
104
106
  return [];
105
107
  const entries = await fsp.readdir(outDir, { withFileTypes: true });
@@ -107,9 +109,24 @@ async function listOwnedGeneratedFiles(outDir, suffix) {
107
109
  for (const entry of entries) {
108
110
  if (!entry.isFile())
109
111
  continue;
110
- if (entry.name.endsWith(suffix)) {
111
- owned.push(path.join(outDir, entry.name));
112
+ if (!entry.name.endsWith(suffix))
113
+ continue;
114
+ const filePath = path.join(outDir, entry.name);
115
+ if (ownershipBanner) {
116
+ // Content-scoped ownership: only sweep files carrying THIS generator's
117
+ // banner, so a shared output dir keeps each generator's cleanup to its
118
+ // own files. A read failure means "not confidently ours" → skip it.
119
+ let contents;
120
+ try {
121
+ contents = await fsp.readFile(filePath, "utf-8");
122
+ }
123
+ catch {
124
+ continue;
125
+ }
126
+ if (!contents.startsWith(ownershipBanner))
127
+ continue;
112
128
  }
129
+ owned.push(filePath);
113
130
  }
114
131
  return owned;
115
132
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generatedFiles.js","sourceRoot":"","sources":["../../../../src/lib/codegen-shared/generatedFiles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generatedFiles.js","sourceRoot":"","sources":["../../../../src/lib/codegen-shared/generatedFiles.ts"],"names":[],"mappings":"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"}
@@ -6,28 +6,19 @@
6
6
  * then either (a) writes them, or (b) compares them against on-disk for
7
7
  * `--check`. No commander dependency, no `process.exit`.
8
8
  *
9
- * Reuses the codegen-v2 machinery:
10
- * - `loadSchemaFromTomlString` (the shared `[models.*]` parser) for record
11
- * interfaces — the database-type `[models.*]` blocks round-trip through
12
- * the same loader and the same `FieldType` vocabulary.
13
- * - The banner + fingerprint header pattern and stale-output cleanup.
14
- *
15
- * Adds the OPERATIONS half (op-params interfaces + per-op result aliases)
16
- * that codegen-v2 has no analog for. A result alias is derived from `op.type`
17
- * and, where the shape is derivable, the op's parsed `definition`: a query op's
18
- * `projection` (#1439), a mutation op's step kinds (#1438), and a pipeline op's
19
- * `return` step (#1437). This file resolves those into the small descriptors
20
- * the templates consume; the templates stay pure string-emitters.
9
+ * The op/record RESOLUTION (parse, schema load, required-ness inference, op
10
+ * params, and per-op result descriptors) lives in the shared, naming-neutral
11
+ * `describeDbType` IR (`dbTypeIR.ts`) — the SAME source the Swift renderer
12
+ * (`swift-codegen/dbGenerator.ts`) consumes (issue #1547 binding 5). This file
13
+ * is now purely the TS *rendering* half: it applies TS identifier naming
14
+ * (`resolveRecordInterfaceName`, `opParamsInterfaceName`, …) to that IR and
15
+ * emits `*.generated.ts` via the pure `dbTemplates` string-emitters. The
16
+ * emitted bytes are unchanged from the former inline implementation.
21
17
  */
22
18
  import { type GeneratedFileMismatch } from "../codegen-shared/generatedFiles.js";
23
- export interface DbCodegenInput {
24
- /** Database type name (drives the output filename). */
25
- databaseType: string;
26
- /** Path to the source `database-types/<type>.toml` file. */
27
- tomlPath: string;
28
- /** Raw TOML content (already read from disk). */
29
- tomlContent: string;
30
- }
19
+ import { type DbCodegenInput } from "./dbTypeIR.js";
20
+ export type { DbCodegenInput } from "./dbTypeIR.js";
21
+ export { inferArrayParamElementTypes, inferRequiredRecordFields, type InferredRecordModelInfo, } from "./dbTypeIR.js";
31
22
  export interface GenerateDbTypesOptions {
32
23
  /** One entry per database-type TOML file to generate from. */
33
24
  inputs: DbCodegenInput[];
@@ -68,69 +59,6 @@ export type DbCheckMismatch = GeneratedFileMismatch;
68
59
  * TOML. Exported so tests can assert on the rendered string directly.
69
60
  */
70
61
  export declare function renderDbTypeFile(input: DbCodegenInput): string;
71
- /**
72
- * Infer the scalar element TS type for op params consumed by a `$in`/`$nin`
73
- * filter operator (#1488, Phase 1). Codegen-only: a param compared with
74
- * `$in`/`$nin` against a model field is definitionally an array, so the
75
- * typed-ops factory (#1441) should emit `<elem>[]` rather than widening an
76
- * untyped/object param to `Record<string, unknown>` (which `string[]` is not
77
- * assignable to).
78
- *
79
- * Kept a small local helper next to {@link inferRequiredRecordFields} rather
80
- * than a shared cross-runtime analysis pass (sponsor decision on #1488).
81
- *
82
- * Returns a map of param name → element TS type. The `"unknown"` sentinel means
83
- * "emit `unknown[]`" — used when the compared field is missing from the model
84
- * schema (or the op has no resolvable model), when the same param is bound to
85
- * fields of differing element types, or when the param is also used as a scalar
86
- * elsewhere (conservative widen, mirroring #845's disagreement rule / #1488
87
- * Fork 4). A param absent from the map is not consumed by any array operator
88
- * and keeps its declared-type mapping (inference never widens such a param).
89
- */
90
- export declare function inferArrayParamElementTypes(op: any, fieldTypesByModel: Map<string, Map<string, string>>): Map<string, string>;
91
- /**
92
- * Per-model result of {@link inferRequiredRecordFields}. Shaped as an object
93
- * (rather than a bare `Set`) so it can grow additional inferred metadata later
94
- * without changing the call-site contract — e.g. future alignment with #845's
95
- * server-side op-params analysis. For now it carries only the set of record
96
- * fields the operation params prove are always supplied at create time.
97
- */
98
- export interface InferredRecordModelInfo {
99
- /** Record field names promoted to non-optional by op-params inference. */
100
- fields: Set<string>;
101
- }
102
- /**
103
- * Infer which record fields are always supplied at create time, by reading the
104
- * `save` operation params (issue #842).
105
- *
106
- * A field is promoted to required for a model only if:
107
- * - at least one `save` (create) op writes it from a bare `$params.X`
108
- * binding, AND
109
- * - EVERY `save` op that writes the field binds it to a param declared
110
- * `required: true` (the "ALL writers agree" rule).
111
- *
112
- * Deliberately conservative:
113
- * - `patch` (and every non-`save` inner op) is excluded — partial updates
114
- * don't guarantee creation-time presence.
115
- * - whole-object saves (`data = "$params.X"`, a string rather than a
116
- * per-field map) carry no field-level mapping, so no field can be promoted
117
- * from them (Q4 skip).
118
- * - only an EXACT top-level bare `$params.X` value counts (the whole binding
119
- * value must match `^\$params\.X$`, and `X` must be a declared top-level
120
- * param). A literal, computed, partially-interpolated value, or a nested
121
- * path (`$params.obj.sub`) never promotes a field — a nested sub-property
122
- * may be absent even when the top-level object param is required. This is
123
- * deliberately stricter than the CLI's lenient `collectParamRefs`
124
- * first-segment rule, which is fine for its validation use but would
125
- * wrongly promote nested bindings here.
126
- * - inner ops are matched to the record model by the inner op's own
127
- * `modelName` when present, falling back to the enclosing operation's
128
- * `modelName`.
129
- *
130
- * Pure: no I/O, no mutation of the input. The caller OR's the result with the
131
- * schema-level `required` flag, so inference only ever ADDS requiredness.
132
- */
133
- export declare function inferRequiredRecordFields(operations: any[]): Map<string, InferredRecordModelInfo>;
134
62
  /**
135
63
  * Run codegen end-to-end across one or more database-type TOML inputs. The
136
64
  * disk lifecycle (write / `--check` / stale cleanup) is delegated to the