@rebasepro/types 0.11.1-canary.gfd39654 → 0.12.0
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/controllers/collection_registry.d.ts +1 -1
- package/dist/controllers/data.d.ts +148 -9
- package/dist/index.es.js +287 -97
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +20 -0
- package/dist/types/api_keys.d.ts +60 -5
- package/dist/types/collections.d.ts +56 -31
- package/dist/types/data_source.d.ts +42 -1
- package/dist/types/database_adapter.d.ts +13 -8
- package/dist/types/entity_callbacks.d.ts +2 -2
- package/dist/types/history.d.ts +62 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/postgres_introspection.d.ts +95 -0
- package/dist/types/project_manifest.d.ts +146 -73
- package/dist/types/properties.d.ts +38 -49
- package/dist/types/storage_source.d.ts +60 -0
- package/dist/types/websockets.d.ts +0 -37
- package/package.json +1 -1
- package/src/controllers/collection_registry.ts +1 -1
- package/src/controllers/data.ts +155 -9
- package/src/types/admin_block.ts +48 -0
- package/src/types/api_keys.ts +61 -5
- package/src/types/collections.ts +68 -39
- package/src/types/data_source.ts +60 -1
- package/src/types/database_adapter.ts +13 -8
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/history.ts +66 -0
- package/src/types/index.ts +2 -0
- package/src/types/postgres_introspection.ts +101 -0
- package/src/types/project_manifest.ts +149 -80
- package/src/types/properties.ts +43 -56
- package/src/types/storage_source.ts +130 -0
- package/src/types/websockets.ts +0 -42
|
@@ -6,7 +6,7 @@ import type { EntityReference } from "../types/entities";
|
|
|
6
6
|
*/
|
|
7
7
|
export type CollectionRegistryController<DB = Record<string, unknown>, EC extends CollectionConfig = CollectionConfig> = {
|
|
8
8
|
/**
|
|
9
|
-
* List of the mapped collections in the
|
|
9
|
+
* List of the mapped collections in the admin.
|
|
10
10
|
* Each entry relates to a collection in the root database.
|
|
11
11
|
* Each of the navigation entries in this field
|
|
12
12
|
* generates an entry in the main menu.
|
|
@@ -108,12 +108,12 @@ export interface FindResponse<M extends Record<string, unknown> = Record<string,
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
-
* Fluent query builder for the **admin
|
|
111
|
+
* Fluent query builder for the **admin admin** — resolves to `FindResponse<M>`
|
|
112
112
|
* (Snapshot-wrapped rows).
|
|
113
113
|
*
|
|
114
114
|
* @internal App developers should use {@link SDKQueryBuilderInterface}
|
|
115
115
|
* (flat rows, returned by `client.data.*` / `context.data.*`). This
|
|
116
|
-
* Snapshot-flavored variant backs the admin
|
|
116
|
+
* Snapshot-flavored variant backs the admin admin internals only.
|
|
117
117
|
*
|
|
118
118
|
* @group Data
|
|
119
119
|
*/
|
|
@@ -129,13 +129,13 @@ export interface QueryBuilderInterface<M extends Record<string, unknown> = Recor
|
|
|
129
129
|
listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
|
|
130
130
|
}
|
|
131
131
|
/**
|
|
132
|
-
* A single collection's CRUD accessor for the **admin
|
|
132
|
+
* A single collection's CRUD accessor for the **admin admin** — every method
|
|
133
133
|
* resolves to `Snapshot`-wrapped rows (`FindResponse<M>` / `Snapshot<M>`).
|
|
134
134
|
*
|
|
135
135
|
* @internal App developers do **not** use this. The public, symmetric surface
|
|
136
136
|
* is {@link SDKCollectionClient} (flat rows), exposed as `client.data.products`
|
|
137
137
|
* in the SDK and `context.data.products` in framework callbacks. This
|
|
138
|
-
* Snapshot-flavored accessor backs the admin
|
|
138
|
+
* Snapshot-flavored accessor backs the admin admin view-model only.
|
|
139
139
|
*
|
|
140
140
|
* @group Data
|
|
141
141
|
*/
|
|
@@ -222,6 +222,86 @@ export interface FindResult<M extends Record<string, unknown> = Record<string, u
|
|
|
222
222
|
/** Pagination metadata */
|
|
223
223
|
meta: PaginationMeta;
|
|
224
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Which column an iteration seeks on, for keyset ("seek") pagination.
|
|
227
|
+
*
|
|
228
|
+
* Either the column name on its own — sorted ascending — or the column plus an
|
|
229
|
+
* explicit direction. The column must be **unique** and must be the column the
|
|
230
|
+
* query is ordered by; see {@link PageWalkOptions.cursor}.
|
|
231
|
+
*
|
|
232
|
+
* @group Data
|
|
233
|
+
*/
|
|
234
|
+
export type CursorSpec<M extends Record<string, unknown> = Record<string, unknown>> = (Extract<keyof M, string>) | {
|
|
235
|
+
field: Extract<keyof M, string>;
|
|
236
|
+
direction?: "asc" | "desc";
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* How {@link SDKCollectionClient.iterate} / {@link SDKCollectionClient.findAll}
|
|
240
|
+
* walk a collection, layered on top of the normal `find()` parameters.
|
|
241
|
+
*
|
|
242
|
+
* @group Data
|
|
243
|
+
*/
|
|
244
|
+
export interface PageWalkOptions<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
245
|
+
/**
|
|
246
|
+
* Rows fetched per request. Defaults to 200; values below 1 are clamped up.
|
|
247
|
+
* This is the request size, not a result cap — the iteration keeps going
|
|
248
|
+
* until the server says there is nothing left.
|
|
249
|
+
*/
|
|
250
|
+
pageSize?: number;
|
|
251
|
+
/**
|
|
252
|
+
* Paginate by **seeking on a column** instead of by offset.
|
|
253
|
+
*
|
|
254
|
+
* Offset paging — the default — re-counts rows on every request, so a row
|
|
255
|
+
* inserted or deleted *while the iteration runs* shifts the window and the
|
|
256
|
+
* walk silently skips or repeats rows. Seeking is immune to that: each page
|
|
257
|
+
* asks for rows strictly after the last one seen, so concurrent writes
|
|
258
|
+
* before the cursor cannot move it.
|
|
259
|
+
*
|
|
260
|
+
* Prefer this whenever the collection has a unique, sortable column
|
|
261
|
+
* (typically its primary key). The column must be unique — a repeated value
|
|
262
|
+
* at a page boundary either skips rows or stalls, and the iterator throws
|
|
263
|
+
* rather than looping — and the query is ordered by it, so a `cursor` and a
|
|
264
|
+
* conflicting `orderBy` is an error, not a silent override.
|
|
265
|
+
*
|
|
266
|
+
* Implemented with the parameters `find()` already takes (an `orderBy` plus
|
|
267
|
+
* a `>` / `<` filter on the cursor column), so it works on every transport
|
|
268
|
+
* and needs nothing new from the server.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* for await (const job of client.data.jobs.iterate({ cursor: "id" })) { … }
|
|
272
|
+
*/
|
|
273
|
+
cursor?: CursorSpec<M>;
|
|
274
|
+
/**
|
|
275
|
+
* Hard ceiling on the number of requests one walk may make, so a server
|
|
276
|
+
* that never stops saying `hasMore` cannot spin forever. Defaults to
|
|
277
|
+
* 10 000 pages; hitting it throws.
|
|
278
|
+
*/
|
|
279
|
+
maxPages?: number;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Parameters accepted by {@link SDKCollectionClient.iterate} — everything
|
|
283
|
+
* `find()` takes except the window itself (`limit`, `offset`, `page`), which
|
|
284
|
+
* the iterator owns, plus the walk options.
|
|
285
|
+
*
|
|
286
|
+
* @group Data
|
|
287
|
+
*/
|
|
288
|
+
export type IterateParams<M extends Record<string, unknown> = Record<string, unknown>> = Omit<FindParams<M>, "limit" | "offset" | "page"> & PageWalkOptions<M>;
|
|
289
|
+
/**
|
|
290
|
+
* Parameters accepted by {@link SDKCollectionClient.findAll}: the iteration
|
|
291
|
+
* parameters plus the ceiling that keeps a whole collection from being pulled
|
|
292
|
+
* into memory unnoticed.
|
|
293
|
+
*
|
|
294
|
+
* @group Data
|
|
295
|
+
*/
|
|
296
|
+
export type FindAllParams<M extends Record<string, unknown> = Record<string, unknown>> = IterateParams<M> & {
|
|
297
|
+
/**
|
|
298
|
+
* Most rows to materialise. Defaults to 10 000. Exceeding it **throws**
|
|
299
|
+
* — a truncated array returned as if it were the whole answer is the
|
|
300
|
+
* kind of quiet wrong that shows up months later in a report. Pass
|
|
301
|
+
* `Infinity` to opt out deliberately, or use `iterate()` to stream.
|
|
302
|
+
*/
|
|
303
|
+
maxRows?: number;
|
|
304
|
+
};
|
|
225
305
|
/**
|
|
226
306
|
* Fluent Query Builder Interface for the SDK client.
|
|
227
307
|
* Returns `FindResult<M>` (flat rows) instead of `FindResponse<M>` (Entity-wrapped).
|
|
@@ -244,7 +324,7 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
244
324
|
* SDK collection client — returns flat rows, no Entity wrapper.
|
|
245
325
|
*
|
|
246
326
|
* This is the public API surface for app developers using
|
|
247
|
-
* `createRebaseClient()`.
|
|
327
|
+
* `createRebaseClient()`. admin internals use `CollectionAccessor` instead.
|
|
248
328
|
*
|
|
249
329
|
* Type parameters:
|
|
250
330
|
* - `M` — the **Row** shape returned by reads (`find`, `findById`, `listen`).
|
|
@@ -290,6 +370,65 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
290
370
|
* Find multiple records with optional filtering, pagination, and sorting.
|
|
291
371
|
*/
|
|
292
372
|
find(params?: FindParams<M>): Promise<FindResult<M>>;
|
|
373
|
+
/**
|
|
374
|
+
* Walk every record matching a query, one row at a time, fetching pages as
|
|
375
|
+
* the consumer consumes them.
|
|
376
|
+
*
|
|
377
|
+
* This is the pagination primitive: `find()` returns one window, `iterate()`
|
|
378
|
+
* returns all of them without the caller hand-rolling the
|
|
379
|
+
* `limit` / `offset += ` / "am I done yet" loop. Nothing is buffered — rows
|
|
380
|
+
* are yielded as each page arrives, so a million-row walk costs one page of
|
|
381
|
+
* memory. `break` stops the walk and no further requests are made.
|
|
382
|
+
*
|
|
383
|
+
* Termination is driven by the server's `meta.hasMore`, never by comparing
|
|
384
|
+
* a page's length against the requested limit — a final page that happens
|
|
385
|
+
* to be exactly full is indistinguishable that way, and a walk that stops
|
|
386
|
+
* there drops rows. An empty page also ends the walk, and
|
|
387
|
+
* {@link PageWalkOptions.maxPages} bounds a server that never stops saying
|
|
388
|
+
* there is more.
|
|
389
|
+
*
|
|
390
|
+
* ## Consistency
|
|
391
|
+
*
|
|
392
|
+
* By default this pages by **offset**, which is only as stable as the table
|
|
393
|
+
* is still: a row inserted or deleted ahead of the cursor between two
|
|
394
|
+
* requests shifts every later window, so the walk can skip a row or hand
|
|
395
|
+
* back the same one twice. That is inherent to offset paging, not a bug
|
|
396
|
+
* here. On a collection with a unique sortable column, pass
|
|
397
|
+
* {@link PageWalkOptions.cursor} to seek on it instead — the walk then
|
|
398
|
+
* asks for rows strictly after the last one it saw, which concurrent writes
|
|
399
|
+
* cannot perturb.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* for await (const job of client.data.jobs.iterate({
|
|
403
|
+
* where: { status: ["==", "queued"] },
|
|
404
|
+
* cursor: "id",
|
|
405
|
+
* pageSize: 500
|
|
406
|
+
* })) {
|
|
407
|
+
* await handle(job);
|
|
408
|
+
* }
|
|
409
|
+
*/
|
|
410
|
+
iterate(params?: IterateParams<M>): AsyncIterableIterator<M>;
|
|
411
|
+
/**
|
|
412
|
+
* {@link iterate}, collected into an array.
|
|
413
|
+
*
|
|
414
|
+
* Convenient when the result is known to be small and awkward to stream.
|
|
415
|
+
* Because "known to be small" is an assumption and not a fact, the result is
|
|
416
|
+
* capped — 10 000 rows by default — and going over the cap **throws**
|
|
417
|
+
* rather than returning a short array that reads like a complete one. Raise
|
|
418
|
+
* {@link FindAllParams.maxRows} when the data really is bigger, or switch to
|
|
419
|
+
* `iterate()` and stream it.
|
|
420
|
+
*
|
|
421
|
+
* The offset-drift caveat on {@link iterate} applies here too.
|
|
422
|
+
*
|
|
423
|
+
* @throws When more rows match than `maxRows` allows.
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* const overdue = await client.data.invoices.findAll({
|
|
427
|
+
* where: { due_at: ["<", today] },
|
|
428
|
+
* cursor: "id"
|
|
429
|
+
* });
|
|
430
|
+
*/
|
|
431
|
+
findAll(params?: FindAllParams<M>): Promise<M[]>;
|
|
293
432
|
/**
|
|
294
433
|
* Find a single record by its ID.
|
|
295
434
|
*/
|
|
@@ -367,16 +506,16 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
367
506
|
include(...relations: string[]): SDKQueryBuilderInterface<M>;
|
|
368
507
|
}
|
|
369
508
|
/**
|
|
370
|
-
* The unified data access object for the **admin
|
|
509
|
+
* The unified data access object for the **admin admin** (Entity-shaped).
|
|
371
510
|
*
|
|
372
511
|
* Access collections as dynamic properties: `data.products.find(...)`. Each
|
|
373
512
|
* accessor returns `Entity`-wrapped records (`{ id, path, values }`) — the
|
|
374
|
-
* view-model the
|
|
513
|
+
* view-model the admin renders. This is what `useData()` / the admin
|
|
375
514
|
* `RebaseContext.data` are backed by.
|
|
376
515
|
*
|
|
377
516
|
* @internal App developers do **not** use this — they use
|
|
378
517
|
* {@link RebaseSdkData} (flat rows), which is what the SDK client and backend
|
|
379
|
-
* `context.data` expose. This Entity-shaped map backs the admin
|
|
518
|
+
* `context.data` expose. This Entity-shaped map backs the admin admin only.
|
|
380
519
|
*
|
|
381
520
|
* @group Data
|
|
382
521
|
*/
|
|
@@ -415,7 +554,7 @@ export type RebaseData<DB = unknown> = {
|
|
|
415
554
|
*
|
|
416
555
|
* Every accessor returns flat rows (the table's columns) via
|
|
417
556
|
* {@link SDKCollectionClient} — access fields directly (`row.title`), never
|
|
418
|
-
* `row.values.title`. The admin
|
|
557
|
+
* `row.values.title`. The admin uses {@link RebaseData} (Entity) instead.
|
|
419
558
|
*
|
|
420
559
|
* @example
|
|
421
560
|
* // Frontend SDK
|
package/dist/index.es.js
CHANGED
|
@@ -336,6 +336,168 @@ var ADMIN_COLLECTION_KEYS = [
|
|
|
336
336
|
"sort",
|
|
337
337
|
"titleProperty"
|
|
338
338
|
];
|
|
339
|
+
/**
|
|
340
|
+
* Every key that belongs inside a *property's* `admin` block, as data.
|
|
341
|
+
*
|
|
342
|
+
* The union of `AdminPropertyOptions` and its per-type extensions
|
|
343
|
+
* (`AdminStringOptions`, `AdminArrayOptions`, …) in `@rebasepro/admin-types`.
|
|
344
|
+
* It lives here for the same reason {@link ADMIN_COLLECTION_KEYS} does: the
|
|
345
|
+
* runtime consumers are core packages that the BaaS guard forbids from
|
|
346
|
+
* importing `@rebasepro/admin-types`. Here it is the boot-time collection
|
|
347
|
+
* validator in `@rebasepro/server`, which has to tell "you left `readOnly` at
|
|
348
|
+
* the top of the property, where nothing reads it" apart from "you invented a
|
|
349
|
+
* key we have never heard of".
|
|
350
|
+
*
|
|
351
|
+
* `@rebasepro/admin-types` re-exports this and asserts it names only real
|
|
352
|
+
* option keys.
|
|
353
|
+
*
|
|
354
|
+
* @group Models
|
|
355
|
+
*/
|
|
356
|
+
var ADMIN_PROPERTY_KEYS = [
|
|
357
|
+
"canAddElements",
|
|
358
|
+
"clearable",
|
|
359
|
+
"columnWidth",
|
|
360
|
+
"customProps",
|
|
361
|
+
"disabled",
|
|
362
|
+
"expanded",
|
|
363
|
+
"Field",
|
|
364
|
+
"Filter",
|
|
365
|
+
"filterOperators",
|
|
366
|
+
"fixedFilter",
|
|
367
|
+
"hideFromCollection",
|
|
368
|
+
"includeEntityLink",
|
|
369
|
+
"includeId",
|
|
370
|
+
"markdown",
|
|
371
|
+
"minimalistView",
|
|
372
|
+
"multiline",
|
|
373
|
+
"Preview",
|
|
374
|
+
"previewAsTag",
|
|
375
|
+
"previewProperties",
|
|
376
|
+
"readOnly",
|
|
377
|
+
"sortable",
|
|
378
|
+
"spreadChildren",
|
|
379
|
+
"urlPreview",
|
|
380
|
+
"widget",
|
|
381
|
+
"widthPercentage"
|
|
382
|
+
];
|
|
383
|
+
//#endregion
|
|
384
|
+
//#region src/types/data_source.ts
|
|
385
|
+
/**
|
|
386
|
+
* The default data-source key, used when a collection does not name a
|
|
387
|
+
* `dataSource`. Shared by the frontend router and the backend driver
|
|
388
|
+
* registry so both agree on "the default database".
|
|
389
|
+
* @group Models
|
|
390
|
+
*/
|
|
391
|
+
var DEFAULT_DATA_SOURCE_KEY = "(default)";
|
|
392
|
+
/**
|
|
393
|
+
* Relation kinds assumed filterable when a driver does not say.
|
|
394
|
+
*
|
|
395
|
+
* `belongsTo` alone: its filter is a comparison on a column of the row being
|
|
396
|
+
* filtered, the one shape that needs no query construction a driver might not
|
|
397
|
+
* have. Everything else is a correlated subquery over another table.
|
|
398
|
+
*
|
|
399
|
+
* @group Models
|
|
400
|
+
*/
|
|
401
|
+
var DEFAULT_FILTERABLE_RELATION_KINDS = ["belongsTo"];
|
|
402
|
+
/** @group Models */
|
|
403
|
+
var POSTGRES_CAPABILITIES = {
|
|
404
|
+
key: "postgres",
|
|
405
|
+
label: "PostgreSQL",
|
|
406
|
+
supportsRelations: true,
|
|
407
|
+
supportsSubcollections: false,
|
|
408
|
+
supportsRLS: true,
|
|
409
|
+
supportsReferences: false,
|
|
410
|
+
supportsColumnTypes: true,
|
|
411
|
+
supportsRealtime: true,
|
|
412
|
+
supportsVectors: true,
|
|
413
|
+
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
414
|
+
filterableRelationKinds: [
|
|
415
|
+
"belongsTo",
|
|
416
|
+
"manyToMany",
|
|
417
|
+
"hasMany",
|
|
418
|
+
"hasOne"
|
|
419
|
+
],
|
|
420
|
+
supportsSQLAdmin: true,
|
|
421
|
+
supportsDocumentAdmin: false,
|
|
422
|
+
supportsSchemaAdmin: true
|
|
423
|
+
};
|
|
424
|
+
/** @group Models */
|
|
425
|
+
var FIREBASE_CAPABILITIES = {
|
|
426
|
+
key: "firestore",
|
|
427
|
+
label: "Firebase / Firestore",
|
|
428
|
+
supportsRelations: false,
|
|
429
|
+
supportsSubcollections: true,
|
|
430
|
+
supportsRLS: false,
|
|
431
|
+
supportsReferences: true,
|
|
432
|
+
supportsColumnTypes: false,
|
|
433
|
+
supportsRealtime: true,
|
|
434
|
+
supportsVectors: false,
|
|
435
|
+
filterOperators: ALL_WHERE_FILTER_OPS.filter((op) => op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
|
|
436
|
+
filterableRelationKinds: [],
|
|
437
|
+
supportsSQLAdmin: false,
|
|
438
|
+
supportsDocumentAdmin: false,
|
|
439
|
+
supportsSchemaAdmin: false
|
|
440
|
+
};
|
|
441
|
+
/** @group Models */
|
|
442
|
+
var MONGODB_CAPABILITIES = {
|
|
443
|
+
key: "mongodb",
|
|
444
|
+
label: "MongoDB",
|
|
445
|
+
supportsRelations: false,
|
|
446
|
+
supportsSubcollections: true,
|
|
447
|
+
supportsRLS: false,
|
|
448
|
+
supportsReferences: true,
|
|
449
|
+
supportsColumnTypes: false,
|
|
450
|
+
supportsRealtime: false,
|
|
451
|
+
supportsVectors: false,
|
|
452
|
+
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
453
|
+
filterableRelationKinds: [],
|
|
454
|
+
supportsSQLAdmin: false,
|
|
455
|
+
supportsDocumentAdmin: true,
|
|
456
|
+
supportsSchemaAdmin: true
|
|
457
|
+
};
|
|
458
|
+
/**
|
|
459
|
+
* Fallback capabilities when the driver is unknown.
|
|
460
|
+
* Enables everything so nothing is hidden unexpectedly.
|
|
461
|
+
* @group Models
|
|
462
|
+
*/
|
|
463
|
+
var DEFAULT_CAPABILITIES = {
|
|
464
|
+
key: "(default)",
|
|
465
|
+
label: "Default",
|
|
466
|
+
supportsRelations: true,
|
|
467
|
+
supportsSubcollections: true,
|
|
468
|
+
supportsRLS: true,
|
|
469
|
+
supportsReferences: true,
|
|
470
|
+
supportsColumnTypes: true,
|
|
471
|
+
supportsRealtime: true,
|
|
472
|
+
supportsVectors: true,
|
|
473
|
+
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
474
|
+
filterableRelationKinds: DEFAULT_FILTERABLE_RELATION_KINDS,
|
|
475
|
+
supportsSQLAdmin: true,
|
|
476
|
+
supportsDocumentAdmin: true,
|
|
477
|
+
supportsSchemaAdmin: true
|
|
478
|
+
};
|
|
479
|
+
var CAPABILITIES_REGISTRY = {
|
|
480
|
+
postgres: POSTGRES_CAPABILITIES,
|
|
481
|
+
firestore: FIREBASE_CAPABILITIES,
|
|
482
|
+
mongodb: MONGODB_CAPABILITIES,
|
|
483
|
+
"(default)": DEFAULT_CAPABILITIES
|
|
484
|
+
};
|
|
485
|
+
/**
|
|
486
|
+
* Look up capabilities for a given engine key.
|
|
487
|
+
* If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
|
|
488
|
+
* @group Models
|
|
489
|
+
*/
|
|
490
|
+
function getDataSourceCapabilities(engine) {
|
|
491
|
+
if (!engine) return POSTGRES_CAPABILITIES;
|
|
492
|
+
return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Register custom capabilities for a third-party driver.
|
|
496
|
+
* @group Models
|
|
497
|
+
*/
|
|
498
|
+
function registerDataSourceCapabilities(capabilities) {
|
|
499
|
+
CAPABILITIES_REGISTRY[capabilities.key] = capabilities;
|
|
500
|
+
}
|
|
339
501
|
//#endregion
|
|
340
502
|
//#region src/types/collections.ts
|
|
341
503
|
/**
|
|
@@ -354,6 +516,29 @@ function isPostgresCollectionConfig(collection) {
|
|
|
354
516
|
return !collection.engine || collection.engine === "postgres";
|
|
355
517
|
}
|
|
356
518
|
/**
|
|
519
|
+
* Narrows to the SQL collection fields — `table`, `relations`,
|
|
520
|
+
* `disableDefaultPolicies` — by asking the engine's declared capabilities
|
|
521
|
+
* rather than by naming Postgres.
|
|
522
|
+
*
|
|
523
|
+
* The two halves of this already existed and were never joined. The engine
|
|
524
|
+
* split (`PostgresCollectionConfig` / `FirebaseCollectionConfig` /
|
|
525
|
+
* `MongoDBCollectionConfig`) said which fields belong to which engine at the
|
|
526
|
+
* type level; {@link DataSourceCapabilities} said the same thing at runtime,
|
|
527
|
+
* down to a `supportsRelations` flag. So call sites guarded on the capability
|
|
528
|
+
* and then read a field the base type had to declare for them — which is why
|
|
529
|
+
* those fields were on the base, and why a MongoDB collection could be written
|
|
530
|
+
* with a `table`.
|
|
531
|
+
*
|
|
532
|
+
* Prefer this over {@link isPostgresCollectionConfig} wherever the question is
|
|
533
|
+
* "does this collection live in a SQL table", so a custom SQL engine
|
|
534
|
+
* registered through `registerDataSourceCapabilities` is included.
|
|
535
|
+
*
|
|
536
|
+
* @group Models
|
|
537
|
+
*/
|
|
538
|
+
function isRelationalCollectionConfig(collection) {
|
|
539
|
+
return getDataSourceCapabilities(collection.engine).supportsRelations;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
357
542
|
* Type guard for Firebase / Firestore collections.
|
|
358
543
|
* @group Models
|
|
359
544
|
*/
|
|
@@ -523,101 +708,6 @@ function isChannelBusInstance(setting) {
|
|
|
523
708
|
return typeof setting?.publish === "function";
|
|
524
709
|
}
|
|
525
710
|
//#endregion
|
|
526
|
-
//#region src/types/data_source.ts
|
|
527
|
-
/**
|
|
528
|
-
* The default data-source key, used when a collection does not name a
|
|
529
|
-
* `dataSource`. Shared by the frontend router and the backend driver
|
|
530
|
-
* registry so both agree on "the default database".
|
|
531
|
-
* @group Models
|
|
532
|
-
*/
|
|
533
|
-
var DEFAULT_DATA_SOURCE_KEY = "(default)";
|
|
534
|
-
/** @group Models */
|
|
535
|
-
var POSTGRES_CAPABILITIES = {
|
|
536
|
-
key: "postgres",
|
|
537
|
-
label: "PostgreSQL",
|
|
538
|
-
supportsRelations: true,
|
|
539
|
-
supportsSubcollections: false,
|
|
540
|
-
supportsRLS: true,
|
|
541
|
-
supportsReferences: false,
|
|
542
|
-
supportsColumnTypes: true,
|
|
543
|
-
supportsRealtime: true,
|
|
544
|
-
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
545
|
-
supportsSQLAdmin: true,
|
|
546
|
-
supportsDocumentAdmin: false,
|
|
547
|
-
supportsSchemaAdmin: true
|
|
548
|
-
};
|
|
549
|
-
/** @group Models */
|
|
550
|
-
var FIREBASE_CAPABILITIES = {
|
|
551
|
-
key: "firestore",
|
|
552
|
-
label: "Firebase / Firestore",
|
|
553
|
-
supportsRelations: false,
|
|
554
|
-
supportsSubcollections: true,
|
|
555
|
-
supportsRLS: false,
|
|
556
|
-
supportsReferences: true,
|
|
557
|
-
supportsColumnTypes: false,
|
|
558
|
-
supportsRealtime: true,
|
|
559
|
-
filterOperators: ALL_WHERE_FILTER_OPS.filter((op) => op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
|
|
560
|
-
supportsSQLAdmin: false,
|
|
561
|
-
supportsDocumentAdmin: false,
|
|
562
|
-
supportsSchemaAdmin: false
|
|
563
|
-
};
|
|
564
|
-
/** @group Models */
|
|
565
|
-
var MONGODB_CAPABILITIES = {
|
|
566
|
-
key: "mongodb",
|
|
567
|
-
label: "MongoDB",
|
|
568
|
-
supportsRelations: false,
|
|
569
|
-
supportsSubcollections: true,
|
|
570
|
-
supportsRLS: false,
|
|
571
|
-
supportsReferences: true,
|
|
572
|
-
supportsColumnTypes: false,
|
|
573
|
-
supportsRealtime: false,
|
|
574
|
-
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
575
|
-
supportsSQLAdmin: false,
|
|
576
|
-
supportsDocumentAdmin: true,
|
|
577
|
-
supportsSchemaAdmin: true
|
|
578
|
-
};
|
|
579
|
-
/**
|
|
580
|
-
* Fallback capabilities when the driver is unknown.
|
|
581
|
-
* Enables everything so nothing is hidden unexpectedly.
|
|
582
|
-
* @group Models
|
|
583
|
-
*/
|
|
584
|
-
var DEFAULT_CAPABILITIES = {
|
|
585
|
-
key: "(default)",
|
|
586
|
-
label: "Default",
|
|
587
|
-
supportsRelations: true,
|
|
588
|
-
supportsSubcollections: true,
|
|
589
|
-
supportsRLS: true,
|
|
590
|
-
supportsReferences: true,
|
|
591
|
-
supportsColumnTypes: true,
|
|
592
|
-
supportsRealtime: true,
|
|
593
|
-
filterOperators: ALL_WHERE_FILTER_OPS,
|
|
594
|
-
supportsSQLAdmin: true,
|
|
595
|
-
supportsDocumentAdmin: true,
|
|
596
|
-
supportsSchemaAdmin: true
|
|
597
|
-
};
|
|
598
|
-
var CAPABILITIES_REGISTRY = {
|
|
599
|
-
postgres: POSTGRES_CAPABILITIES,
|
|
600
|
-
firestore: FIREBASE_CAPABILITIES,
|
|
601
|
-
mongodb: MONGODB_CAPABILITIES,
|
|
602
|
-
"(default)": DEFAULT_CAPABILITIES
|
|
603
|
-
};
|
|
604
|
-
/**
|
|
605
|
-
* Look up capabilities for a given engine key.
|
|
606
|
-
* If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
|
|
607
|
-
* @group Models
|
|
608
|
-
*/
|
|
609
|
-
function getDataSourceCapabilities(engine) {
|
|
610
|
-
if (!engine) return POSTGRES_CAPABILITIES;
|
|
611
|
-
return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Register custom capabilities for a third-party driver.
|
|
615
|
-
* @group Models
|
|
616
|
-
*/
|
|
617
|
-
function registerDataSourceCapabilities(capabilities) {
|
|
618
|
-
CAPABILITIES_REGISTRY[capabilities.key] = capabilities;
|
|
619
|
-
}
|
|
620
|
-
//#endregion
|
|
621
711
|
//#region src/types/storage_source.ts
|
|
622
712
|
/**
|
|
623
713
|
* Describes a named storage backend — a place files live.
|
|
@@ -638,6 +728,98 @@ function registerDataSourceCapabilities(capabilities) {
|
|
|
638
728
|
* @group Models
|
|
639
729
|
*/
|
|
640
730
|
var DEFAULT_STORAGE_SOURCE_KEY = "(default)";
|
|
731
|
+
/**
|
|
732
|
+
* The environment-variable suffix for a storage or data source key.
|
|
733
|
+
*
|
|
734
|
+
* `""` for the default source — so a single-bucket project keeps configuring
|
|
735
|
+
* plain `S3_BUCKET` — and `__<KEY>` for every named one, uppercased with
|
|
736
|
+
* non-alphanumerics collapsed to underscores: `media-cdn` → `S3_BUCKET__MEDIA_CDN`.
|
|
737
|
+
*
|
|
738
|
+
* The rule derives the variable name from the declared key rather than
|
|
739
|
+
* discovering keys by scanning the environment. Scanning would have to guess how
|
|
740
|
+
* `S3_BUCKET__MEDIA_CDN` splits into a key; deriving cannot be ambiguous, and a
|
|
741
|
+
* typo surfaces as a missing source at boot instead of a silently ignored
|
|
742
|
+
* variable.
|
|
743
|
+
*
|
|
744
|
+
* It lives in this package, with no dependencies, because four things must agree
|
|
745
|
+
* on it exactly: the CLI (validating a build), the runtime (reading its own
|
|
746
|
+
* environment), the control plane (writing a tenant's Secret), and the docs. A
|
|
747
|
+
* second implementation of a naming convention is a second chance to disagree.
|
|
748
|
+
*
|
|
749
|
+
* @group Models
|
|
750
|
+
*/
|
|
751
|
+
function storageEnvSuffix(key, defaultKey = DEFAULT_STORAGE_SOURCE_KEY) {
|
|
752
|
+
if (!key || key === defaultKey) return "";
|
|
753
|
+
const normalized = key.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
754
|
+
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.`);
|
|
755
|
+
return `__${normalized}`;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Two distinct keys that collapse onto the same variable name, or `null`.
|
|
759
|
+
*
|
|
760
|
+
* `media-cdn` and `media_cdn` are different source keys but the same suffix, so
|
|
761
|
+
* without this one of them silently reads the other's configuration. Returns the
|
|
762
|
+
* offending pair rather than throwing, so each caller can raise it in its own
|
|
763
|
+
* idiom — a `BundleError` at boot, a build failure in the CLI, a rejected deploy
|
|
764
|
+
* in a control plane.
|
|
765
|
+
*
|
|
766
|
+
* @group Models
|
|
767
|
+
*/
|
|
768
|
+
function findStorageSuffixCollision(keys, defaultKey = DEFAULT_STORAGE_SOURCE_KEY) {
|
|
769
|
+
const seen = /* @__PURE__ */ new Map();
|
|
770
|
+
for (const key of keys) {
|
|
771
|
+
const suffix = storageEnvSuffix(key, defaultKey);
|
|
772
|
+
const existing = seen.get(suffix);
|
|
773
|
+
if (existing !== void 0 && existing !== key) return {
|
|
774
|
+
a: existing,
|
|
775
|
+
b: key,
|
|
776
|
+
suffix
|
|
777
|
+
};
|
|
778
|
+
seen.set(suffix, key);
|
|
779
|
+
}
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Merge the two places a project may declare storage sources into one list.
|
|
784
|
+
*
|
|
785
|
+
* `rebase.json` is authoritative for every field it states. Config code may add
|
|
786
|
+
* sources it does not mention and fill in fields it left out, but may not
|
|
787
|
+
* contradict it: the manifest is what a host reads to decide which buckets need
|
|
788
|
+
* configuring, and a runtime that quietly disagreed with it would put the
|
|
789
|
+
* console back to describing a topology the tenant does not have — the exact
|
|
790
|
+
* failure this whole mechanism exists to end.
|
|
791
|
+
*
|
|
792
|
+
* Note what is *not* here: no default source is invented when both inputs are
|
|
793
|
+
* empty. That decision belongs to the resolver, which knows whether declaring
|
|
794
|
+
* nothing means "one plain bucket" (it does) or "no storage at all".
|
|
795
|
+
*
|
|
796
|
+
* @group Models
|
|
797
|
+
*/
|
|
798
|
+
function normalizeStorageSources(declared, exported) {
|
|
799
|
+
const merged = /* @__PURE__ */ new Map();
|
|
800
|
+
const declaredEntries = Array.isArray(declared) ? declared.filter((d) => d?.key).map((d) => [d.key, d]) : Object.entries(declared ?? {});
|
|
801
|
+
for (const [key, config] of declaredEntries) merged.set(key, {
|
|
802
|
+
key,
|
|
803
|
+
engine: config.engine,
|
|
804
|
+
transport: config.transport ?? "server",
|
|
805
|
+
...config.label !== void 0 ? { label: config.label } : {}
|
|
806
|
+
});
|
|
807
|
+
for (const definition of exported ?? []) {
|
|
808
|
+
if (!definition?.key) continue;
|
|
809
|
+
const existing = merged.get(definition.key);
|
|
810
|
+
if (!existing) {
|
|
811
|
+
merged.set(definition.key, {
|
|
812
|
+
key: definition.key,
|
|
813
|
+
engine: definition.engine,
|
|
814
|
+
transport: definition.transport ?? "server",
|
|
815
|
+
...definition.label !== void 0 ? { label: definition.label } : {}
|
|
816
|
+
});
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
if (existing.label === void 0 && definition.label !== void 0) existing.label = definition.label;
|
|
820
|
+
}
|
|
821
|
+
return Array.from(merged.values());
|
|
822
|
+
}
|
|
641
823
|
//#endregion
|
|
642
824
|
//#region src/types/component_ref.ts
|
|
643
825
|
/**
|
|
@@ -656,8 +838,16 @@ function isLazyComponentRef(ref) {
|
|
|
656
838
|
* not read. A runtime accepts any bundle whose `bundleFormat` is less than or
|
|
657
839
|
* equal to its own — old bundles keep booting on new runtimes, which is the
|
|
658
840
|
* whole point of separating the artifact from the engine.
|
|
841
|
+
*
|
|
842
|
+
* - **1** — `mode: "cms" | "baas" | "static"`, `entry.static` a single directory
|
|
843
|
+
* string, `entry.admin` for a bundled admin panel.
|
|
844
|
+
* - **2** — `kind: "backend" | "static"`, `entry.static` a list of
|
|
845
|
+
* {@link RebaseBundleStatic}, `entry.admin` removed. A format-1 runtime reading
|
|
846
|
+
* one of these would find no `mode` and an array where it expects a string, so
|
|
847
|
+
* the bump is what turns that into a refusal to boot instead of a bundle that
|
|
848
|
+
* starts and serves nothing.
|
|
659
849
|
*/
|
|
660
|
-
var BUNDLE_FORMAT_VERSION =
|
|
850
|
+
var BUNDLE_FORMAT_VERSION = 2;
|
|
661
851
|
/**
|
|
662
852
|
* The runtime contract major.
|
|
663
853
|
*
|
|
@@ -955,6 +1145,6 @@ function isPublicStoragePath(path) {
|
|
|
955
1145
|
return p.startsWith("public/") || p.startsWith(`default/public/`);
|
|
956
1146
|
}
|
|
957
1147
|
//#endregion
|
|
958
|
-
export { ADMIN_COLLECTION_KEYS, ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, BUNDLE_FORMAT_VERSION, CANONICAL_TO_REST, DEFAULT_CAPABILITIES, DEFAULT_DATA_SOURCE_KEY, DEFAULT_LIST_LIMIT, DEFAULT_STORAGE_SOURCE_KEY, DEFAULT_VECTOR_LIST_LIMIT, EntityReference, EntityRelation, FIREBASE_CAPABILITIES, GeoPoint, MAX_LIST_LIMIT, MONGODB_CAPABILITIES, NULL_OPS, POSTGRES_CAPABILITIES, PUBLIC_STORAGE_PREFIX, REST_TO_CANONICAL, RUNTIME_CONTRACT_VERSION, RebaseApiError, RebaseClientError, SCHEMA_VERSION_HEADER, Vector, canonicalSchemaPayload, computeSchemaVersion, deserializeCollections, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, hasForeignKeyOnTarget, isBranchAdmin, isChannelBusInstance, isDocumentAdmin, isFirebaseCollectionConfig, isLazyComponentRef, isManyToMany, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStoragePath, isSQLAdmin, isSchemaAdmin, isSerializedCollectionRef, isToMany, policy, registerDataSourceCapabilities, resolveClientListLimit, serializeCollections, toCanonicalOp };
|
|
1148
|
+
export { ADMIN_COLLECTION_KEYS, ADMIN_PROPERTY_KEYS, ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, BUNDLE_FORMAT_VERSION, CANONICAL_TO_REST, DEFAULT_CAPABILITIES, DEFAULT_DATA_SOURCE_KEY, DEFAULT_FILTERABLE_RELATION_KINDS, DEFAULT_LIST_LIMIT, DEFAULT_STORAGE_SOURCE_KEY, DEFAULT_VECTOR_LIST_LIMIT, EntityReference, EntityRelation, FIREBASE_CAPABILITIES, GeoPoint, MAX_LIST_LIMIT, MONGODB_CAPABILITIES, NULL_OPS, POSTGRES_CAPABILITIES, PUBLIC_STORAGE_PREFIX, REST_TO_CANONICAL, RUNTIME_CONTRACT_VERSION, RebaseApiError, RebaseClientError, SCHEMA_VERSION_HEADER, Vector, canonicalSchemaPayload, computeSchemaVersion, deserializeCollections, findStorageSuffixCollision, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, hasForeignKeyOnTarget, isBranchAdmin, isChannelBusInstance, isDocumentAdmin, isFirebaseCollectionConfig, isLazyComponentRef, isManyToMany, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStoragePath, isRelationalCollectionConfig, isSQLAdmin, isSchemaAdmin, isSerializedCollectionRef, isToMany, normalizeStorageSources, policy, registerDataSourceCapabilities, resolveClientListLimit, serializeCollections, storageEnvSuffix, toCanonicalOp };
|
|
959
1149
|
|
|
960
1150
|
//# sourceMappingURL=index.es.js.map
|