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
@@ -0,0 +1,254 @@
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
+ // Computed presence flag for the write-only Google client secret (#1603).
85
+ // GET returns the boolean instead of the secret value; there is no server
86
+ // setter, so it never syncs — same classification as `hasGoogleAuth`.
87
+ "googleClientSecretSet",
88
+ "hasAppleAuth",
89
+ "hasPasskey",
90
+ "createdAt",
91
+ "modifiedAt",
92
+ ]);
93
+ /**
94
+ * Fields that ARE still writable server-side (present in the `PUT /settings`
95
+ * allow-list) but are deliberately excluded from TOML because a newer field
96
+ * supersedes them. Kept distinct from `IGNORED_GET_KEYS` so the coverage test's
97
+ * "every allow-listed field is covered" claim stays true — these are excluded,
98
+ * not read-only. (Codex design-review concern #1.)
99
+ */
100
+ export const DEPRECATED_WRITABLE_EXCLUDED = new Set([
101
+ "passkeyRpId",
102
+ "passkeyRpName",
103
+ ]);
104
+ /** Push error for a hand-added `googleClientSecret` — points at a real command. */
105
+ export const GOOGLE_CLIENT_SECRET_PUSH_ERROR = 'app.toml must not contain a "googleClientSecret" key under [auth]. ' +
106
+ "Secrets are excluded from synced config by design. Remove the key, then set " +
107
+ "the secret with:\n primitive apps update <appId> --google-client-secret <secret>";
108
+ const DESCRIPTOR_BY_SECTION = (() => {
109
+ const m = new Map();
110
+ for (const d of APP_SETTINGS_DESCRIPTOR) {
111
+ const list = m.get(d.section) ?? [];
112
+ list.push(d);
113
+ m.set(d.section, list);
114
+ }
115
+ return m;
116
+ })();
117
+ /** Descriptor `field` names, for parity/coverage tests. */
118
+ export const DESCRIPTOR_FIELDS = new Set(APP_SETTINGS_DESCRIPTOR.map((d) => d.field));
119
+ function typeOfValue(value) {
120
+ if (value === null || value === undefined)
121
+ return "null";
122
+ if (typeof value === "boolean")
123
+ return "boolean";
124
+ if (typeof value === "number")
125
+ return "number";
126
+ if (typeof value === "string")
127
+ return "string";
128
+ if (Array.isArray(value))
129
+ return "string[]";
130
+ if (typeof value === "object")
131
+ return "object";
132
+ return "unknown";
133
+ }
134
+ /** True if a value should be omitted under `emit: "whenSet"`. */
135
+ function isEmptyForEmit(value, type) {
136
+ if (value === null || value === undefined)
137
+ return true;
138
+ if (type === "string")
139
+ return value === "";
140
+ if (type === "string[]")
141
+ return !Array.isArray(value) || value.length === 0;
142
+ if (type === "object")
143
+ return (typeof value !== "object" ||
144
+ value === null ||
145
+ Object.keys(value).length === 0);
146
+ return false; // booleans (false) and numbers (0) are meaningful, never empty
147
+ }
148
+ /**
149
+ * Validate a push value against its descriptor type. Returns an error string
150
+ * (field-named) on mismatch, or `null` when the value is acceptable. Arrays are
151
+ * checked element-by-element so a `["a", 1]` mistype is caught.
152
+ */
153
+ function typeError(descriptor, value) {
154
+ const actual = typeOfValue(value);
155
+ if (actual === "null")
156
+ return null; // null clears; server owns clear semantics
157
+ if (descriptor.type === "string[]") {
158
+ if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
159
+ return `[${descriptor.section}].${descriptor.key} must be an array of strings (got ${actual})`;
160
+ }
161
+ return null;
162
+ }
163
+ if (descriptor.type === "object") {
164
+ if (actual !== "object") {
165
+ return `[${descriptor.section}].${descriptor.key} must be a table (got ${actual})`;
166
+ }
167
+ return null;
168
+ }
169
+ if (actual !== descriptor.type) {
170
+ return `[${descriptor.section}].${descriptor.key} must be a ${descriptor.type} (got ${actual})`;
171
+ }
172
+ return null;
173
+ }
174
+ /**
175
+ * Build one `app.toml` section object from server settings (pull direction).
176
+ * Secret fields are never written. Applies each field's `emit` rule; a `null`
177
+ * value is always omitted (TOML cannot encode null).
178
+ */
179
+ export function serializeSection(settings, section) {
180
+ const out = {};
181
+ for (const d of DESCRIPTOR_BY_SECTION.get(section) ?? []) {
182
+ if (d.secret)
183
+ continue;
184
+ const value = settings[d.field];
185
+ if (value === null || value === undefined)
186
+ continue;
187
+ if (d.emit === "whenSet" && isEmptyForEmit(value, d.type))
188
+ continue;
189
+ out[d.key] = value;
190
+ }
191
+ return out;
192
+ }
193
+ /**
194
+ * Build the full `app.toml` data object (all sections) from server settings.
195
+ * Empty sections are omitted, though in practice every section has at least one
196
+ * `emit: "always"` key so all four are present.
197
+ */
198
+ export function serializeAppSettingsToToml(settings) {
199
+ const data = {};
200
+ for (const section of APP_SETTINGS_SECTIONS) {
201
+ const obj = serializeSection(settings, section);
202
+ if (Object.keys(obj).length > 0)
203
+ data[section] = obj;
204
+ }
205
+ return data;
206
+ }
207
+ /**
208
+ * Translate a parsed `app.toml` object into a `PUT /settings` payload (push
209
+ * direction). Only keys present in the TOML are forwarded — an omitted key
210
+ * never overwrites server state. Unknown keys warn; type mismatches and any
211
+ * secret key are hard errors that the caller must treat as abort-before-PUT.
212
+ *
213
+ * `isCrossAppPush` strips `name` so a cross-app push never overwrites the
214
+ * target app's name.
215
+ */
216
+ export function parseTomlToAppSettings(tomlData, options = {}) {
217
+ const settings = {};
218
+ const warnings = [];
219
+ const errors = [];
220
+ for (const section of APP_SETTINGS_SECTIONS) {
221
+ const sectionData = tomlData?.[section];
222
+ if (sectionData === undefined || sectionData === null)
223
+ continue;
224
+ if (typeof sectionData !== "object" || Array.isArray(sectionData)) {
225
+ errors.push(`[${section}] must be a table`);
226
+ continue;
227
+ }
228
+ const descriptors = DESCRIPTOR_BY_SECTION.get(section) ?? [];
229
+ const byKey = new Map(descriptors.map((d) => [d.key, d]));
230
+ for (const key of Object.keys(sectionData)) {
231
+ const d = byKey.get(key);
232
+ if (!d) {
233
+ warnings.push(`Unrecognized [${section}] key "${key}" in app.toml — ignored. ` +
234
+ `Recognized keys: ${descriptors.map((x) => x.key).join(", ")}.`);
235
+ continue;
236
+ }
237
+ if (d.secret) {
238
+ errors.push(GOOGLE_CLIENT_SECRET_PUSH_ERROR);
239
+ continue;
240
+ }
241
+ if (options.isCrossAppPush && d.field === "name")
242
+ continue;
243
+ const value = sectionData[key];
244
+ const err = typeError(d, value);
245
+ if (err) {
246
+ errors.push(err);
247
+ continue;
248
+ }
249
+ settings[d.field] = value;
250
+ }
251
+ }
252
+ return { settings, warnings, errors };
253
+ }
254
+ //# 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,42 @@ 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;
70
+ /**
71
+ * Banners belonging to OTHER generators that must never be overwritten by
72
+ * this run (issue #1653, class 3b). When two generators share one `--output`
73
+ * dir and a name coincides (e.g. a workflow key equals a database type name),
74
+ * both resolve to the identical `<name>.generated.swift` path. Without this
75
+ * guard the second run silently clobbers the first (cleanup skips the foreign
76
+ * file because it carries the other banner, then the write loop overwrites
77
+ * it). Before writing OR checking, if a target path already holds a file whose
78
+ * content starts with one of these foreign banners, the run fails.
79
+ */
80
+ foreignOwnershipBanners?: string[];
81
+ /**
82
+ * Builds the error thrown when a `foreignOwnershipBanners` collision is
83
+ * detected. Lets the caller throw its own named error (e.g. the Swift path's
84
+ * `SwiftCodegenError`) without this shared module depending on it. When unset,
85
+ * a generic `Error` is thrown.
86
+ */
87
+ onForeignBannerCollision?: (info: {
88
+ filePath: string;
89
+ foreignBanner: string;
90
+ }) => Error;
55
91
  }
