@rebasepro/types 0.10.1-canary.6f89f77 → 0.10.1-canary.7801eed
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/call_context.d.ts +51 -0
- package/dist/controllers/auth_state.d.ts +23 -0
- package/dist/controllers/collection_registry.d.ts +5 -1
- package/dist/controllers/data.d.ts +17 -11
- package/dist/controllers/data_driver.d.ts +2 -2
- package/dist/controllers/index.d.ts +1 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +361 -1
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +34 -0
- package/dist/types/backend.d.ts +53 -1
- package/dist/types/channel_bus.d.ts +192 -0
- package/dist/types/collection_contract.d.ts +43 -0
- package/dist/types/collections.d.ts +57 -773
- package/dist/types/component_ref.d.ts +39 -6
- package/dist/types/entity_callbacks.d.ts +1 -1
- package/dist/types/filter-operators.d.ts +18 -0
- package/dist/types/index.d.ts +7 -15
- package/dist/types/project_manifest.d.ts +336 -0
- package/dist/types/properties.d.ts +37 -230
- package/dist/types/relations.d.ts +231 -247
- package/dist/types/schema_version.d.ts +18 -0
- package/dist/types/security_rules.d.ts +320 -0
- package/dist/types/storage_authorize.d.ts +74 -0
- package/package.json +3 -6
- package/src/call_context.ts +56 -0
- package/src/controllers/auth_state.ts +24 -0
- package/src/controllers/collection_registry.ts +5 -1
- package/src/controllers/data.ts +17 -11
- package/src/controllers/data_driver.ts +2 -2
- package/src/controllers/index.ts +1 -10
- package/src/index.ts +1 -1
- package/src/types/admin_block.ts +75 -0
- package/src/types/backend.ts +57 -1
- package/src/types/channel_bus.ts +202 -0
- package/src/types/collection_contract.ts +278 -0
- package/src/types/collections.ts +69 -832
- package/src/types/component_ref.ts +40 -6
- package/src/types/entity_callbacks.ts +1 -1
- package/src/types/filter-operators.ts +21 -0
- package/src/types/index.ts +7 -15
- package/src/types/policy.ts +25 -11
- package/src/types/project_manifest.ts +362 -0
- package/src/types/properties.ts +36 -260
- package/src/types/relations.ts +264 -249
- package/src/types/schema_version.ts +112 -0
- package/src/types/security_rules.ts +344 -0
- package/src/types/storage_authorize.ts +77 -0
- package/dist/controllers/analytics_controller.d.ts +0 -7
- package/dist/controllers/auth.d.ts +0 -110
- package/dist/controllers/customization_controller.d.ts +0 -61
- package/dist/controllers/dialogs_controller.d.ts +0 -36
- package/dist/controllers/local_config_persistence.d.ts +0 -20
- package/dist/controllers/navigation.d.ts +0 -225
- package/dist/controllers/registry.d.ts +0 -80
- package/dist/controllers/side_dialogs_controller.d.ts +0 -67
- package/dist/controllers/side_panel_controller.d.ts +0 -97
- package/dist/controllers/snackbar.d.ts +0 -24
- package/dist/rebase_context.d.ts +0 -110
- package/dist/types/breadcrumbs.d.ts +0 -26
- package/dist/types/builders.d.ts +0 -15
- package/dist/types/component_overrides.d.ts +0 -196
- package/dist/types/entity_actions.d.ts +0 -104
- package/dist/types/entity_link_builder.d.ts +0 -7
- package/dist/types/entity_views.d.ts +0 -95
- package/dist/types/export_import.d.ts +0 -21
- package/dist/types/formex.d.ts +0 -40
- package/dist/types/locales.d.ts +0 -4
- package/dist/types/modify_collections.d.ts +0 -5
- package/dist/types/plugins.d.ts +0 -277
- package/dist/types/property_config.d.ts +0 -74
- package/dist/types/slots.d.ts +0 -262
- package/dist/types/translations.d.ts +0 -915
- package/dist/types/user_management_delegate.d.ts +0 -22
- package/src/controllers/analytics_controller.tsx +0 -57
- package/src/controllers/auth.tsx +0 -121
- package/src/controllers/customization_controller.tsx +0 -72
- package/src/controllers/dialogs_controller.tsx +0 -37
- package/src/controllers/local_config_persistence.tsx +0 -22
- package/src/controllers/navigation.ts +0 -267
- package/src/controllers/registry.ts +0 -95
- package/src/controllers/side_dialogs_controller.tsx +0 -82
- package/src/controllers/side_panel_controller.tsx +0 -112
- package/src/controllers/snackbar.ts +0 -29
- package/src/rebase_context.tsx +0 -130
- package/src/types/breadcrumbs.ts +0 -27
- package/src/types/builders.ts +0 -17
- package/src/types/component_overrides.ts +0 -244
- package/src/types/entity_actions.tsx +0 -125
- package/src/types/entity_link_builder.ts +0 -8
- package/src/types/entity_views.tsx +0 -114
- package/src/types/export_import.ts +0 -26
- package/src/types/formex.ts +0 -45
- package/src/types/locales.ts +0 -81
- package/src/types/modify_collections.tsx +0 -6
- package/src/types/plugins.tsx +0 -346
- package/src/types/property_config.tsx +0 -95
- package/src/types/slots.tsx +0 -307
- package/src/types/translations.ts +0 -1026
- package/src/types/user_management_delegate.ts +0 -23
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { StorageSource } from "./controllers/storage";
|
|
2
|
+
import type { RebaseClient } from "./controllers/client";
|
|
3
|
+
import type { RebaseSdkData } from "./controllers/data";
|
|
4
|
+
import type { User } from "./users";
|
|
5
|
+
/**
|
|
6
|
+
* Context that is provided to entity callbacks (hooks).
|
|
7
|
+
* It contains only the dependencies that are available in both the frontend and the backend.
|
|
8
|
+
*
|
|
9
|
+
* This is the *whole* context a collection callback gets, and it lives apart from
|
|
10
|
+
* {@link RebaseContext} on purpose. `RebaseContext` widens it with nine admin-panel
|
|
11
|
+
* controllers — navigation, side dialogs, snackbars — none of which exist in a
|
|
12
|
+
* backend process. Keeping them in one type meant every backend module that
|
|
13
|
+
* touched a callback signature transitively named the admin UI.
|
|
14
|
+
*
|
|
15
|
+
* @group Hooks and utilities
|
|
16
|
+
*/
|
|
17
|
+
export type RebaseCallContext<USER extends User = User> = {
|
|
18
|
+
/**
|
|
19
|
+
* The Rebase client instance.
|
|
20
|
+
* Available in all entity callbacks (beforeSave, afterSave, afterRead,
|
|
21
|
+
* beforeDelete, afterDelete) and in CollectionActionsProps via context.
|
|
22
|
+
* Use it to call backend functions, access data, storage, etc.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // In a beforeSave callback:
|
|
26
|
+
* const result = await context.client.functions.invoke('my-function', { ... });
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // In a CollectionAction component:
|
|
30
|
+
* const { client } = props.context;
|
|
31
|
+
* const result = await client.functions.invoke('extract-job', { url });
|
|
32
|
+
*/
|
|
33
|
+
client: RebaseClient;
|
|
34
|
+
/**
|
|
35
|
+
* Unified data access — `context.data.products.create(...)`.
|
|
36
|
+
* Access any collection as a dynamic property.
|
|
37
|
+
*
|
|
38
|
+
* Returns flat rows (`{ id, ...columns }`), identical to the frontend SDK
|
|
39
|
+
* client — so `context.data` in a backend callback and `client.data` in the
|
|
40
|
+
* frontend behave the same way (`row.title`, never `row.values.title`).
|
|
41
|
+
*/
|
|
42
|
+
data: RebaseSdkData;
|
|
43
|
+
/**
|
|
44
|
+
* Used storage implementation
|
|
45
|
+
*/
|
|
46
|
+
storageSource: StorageSource;
|
|
47
|
+
/**
|
|
48
|
+
* Set by the backend when callbacks are executed on the server.
|
|
49
|
+
*/
|
|
50
|
+
user?: USER;
|
|
51
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { User } from "../users";
|
|
2
|
+
/**
|
|
3
|
+
* The read-only slice of authentication state that property resolution needs.
|
|
4
|
+
*
|
|
5
|
+
* `dynamicProps`, `conditions` and the JSON-Logic condition context all want the
|
|
6
|
+
* same one thing: who is asking. They used to be handed the entire
|
|
7
|
+
* {@link AuthController} — `signOut`, `googleLogin`, `authLoading`, thirty-odd
|
|
8
|
+
* members of frontend machinery — which meant `properties.ts` named a frontend
|
|
9
|
+
* controller, and so did `resolveProperty` in `@rebasepro/common`, which the
|
|
10
|
+
* Postgres schema generator calls at build time. A backend generating DDL had to
|
|
11
|
+
* satisfy a type with a login method in it.
|
|
12
|
+
*
|
|
13
|
+
* `User` already carries `roles` and `metadata`, so this is not a reduction in
|
|
14
|
+
* what a dynamic property can decide on — only in what it has to be given.
|
|
15
|
+
* An `AuthController` satisfies this structurally, so the frontend passes the
|
|
16
|
+
* controller it already has.
|
|
17
|
+
*
|
|
18
|
+
* @group Hooks and utilities
|
|
19
|
+
*/
|
|
20
|
+
export interface AuthState<USER extends User = User> {
|
|
21
|
+
/** The signed-in user, or `null` when nobody is. */
|
|
22
|
+
user: USER | null;
|
|
23
|
+
}
|
|
@@ -10,8 +10,12 @@ export type CollectionRegistryController<DB = Record<string, unknown>, EC extend
|
|
|
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.
|
|
13
|
+
*
|
|
14
|
+
* `EC`, like {@link getCollection} — this was hardcoded to `CollectionConfig`
|
|
15
|
+
* while `getCollection` honoured the parameter, so the admin panel got its
|
|
16
|
+
* view model from one and the raw contract from the other.
|
|
13
17
|
*/
|
|
14
|
-
collections?:
|
|
18
|
+
collections?: EC[];
|
|
15
19
|
/**
|
|
16
20
|
* Is the registry ready to be used
|
|
17
21
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Entity, EntityValues } from "../types/entities";
|
|
2
|
-
import { WhereFilterOp, FilterValues, OrderByTuple } from "../types/filter-operators";
|
|
2
|
+
import { WhereFilterOp, FieldPath, FilterValues, OrderByTuple } from "../types/filter-operators";
|
|
3
3
|
export type WhereValue<T> = T | T[] | null;
|
|
4
4
|
export interface LogicalCondition {
|
|
5
5
|
type: "and" | "or";
|
|
@@ -39,7 +39,7 @@ export interface FilterCondition {
|
|
|
39
39
|
*
|
|
40
40
|
* @group Data
|
|
41
41
|
*/
|
|
42
|
-
export interface FindParams {
|
|
42
|
+
export interface FindParams<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
43
43
|
/** Maximum number of items to return (default: 20). */
|
|
44
44
|
limit?: number;
|
|
45
45
|
/**
|
|
@@ -65,7 +65,7 @@ export interface FindParams {
|
|
|
65
65
|
* { role: ["in", ["admin", "editor"]] }
|
|
66
66
|
* { age: [[">=", 18], ["<", 65]] }
|
|
67
67
|
*/
|
|
68
|
-
where?: FilterValues<
|
|
68
|
+
where?: FilterValues<FieldPath<M>>;
|
|
69
69
|
/**
|
|
70
70
|
* Logical grouping conditions (AND/OR). Use this for anything `where`
|
|
71
71
|
* can't express — notably OR-ing conditions. AND-ed with `where` and
|
|
@@ -76,8 +76,14 @@ export interface FindParams {
|
|
|
76
76
|
* Sort order as a `[field, direction]` tuple.
|
|
77
77
|
* @example orderBy: ["created_at", "desc"]
|
|
78
78
|
*/
|
|
79
|
-
orderBy?: OrderByTuple
|
|
80
|
-
/**
|
|
79
|
+
orderBy?: OrderByTuple<FieldPath<M>>;
|
|
80
|
+
/**
|
|
81
|
+
* Relations to include in the response.
|
|
82
|
+
*
|
|
83
|
+
* Deliberately `string[]` and not checked against `M`: a relation name
|
|
84
|
+
* comes from the collection's `relations`, not from its columns, so nothing
|
|
85
|
+
* in a generated row type can validate one.
|
|
86
|
+
*/
|
|
81
87
|
include?: string[];
|
|
82
88
|
/**
|
|
83
89
|
* Full-text search string. Matched (OR-ed) across the collection's
|
|
@@ -137,7 +143,7 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
137
143
|
/**
|
|
138
144
|
* Find multiple records with optional filtering, pagination, and sorting.
|
|
139
145
|
*/
|
|
140
|
-
find(params?: FindParams): Promise<FindResponse<M>>;
|
|
146
|
+
find(params?: FindParams<M>): Promise<FindResponse<M>>;
|
|
141
147
|
/**
|
|
142
148
|
* Find a single record by its ID.
|
|
143
149
|
*/
|
|
@@ -171,7 +177,7 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
171
177
|
* Subscribe to a collection for real-time updates.
|
|
172
178
|
* Optional method, may not be supported by all implementations (like stateless HTTP clients).
|
|
173
179
|
*/
|
|
174
|
-
listen?(params: FindParams | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
|
|
180
|
+
listen?(params: FindParams<M> | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
|
|
175
181
|
/**
|
|
176
182
|
* Subscribe to a single record for real-time updates.
|
|
177
183
|
* Optional method.
|
|
@@ -180,7 +186,7 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
180
186
|
/**
|
|
181
187
|
* Count the number of records matching the given filter.
|
|
182
188
|
*/
|
|
183
|
-
count?(params?: FindParams): Promise<number>;
|
|
189
|
+
count?(params?: FindParams<M>): Promise<number>;
|
|
184
190
|
where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): QueryBuilderInterface<M>;
|
|
185
191
|
where(logicalCondition: LogicalCondition): QueryBuilderInterface<M>;
|
|
186
192
|
orderBy(column: keyof M & string, direction?: "asc" | "desc"): QueryBuilderInterface<M>;
|
|
@@ -263,7 +269,7 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
263
269
|
/**
|
|
264
270
|
* Find multiple records with optional filtering, pagination, and sorting.
|
|
265
271
|
*/
|
|
266
|
-
find(params?: FindParams): Promise<FindResult<M>>;
|
|
272
|
+
find(params?: FindParams<M>): Promise<FindResult<M>>;
|
|
267
273
|
/**
|
|
268
274
|
* Find a single record by its ID.
|
|
269
275
|
*/
|
|
@@ -323,7 +329,7 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
323
329
|
/**
|
|
324
330
|
* Subscribe to a collection for real-time updates.
|
|
325
331
|
*/
|
|
326
|
-
listen?(params: FindParams | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
332
|
+
listen?(params: FindParams<M> | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
327
333
|
/**
|
|
328
334
|
* Subscribe to a single record for real-time updates.
|
|
329
335
|
*/
|
|
@@ -331,7 +337,7 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
331
337
|
/**
|
|
332
338
|
* Count the number of records matching the given filter.
|
|
333
339
|
*/
|
|
334
|
-
count?(params?: FindParams): Promise<number>;
|
|
340
|
+
count?(params?: FindParams<M>): Promise<number>;
|
|
335
341
|
where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): SDKQueryBuilderInterface<M>;
|
|
336
342
|
where(logicalCondition: LogicalCondition): SDKQueryBuilderInterface<M>;
|
|
337
343
|
orderBy(column: keyof M & string, direction?: "asc" | "desc"): SDKQueryBuilderInterface<M>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EntityStatus, EntityValues } from "../types/entities";
|
|
2
2
|
import type { CollectionConfig, FilterValues } from "../types/collections";
|
|
3
|
-
import type {
|
|
3
|
+
import type { RebaseCallContext } from "../call_context";
|
|
4
4
|
/**
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
@@ -240,7 +240,7 @@ export interface DataDriver {
|
|
|
240
240
|
delegateToCMSModel?: (data: unknown) => unknown;
|
|
241
241
|
cmsToDelegateModel?: (data: unknown) => unknown;
|
|
242
242
|
initTextSearch?: (props: {
|
|
243
|
-
context:
|
|
243
|
+
context: RebaseCallContext;
|
|
244
244
|
path: string;
|
|
245
245
|
databaseId?: string;
|
|
246
246
|
collection: CollectionConfig;
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
export * from "./collection_registry";
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./auth";
|
|
2
|
+
export * from "./auth_state";
|
|
4
3
|
export * from "./data";
|
|
5
4
|
export * from "./database_admin";
|
|
6
5
|
export * from "./data_driver";
|
|
7
|
-
export * from "./local_config_persistence";
|
|
8
|
-
export * from "./navigation";
|
|
9
6
|
export * from "./effective_role";
|
|
10
7
|
export * from "./storage";
|
|
11
8
|
export * from "./email";
|
|
12
9
|
export * from "./client";
|
|
13
|
-
export * from "./customization_controller";
|
|
14
|
-
export * from "./side_panel_controller";
|
|
15
|
-
export * from "./side_dialogs_controller";
|
|
16
|
-
export * from "./dialogs_controller";
|
|
17
|
-
export * from "./snackbar";
|
|
18
|
-
export * from "./registry";
|
package/dist/index.d.ts
CHANGED
package/dist/index.es.js
CHANGED
|
@@ -264,10 +264,90 @@ function toCanonicalOp(op) {
|
|
|
264
264
|
return REST_TO_CANONICAL[op];
|
|
265
265
|
}
|
|
266
266
|
//#endregion
|
|
267
|
+
//#region src/types/admin_block.ts
|
|
268
|
+
/**
|
|
269
|
+
* The keys of a collection's admin block, as data.
|
|
270
|
+
*
|
|
271
|
+
* There is no *type* for the block in this package any more, and that is the point:
|
|
272
|
+
* `admin` is not declared on `BaseCollectionConfig` or on any property here, so a
|
|
273
|
+
* BaaS install cannot even write one. `@rebasepro/admin-types` adds the field back by
|
|
274
|
+
* declaration merging, which is why installing it is what makes the admin surface
|
|
275
|
+
* appear.
|
|
276
|
+
*
|
|
277
|
+
* The *list* still has to live here, because three runtime consumers need it and two
|
|
278
|
+
* of them are core — see below.
|
|
279
|
+
*/
|
|
280
|
+
/**
|
|
281
|
+
* Every key that belongs inside a collection's `admin` block, as data.
|
|
282
|
+
*
|
|
283
|
+
* The type that describes these fields is `AdminCollectionOptions` in
|
|
284
|
+
* `@rebasepro/admin-types`, and it is erased at build time — but three runtime
|
|
285
|
+
* consumers need the list, and two of them are core:
|
|
286
|
+
*
|
|
287
|
+
* - `serializeCollections`, to drop the block from the contract
|
|
288
|
+
* - the ts-morph schema editor in `@rebasepro/server`, which rewrites collection
|
|
289
|
+
* files on disk from the admin panel and has to know where each key goes. A key
|
|
290
|
+
* missing from this list gets written to the *top level* of the file, where the
|
|
291
|
+
* backend ignores it and the panel never finds it again.
|
|
292
|
+
* - the `collections-admin-block` codemod
|
|
293
|
+
*
|
|
294
|
+
* `@rebasepro/admin-types` re-exports this and asserts it names only real option
|
|
295
|
+
* keys; the count is pinned by a test there.
|
|
296
|
+
*
|
|
297
|
+
* @group Models
|
|
298
|
+
*/
|
|
299
|
+
var ADMIN_COLLECTION_KEYS = [
|
|
300
|
+
"Actions",
|
|
301
|
+
"additionalFields",
|
|
302
|
+
"alwaysApplyDefaultValues",
|
|
303
|
+
"components",
|
|
304
|
+
"defaultEntityAction",
|
|
305
|
+
"defaultFilter",
|
|
306
|
+
"defaultSelectedView",
|
|
307
|
+
"defaultSize",
|
|
308
|
+
"defaultViewMode",
|
|
309
|
+
"disableDefaultActions",
|
|
310
|
+
"enabledViews",
|
|
311
|
+
"entityActions",
|
|
312
|
+
"entityViews",
|
|
313
|
+
"exportable",
|
|
314
|
+
"filterPresets",
|
|
315
|
+
"fixedFilter",
|
|
316
|
+
"formAutoSave",
|
|
317
|
+
"formView",
|
|
318
|
+
"group",
|
|
319
|
+
"hideFromNavigation",
|
|
320
|
+
"hideIdFromCollection",
|
|
321
|
+
"hideIdFromForm",
|
|
322
|
+
"icon",
|
|
323
|
+
"includeJsonView",
|
|
324
|
+
"inlineEditing",
|
|
325
|
+
"kanban",
|
|
326
|
+
"listProperties",
|
|
327
|
+
"localChangesBackup",
|
|
328
|
+
"openEntityMode",
|
|
329
|
+
"orderProperty",
|
|
330
|
+
"pagination",
|
|
331
|
+
"previewProperties",
|
|
332
|
+
"propertiesOrder",
|
|
333
|
+
"selectionController",
|
|
334
|
+
"selectionEnabled",
|
|
335
|
+
"sideDialogWidth",
|
|
336
|
+
"sort",
|
|
337
|
+
"titleProperty"
|
|
338
|
+
];
|
|
339
|
+
//#endregion
|
|
267
340
|
//#region src/types/collections.ts
|
|
268
341
|
/**
|
|
269
342
|
* Type guard for PostgreSQL collections.
|
|
270
343
|
* Returns true if the collection uses the Postgres engine (or the default engine).
|
|
344
|
+
*
|
|
345
|
+
* Generic over the *input* type, and narrows by intersection rather than
|
|
346
|
+
* replacement. Narrowing to a bare `PostgresCollectionConfig` discarded whatever
|
|
347
|
+
* the caller actually had — most visibly the admin panel's view model, whose
|
|
348
|
+
* flattened presentation fields vanished the moment a collection passed through
|
|
349
|
+
* one of these guards.
|
|
350
|
+
*
|
|
271
351
|
* @group Models
|
|
272
352
|
*/
|
|
273
353
|
function isPostgresCollectionConfig(collection) {
|
|
@@ -311,6 +391,20 @@ function getDeclaredSubcollections(collection) {
|
|
|
311
391
|
return collection.subcollections;
|
|
312
392
|
}
|
|
313
393
|
//#endregion
|
|
394
|
+
//#region src/types/relations.ts
|
|
395
|
+
/** @group Models */
|
|
396
|
+
function hasForeignKeyOnTarget(relation) {
|
|
397
|
+
return relation.kind === "hasOne" || relation.kind === "hasMany";
|
|
398
|
+
}
|
|
399
|
+
/** @group Models */
|
|
400
|
+
function isManyToMany(relation) {
|
|
401
|
+
return relation.kind === "manyToMany";
|
|
402
|
+
}
|
|
403
|
+
/** @group Models */
|
|
404
|
+
function isToMany(relation) {
|
|
405
|
+
return relation.cardinality === "many";
|
|
406
|
+
}
|
|
407
|
+
//#endregion
|
|
314
408
|
//#region src/types/policy.ts
|
|
315
409
|
/**
|
|
316
410
|
* The id a request without a logged-in user reports as `auth.uid()`.
|
|
@@ -416,6 +510,19 @@ function isBranchAdmin(admin) {
|
|
|
416
510
|
return !!admin && typeof admin.createBranch === "function";
|
|
417
511
|
}
|
|
418
512
|
//#endregion
|
|
513
|
+
//#region src/types/channel_bus.ts
|
|
514
|
+
/**
|
|
515
|
+
* Whether `setting` is an already-constructed transport rather than a request
|
|
516
|
+
* for a built-in one.
|
|
517
|
+
*
|
|
518
|
+
* Structural rather than nominal so that an instance from a *different copy* of
|
|
519
|
+
* `@rebasepro/types` — an entirely normal outcome of a separately versioned
|
|
520
|
+
* transport package — is still recognised.
|
|
521
|
+
*/
|
|
522
|
+
function isChannelBusInstance(setting) {
|
|
523
|
+
return typeof setting?.publish === "function";
|
|
524
|
+
}
|
|
525
|
+
//#endregion
|
|
419
526
|
//#region src/types/data_source.ts
|
|
420
527
|
/**
|
|
421
528
|
* The default data-source key, used when a collection does not name a
|
|
@@ -541,6 +648,259 @@ function isLazyComponentRef(ref) {
|
|
|
541
648
|
return typeof ref === "object" && ref !== null && "__rebaseLazy" in ref && ref.__rebaseLazy === true;
|
|
542
649
|
}
|
|
543
650
|
//#endregion
|
|
651
|
+
//#region src/types/project_manifest.ts
|
|
652
|
+
/**
|
|
653
|
+
* Version of the bundle *format* itself.
|
|
654
|
+
*
|
|
655
|
+
* Bumped only when the on-disk layout changes in a way an older runtime could
|
|
656
|
+
* not read. A runtime accepts any bundle whose `bundleFormat` is less than or
|
|
657
|
+
* equal to its own — old bundles keep booting on new runtimes, which is the
|
|
658
|
+
* whole point of separating the artifact from the engine.
|
|
659
|
+
*/
|
|
660
|
+
var BUNDLE_FORMAT_VERSION = 1;
|
|
661
|
+
/**
|
|
662
|
+
* The runtime contract major.
|
|
663
|
+
*
|
|
664
|
+
* Distinct from the `@rebasepro/server` package version: the package may release
|
|
665
|
+
* any number of minors and patches while this stays put. It changes only when
|
|
666
|
+
* the bundle/runtime contract breaks compatibility, and a project's
|
|
667
|
+
* `manifest.runtime` range is matched against *this*.
|
|
668
|
+
*/
|
|
669
|
+
var RUNTIME_CONTRACT_VERSION = 1;
|
|
670
|
+
/** Header carrying the schema version an SDK was generated from. */
|
|
671
|
+
var SCHEMA_VERSION_HEADER = "x-rebase-schema";
|
|
672
|
+
//#endregion
|
|
673
|
+
//#region src/types/collection_contract.ts
|
|
674
|
+
function isSerializedCollectionRef(value) {
|
|
675
|
+
return typeof value === "object" && value !== null && typeof value.__collectionRef === "string";
|
|
676
|
+
}
|
|
677
|
+
/** Depth limit for the walk — deep enough for real configs, finite for cyclic ones. */
|
|
678
|
+
var MAX_DEPTH = 64;
|
|
679
|
+
/**
|
|
680
|
+
* Resolve whatever a `target` thunk returns down to a collection.
|
|
681
|
+
*
|
|
682
|
+
* A target may be the collection, a module namespace (when the authoring file
|
|
683
|
+
* used `import * as`), or a default-export wrapper. All three appear in real
|
|
684
|
+
* projects, and the SDK generator already unwraps them the same way.
|
|
685
|
+
*/
|
|
686
|
+
function unwrapTarget(value) {
|
|
687
|
+
if (!value || typeof value !== "object") return void 0;
|
|
688
|
+
const candidate = value;
|
|
689
|
+
if (candidate.default || candidate.__esModule) {
|
|
690
|
+
const inner = candidate.default;
|
|
691
|
+
if (inner && typeof inner === "object") return inner;
|
|
692
|
+
}
|
|
693
|
+
if (candidate.properties) return value;
|
|
694
|
+
}
|
|
695
|
+
/** The identity a serialized reference uses. Slug first — it is the routing key. */
|
|
696
|
+
function refFor(collection) {
|
|
697
|
+
if (!collection) return void 0;
|
|
698
|
+
const withPath = collection;
|
|
699
|
+
return collection.slug || withPath.path || collection.name;
|
|
700
|
+
}
|
|
701
|
+
function toSerializable(value, seen, depth, state, key) {
|
|
702
|
+
if (depth > MAX_DEPTH) {
|
|
703
|
+
state.truncations++;
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
if (typeof value === "function") {
|
|
707
|
+
if (key === "target") try {
|
|
708
|
+
const ref = refFor(unwrapTarget(value()));
|
|
709
|
+
return ref ? { __collectionRef: ref } : void 0;
|
|
710
|
+
} catch {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (value === null || typeof value !== "object") return value;
|
|
716
|
+
if (value instanceof Date) return value.toISOString();
|
|
717
|
+
if (value instanceof RegExp) return value.source;
|
|
718
|
+
if (seen.has(value)) {
|
|
719
|
+
state.truncations++;
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const cached = state.memo.get(value);
|
|
723
|
+
if (cached !== void 0) return cached;
|
|
724
|
+
seen.add(value);
|
|
725
|
+
const truncationsBefore = state.truncations;
|
|
726
|
+
const memoize = (result) => {
|
|
727
|
+
if (result !== void 0 && state.truncations === truncationsBefore) state.memo.set(value, result);
|
|
728
|
+
return result;
|
|
729
|
+
};
|
|
730
|
+
try {
|
|
731
|
+
if (Array.isArray(value)) {
|
|
732
|
+
const items = value.map((item) => toSerializable(item, seen, depth + 1, state)).filter((item) => item !== void 0);
|
|
733
|
+
return memoize(value.length > 0 && items.length === 0 ? void 0 : items);
|
|
734
|
+
}
|
|
735
|
+
if ("$$typeof" in value) return void 0;
|
|
736
|
+
const entries = Object.entries(value);
|
|
737
|
+
const out = {};
|
|
738
|
+
for (const [k, v] of entries) {
|
|
739
|
+
const converted = toSerializable(v, seen, depth + 1, state, k);
|
|
740
|
+
if (converted !== void 0) out[k] = converted;
|
|
741
|
+
}
|
|
742
|
+
if (entries.length > 0 && Object.keys(out).length === 0) return void 0;
|
|
743
|
+
return memoize(out);
|
|
744
|
+
} finally {
|
|
745
|
+
seen.delete(value);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Serialize collections for transport over the contract endpoint.
|
|
750
|
+
*
|
|
751
|
+
* Sorted by slug so the output — and therefore the schema hash computed from it
|
|
752
|
+
* — does not depend on filesystem ordering.
|
|
753
|
+
*/
|
|
754
|
+
function serializeCollections(collections) {
|
|
755
|
+
return [...collections].sort((a, b) => String(a.slug ?? "").localeCompare(String(b.slug ?? ""))).map((collection) => toSerializable(withoutAdminBlock(collection), /* @__PURE__ */ new WeakSet(), 0, {
|
|
756
|
+
memo: /* @__PURE__ */ new WeakMap(),
|
|
757
|
+
truncations: 0
|
|
758
|
+
})).filter((c) => c !== void 0);
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Drop the admin block before the walk.
|
|
762
|
+
*
|
|
763
|
+
* Nothing downstream of serialization is an admin panel. The contract endpoint
|
|
764
|
+
* feeds remote SDK generation, and `rebase build` writes the result into a bundle
|
|
765
|
+
* manifest that only the backend runtime reads. The block would survive the walk
|
|
766
|
+
* as a husk anyway — its React elements and component functions are dropped
|
|
767
|
+
* individually — and that husk has two costs worth avoiding: it puts every custom
|
|
768
|
+
* component's *file path* on an endpoint whose job is to describe data shapes, and
|
|
769
|
+
* it grows a payload that is fetched and cached per project.
|
|
770
|
+
*
|
|
771
|
+
* Removing it here rather than at each call site means one chokepoint, so a future
|
|
772
|
+
* consumer of `serializeCollections` cannot forget.
|
|
773
|
+
*
|
|
774
|
+
* Child collections carry their own block, so this recurses — stripping only the
|
|
775
|
+
* top level was the mistake `stripNonClientFields` in the contract routes already
|
|
776
|
+
* had to fix once for security rules.
|
|
777
|
+
*/
|
|
778
|
+
function withoutAdminBlock(collection) {
|
|
779
|
+
const { admin: _admin, ...rest } = collection;
|
|
780
|
+
const nested = rest;
|
|
781
|
+
if (Array.isArray(nested.subcollections)) nested.subcollections = nested.subcollections.map((child) => withoutAdminBlock(child));
|
|
782
|
+
return rest;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Rebuild collections received from a contract endpoint.
|
|
786
|
+
*
|
|
787
|
+
* Relation refs become real thunks resolving through the returned set, so
|
|
788
|
+
* downstream consumers — the SDK generator above all — see exactly the shape
|
|
789
|
+
* they would have seen had the collections been imported from source.
|
|
790
|
+
*
|
|
791
|
+
* A ref naming a collection that is not in the payload resolves to `undefined`
|
|
792
|
+
* rather than throwing: the generator already tolerates an unresolvable target
|
|
793
|
+
* by falling back to a permissive key type, and a partial contract should still
|
|
794
|
+
* produce a usable SDK.
|
|
795
|
+
*/
|
|
796
|
+
function deserializeCollections(payload) {
|
|
797
|
+
const collections = payload.filter((c) => typeof c === "object" && c !== null).map((c) => ({ ...c }));
|
|
798
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
799
|
+
for (const collection of collections) {
|
|
800
|
+
const ref = refFor(collection);
|
|
801
|
+
if (ref) bySlug.set(ref, collection);
|
|
802
|
+
}
|
|
803
|
+
const rehydrate = (value, depth) => {
|
|
804
|
+
if (depth > MAX_DEPTH || !value || typeof value !== "object") return;
|
|
805
|
+
if (Array.isArray(value)) {
|
|
806
|
+
for (const item of value) rehydrate(item, depth + 1);
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const record = value;
|
|
810
|
+
for (const [key, child] of Object.entries(record)) {
|
|
811
|
+
if (key === "target" && isSerializedCollectionRef(child)) {
|
|
812
|
+
const slug = child.__collectionRef;
|
|
813
|
+
record.target = () => bySlug.get(slug);
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
rehydrate(child, depth + 1);
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
for (const collection of collections) rehydrate(collection, 0);
|
|
820
|
+
return collections;
|
|
821
|
+
}
|
|
822
|
+
//#endregion
|
|
823
|
+
//#region src/types/schema_version.ts
|
|
824
|
+
/**
|
|
825
|
+
* The schema version stamp.
|
|
826
|
+
*
|
|
827
|
+
* One function, used in three places that must agree or the whole drift-detection
|
|
828
|
+
* story is noise: `rebase build` writes it into a bundle manifest, the runtime
|
|
829
|
+
* serves it from the contract endpoint, and a generated SDK records the value it
|
|
830
|
+
* was built from. If any two of those computed it differently, every client would
|
|
831
|
+
* look permanently out of date.
|
|
832
|
+
*
|
|
833
|
+
* It covers **collections only** — the client's contract is the shape of the
|
|
834
|
+
* data, so editing a hook or a server function must not invalidate every SDK in
|
|
835
|
+
* every repository. That is a deliberate narrowing, not an oversight.
|
|
836
|
+
*/
|
|
837
|
+
/** Stable stringify: object keys sorted at every level, so key order cannot alter the hash. */
|
|
838
|
+
function canonicalize(value) {
|
|
839
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
840
|
+
if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
|
|
841
|
+
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(",")}}`;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Reduce a collection to the parts a generated client is actually built from.
|
|
845
|
+
*
|
|
846
|
+
* The version answers one question — "is this SDK stale?" — so it must change
|
|
847
|
+
* exactly when the generated types could change, and never otherwise. Hashing a
|
|
848
|
+
* whole collection fails both halves of that:
|
|
849
|
+
*
|
|
850
|
+
* - Security rules, callbacks, icons, groups and UI settings do not appear in a
|
|
851
|
+
* generated client, so including them reports perfectly current SDKs as stale.
|
|
852
|
+
* - Worse, they are not stable *inputs*. The runtime applies default security
|
|
853
|
+
* rules when it loads collections, so the same source hashed before and after
|
|
854
|
+
* loading produced two different answers — a build-time stamp that could never
|
|
855
|
+
* match the server that served it.
|
|
856
|
+
*
|
|
857
|
+
* Codegen reads the slug (for the `Database` key and type names), the properties,
|
|
858
|
+
* and the relations. That is the projection.
|
|
859
|
+
*/
|
|
860
|
+
function projectForCodegen(collection) {
|
|
861
|
+
const source = collection;
|
|
862
|
+
return {
|
|
863
|
+
slug: collection.slug ?? source.path,
|
|
864
|
+
properties: collection.properties,
|
|
865
|
+
relations: source.relations,
|
|
866
|
+
engine: source.engine,
|
|
867
|
+
dataSource: source.dataSource,
|
|
868
|
+
subcollections: source.subcollections?.map(projectForCodegen)
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Compute the canonical string a schema version hashes.
|
|
873
|
+
*
|
|
874
|
+
* Exposed separately so the hashing itself can differ by environment: Node has
|
|
875
|
+
* `crypto`, and callers without it can still compare canonical forms directly.
|
|
876
|
+
*/
|
|
877
|
+
function canonicalSchemaPayload(collections) {
|
|
878
|
+
return canonicalize(serializeCollections(collections).map((collection) => projectForCodegen(collection)));
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* A short, non-cryptographic digest of the canonical payload.
|
|
882
|
+
*
|
|
883
|
+
* FNV-1a style, 64 bits, as two 32-bit halves. This is an identity, not a
|
|
884
|
+
* security boundary: nothing trusts a schema version to prove anything, it only
|
|
885
|
+
* answers "is this the same schema as before". A hand-rolled hash keeps this
|
|
886
|
+
* module free of `node:crypto`, so the identical function runs in the browser,
|
|
887
|
+
* in the CLI, and in the runtime — which is the property that actually matters.
|
|
888
|
+
*/
|
|
889
|
+
function computeSchemaVersion(collections) {
|
|
890
|
+
const payload = canonicalSchemaPayload(collections);
|
|
891
|
+
let h1 = 2166136261;
|
|
892
|
+
let h2 = 16777619;
|
|
893
|
+
for (let i = 0; i < payload.length; i++) {
|
|
894
|
+
const code = payload.charCodeAt(i);
|
|
895
|
+
h1 ^= code;
|
|
896
|
+
h1 = h1 + ((h1 << 1) + (h1 << 4) + (h1 << 7) + (h1 << 8) + (h1 << 24)) >>> 0;
|
|
897
|
+
h2 ^= code + i;
|
|
898
|
+
h2 = h2 + ((h2 << 1) + (h2 << 5) + (h2 << 9) + (h2 << 15) + (h2 << 24)) >>> 0;
|
|
899
|
+
}
|
|
900
|
+
const hex = (n) => n.toString(16).padStart(8, "0");
|
|
901
|
+
return `v1:${hex(h1)}${hex(h2)}`;
|
|
902
|
+
}
|
|
903
|
+
//#endregion
|
|
544
904
|
//#region src/controllers/data_driver.ts
|
|
545
905
|
/** Rows returned for a plain / text-search list read when the client sends no `limit`. */
|
|
546
906
|
var DEFAULT_LIST_LIMIT = 50;
|
|
@@ -595,6 +955,6 @@ function isPublicStoragePath(path) {
|
|
|
595
955
|
return p.startsWith("public/") || p.startsWith(`default/public/`);
|
|
596
956
|
}
|
|
597
957
|
//#endregion
|
|
598
|
-
export { ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, 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, RebaseApiError, RebaseClientError, Vector, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, isBranchAdmin, isDocumentAdmin, isFirebaseCollectionConfig, isLazyComponentRef, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStoragePath, isSQLAdmin, isSchemaAdmin, policy, registerDataSourceCapabilities, resolveClientListLimit, toCanonicalOp };
|
|
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 };
|
|
599
959
|
|
|
600
960
|
//# sourceMappingURL=index.es.js.map
|