primitive-admin 1.0.54 → 1.0.55
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.
- package/dist/bin/primitive.js +2 -0
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/apps.js +54 -2
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/databases.js +31 -10
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +77 -0
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/settings.d.ts +15 -0
- package/dist/src/commands/settings.js +102 -0
- package/dist/src/commands/settings.js.map +1 -0
- package/dist/src/commands/sync-app-settings.d.ts +105 -0
- package/dist/src/commands/sync-app-settings.js +339 -0
- package/dist/src/commands/sync-app-settings.js.map +1 -0
- package/dist/src/commands/sync.d.ts +34 -19
- package/dist/src/commands/sync.js +373 -200
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/workflows.js +32 -10
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +2 -0
- package/dist/src/lib/api-client.js +6 -0
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +108 -0
- package/dist/src/lib/app-settings-descriptor.js +250 -0
- package/dist/src/lib/app-settings-descriptor.js.map +1 -0
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +15 -0
- package/dist/src/lib/codegen-shared/generatedFiles.js +27 -10
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
- package/dist/src/lib/db-codegen/dbGenerator.d.ts +11 -83
- package/dist/src/lib/db-codegen/dbGenerator.js +93 -556
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/db-codegen/dbNaming.d.ts +15 -7
- package/dist/src/lib/db-codegen/dbNaming.js +25 -13
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +55 -4
- package/dist/src/lib/db-codegen/dbTemplates.js +169 -40
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +101 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +200 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +68 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js +380 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
- package/dist/src/lib/swift-codegen/generator.d.ts +84 -0
- package/dist/src/lib/swift-codegen/generator.js +178 -0
- package/dist/src/lib/swift-codegen/generator.js.map +1 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
- package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
- package/dist/src/lib/sync-resource-types.d.ts +225 -0
- package/dist/src/lib/sync-resource-types.js +394 -0
- package/dist/src/lib/sync-resource-types.js.map +1 -0
- package/dist/src/lib/workflow-codegen/generator.d.ts +18 -5
- package/dist/src/lib/workflow-codegen/generator.js +116 -41
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +85 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js +71 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
- 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`)
|
|
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
|
-
|
|
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":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,GAAG,EAAE,MAAM,IAAI,CAAC;
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|