@rebasepro/server 0.12.0 → 0.12.1-canary.gdfba2a1
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/GCSStorageController-BEmDYFKc.js +216 -0
- package/dist/GCSStorageController-BEmDYFKc.js.map +1 -0
- package/dist/S3StorageController-CK7r5yZb.js +243 -0
- package/dist/S3StorageController-CK7r5yZb.js.map +1 -0
- package/dist/admin_block-BGQFSAuV.js +123 -0
- package/dist/admin_block-BGQFSAuV.js.map +1 -0
- package/dist/auth-Bb7XFCKN.js +8898 -0
- package/dist/auth-Bb7XFCKN.js.map +1 -0
- package/dist/backend-CIxN4FVm.js +15 -0
- package/dist/backend-CIxN4FVm.js.map +1 -0
- package/dist/backup-C3Bah7XZ.js +163 -0
- package/dist/backup-C3Bah7XZ.js.map +1 -0
- package/dist/boot/boot.d.ts +20 -0
- package/dist/boot/fetch-bundle.d.ts +43 -0
- package/dist/contract-routes-Dj8i5AiM.js +264 -0
- package/dist/contract-routes-Dj8i5AiM.js.map +1 -0
- package/dist/cron/cron-scheduler.d.ts +34 -0
- package/dist/cron-loader-B1S2MCSl.js +63 -0
- package/dist/cron-loader-B1S2MCSl.js.map +1 -0
- package/dist/cron-routes-Do325hDt.js +62 -0
- package/dist/cron-routes-Do325hDt.js.map +1 -0
- package/dist/cron-scheduler-B3RFt0HS.js +647 -0
- package/dist/cron-scheduler-B3RFt0HS.js.map +1 -0
- package/dist/cron-store-BywZsyfZ.js +164 -0
- package/dist/cron-store-BywZsyfZ.js.map +1 -0
- package/dist/dynamic-import-Dvh-K5fl.js.map +1 -1
- package/dist/errors-BYAQztMf.js +222 -0
- package/dist/errors-BYAQztMf.js.map +1 -0
- package/dist/function-loader-B_1fYfUY.js +86 -0
- package/dist/function-loader-B_1fYfUY.js.map +1 -0
- package/dist/function-routes-C0cLIy3N.js +28 -0
- package/dist/function-routes-C0cLIy3N.js.map +1 -0
- package/dist/index.es.js +7480 -17861
- package/dist/index.es.js.map +1 -1
- package/dist/{jwt-D-eI6TTu.js → jwt-DD6EtpGj.js} +32 -13
- package/dist/{jwt-D-eI6TTu.js.map → jwt-DD6EtpGj.js.map} +1 -1
- package/dist/logger-BYU66ENZ.js.map +1 -1
- package/dist/logs-routes-BYA72C_C.js +100 -0
- package/dist/logs-routes-BYA72C_C.js.map +1 -0
- package/dist/{openapi-generator-Bjzmb5cn.js → openapi-generator-DFDS7kVk.js} +9 -3
- package/dist/openapi-generator-DFDS7kVk.js.map +1 -0
- package/dist/{schema-editor-routes-DDxfOIid.js → schema-editor-routes-CZVW2iBr.js} +4 -3
- package/dist/{schema-editor-routes-DDxfOIid.js.map → schema-editor-routes-CZVW2iBr.js.map} +1 -1
- package/dist/{src-CoOAMnBh.js → src-DymRyxdb.js} +196 -65
- package/dist/src-DymRyxdb.js.map +1 -0
- package/dist/src-_qQ3RNCK.js +279 -0
- package/dist/src-_qQ3RNCK.js.map +1 -0
- package/dist/types-DSnOC4mF.js +38 -0
- package/dist/types-DSnOC4mF.js.map +1 -0
- package/package.json +10 -10
- package/dist/openapi-generator-Bjzmb5cn.js.map +0 -1
- package/dist/src-CoOAMnBh.js.map +0 -1
- package/dist/src-Ivjud8jD.js +0 -957
- package/dist/src-Ivjud8jD.js.map +0 -1
- /package/dist/{chunk-DSJWtz9O.js → rolldown-runtime-DSJWtz9O.js} +0 -0
package/dist/src-Ivjud8jD.js
DELETED
|
@@ -1,957 +0,0 @@
|
|
|
1
|
-
import { createRequire as __createRequire } from "module";
|
|
2
|
-
import "process";
|
|
3
|
-
__createRequire(import.meta.url);
|
|
4
|
-
//#region ../types/src/errors.ts
|
|
5
|
-
/**
|
|
6
|
-
* The single error type thrown across the entire Rebase client surface —
|
|
7
|
-
* HTTP data/control-plane calls, realtime/WebSocket operations, and
|
|
8
|
-
* client-side logic errors (e.g. an unknown collection accessor). A `catch`
|
|
9
|
-
* block only ever needs to check for this one class:
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { RebaseApiError } from "@rebasepro/client"; // re-exported
|
|
13
|
-
*
|
|
14
|
-
* try {
|
|
15
|
-
* await client.data.products.update(id, { price: 9 });
|
|
16
|
-
* } catch (e) {
|
|
17
|
-
* if (e instanceof RebaseApiError) {
|
|
18
|
-
* if (e.status === 404) { ... } // HTTP failures carry a status
|
|
19
|
-
* console.error(e.code, e.details);
|
|
20
|
-
* }
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* `status` is present for HTTP failures and `undefined` otherwise, so its
|
|
25
|
-
* presence distinguishes transport-level errors from realtime/logic errors.
|
|
26
|
-
*
|
|
27
|
-
* @group Errors
|
|
28
|
-
*/
|
|
29
|
-
var RebaseApiError = class extends Error {
|
|
30
|
-
/** HTTP status code, or `undefined` for non-HTTP errors. */
|
|
31
|
-
status;
|
|
32
|
-
/** Stable machine-readable error code, when the server supplied one. */
|
|
33
|
-
code;
|
|
34
|
-
/** Structured error payload from the server, when present. */
|
|
35
|
-
details;
|
|
36
|
-
constructor(message, init = {}) {
|
|
37
|
-
super(message);
|
|
38
|
-
this.name = "RebaseApiError";
|
|
39
|
-
this.status = init.status;
|
|
40
|
-
this.code = init.code;
|
|
41
|
-
this.details = init.details;
|
|
42
|
-
if (init.cause !== void 0) this.cause = init.cause;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Client-side logic error — raised before any request is made (e.g. accessing
|
|
47
|
-
* an unknown collection accessor when a typed dictionary is configured).
|
|
48
|
-
*
|
|
49
|
-
* A subclass of {@link RebaseApiError} (with no `status`), so a single
|
|
50
|
-
* `catch (e) { if (e instanceof RebaseApiError) ... }` handles it too.
|
|
51
|
-
*
|
|
52
|
-
* @group Errors
|
|
53
|
-
*/
|
|
54
|
-
var RebaseClientError = class extends RebaseApiError {
|
|
55
|
-
constructor(message) {
|
|
56
|
-
super(message);
|
|
57
|
-
this.name = "RebaseClientError";
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
//#endregion
|
|
61
|
-
//#region ../types/src/types/entities.ts
|
|
62
|
-
/**
|
|
63
|
-
* Class used to create a reference to a entity in a different path.
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* // Simple reference (most common case - single driver, single db)
|
|
67
|
-
* new EntityReference({ id: "123", path: "users" })
|
|
68
|
-
*
|
|
69
|
-
* // Reference to a different driver (e.g., Firestore)
|
|
70
|
-
* new EntityReference({ id: "123", path: "analytics", driver: "firestore" })
|
|
71
|
-
*
|
|
72
|
-
* // Reference to a specific database within a driver
|
|
73
|
-
* new EntityReference({ id: "123", path: "orders", driver: "postgres", databaseId: "orders_db" })
|
|
74
|
-
*/
|
|
75
|
-
var EntityReference = class {
|
|
76
|
-
__type = "reference";
|
|
77
|
-
/**
|
|
78
|
-
* ID of the entity
|
|
79
|
-
*/
|
|
80
|
-
id;
|
|
81
|
-
/**
|
|
82
|
-
* A string representing the path of the referenced document (relative
|
|
83
|
-
* to the root of the database).
|
|
84
|
-
*/
|
|
85
|
-
path;
|
|
86
|
-
/**
|
|
87
|
-
* Which driver (e.g., 'postgres', 'firestore').
|
|
88
|
-
* Defaults to "(default)" if not specified.
|
|
89
|
-
*/
|
|
90
|
-
driver;
|
|
91
|
-
/**
|
|
92
|
-
* Which database within the driver.
|
|
93
|
-
* Defaults to "(default)" if not specified.
|
|
94
|
-
*/
|
|
95
|
-
databaseId;
|
|
96
|
-
/**
|
|
97
|
-
* Create a reference to a entity.
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* // Simple reference (most common case)
|
|
101
|
-
* new EntityReference({ id: "123", path: "users" })
|
|
102
|
-
*
|
|
103
|
-
* // With driver
|
|
104
|
-
* new EntityReference({ id: "123", path: "analytics", driver: "firestore" })
|
|
105
|
-
*/
|
|
106
|
-
constructor(props) {
|
|
107
|
-
this.id = props.id;
|
|
108
|
-
this.path = props.path;
|
|
109
|
-
this.driver = props.driver;
|
|
110
|
-
this.databaseId = props.databaseId;
|
|
111
|
-
}
|
|
112
|
-
get pathWithId() {
|
|
113
|
-
return `${this.path}/${this.id}`;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Get the full path including driver and database prefixes if specified.
|
|
117
|
-
* For the common case (single driver, single db), this just returns pathWithId.
|
|
118
|
-
*/
|
|
119
|
-
get fullPath() {
|
|
120
|
-
const parts = [];
|
|
121
|
-
if (this.driver && this.driver !== "(default)") parts.push(this.driver);
|
|
122
|
-
if (this.databaseId && this.databaseId !== "(default)") parts.push(this.databaseId);
|
|
123
|
-
if (parts.length > 0) return `${parts.join(":")}:::${this.path}/${this.id}`;
|
|
124
|
-
return this.pathWithId;
|
|
125
|
-
}
|
|
126
|
-
isEntityReference() {
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* Class used to create a reference to a entity in a different path
|
|
132
|
-
*/
|
|
133
|
-
var EntityRelation = class {
|
|
134
|
-
__type = "relation";
|
|
135
|
-
/**
|
|
136
|
-
* ID of the entity
|
|
137
|
-
*/
|
|
138
|
-
id;
|
|
139
|
-
/**
|
|
140
|
-
* A string representing the path of the referenced document (relative
|
|
141
|
-
* to the root of the database).
|
|
142
|
-
*/
|
|
143
|
-
path;
|
|
144
|
-
/**
|
|
145
|
-
* Pre-fetched data payload to eliminate N+1 queries.
|
|
146
|
-
* When present, clients can use this directly instead of fetching.
|
|
147
|
-
*/
|
|
148
|
-
data;
|
|
149
|
-
constructor(id, path, data) {
|
|
150
|
-
this.id = id;
|
|
151
|
-
this.path = path;
|
|
152
|
-
this.data = data;
|
|
153
|
-
}
|
|
154
|
-
get pathWithId() {
|
|
155
|
-
return `${this.path}/${this.id}`;
|
|
156
|
-
}
|
|
157
|
-
isEntityReference() {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
isEntityRelation() {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
var GeoPoint = class {
|
|
165
|
-
/**
|
|
166
|
-
* The latitude of this GeoPoint instance.
|
|
167
|
-
*/
|
|
168
|
-
latitude;
|
|
169
|
-
/**
|
|
170
|
-
* The longitude of this GeoPoint instance.
|
|
171
|
-
*/
|
|
172
|
-
longitude;
|
|
173
|
-
constructor(latitude, longitude) {
|
|
174
|
-
this.latitude = latitude;
|
|
175
|
-
this.longitude = longitude;
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
var Vector = class {
|
|
179
|
-
value;
|
|
180
|
-
constructor(value) {
|
|
181
|
-
this.value = value;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
//#endregion
|
|
185
|
-
//#region ../types/src/types/filter-operators.ts
|
|
186
|
-
/** Maps canonical operators to their REST short-code equivalents. */
|
|
187
|
-
var CANONICAL_TO_REST = {
|
|
188
|
-
"==": "eq",
|
|
189
|
-
"!=": "neq",
|
|
190
|
-
">": "gt",
|
|
191
|
-
">=": "gte",
|
|
192
|
-
"<": "lt",
|
|
193
|
-
"<=": "lte",
|
|
194
|
-
"in": "in",
|
|
195
|
-
"not-in": "nin",
|
|
196
|
-
"array-contains": "cs",
|
|
197
|
-
"array-contains-any": "csa",
|
|
198
|
-
"like": "like",
|
|
199
|
-
"ilike": "ilike",
|
|
200
|
-
"not-like": "nlike",
|
|
201
|
-
"not-ilike": "nilike",
|
|
202
|
-
"is-null": "isnull",
|
|
203
|
-
"is-not-null": "notnull"
|
|
204
|
-
};
|
|
205
|
-
/** Maps REST short-code operators to their canonical equivalents. */
|
|
206
|
-
var REST_TO_CANONICAL = {
|
|
207
|
-
"eq": "==",
|
|
208
|
-
"neq": "!=",
|
|
209
|
-
"gt": ">",
|
|
210
|
-
"gte": ">=",
|
|
211
|
-
"lt": "<",
|
|
212
|
-
"lte": "<=",
|
|
213
|
-
"in": "in",
|
|
214
|
-
"nin": "not-in",
|
|
215
|
-
"cs": "array-contains",
|
|
216
|
-
"csa": "array-contains-any",
|
|
217
|
-
"like": "like",
|
|
218
|
-
"ilike": "ilike",
|
|
219
|
-
"nlike": "not-like",
|
|
220
|
-
"nilike": "not-ilike",
|
|
221
|
-
"isnull": "is-null",
|
|
222
|
-
"notnull": "is-not-null"
|
|
223
|
-
};
|
|
224
|
-
/**
|
|
225
|
-
* Operators that test for null/not-null and therefore ignore their value.
|
|
226
|
-
* Codecs normalize the value of these conditions to `null`.
|
|
227
|
-
*/
|
|
228
|
-
var NULL_OPS = new Set(["is-null", "is-not-null"]);
|
|
229
|
-
/**
|
|
230
|
-
* Every canonical operator, in a stable order. Useful for engine capability
|
|
231
|
-
* declarations ({@link DataSourceCapabilities.filterOperators}) and for
|
|
232
|
-
* building operator subsets.
|
|
233
|
-
* @group Models
|
|
234
|
-
*/
|
|
235
|
-
var ALL_WHERE_FILTER_OPS = [
|
|
236
|
-
"<",
|
|
237
|
-
"<=",
|
|
238
|
-
"==",
|
|
239
|
-
"!=",
|
|
240
|
-
">=",
|
|
241
|
-
">",
|
|
242
|
-
"in",
|
|
243
|
-
"not-in",
|
|
244
|
-
"array-contains",
|
|
245
|
-
"array-contains-any",
|
|
246
|
-
"like",
|
|
247
|
-
"ilike",
|
|
248
|
-
"not-like",
|
|
249
|
-
"not-ilike",
|
|
250
|
-
"is-null",
|
|
251
|
-
"is-not-null"
|
|
252
|
-
];
|
|
253
|
-
/** All canonical operator strings for runtime validation. */
|
|
254
|
-
var CANONICAL_OPS = new Set(ALL_WHERE_FILTER_OPS);
|
|
255
|
-
/**
|
|
256
|
-
* Resolve any operator string (canonical or REST short-code) to its
|
|
257
|
-
* canonical `WhereFilterOp` form. Returns `undefined` for unknown operators.
|
|
258
|
-
*
|
|
259
|
-
* @example
|
|
260
|
-
* toCanonicalOp("==") // "=="
|
|
261
|
-
* toCanonicalOp("eq") // "=="
|
|
262
|
-
* toCanonicalOp("cs") // "array-contains"
|
|
263
|
-
* toCanonicalOp("xyz") // undefined
|
|
264
|
-
*/
|
|
265
|
-
function toCanonicalOp(op) {
|
|
266
|
-
if (CANONICAL_OPS.has(op)) return op;
|
|
267
|
-
return REST_TO_CANONICAL[op];
|
|
268
|
-
}
|
|
269
|
-
//#endregion
|
|
270
|
-
//#region ../types/src/types/admin_block.ts
|
|
271
|
-
/**
|
|
272
|
-
* The keys of a collection's admin block, as data.
|
|
273
|
-
*
|
|
274
|
-
* There is no *type* for the block in this package any more, and that is the point:
|
|
275
|
-
* `admin` is not declared on `BaseCollectionConfig` or on any property here, so a
|
|
276
|
-
* BaaS install cannot even write one. `@rebasepro/admin-types` adds the field back by
|
|
277
|
-
* declaration merging, which is why installing it is what makes the admin surface
|
|
278
|
-
* appear.
|
|
279
|
-
*
|
|
280
|
-
* The *list* still has to live here, because three runtime consumers need it and two
|
|
281
|
-
* of them are core — see below.
|
|
282
|
-
*/
|
|
283
|
-
/**
|
|
284
|
-
* Every key that belongs inside a collection's `admin` block, as data.
|
|
285
|
-
*
|
|
286
|
-
* The type that describes these fields is `AdminCollectionOptions` in
|
|
287
|
-
* `@rebasepro/admin-types`, and it is erased at build time — but three runtime
|
|
288
|
-
* consumers need the list, and two of them are core:
|
|
289
|
-
*
|
|
290
|
-
* - `serializeCollections`, to drop the block from the contract
|
|
291
|
-
* - the ts-morph schema editor in `@rebasepro/server`, which rewrites collection
|
|
292
|
-
* files on disk from the admin panel and has to know where each key goes. A key
|
|
293
|
-
* missing from this list gets written to the *top level* of the file, where the
|
|
294
|
-
* backend ignores it and the panel never finds it again.
|
|
295
|
-
* - the `collections-admin-block` codemod
|
|
296
|
-
*
|
|
297
|
-
* `@rebasepro/admin-types` re-exports this and asserts it names only real option
|
|
298
|
-
* keys; the count is pinned by a test there.
|
|
299
|
-
*
|
|
300
|
-
* @group Models
|
|
301
|
-
*/
|
|
302
|
-
var ADMIN_COLLECTION_KEYS = [
|
|
303
|
-
"Actions",
|
|
304
|
-
"additionalFields",
|
|
305
|
-
"alwaysApplyDefaultValues",
|
|
306
|
-
"components",
|
|
307
|
-
"defaultEntityAction",
|
|
308
|
-
"defaultFilter",
|
|
309
|
-
"defaultSelectedView",
|
|
310
|
-
"defaultSize",
|
|
311
|
-
"defaultViewMode",
|
|
312
|
-
"disableDefaultActions",
|
|
313
|
-
"enabledViews",
|
|
314
|
-
"entityActions",
|
|
315
|
-
"entityViews",
|
|
316
|
-
"exportable",
|
|
317
|
-
"filterPresets",
|
|
318
|
-
"fixedFilter",
|
|
319
|
-
"formAutoSave",
|
|
320
|
-
"formView",
|
|
321
|
-
"group",
|
|
322
|
-
"hideFromNavigation",
|
|
323
|
-
"hideIdFromCollection",
|
|
324
|
-
"hideIdFromForm",
|
|
325
|
-
"icon",
|
|
326
|
-
"includeJsonView",
|
|
327
|
-
"inlineEditing",
|
|
328
|
-
"kanban",
|
|
329
|
-
"listProperties",
|
|
330
|
-
"localChangesBackup",
|
|
331
|
-
"openEntityMode",
|
|
332
|
-
"orderProperty",
|
|
333
|
-
"pagination",
|
|
334
|
-
"previewProperties",
|
|
335
|
-
"propertiesOrder",
|
|
336
|
-
"selectionController",
|
|
337
|
-
"selectionEnabled",
|
|
338
|
-
"sideDialogWidth",
|
|
339
|
-
"sort",
|
|
340
|
-
"titleProperty"
|
|
341
|
-
];
|
|
342
|
-
/**
|
|
343
|
-
* Every key that belongs inside a *property's* `admin` block, as data.
|
|
344
|
-
*
|
|
345
|
-
* The union of `AdminPropertyOptions` and its per-type extensions
|
|
346
|
-
* (`AdminStringOptions`, `AdminArrayOptions`, …) in `@rebasepro/admin-types`.
|
|
347
|
-
* It lives here for the same reason {@link ADMIN_COLLECTION_KEYS} does: the
|
|
348
|
-
* runtime consumers are core packages that the BaaS guard forbids from
|
|
349
|
-
* importing `@rebasepro/admin-types`. Here it is the boot-time collection
|
|
350
|
-
* validator in `@rebasepro/server`, which has to tell "you left `readOnly` at
|
|
351
|
-
* the top of the property, where nothing reads it" apart from "you invented a
|
|
352
|
-
* key we have never heard of".
|
|
353
|
-
*
|
|
354
|
-
* `@rebasepro/admin-types` re-exports this and asserts it names only real
|
|
355
|
-
* option keys.
|
|
356
|
-
*
|
|
357
|
-
* @group Models
|
|
358
|
-
*/
|
|
359
|
-
var ADMIN_PROPERTY_KEYS = [
|
|
360
|
-
"canAddElements",
|
|
361
|
-
"clearable",
|
|
362
|
-
"columnWidth",
|
|
363
|
-
"customProps",
|
|
364
|
-
"disabled",
|
|
365
|
-
"expanded",
|
|
366
|
-
"Field",
|
|
367
|
-
"Filter",
|
|
368
|
-
"filterOperators",
|
|
369
|
-
"fixedFilter",
|
|
370
|
-
"hideFromCollection",
|
|
371
|
-
"includeEntityLink",
|
|
372
|
-
"includeId",
|
|
373
|
-
"markdown",
|
|
374
|
-
"minimalistView",
|
|
375
|
-
"multiline",
|
|
376
|
-
"Preview",
|
|
377
|
-
"previewAsTag",
|
|
378
|
-
"previewProperties",
|
|
379
|
-
"readOnly",
|
|
380
|
-
"sortable",
|
|
381
|
-
"spreadChildren",
|
|
382
|
-
"urlPreview",
|
|
383
|
-
"widget",
|
|
384
|
-
"widthPercentage"
|
|
385
|
-
];
|
|
386
|
-
//#endregion
|
|
387
|
-
//#region ../types/src/types/data_source.ts
|
|
388
|
-
/**
|
|
389
|
-
* The default data-source key, used when a collection does not name a
|
|
390
|
-
* `dataSource`. Shared by the frontend router and the backend driver
|
|
391
|
-
* registry so both agree on "the default database".
|
|
392
|
-
* @group Models
|
|
393
|
-
*/
|
|
394
|
-
var DEFAULT_DATA_SOURCE_KEY = "(default)";
|
|
395
|
-
/**
|
|
396
|
-
* Relation kinds assumed filterable when a driver does not say.
|
|
397
|
-
*
|
|
398
|
-
* `belongsTo` alone: its filter is a comparison on a column of the row being
|
|
399
|
-
* filtered, the one shape that needs no query construction a driver might not
|
|
400
|
-
* have. Everything else is a correlated subquery over another table.
|
|
401
|
-
*
|
|
402
|
-
* @group Models
|
|
403
|
-
*/
|
|
404
|
-
var DEFAULT_FILTERABLE_RELATION_KINDS = ["belongsTo"];
|
|
405
|
-
/** @group Models */
|
|
406
|
-
var POSTGRES_CAPABILITIES = {
|
|
407
|
-
key: "postgres",
|
|
408
|
-
label: "PostgreSQL",
|
|
409
|
-
supportsRelations: true,
|
|
410
|
-
supportsSubcollections: false,
|
|
411
|
-
supportsRLS: true,
|
|
412
|
-
supportsReferences: false,
|
|
413
|
-
supportsColumnTypes: true,
|
|
414
|
-
supportsRealtime: true,
|
|
415
|
-
supportsVectors: true,
|
|
416
|
-
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
417
|
-
filterableRelationKinds: [
|
|
418
|
-
"belongsTo",
|
|
419
|
-
"manyToMany",
|
|
420
|
-
"hasMany",
|
|
421
|
-
"hasOne"
|
|
422
|
-
],
|
|
423
|
-
supportsSQLAdmin: true,
|
|
424
|
-
supportsDocumentAdmin: false,
|
|
425
|
-
supportsSchemaAdmin: true
|
|
426
|
-
};
|
|
427
|
-
/** @group Models */
|
|
428
|
-
var FIREBASE_CAPABILITIES = {
|
|
429
|
-
key: "firestore",
|
|
430
|
-
label: "Firebase / Firestore",
|
|
431
|
-
supportsRelations: false,
|
|
432
|
-
supportsSubcollections: true,
|
|
433
|
-
supportsRLS: false,
|
|
434
|
-
supportsReferences: true,
|
|
435
|
-
supportsColumnTypes: false,
|
|
436
|
-
supportsRealtime: true,
|
|
437
|
-
supportsVectors: false,
|
|
438
|
-
filterOperators: ALL_WHERE_FILTER_OPS.filter((op) => op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
|
|
439
|
-
filterableRelationKinds: [],
|
|
440
|
-
supportsSQLAdmin: false,
|
|
441
|
-
supportsDocumentAdmin: false,
|
|
442
|
-
supportsSchemaAdmin: false
|
|
443
|
-
};
|
|
444
|
-
/** @group Models */
|
|
445
|
-
var MONGODB_CAPABILITIES = {
|
|
446
|
-
key: "mongodb",
|
|
447
|
-
label: "MongoDB",
|
|
448
|
-
supportsRelations: false,
|
|
449
|
-
supportsSubcollections: true,
|
|
450
|
-
supportsRLS: false,
|
|
451
|
-
supportsReferences: true,
|
|
452
|
-
supportsColumnTypes: false,
|
|
453
|
-
supportsRealtime: false,
|
|
454
|
-
supportsVectors: false,
|
|
455
|
-
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
456
|
-
filterableRelationKinds: [],
|
|
457
|
-
supportsSQLAdmin: false,
|
|
458
|
-
supportsDocumentAdmin: true,
|
|
459
|
-
supportsSchemaAdmin: true
|
|
460
|
-
};
|
|
461
|
-
/**
|
|
462
|
-
* Fallback capabilities when the driver is unknown.
|
|
463
|
-
* Enables everything so nothing is hidden unexpectedly.
|
|
464
|
-
* @group Models
|
|
465
|
-
*/
|
|
466
|
-
var DEFAULT_CAPABILITIES = {
|
|
467
|
-
key: "(default)",
|
|
468
|
-
label: "Default",
|
|
469
|
-
supportsRelations: true,
|
|
470
|
-
supportsSubcollections: true,
|
|
471
|
-
supportsRLS: true,
|
|
472
|
-
supportsReferences: true,
|
|
473
|
-
supportsColumnTypes: true,
|
|
474
|
-
supportsRealtime: true,
|
|
475
|
-
supportsVectors: true,
|
|
476
|
-
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
477
|
-
filterableRelationKinds: DEFAULT_FILTERABLE_RELATION_KINDS,
|
|
478
|
-
supportsSQLAdmin: true,
|
|
479
|
-
supportsDocumentAdmin: true,
|
|
480
|
-
supportsSchemaAdmin: true
|
|
481
|
-
};
|
|
482
|
-
var CAPABILITIES_REGISTRY = {
|
|
483
|
-
postgres: POSTGRES_CAPABILITIES,
|
|
484
|
-
firestore: FIREBASE_CAPABILITIES,
|
|
485
|
-
mongodb: MONGODB_CAPABILITIES,
|
|
486
|
-
"(default)": DEFAULT_CAPABILITIES
|
|
487
|
-
};
|
|
488
|
-
/**
|
|
489
|
-
* Look up capabilities for a given engine key.
|
|
490
|
-
* If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
|
|
491
|
-
* @group Models
|
|
492
|
-
*/
|
|
493
|
-
function getDataSourceCapabilities(engine) {
|
|
494
|
-
if (!engine) return POSTGRES_CAPABILITIES;
|
|
495
|
-
return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
|
|
496
|
-
}
|
|
497
|
-
//#endregion
|
|
498
|
-
//#region ../types/src/types/collections.ts
|
|
499
|
-
/**
|
|
500
|
-
* Type guard for PostgreSQL collections.
|
|
501
|
-
* Returns true if the collection uses the Postgres engine (or the default engine).
|
|
502
|
-
*
|
|
503
|
-
* Generic over the *input* type, and narrows by intersection rather than
|
|
504
|
-
* replacement. Narrowing to a bare `PostgresCollectionConfig` discarded whatever
|
|
505
|
-
* the caller actually had — most visibly the admin panel's view model, whose
|
|
506
|
-
* flattened presentation fields vanished the moment a collection passed through
|
|
507
|
-
* one of these guards.
|
|
508
|
-
*
|
|
509
|
-
* @group Models
|
|
510
|
-
*/
|
|
511
|
-
function isPostgresCollectionConfig(collection) {
|
|
512
|
-
return !collection.engine || collection.engine === "postgres";
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Narrows to the SQL collection fields — `table`, `relations`,
|
|
516
|
-
* `disableDefaultPolicies` — by asking the engine's declared capabilities
|
|
517
|
-
* rather than by naming Postgres.
|
|
518
|
-
*
|
|
519
|
-
* The two halves of this already existed and were never joined. The engine
|
|
520
|
-
* split (`PostgresCollectionConfig` / `FirebaseCollectionConfig` /
|
|
521
|
-
* `MongoDBCollectionConfig`) said which fields belong to which engine at the
|
|
522
|
-
* type level; {@link DataSourceCapabilities} said the same thing at runtime,
|
|
523
|
-
* down to a `supportsRelations` flag. So call sites guarded on the capability
|
|
524
|
-
* and then read a field the base type had to declare for them — which is why
|
|
525
|
-
* those fields were on the base, and why a MongoDB collection could be written
|
|
526
|
-
* with a `table`.
|
|
527
|
-
*
|
|
528
|
-
* Prefer this over {@link isPostgresCollectionConfig} wherever the question is
|
|
529
|
-
* "does this collection live in a SQL table", so a custom SQL engine
|
|
530
|
-
* registered through `registerDataSourceCapabilities` is included.
|
|
531
|
-
*
|
|
532
|
-
* @group Models
|
|
533
|
-
*/
|
|
534
|
-
function isRelationalCollectionConfig(collection) {
|
|
535
|
-
return getDataSourceCapabilities(collection.engine).supportsRelations;
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Type guard for Firebase / Firestore collections.
|
|
539
|
-
* @group Models
|
|
540
|
-
*/
|
|
541
|
-
function isFirebaseCollectionConfig(collection) {
|
|
542
|
-
return collection.engine === "firestore";
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Type guard for MongoDB collections.
|
|
546
|
-
* @group Models
|
|
547
|
-
*/
|
|
548
|
-
function isMongoDBCollectionConfig(collection) {
|
|
549
|
-
return collection.engine === "mongodb";
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* Returns the data path for a collection.
|
|
553
|
-
* For Firestore or MongoDB collections with a `path`, returns that value;
|
|
554
|
-
* otherwise falls back to `slug`.
|
|
555
|
-
*/
|
|
556
|
-
function getCollectionDataPath(collection) {
|
|
557
|
-
if (isFirebaseCollectionConfig(collection) && collection.path) return collection.path;
|
|
558
|
-
if (isMongoDBCollectionConfig(collection) && collection.path) return collection.path;
|
|
559
|
-
return collection.slug;
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
* Reads a collection's driver-declared subcollections thunk (the `subcollections`
|
|
563
|
-
* field) independent of engine identity, so engine-agnostic code doesn't have to
|
|
564
|
-
* type-guard against a specific driver. Returns `undefined` when the collection
|
|
565
|
-
* declares none.
|
|
566
|
-
*
|
|
567
|
-
* Pair with `getDataSourceCapabilities(engine).supportsSubcollections` to decide
|
|
568
|
-
* whether the engine honours subcollections at all before reading them.
|
|
569
|
-
* @group Models
|
|
570
|
-
*/
|
|
571
|
-
function getDeclaredSubcollections(collection) {
|
|
572
|
-
return collection.subcollections;
|
|
573
|
-
}
|
|
574
|
-
//#endregion
|
|
575
|
-
//#region ../types/src/types/relations.ts
|
|
576
|
-
/** @group Models */
|
|
577
|
-
function isToMany(relation) {
|
|
578
|
-
return relation.cardinality === "many";
|
|
579
|
-
}
|
|
580
|
-
//#endregion
|
|
581
|
-
//#region ../types/src/types/policy.ts
|
|
582
|
-
/** @group Models */
|
|
583
|
-
var policy = {
|
|
584
|
-
true: () => ({ kind: "true" }),
|
|
585
|
-
false: () => ({ kind: "false" }),
|
|
586
|
-
and: (...operands) => ({
|
|
587
|
-
kind: "and",
|
|
588
|
-
operands
|
|
589
|
-
}),
|
|
590
|
-
or: (...operands) => ({
|
|
591
|
-
kind: "or",
|
|
592
|
-
operands
|
|
593
|
-
}),
|
|
594
|
-
not: (operand) => ({
|
|
595
|
-
kind: "not",
|
|
596
|
-
operand
|
|
597
|
-
}),
|
|
598
|
-
compare: (left, op, right) => ({
|
|
599
|
-
kind: "compare",
|
|
600
|
-
op,
|
|
601
|
-
left,
|
|
602
|
-
right
|
|
603
|
-
}),
|
|
604
|
-
rolesOverlap: (roles) => ({
|
|
605
|
-
kind: "rolesOverlap",
|
|
606
|
-
roles
|
|
607
|
-
}),
|
|
608
|
-
rolesContain: (roles) => ({
|
|
609
|
-
kind: "rolesContain",
|
|
610
|
-
roles
|
|
611
|
-
}),
|
|
612
|
-
authenticated: () => ({ kind: "authenticated" }),
|
|
613
|
-
serverContext: () => ({ kind: "serverContext" }),
|
|
614
|
-
existsIn: (args) => ({
|
|
615
|
-
kind: "existsIn",
|
|
616
|
-
collection: args.collection,
|
|
617
|
-
where: args.where
|
|
618
|
-
}),
|
|
619
|
-
raw: (sql) => ({
|
|
620
|
-
kind: "raw",
|
|
621
|
-
sql
|
|
622
|
-
}),
|
|
623
|
-
field: (name) => ({
|
|
624
|
-
kind: "field",
|
|
625
|
-
name
|
|
626
|
-
}),
|
|
627
|
-
outerField: (name) => ({
|
|
628
|
-
kind: "outerField",
|
|
629
|
-
name
|
|
630
|
-
}),
|
|
631
|
-
literal: (value) => ({
|
|
632
|
-
kind: "literal",
|
|
633
|
-
value
|
|
634
|
-
}),
|
|
635
|
-
authUid: () => ({ kind: "authUid" }),
|
|
636
|
-
authRoles: () => ({ kind: "authRoles" })
|
|
637
|
-
};
|
|
638
|
-
//#endregion
|
|
639
|
-
//#region ../types/src/types/backend.ts
|
|
640
|
-
/**
|
|
641
|
-
* Type guard: does this admin support SQL operations?
|
|
642
|
-
* @group Admin
|
|
643
|
-
*/
|
|
644
|
-
function isSQLAdmin(admin) {
|
|
645
|
-
return !!admin && typeof admin.executeSql === "function";
|
|
646
|
-
}
|
|
647
|
-
//#endregion
|
|
648
|
-
//#region ../types/src/types/storage_source.ts
|
|
649
|
-
/**
|
|
650
|
-
* Describes a named storage backend — a place files live.
|
|
651
|
-
*
|
|
652
|
-
* Declared once and shared front + back: the frontend uses it to decide
|
|
653
|
-
* transport (HTTP proxy vs direct SDK), the backend uses the same `key`
|
|
654
|
-
* to resolve a StorageController, and collection properties reference
|
|
655
|
-
* a definition by its `key` via `StorageConfig.storageSource`.
|
|
656
|
-
*
|
|
657
|
-
* This mirrors the {@link DataSourceDefinition} pattern used for databases.
|
|
658
|
-
*
|
|
659
|
-
* @group Models
|
|
660
|
-
*/
|
|
661
|
-
/**
|
|
662
|
-
* The default storage source key, used when a property does not specify
|
|
663
|
-
* a `storageSource`. Shared by the frontend and backend registries so
|
|
664
|
-
* both agree on "the default storage backend".
|
|
665
|
-
* @group Models
|
|
666
|
-
*/
|
|
667
|
-
var DEFAULT_STORAGE_SOURCE_KEY = "(default)";
|
|
668
|
-
/**
|
|
669
|
-
* The environment-variable suffix for a storage or data source key.
|
|
670
|
-
*
|
|
671
|
-
* `""` for the default source — so a single-bucket project keeps configuring
|
|
672
|
-
* plain `S3_BUCKET` — and `__<KEY>` for every named one, uppercased with
|
|
673
|
-
* non-alphanumerics collapsed to underscores: `media-cdn` → `S3_BUCKET__MEDIA_CDN`.
|
|
674
|
-
*
|
|
675
|
-
* The rule derives the variable name from the declared key rather than
|
|
676
|
-
* discovering keys by scanning the environment. Scanning would have to guess how
|
|
677
|
-
* `S3_BUCKET__MEDIA_CDN` splits into a key; deriving cannot be ambiguous, and a
|
|
678
|
-
* typo surfaces as a missing source at boot instead of a silently ignored
|
|
679
|
-
* variable.
|
|
680
|
-
*
|
|
681
|
-
* It lives in this package, with no dependencies, because four things must agree
|
|
682
|
-
* on it exactly: the CLI (validating a build), the runtime (reading its own
|
|
683
|
-
* environment), the control plane (writing a tenant's Secret), and the docs. A
|
|
684
|
-
* second implementation of a naming convention is a second chance to disagree.
|
|
685
|
-
*
|
|
686
|
-
* @group Models
|
|
687
|
-
*/
|
|
688
|
-
function storageEnvSuffix(key, defaultKey = DEFAULT_STORAGE_SOURCE_KEY) {
|
|
689
|
-
if (!key || key === defaultKey) return "";
|
|
690
|
-
const normalized = key.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
691
|
-
if (!normalized) throw new Error(`Source key "${key}" cannot be turned into an environment variable name. Use a key containing at least one letter or digit.`);
|
|
692
|
-
return `__${normalized}`;
|
|
693
|
-
}
|
|
694
|
-
/**
|
|
695
|
-
* Two distinct keys that collapse onto the same variable name, or `null`.
|
|
696
|
-
*
|
|
697
|
-
* `media-cdn` and `media_cdn` are different source keys but the same suffix, so
|
|
698
|
-
* without this one of them silently reads the other's configuration. Returns the
|
|
699
|
-
* offending pair rather than throwing, so each caller can raise it in its own
|
|
700
|
-
* idiom — a `BundleError` at boot, a build failure in the CLI, a rejected deploy
|
|
701
|
-
* in a control plane.
|
|
702
|
-
*
|
|
703
|
-
* @group Models
|
|
704
|
-
*/
|
|
705
|
-
function findStorageSuffixCollision(keys, defaultKey = DEFAULT_STORAGE_SOURCE_KEY) {
|
|
706
|
-
const seen = /* @__PURE__ */ new Map();
|
|
707
|
-
for (const key of keys) {
|
|
708
|
-
const suffix = storageEnvSuffix(key, defaultKey);
|
|
709
|
-
const existing = seen.get(suffix);
|
|
710
|
-
if (existing !== void 0 && existing !== key) return {
|
|
711
|
-
a: existing,
|
|
712
|
-
b: key,
|
|
713
|
-
suffix
|
|
714
|
-
};
|
|
715
|
-
seen.set(suffix, key);
|
|
716
|
-
}
|
|
717
|
-
return null;
|
|
718
|
-
}
|
|
719
|
-
/**
|
|
720
|
-
* Merge the two places a project may declare storage sources into one list.
|
|
721
|
-
*
|
|
722
|
-
* `rebase.json` is authoritative for every field it states. Config code may add
|
|
723
|
-
* sources it does not mention and fill in fields it left out, but may not
|
|
724
|
-
* contradict it: the manifest is what a host reads to decide which buckets need
|
|
725
|
-
* configuring, and a runtime that quietly disagreed with it would put the
|
|
726
|
-
* console back to describing a topology the tenant does not have — the exact
|
|
727
|
-
* failure this whole mechanism exists to end.
|
|
728
|
-
*
|
|
729
|
-
* Note what is *not* here: no default source is invented when both inputs are
|
|
730
|
-
* empty. That decision belongs to the resolver, which knows whether declaring
|
|
731
|
-
* nothing means "one plain bucket" (it does) or "no storage at all".
|
|
732
|
-
*
|
|
733
|
-
* @group Models
|
|
734
|
-
*/
|
|
735
|
-
function normalizeStorageSources(declared, exported) {
|
|
736
|
-
const merged = /* @__PURE__ */ new Map();
|
|
737
|
-
const declaredEntries = Array.isArray(declared) ? declared.filter((d) => d?.key).map((d) => [d.key, d]) : Object.entries(declared ?? {});
|
|
738
|
-
for (const [key, config] of declaredEntries) merged.set(key, {
|
|
739
|
-
key,
|
|
740
|
-
engine: config.engine,
|
|
741
|
-
transport: config.transport ?? "server",
|
|
742
|
-
...config.label !== void 0 ? { label: config.label } : {}
|
|
743
|
-
});
|
|
744
|
-
for (const definition of exported ?? []) {
|
|
745
|
-
if (!definition?.key) continue;
|
|
746
|
-
const existing = merged.get(definition.key);
|
|
747
|
-
if (!existing) {
|
|
748
|
-
merged.set(definition.key, {
|
|
749
|
-
key: definition.key,
|
|
750
|
-
engine: definition.engine,
|
|
751
|
-
transport: definition.transport ?? "server",
|
|
752
|
-
...definition.label !== void 0 ? { label: definition.label } : {}
|
|
753
|
-
});
|
|
754
|
-
continue;
|
|
755
|
-
}
|
|
756
|
-
if (existing.label === void 0 && definition.label !== void 0) existing.label = definition.label;
|
|
757
|
-
}
|
|
758
|
-
return Array.from(merged.values());
|
|
759
|
-
}
|
|
760
|
-
//#endregion
|
|
761
|
-
//#region ../types/src/types/project_manifest.ts
|
|
762
|
-
/** Header carrying the schema version an SDK was generated from. */
|
|
763
|
-
var SCHEMA_VERSION_HEADER = "x-rebase-schema";
|
|
764
|
-
//#endregion
|
|
765
|
-
//#region ../types/src/types/collection_contract.ts
|
|
766
|
-
/** Depth limit for the walk — deep enough for real configs, finite for cyclic ones. */
|
|
767
|
-
var MAX_DEPTH = 64;
|
|
768
|
-
/**
|
|
769
|
-
* Resolve whatever a `target` thunk returns down to a collection.
|
|
770
|
-
*
|
|
771
|
-
* A target may be the collection, a module namespace (when the authoring file
|
|
772
|
-
* used `import * as`), or a default-export wrapper. All three appear in real
|
|
773
|
-
* projects, and the SDK generator already unwraps them the same way.
|
|
774
|
-
*/
|
|
775
|
-
function unwrapTarget(value) {
|
|
776
|
-
if (!value || typeof value !== "object") return void 0;
|
|
777
|
-
const candidate = value;
|
|
778
|
-
if (candidate.default || candidate.__esModule) {
|
|
779
|
-
const inner = candidate.default;
|
|
780
|
-
if (inner && typeof inner === "object") return inner;
|
|
781
|
-
}
|
|
782
|
-
if (candidate.properties) return value;
|
|
783
|
-
}
|
|
784
|
-
/** The identity a serialized reference uses. Slug first — it is the routing key. */
|
|
785
|
-
function refFor(collection) {
|
|
786
|
-
if (!collection) return void 0;
|
|
787
|
-
const withPath = collection;
|
|
788
|
-
return collection.slug || withPath.path || collection.name;
|
|
789
|
-
}
|
|
790
|
-
function toSerializable(value, seen, depth, state, key) {
|
|
791
|
-
if (depth > MAX_DEPTH) {
|
|
792
|
-
state.truncations++;
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
if (typeof value === "function") {
|
|
796
|
-
if (key === "target") try {
|
|
797
|
-
const ref = refFor(unwrapTarget(value()));
|
|
798
|
-
return ref ? { __collectionRef: ref } : void 0;
|
|
799
|
-
} catch {
|
|
800
|
-
return;
|
|
801
|
-
}
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
if (value === null || typeof value !== "object") return value;
|
|
805
|
-
if (value instanceof Date) return value.toISOString();
|
|
806
|
-
if (value instanceof RegExp) return value.source;
|
|
807
|
-
if (seen.has(value)) {
|
|
808
|
-
state.truncations++;
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
const cached = state.memo.get(value);
|
|
812
|
-
if (cached !== void 0) return cached;
|
|
813
|
-
seen.add(value);
|
|
814
|
-
const truncationsBefore = state.truncations;
|
|
815
|
-
const memoize = (result) => {
|
|
816
|
-
if (result !== void 0 && state.truncations === truncationsBefore) state.memo.set(value, result);
|
|
817
|
-
return result;
|
|
818
|
-
};
|
|
819
|
-
try {
|
|
820
|
-
if (Array.isArray(value)) {
|
|
821
|
-
const items = value.map((item) => toSerializable(item, seen, depth + 1, state)).filter((item) => item !== void 0);
|
|
822
|
-
return memoize(value.length > 0 && items.length === 0 ? void 0 : items);
|
|
823
|
-
}
|
|
824
|
-
if ("$$typeof" in value) return void 0;
|
|
825
|
-
const entries = Object.entries(value);
|
|
826
|
-
const out = {};
|
|
827
|
-
for (const [k, v] of entries) {
|
|
828
|
-
const converted = toSerializable(v, seen, depth + 1, state, k);
|
|
829
|
-
if (converted !== void 0) out[k] = converted;
|
|
830
|
-
}
|
|
831
|
-
if (entries.length > 0 && Object.keys(out).length === 0) return void 0;
|
|
832
|
-
return memoize(out);
|
|
833
|
-
} finally {
|
|
834
|
-
seen.delete(value);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
/**
|
|
838
|
-
* Serialize collections for transport over the contract endpoint.
|
|
839
|
-
*
|
|
840
|
-
* Sorted by slug so the output — and therefore the schema hash computed from it
|
|
841
|
-
* — does not depend on filesystem ordering.
|
|
842
|
-
*/
|
|
843
|
-
function serializeCollections(collections) {
|
|
844
|
-
return [...collections].sort((a, b) => String(a.slug ?? "").localeCompare(String(b.slug ?? ""))).map((collection) => toSerializable(withoutAdminBlock(collection), /* @__PURE__ */ new WeakSet(), 0, {
|
|
845
|
-
memo: /* @__PURE__ */ new WeakMap(),
|
|
846
|
-
truncations: 0
|
|
847
|
-
})).filter((c) => c !== void 0);
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* Drop the admin block before the walk.
|
|
851
|
-
*
|
|
852
|
-
* Nothing downstream of serialization is an admin panel. The contract endpoint
|
|
853
|
-
* feeds remote SDK generation, and `rebase build` writes the result into a bundle
|
|
854
|
-
* manifest that only the backend runtime reads. The block would survive the walk
|
|
855
|
-
* as a husk anyway — its React elements and component functions are dropped
|
|
856
|
-
* individually — and that husk has two costs worth avoiding: it puts every custom
|
|
857
|
-
* component's *file path* on an endpoint whose job is to describe data shapes, and
|
|
858
|
-
* it grows a payload that is fetched and cached per project.
|
|
859
|
-
*
|
|
860
|
-
* Removing it here rather than at each call site means one chokepoint, so a future
|
|
861
|
-
* consumer of `serializeCollections` cannot forget.
|
|
862
|
-
*
|
|
863
|
-
* Child collections carry their own block, so this recurses — stripping only the
|
|
864
|
-
* top level was the mistake `stripNonClientFields` in the contract routes already
|
|
865
|
-
* had to fix once for security rules.
|
|
866
|
-
*/
|
|
867
|
-
function withoutAdminBlock(collection) {
|
|
868
|
-
const { admin: _admin, ...rest } = collection;
|
|
869
|
-
const nested = rest;
|
|
870
|
-
if (Array.isArray(nested.subcollections)) nested.subcollections = nested.subcollections.map((child) => withoutAdminBlock(child));
|
|
871
|
-
return rest;
|
|
872
|
-
}
|
|
873
|
-
//#endregion
|
|
874
|
-
//#region ../types/src/types/schema_version.ts
|
|
875
|
-
/**
|
|
876
|
-
* The schema version stamp.
|
|
877
|
-
*
|
|
878
|
-
* One function, used in three places that must agree or the whole drift-detection
|
|
879
|
-
* story is noise: `rebase build` writes it into a bundle manifest, the runtime
|
|
880
|
-
* serves it from the contract endpoint, and a generated SDK records the value it
|
|
881
|
-
* was built from. If any two of those computed it differently, every client would
|
|
882
|
-
* look permanently out of date.
|
|
883
|
-
*
|
|
884
|
-
* It covers **collections only** — the client's contract is the shape of the
|
|
885
|
-
* data, so editing a hook or a server function must not invalidate every SDK in
|
|
886
|
-
* every repository. That is a deliberate narrowing, not an oversight.
|
|
887
|
-
*/
|
|
888
|
-
/** Stable stringify: object keys sorted at every level, so key order cannot alter the hash. */
|
|
889
|
-
function canonicalize(value) {
|
|
890
|
-
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
891
|
-
if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
|
|
892
|
-
return `{${Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${JSON.stringify(k)}:${canonicalize(v)}`).join(",")}}`;
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Reduce a collection to the parts a generated client is actually built from.
|
|
896
|
-
*
|
|
897
|
-
* The version answers one question — "is this SDK stale?" — so it must change
|
|
898
|
-
* exactly when the generated types could change, and never otherwise. Hashing a
|
|
899
|
-
* whole collection fails both halves of that:
|
|
900
|
-
*
|
|
901
|
-
* - Security rules, callbacks, icons, groups and UI settings do not appear in a
|
|
902
|
-
* generated client, so including them reports perfectly current SDKs as stale.
|
|
903
|
-
* - Worse, they are not stable *inputs*. The runtime applies default security
|
|
904
|
-
* rules when it loads collections, so the same source hashed before and after
|
|
905
|
-
* loading produced two different answers — a build-time stamp that could never
|
|
906
|
-
* match the server that served it.
|
|
907
|
-
*
|
|
908
|
-
* Codegen reads the slug (for the `Database` key and type names), the properties,
|
|
909
|
-
* and the relations. That is the projection.
|
|
910
|
-
*/
|
|
911
|
-
function projectForCodegen(collection) {
|
|
912
|
-
const source = collection;
|
|
913
|
-
return {
|
|
914
|
-
slug: collection.slug ?? source.path,
|
|
915
|
-
properties: collection.properties,
|
|
916
|
-
relations: source.relations,
|
|
917
|
-
engine: source.engine,
|
|
918
|
-
dataSource: source.dataSource,
|
|
919
|
-
subcollections: source.subcollections?.map(projectForCodegen)
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
/**
|
|
923
|
-
* Compute the canonical string a schema version hashes.
|
|
924
|
-
*
|
|
925
|
-
* Exposed separately so the hashing itself can differ by environment: Node has
|
|
926
|
-
* `crypto`, and callers without it can still compare canonical forms directly.
|
|
927
|
-
*/
|
|
928
|
-
function canonicalSchemaPayload(collections) {
|
|
929
|
-
return canonicalize(serializeCollections(collections).map((collection) => projectForCodegen(collection)));
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* A short, non-cryptographic digest of the canonical payload.
|
|
933
|
-
*
|
|
934
|
-
* FNV-1a style, 64 bits, as two 32-bit halves. This is an identity, not a
|
|
935
|
-
* security boundary: nothing trusts a schema version to prove anything, it only
|
|
936
|
-
* answers "is this the same schema as before". A hand-rolled hash keeps this
|
|
937
|
-
* module free of `node:crypto`, so the identical function runs in the browser,
|
|
938
|
-
* in the CLI, and in the runtime — which is the property that actually matters.
|
|
939
|
-
*/
|
|
940
|
-
function computeSchemaVersion(collections) {
|
|
941
|
-
const payload = canonicalSchemaPayload(collections);
|
|
942
|
-
let h1 = 2166136261;
|
|
943
|
-
let h2 = 16777619;
|
|
944
|
-
for (let i = 0; i < payload.length; i++) {
|
|
945
|
-
const code = payload.charCodeAt(i);
|
|
946
|
-
h1 ^= code;
|
|
947
|
-
h1 = h1 + ((h1 << 1) + (h1 << 4) + (h1 << 7) + (h1 << 8) + (h1 << 24)) >>> 0;
|
|
948
|
-
h2 ^= code + i;
|
|
949
|
-
h2 = h2 + ((h2 << 1) + (h2 << 5) + (h2 << 9) + (h2 << 15) + (h2 << 24)) >>> 0;
|
|
950
|
-
}
|
|
951
|
-
const hex = (n) => n.toString(16).padStart(8, "0");
|
|
952
|
-
return `v1:${hex(h1)}${hex(h2)}`;
|
|
953
|
-
}
|
|
954
|
-
//#endregion
|
|
955
|
-
export { EntityReference as C, RebaseApiError as D, Vector as E, RebaseClientError as O, toCanonicalOp as S, GeoPoint as T, ADMIN_COLLECTION_KEYS as _, findStorageSuffixCollision as a, NULL_OPS as b, isSQLAdmin as c, getCollectionDataPath as d, getDeclaredSubcollections as f, getDataSourceCapabilities as g, DEFAULT_DATA_SOURCE_KEY as h, DEFAULT_STORAGE_SOURCE_KEY as i, policy as l, isRelationalCollectionConfig as m, serializeCollections as n, normalizeStorageSources as o, isPostgresCollectionConfig as p, SCHEMA_VERSION_HEADER as r, storageEnvSuffix as s, computeSchemaVersion as t, isToMany as u, ADMIN_PROPERTY_KEYS as v, EntityRelation as w, REST_TO_CANONICAL as x, CANONICAL_TO_REST as y };
|
|
956
|
-
|
|
957
|
-
//# sourceMappingURL=src-Ivjud8jD.js.map
|