56
92
  /**
57
93
  * Write (or `--check`) a set of rendered generated files, handling orphan
@@ -23,11 +23,15 @@ const DEFAULT_GENERATED_SUFFIX = ".generated.ts";
23
23
  export async function writeOrCheckGeneratedFiles(options) {
24
24
  const outAbs = path.resolve(options.outputDir);
25
25
  const suffix = options.generatedSuffix ?? DEFAULT_GENERATED_SUFFIX;
26
+ // Cross-generator collision guard (issue #1653, class 3b). Runs BEFORE the
27
+ // check/write branch so `--check` reports the named collision too, rather than
28
+ // a generic `differs`.
29
+ await assertNoForeignBannerCollision(options.filesToWrite, options.foreignOwnershipBanners, options.onForeignBannerCollision);
26
30
  if (options.check === true) {
27
- return await runCheck(outAbs, options.filesToWrite, options.fullOwnership, suffix);
31
+ return await runCheck(outAbs, options.filesToWrite, options.fullOwnership, suffix, options.ownershipBanner);
28
32
  }
29
33
  await fsp.mkdir(outAbs, { recursive: true });
30
- const deletedFiles = await cleanupGeneratedOutputs(outAbs, options.filesToWrite, options.fullOwnership, suffix);
34
+ const deletedFiles = await cleanupGeneratedOutputs(outAbs, options.filesToWrite, options.fullOwnership, suffix, options.ownershipBanner);
31
35
  const writtenFiles = [];
32
36
  for (const [filePath, content] of options.filesToWrite) {
33
37
  await fsp.writeFile(filePath, content, "utf-8");
@@ -37,7 +41,43 @@ export async function writeOrCheckGeneratedFiles(options) {
37
41
  deletedFiles.sort();
38
42
  return { writtenFiles, deletedFiles, mismatches: [] };
39
43
  }
40
- async function runCheck(outAbs, filesToWrite, fullOwnership, suffix) {
44
+ /**
45
+ * Fail if any target path already holds a file owned by a DIFFERENT generator
46
+ * (its content starts with a foreign ownership banner). A genuinely absent file
47
+ * (ENOENT) is not a collision and is skipped; any other read error is
48
+ * propagated (abort) so the write path never truncates a file whose banner
49
+ * could not be verified. Runs in both the write and `--check` paths.
50
+ */
51
+ async function assertNoForeignBannerCollision(filesToWrite, foreignBanners, onCollision) {
52
+ if (!foreignBanners || foreignBanners.length === 0)
53
+ return;
54
+ for (const filePath of filesToWrite.keys()) {
55
+ let contents;
56
+ try {
57
+ contents = await fsp.readFile(filePath, "utf-8");
58
+ }
59
+ catch (err) {
60
+ if (err && err.code === "ENOENT") {
61
+ continue; // genuinely absent → not a collision
62
+ }
63
+ // Any other read error (e.g. EACCES on an owner-write-only file) means
64
+ // the banner could NOT be verified. Treating it as absent is fail-open:
65
+ // the write path would then truncate a foreign file whose banner was
66
+ // never checked. Rethrow so the run aborts, matching the sibling
67
+ // `runCheck`.
68
+ throw err;
69
+ }
70
+ const foreignBanner = foreignBanners.find((b) => contents.startsWith(b));
71
+ if (foreignBanner !== undefined) {
72
+ throw onCollision
73
+ ? onCollision({ filePath, foreignBanner })
74
+ : new Error(`codegen: output collision — "${filePath}" is already owned by a ` +
75
+ `different generator (banner "${foreignBanner.trim()}"). Give ` +
76
+ `one generator a separate --output directory.`);
77
+ }
78
+ }
79
+ }
80
+ async function runCheck(outAbs, filesToWrite, fullOwnership, suffix, ownershipBanner) {
41
81
  const mismatches = [];
42
82
  for (const [filePath, expected] of filesToWrite) {
43
83
  let actual;
@@ -64,7 +104,7 @@ async function runCheck(outAbs, filesToWrite, fullOwnership, suffix) {
64
104
  // owns a subset: `filesToWrite` is then partial, so sibling files aren't
65
105
  // "stale" — they just weren't in scope.
66
106
  if (fullOwnership && (await dirExists(outAbs))) {
67
- const onDisk = await listOwnedGeneratedFiles(outAbs, suffix);
107
+ const onDisk = await listOwnedGeneratedFiles(outAbs, suffix, ownershipBanner);
68
108
  const expectedPaths = new Set(filesToWrite.keys());
69
109
  for (const filePath of onDisk) {
70
110
  if (!expectedPaths.has(filePath)) {
@@ -78,13 +118,13 @@ async function runCheck(outAbs, filesToWrite, fullOwnership, suffix) {
78
118
  mismatches,
79
119
  };
80
120
  }
81
- async function cleanupGeneratedOutputs(outDir, filesToWrite, fullOwnership, suffix) {
121
+ async function cleanupGeneratedOutputs(outDir, filesToWrite, fullOwnership, suffix, ownershipBanner) {
82
122
  // A filtered run only owns a subset; `filesToWrite` does not represent the
83
123
  // full set of generated files, so skip orphan cleanup to avoid destroying
84
124
  // sibling files. Full cleanup only happens on the unfiltered run.
85
125
  if (!fullOwnership)
86
126
  return [];
87
- const onDisk = await listOwnedGeneratedFiles(outDir, suffix);
127
+ const onDisk = await listOwnedGeneratedFiles(outDir, suffix, ownershipBanner);
88
128
  const expectedPaths = new Set(filesToWrite.keys());
89
129
  const deleted = [];
90
130
  for (const filePath of onDisk) {
@@ -97,9 +137,11 @@ async function cleanupGeneratedOutputs(outDir, filesToWrite, fullOwnership, suff
97
137
  }
98
138
  /**
99
139
  * List only the generator-owned files in `outDir`, decided by the `suffix`
100
- * (`.generated.ts`). Hand-written files are never touched.
140
+ * (`.generated.ts`) and, when given, an `ownershipBanner` prefix on the file's
141
+ * content. Hand-written files — and files owned by a DIFFERENT generator that
142
+ * happen to share the suffix — are never touched.
101
143
  */
102
- async function listOwnedGeneratedFiles(outDir, suffix) {
144
+ async function listOwnedGeneratedFiles(outDir, suffix, ownershipBanner) {
103
145
  if (!(await dirExists(outDir)))
104
146
  return [];
105
147
  const entries = await fsp.readdir(outDir, { withFileTypes: true });
@@ -107,9 +149,24 @@ async function listOwnedGeneratedFiles(outDir, suffix) {
107
149
  for (const entry of entries) {
108
150
  if (!entry.isFile())
109
151
  continue;
110
- if (entry.name.endsWith(suffix)) {
111
- owned.push(path.join(outDir, entry.name));
152
+ if (!entry.name.endsWith(suffix))
153
+ continue;
154
+ const filePath = path.join(outDir, entry.name);
155
+ if (ownershipBanner) {
156
+ // Content-scoped ownership: only sweep files carrying THIS generator's
157
+ // banner, so a shared output dir keeps each generator's cleanup to its
158
+ // own files. A read failure means "not confidently ours" → skip it.
159
+ let contents;
160
+ try {
161
+ contents = await fsp.readFile(filePath, "utf-8");
162
+ }
163
+ catch {
164
+ continue;
165
+ }
166
+ if (!contents.startsWith(ownershipBanner))
167
+ continue;
112
168
  }
169
+ owned.push(filePath);
113
170
  }
114
171
  return owned;
115
172
  }
@@ -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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"}