@rebasepro/types 0.7.0 → 0.9.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/README.md +10 -10
- package/dist/controllers/auth.d.ts +1 -1
- package/dist/controllers/client.d.ts +237 -7
- package/dist/controllers/collection_registry.d.ts +3 -3
- package/dist/controllers/customization_controller.d.ts +1 -1
- package/dist/controllers/data.d.ts +285 -81
- package/dist/controllers/data_driver.d.ts +50 -37
- package/dist/controllers/index.d.ts +1 -1
- package/dist/controllers/local_config_persistence.d.ts +4 -4
- package/dist/controllers/navigation.d.ts +2 -2
- package/dist/controllers/registry.d.ts +17 -6
- package/dist/controllers/{side_entity_controller.d.ts → side_panel_controller.d.ts} +7 -7
- package/dist/controllers/storage.d.ts +39 -0
- package/dist/errors.d.ts +64 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +290 -16
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +305 -18
- package/dist/index.umd.js.map +1 -1
- package/dist/rebase_context.d.ts +8 -4
- package/dist/types/auth_adapter.d.ts +9 -6
- package/dist/types/backend.d.ts +30 -26
- package/dist/types/builders.d.ts +2 -2
- package/dist/types/collections.d.ts +211 -136
- package/dist/types/component_overrides.d.ts +61 -3
- package/dist/types/cron.d.ts +10 -1
- package/dist/types/data_source.d.ts +18 -5
- package/dist/types/database_adapter.d.ts +4 -3
- package/dist/types/entities.d.ts +7 -7
- package/dist/types/entity_actions.d.ts +7 -7
- package/dist/types/entity_callbacks.d.ts +55 -43
- package/dist/types/entity_views.d.ts +3 -3
- package/dist/types/filter-operators.d.ts +153 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/modify_collections.d.ts +2 -2
- package/dist/types/plugins.d.ts +9 -9
- package/dist/types/policy.d.ts +191 -0
- package/dist/types/properties.d.ts +153 -43
- package/dist/types/property_config.d.ts +1 -1
- package/dist/types/relations.d.ts +3 -3
- package/dist/types/slots.d.ts +14 -14
- package/dist/types/storage_source.d.ts +83 -0
- package/dist/types/websockets.d.ts +12 -13
- package/dist/users/user.d.ts +21 -9
- package/package.json +1 -1
- package/src/controllers/auth.tsx +1 -1
- package/src/controllers/client.ts +275 -7
- package/src/controllers/collection_registry.ts +3 -3
- package/src/controllers/customization_controller.tsx +1 -1
- package/src/controllers/data.ts +309 -97
- package/src/controllers/data_driver.ts +49 -40
- package/src/controllers/index.ts +1 -1
- package/src/controllers/local_config_persistence.tsx +4 -4
- package/src/controllers/navigation.ts +2 -2
- package/src/controllers/registry.ts +18 -6
- package/src/controllers/{side_entity_controller.tsx → side_panel_controller.tsx} +7 -7
- package/src/controllers/storage.ts +60 -1
- package/src/errors.ts +80 -0
- package/src/index.ts +1 -0
- package/src/rebase_context.tsx +8 -4
- package/src/types/auth_adapter.ts +9 -6
- package/src/types/backend.ts +41 -36
- package/src/types/builders.ts +2 -2
- package/src/types/collections.ts +256 -172
- package/src/types/component_overrides.ts +72 -5
- package/src/types/cron.ts +10 -1
- package/src/types/data_source.ts +29 -7
- package/src/types/database_adapter.ts +4 -3
- package/src/types/entities.ts +7 -7
- package/src/types/entity_actions.tsx +7 -7
- package/src/types/entity_callbacks.ts +58 -47
- package/src/types/entity_views.tsx +3 -3
- package/src/types/filter-operators.ts +240 -0
- package/src/types/index.ts +3 -2
- package/src/types/modify_collections.tsx +2 -2
- package/src/types/plugins.tsx +9 -9
- package/src/types/policy.ts +229 -0
- package/src/types/properties.ts +164 -44
- package/src/types/property_config.tsx +0 -1
- package/src/types/relations.ts +3 -3
- package/src/types/slots.tsx +14 -14
- package/src/types/storage_source.ts +90 -0
- package/src/types/websockets.ts +12 -14
- package/src/users/user.ts +22 -9
- package/dist/types/backend_hooks.d.ts +0 -109
- package/dist/types/entity_overrides.d.ts +0 -10
- package/src/types/backend_hooks.ts +0 -114
- package/src/types/entity_overrides.tsx +0 -11
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import type { CollectionRegistryController } from "./collection_registry";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
2
|
+
import type { EntityStatus, EntityValues } from "../types/entities";
|
|
3
|
+
import type { CollectionConfig, FilterValues } from "../types/collections";
|
|
4
4
|
import type { RebaseContext } from "../rebase_context";
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
|
-
export interface
|
|
10
|
+
export interface FetchOneProps<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
11
11
|
path: string;
|
|
12
|
-
|
|
12
|
+
id: string | number;
|
|
13
13
|
databaseId?: string;
|
|
14
|
-
collection?:
|
|
14
|
+
collection?: CollectionConfig<M>
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @internal
|
|
19
19
|
*/
|
|
20
|
-
export type
|
|
21
|
-
|
|
20
|
+
export type ListenOneProps<M extends Record<string, unknown> = Record<string, unknown>> =
|
|
21
|
+
FetchOneProps<M>
|
|
22
22
|
& {
|
|
23
|
-
onUpdate: (
|
|
23
|
+
onUpdate: (row: Record<string, unknown> | null) => void,
|
|
24
24
|
onError?: (error: Error) => void,
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -45,7 +45,7 @@ export interface VectorSearchParams {
|
|
|
45
45
|
*/
|
|
46
46
|
export interface FetchCollectionProps<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
47
47
|
path: string;
|
|
48
|
-
collection?:
|
|
48
|
+
collection?: CollectionConfig<M>;
|
|
49
49
|
filter?: FilterValues<Extract<keyof M, string>>,
|
|
50
50
|
limit?: number;
|
|
51
51
|
offset?: number;
|
|
@@ -63,42 +63,50 @@ export interface FetchCollectionProps<M extends Record<string, unknown> = Record
|
|
|
63
63
|
export type ListenCollectionProps<M extends Record<string, unknown> = Record<string, unknown>> =
|
|
64
64
|
FetchCollectionProps<M> &
|
|
65
65
|
{
|
|
66
|
-
onUpdate: (
|
|
66
|
+
onUpdate: (rows: Record<string, unknown>[]) => void;
|
|
67
67
|
onError?: (error: Error) => void;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* @internal
|
|
72
72
|
*/
|
|
73
|
-
export interface
|
|
73
|
+
export interface SaveProps<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
74
74
|
path: string;
|
|
75
75
|
values: Partial<EntityValues<M>>;
|
|
76
|
-
|
|
76
|
+
id?: string | number; // can be empty for new entities
|
|
77
77
|
previousValues?: Partial<EntityValues<M>>;
|
|
78
|
-
collection?:
|
|
78
|
+
collection?: CollectionConfig<M>;
|
|
79
79
|
status: EntityStatus;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* @internal
|
|
84
84
|
*/
|
|
85
|
-
export interface
|
|
86
|
-
|
|
87
|
-
collection?:
|
|
85
|
+
export interface DeleteProps<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
86
|
+
row: { id: string | number; path: string; values?: Partial<EntityValues<M>> };
|
|
87
|
+
collection?: CollectionConfig<M>;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export type FilterCombinationValidProps = {
|
|
91
91
|
path: string;
|
|
92
92
|
databaseId?: string;
|
|
93
|
-
collection:
|
|
93
|
+
collection: CollectionConfig;
|
|
94
94
|
filterValues: FilterValues<string>;
|
|
95
95
|
sortBy?: [string, "asc" | "desc"];
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
99
|
+
* The integration SPI for plugging a data backend into Rebase.
|
|
100
|
+
*
|
|
101
|
+
* Implement this interface to connect a custom backend (or use a built-in
|
|
102
|
+
* driver such as the Firestore one) and register it on
|
|
103
|
+
* `<Rebase dataSources>`. Rebase wraps drivers via `buildRebaseData` and
|
|
104
|
+
* routes collections to them by their `dataSource` key.
|
|
105
|
+
*
|
|
106
|
+
* For *consuming* data in application code, use `RebaseData` /
|
|
107
|
+
* `context.data` instead — this interface is only for providing it.
|
|
108
|
+
*
|
|
109
|
+
* @group Datasource
|
|
102
110
|
*/
|
|
103
111
|
export interface DataDriver {
|
|
104
112
|
|
|
@@ -115,9 +123,9 @@ export interface DataDriver {
|
|
|
115
123
|
/**
|
|
116
124
|
* Fetch data from a collection
|
|
117
125
|
* @param props
|
|
118
|
-
* @return Promise of
|
|
126
|
+
* @return Promise of flat rows
|
|
119
127
|
*/
|
|
120
|
-
fetchCollection<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<
|
|
128
|
+
fetchCollection<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Record<string, unknown>[]>;
|
|
121
129
|
|
|
122
130
|
/**
|
|
123
131
|
* Listen to a collection in a given path. If you don't implement this method
|
|
@@ -128,30 +136,30 @@ export interface DataDriver {
|
|
|
128
136
|
listenCollection?<M extends Record<string, unknown> = Record<string, unknown>>(props: ListenCollectionProps<M>): () => void;
|
|
129
137
|
|
|
130
138
|
/**
|
|
131
|
-
* Retrieve
|
|
139
|
+
* Retrieve a single row given a path and a collection
|
|
132
140
|
* @param props
|
|
133
141
|
*/
|
|
134
|
-
|
|
142
|
+
fetchOne<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchOneProps<M>): Promise<Record<string, unknown> | undefined>;
|
|
135
143
|
|
|
136
144
|
/**
|
|
137
|
-
* Get realtime updates on one
|
|
145
|
+
* Get realtime updates on one row.
|
|
138
146
|
* @param props
|
|
139
147
|
* @return Function to cancel subscription
|
|
140
148
|
*/
|
|
141
|
-
|
|
149
|
+
listenOne?<M extends Record<string, unknown> = Record<string, unknown>>(props: ListenOneProps<M>): () => void;
|
|
142
150
|
|
|
143
151
|
/**
|
|
144
|
-
* Save
|
|
152
|
+
* Save a row to the specified path
|
|
145
153
|
* @param props
|
|
146
154
|
*/
|
|
147
|
-
|
|
155
|
+
save<M extends Record<string, unknown> = Record<string, unknown>>(props: SaveProps<M>): Promise<Record<string, unknown>>;
|
|
148
156
|
|
|
149
157
|
/**
|
|
150
|
-
* Delete
|
|
158
|
+
* Delete a entity
|
|
151
159
|
* @param props
|
|
152
160
|
* @return was the whole deletion flow successful
|
|
153
161
|
*/
|
|
154
|
-
|
|
162
|
+
delete<M extends Record<string, unknown> = Record<string, unknown>>(props: DeleteProps<M>): Promise<void>;
|
|
155
163
|
|
|
156
164
|
/**
|
|
157
165
|
* Delete all entities from a collection.
|
|
@@ -164,7 +172,7 @@ export interface DataDriver {
|
|
|
164
172
|
* @param path Collection path
|
|
165
173
|
* @param name of the property
|
|
166
174
|
* @param value
|
|
167
|
-
* @param
|
|
175
|
+
* @param id
|
|
168
176
|
* @param collection
|
|
169
177
|
* @return `true` if there are no other fields besides the given entity
|
|
170
178
|
*/
|
|
@@ -172,14 +180,14 @@ export interface DataDriver {
|
|
|
172
180
|
path: string,
|
|
173
181
|
name: string,
|
|
174
182
|
value: unknown,
|
|
175
|
-
|
|
176
|
-
collection?:
|
|
183
|
+
id?: string | number,
|
|
184
|
+
collection?: CollectionConfig
|
|
177
185
|
): Promise<boolean>;
|
|
178
186
|
|
|
179
187
|
/**
|
|
180
188
|
* Count the number of entities in a collection
|
|
181
189
|
*/
|
|
182
|
-
|
|
190
|
+
count?<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;
|
|
183
191
|
|
|
184
192
|
/**
|
|
185
193
|
* Check if the given filter combination is valid
|
|
@@ -202,7 +210,7 @@ export interface DataDriver {
|
|
|
202
210
|
context: RebaseContext,
|
|
203
211
|
path: string,
|
|
204
212
|
databaseId?: string,
|
|
205
|
-
collection:
|
|
213
|
+
collection: CollectionConfig,
|
|
206
214
|
parentCollectionSlugs?: string[];
|
|
207
215
|
parentEntityIds?: string[];
|
|
208
216
|
}) => Promise<boolean>;
|
|
@@ -216,7 +224,7 @@ export interface DataDriver {
|
|
|
216
224
|
|
|
217
225
|
/**
|
|
218
226
|
* Optional REST-optimised fetch service. When present, the REST API
|
|
219
|
-
* generator uses these methods instead of the generic `
|
|
227
|
+
* generator uses these methods instead of the generic `fetchOne` /
|
|
220
228
|
* `fetchCollection` pipeline, enabling include-aware eager-loading.
|
|
221
229
|
*/
|
|
222
230
|
restFetchService?: RestFetchService;
|
|
@@ -244,8 +252,9 @@ export interface DataDriver {
|
|
|
244
252
|
* REST-optimised fetch service exposed by drivers that support
|
|
245
253
|
* eager-loading of relations via `include`.
|
|
246
254
|
*
|
|
247
|
-
* The methods return flattened rows (`{ id, ...columns }`)
|
|
248
|
-
*
|
|
255
|
+
* The methods return flattened rows (`{ id, ...columns }`) with
|
|
256
|
+
* included relations inlined as plain nested rows — the shape served
|
|
257
|
+
* to app developers through the REST API / SDK client.
|
|
249
258
|
*
|
|
250
259
|
* @group DataDriver
|
|
251
260
|
*/
|
|
@@ -272,9 +281,9 @@ export interface RestFetchService {
|
|
|
272
281
|
/**
|
|
273
282
|
* Fetch a single flattened entity with optional relation includes.
|
|
274
283
|
*/
|
|
275
|
-
|
|
284
|
+
fetchOneForRest(
|
|
276
285
|
collectionPath: string,
|
|
277
|
-
|
|
286
|
+
id: string | number,
|
|
278
287
|
include?: string[],
|
|
279
288
|
databaseId?: string
|
|
280
289
|
): Promise<Record<string, unknown> | null>;
|
package/src/controllers/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ export * from "./storage";
|
|
|
14
14
|
export * from "./email";
|
|
15
15
|
export * from "./client";
|
|
16
16
|
export * from "./customization_controller";
|
|
17
|
-
export * from "./
|
|
17
|
+
export * from "./side_panel_controller";
|
|
18
18
|
export * from "./side_dialogs_controller";
|
|
19
19
|
export * from "./dialogs_controller";
|
|
20
20
|
export * from "./snackbar";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CollectionConfig } from "../types/collections";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @group Models
|
|
5
5
|
*/
|
|
6
|
-
export type
|
|
6
|
+
export type PartialCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>> = Partial<CollectionConfig<M>>;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* This interface is in charge of defining the controller that persists
|
|
@@ -11,8 +11,8 @@ export type PartialEntityCollection<M extends Record<string, unknown> = Record<s
|
|
|
11
11
|
* a data source, such as local storage or Firestore.
|
|
12
12
|
*/
|
|
13
13
|
export interface UserConfigurationPersistence {
|
|
14
|
-
onCollectionModified: <M extends Record<string, unknown> = Record<string, unknown>>(path: string, partialCollection:
|
|
15
|
-
getCollectionConfig: <M extends Record<string, unknown> = Record<string, unknown>>(path: string) =>
|
|
14
|
+
onCollectionModified: <M extends Record<string, unknown> = Record<string, unknown>>(path: string, partialCollection: PartialCollectionConfig<M>) => void;
|
|
15
|
+
getCollectionConfig: <M extends Record<string, unknown> = Record<string, unknown>>(path: string) => PartialCollectionConfig<M>;
|
|
16
16
|
recentlyVisitedPaths: string[];
|
|
17
17
|
setRecentlyVisitedPaths: (paths: string[]) => void;
|
|
18
18
|
favouritePaths: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { EntityReference } from "../types/entities";
|
|
3
|
-
import type {
|
|
3
|
+
import type { CollectionConfig } from "../types/collections";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -248,7 +248,7 @@ export interface NavigationEntry {
|
|
|
248
248
|
name: string;
|
|
249
249
|
slug: string;
|
|
250
250
|
type: "collection" | "view" | "admin";
|
|
251
|
-
collection?:
|
|
251
|
+
collection?: CollectionConfig;
|
|
252
252
|
view?: AppView;
|
|
253
253
|
description?: string;
|
|
254
254
|
group: string;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
2
|
+
import type { CollectionConfig } from "../types/collections";
|
|
3
|
+
import type { CollectionConfigsBuilder, AppViewsBuilder } from "../types/builders";
|
|
4
4
|
import type { EntityCustomView } from "../types/entity_views";
|
|
5
5
|
import type { EntityAction } from "../types/entity_actions";
|
|
6
6
|
import type { AppView, NavigationGroupMapping } from "./navigation";
|
|
7
|
-
import type { RebasePlugin } from "../types/plugins";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Options to enable the built-in collection editor.
|
|
@@ -22,8 +21,8 @@ export interface CollectionEditorOptions {
|
|
|
22
21
|
pathSuggestions?: string[];
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
export interface RebaseCMSConfig<EC extends
|
|
26
|
-
collections?: EC[] |
|
|
24
|
+
export interface RebaseCMSConfig<EC extends CollectionConfig = CollectionConfig> {
|
|
25
|
+
collections?: EC[] | CollectionConfigsBuilder<EC>;
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
28
|
* Custom top-level views added to the main navigation.
|
|
@@ -35,7 +34,6 @@ export interface RebaseCMSConfig<EC extends EntityCollection = EntityCollection>
|
|
|
35
34
|
homePage?: ReactNode;
|
|
36
35
|
entityViews?: EntityCustomView[];
|
|
37
36
|
entityActions?: EntityAction[];
|
|
38
|
-
plugins?: RebasePlugin[];
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
39
|
* Centralized configuration for how collections and views are grouped
|
|
@@ -53,6 +51,20 @@ export interface RebaseCMSConfig<EC extends EntityCollection = EntityCollection>
|
|
|
53
51
|
* are all auto-wired — no plugin or manual view injection needed.
|
|
54
52
|
*/
|
|
55
53
|
collectionEditor?: boolean | CollectionEditorOptions;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* URL path prefix the admin is mounted under, when it does not live at the
|
|
57
|
+
* site root. Set this when the admin is rendered inside a path-prefixed
|
|
58
|
+
* route (e.g. `<Route path="/admin/*">`) so URL⇄collection resolution
|
|
59
|
+
* accounts for the prefix — otherwise the current path won't be recognized
|
|
60
|
+
* as a collection path and views hang on a spinner with no data fetch.
|
|
61
|
+
*
|
|
62
|
+
* Do NOT set this when mounting via a react-router `basename` — react-router
|
|
63
|
+
* already strips the prefix from the location, so the default (`/`) is correct.
|
|
64
|
+
*
|
|
65
|
+
* @default "/"
|
|
66
|
+
*/
|
|
67
|
+
basePath?: string;
|
|
56
68
|
}
|
|
57
69
|
|
|
58
70
|
export interface RebaseStudioConfig {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Entity } from "../types/entities";
|
|
2
|
-
import type {
|
|
2
|
+
import type { CollectionConfig } from "../types/collections";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Props used to open a side dialog
|
|
6
6
|
* @group Hooks and utilities
|
|
7
7
|
*/
|
|
8
|
-
export interface
|
|
8
|
+
export interface SidePanelBindingProps<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Absolute path of the entity
|
|
@@ -38,7 +38,7 @@ export interface EntitySidePanelProps<M extends Record<string, unknown> = Record
|
|
|
38
38
|
* Collection representing the entities of this view.
|
|
39
39
|
* If you leave it blank it will be induced by your navigation
|
|
40
40
|
*/
|
|
41
|
-
collection?:
|
|
41
|
+
collection?: CollectionConfig<M>;
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Should update the URL when opening the dialog.
|
|
@@ -87,7 +87,7 @@ export interface EntitySidePanelProps<M extends Record<string, unknown> = Record
|
|
|
87
87
|
* Controller to open the side dialog displaying entity forms
|
|
88
88
|
* @group Hooks and utilities
|
|
89
89
|
*/
|
|
90
|
-
export interface
|
|
90
|
+
export interface SidePanelController {
|
|
91
91
|
/**
|
|
92
92
|
* Close the last panel
|
|
93
93
|
*/
|
|
@@ -98,15 +98,15 @@ export interface SideEntityController {
|
|
|
98
98
|
* of the view is fetched from the collections you have specified in the
|
|
99
99
|
* navigation.
|
|
100
100
|
* At least you need to pass the path of the entity you would like
|
|
101
|
-
* to edit. You can set
|
|
101
|
+
* to edit. You can set a entityId if you would like to edit and existing one
|
|
102
102
|
* (or a new one with that id).
|
|
103
103
|
* @param props
|
|
104
104
|
*/
|
|
105
|
-
open: <M extends Record<string, unknown> = Record<string, unknown>>(props:
|
|
105
|
+
open: <M extends Record<string, unknown> = Record<string, unknown>>(props: SidePanelBindingProps<M>) => void;
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
108
|
* Replace the last open entity panel with the given one.
|
|
109
109
|
* @param props
|
|
110
110
|
*/
|
|
111
|
-
replace: <M extends Record<string, unknown> = Record<string, unknown>>(props:
|
|
111
|
+
replace: <M extends Record<string, unknown> = Record<string, unknown>>(props: SidePanelBindingProps<M>) => void;
|
|
112
112
|
}
|
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path prefix that marks an object as **public**. Files stored under this
|
|
3
|
+
* prefix are served without any auth token via a stable, permanent,
|
|
4
|
+
* CDN-cacheable URL (see {@link StorageSource.getSignedUrl}). Shared by the
|
|
5
|
+
* client SDK and the backend so both agree on which objects are public.
|
|
6
|
+
*
|
|
7
|
+
* @group Models
|
|
8
|
+
*/
|
|
9
|
+
export const PUBLIC_STORAGE_PREFIX = "public/";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* True when a storage key/path points at a public object (lives under
|
|
13
|
+
* {@link PUBLIC_STORAGE_PREFIX}). The check is applied to the key *within the
|
|
14
|
+
* bucket* — strip any `bucket/` and `scheme://` prefixes first.
|
|
15
|
+
*
|
|
16
|
+
* @group Models
|
|
17
|
+
*/
|
|
18
|
+
export function isPublicStoragePath(path: string | null | undefined): boolean {
|
|
19
|
+
if (!path) return false;
|
|
20
|
+
let p = path;
|
|
21
|
+
const scheme = p.indexOf("://");
|
|
22
|
+
if (scheme !== -1) p = p.substring(scheme + 3);
|
|
23
|
+
p = p.replace(/^\/+/, "");
|
|
24
|
+
|
|
25
|
+
// Defense-in-depth: a path containing traversal segments is never public,
|
|
26
|
+
// so an attacker can't reach a private object via `public/../secret`.
|
|
27
|
+
if (p.split("/").some((seg) => seg === "..")) return false;
|
|
28
|
+
|
|
29
|
+
// Public iff the object **key** starts with the public prefix. A single
|
|
30
|
+
// leading `default/` bucket segment is tolerated (the default bucket).
|
|
31
|
+
// A substring match is deliberately NOT used — a private object under a
|
|
32
|
+
// folder literally named `public` (e.g. `reports/public/q3.pdf`) must stay
|
|
33
|
+
// private. Named buckets: pass the key (not `bucket/key`) so the prefix is
|
|
34
|
+
// anchored; otherwise it falls back to a private, token-scoped URL (safe).
|
|
35
|
+
return p.startsWith(PUBLIC_STORAGE_PREFIX) || p.startsWith(`default/${PUBLIC_STORAGE_PREFIX}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
1
38
|
/**
|
|
2
39
|
* @group Models
|
|
3
40
|
*/
|
|
@@ -5,7 +42,14 @@ export interface UploadFileProps {
|
|
|
5
42
|
file: File,
|
|
6
43
|
key: string,
|
|
7
44
|
metadata?: Record<string, unknown>,
|
|
8
|
-
bucket?: string
|
|
45
|
+
bucket?: string,
|
|
46
|
+
/**
|
|
47
|
+
* Store this object as **public**: it is placed under
|
|
48
|
+
* {@link PUBLIC_STORAGE_PREFIX} and served via a stable, token-less,
|
|
49
|
+
* permanent URL (safe to persist in a database and cache on a CDN).
|
|
50
|
+
* Defaults to `false` (private, short-lived signed URLs).
|
|
51
|
+
*/
|
|
52
|
+
public?: boolean
|
|
9
53
|
}
|
|
10
54
|
|
|
11
55
|
/**
|
|
@@ -74,6 +118,21 @@ export declare interface DownloadMetadata {
|
|
|
74
118
|
contentType: string;
|
|
75
119
|
|
|
76
120
|
customMetadata: Record<string, unknown>;
|
|
121
|
+
/**
|
|
122
|
+
* Optional short-lived download token (for local/server-mediated storage).
|
|
123
|
+
* Absent for public objects, which need no token.
|
|
124
|
+
*/
|
|
125
|
+
token?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Optional remaining lifetime of the token, in seconds.
|
|
128
|
+
*/
|
|
129
|
+
tokenExpiresIn?: number;
|
|
130
|
+
/**
|
|
131
|
+
* True when this object is public: it is served without a token via a
|
|
132
|
+
* stable, permanent, CDN-cacheable URL. When set, the client builds a
|
|
133
|
+
* token-less URL and caches it indefinitely.
|
|
134
|
+
*/
|
|
135
|
+
public?: boolean;
|
|
77
136
|
}
|
|
78
137
|
|
|
79
138
|
/**
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured initializer for {@link RebaseApiError}.
|
|
3
|
+
*
|
|
4
|
+
* @group Errors
|
|
5
|
+
*/
|
|
6
|
+
export interface RebaseErrorInit {
|
|
7
|
+
/**
|
|
8
|
+
* HTTP status code, when the error originated from an HTTP response.
|
|
9
|
+
* Left `undefined` for realtime/WebSocket, network, and client-side
|
|
10
|
+
* logic errors that have no HTTP status.
|
|
11
|
+
*/
|
|
12
|
+
status?: number;
|
|
13
|
+
/** Stable, machine-readable error code (e.g. `"NOT_FOUND"`, `"BAD_REQUEST"`). */
|
|
14
|
+
code?: string;
|
|
15
|
+
/** Structured error payload returned by the server, when present. */
|
|
16
|
+
details?: unknown;
|
|
17
|
+
/** The underlying error this one wraps, if any. */
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The single error type thrown across the entire Rebase client surface —
|
|
23
|
+
* HTTP data/control-plane calls, realtime/WebSocket operations, and
|
|
24
|
+
* client-side logic errors (e.g. an unknown collection accessor). A `catch`
|
|
25
|
+
* block only ever needs to check for this one class:
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { RebaseApiError } from "@rebasepro/client"; // re-exported
|
|
29
|
+
*
|
|
30
|
+
* try {
|
|
31
|
+
* await client.data.products.update(id, { price: 9 });
|
|
32
|
+
* } catch (e) {
|
|
33
|
+
* if (e instanceof RebaseApiError) {
|
|
34
|
+
* if (e.status === 404) { ... } // HTTP failures carry a status
|
|
35
|
+
* console.error(e.code, e.details);
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* `status` is present for HTTP failures and `undefined` otherwise, so its
|
|
41
|
+
* presence distinguishes transport-level errors from realtime/logic errors.
|
|
42
|
+
*
|
|
43
|
+
* @group Errors
|
|
44
|
+
*/
|
|
45
|
+
export class RebaseApiError extends Error {
|
|
46
|
+
/** HTTP status code, or `undefined` for non-HTTP errors. */
|
|
47
|
+
readonly status?: number;
|
|
48
|
+
/** Stable machine-readable error code, when the server supplied one. */
|
|
49
|
+
readonly code?: string;
|
|
50
|
+
/** Structured error payload from the server, when present. */
|
|
51
|
+
readonly details?: unknown;
|
|
52
|
+
|
|
53
|
+
constructor(message: string, init: RebaseErrorInit = {}) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = "RebaseApiError";
|
|
56
|
+
this.status = init.status;
|
|
57
|
+
this.code = init.code;
|
|
58
|
+
this.details = init.details;
|
|
59
|
+
if (init.cause !== undefined) {
|
|
60
|
+
// `cause` is standard on Error but not always in the lib target's type.
|
|
61
|
+
(this as { cause?: unknown }).cause = init.cause;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Client-side logic error — raised before any request is made (e.g. accessing
|
|
68
|
+
* an unknown collection accessor when a typed dictionary is configured).
|
|
69
|
+
*
|
|
70
|
+
* A subclass of {@link RebaseApiError} (with no `status`), so a single
|
|
71
|
+
* `catch (e) { if (e instanceof RebaseApiError) ... }` handles it too.
|
|
72
|
+
*
|
|
73
|
+
* @group Errors
|
|
74
|
+
*/
|
|
75
|
+
export class RebaseClientError extends RebaseApiError {
|
|
76
|
+
constructor(message: string) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.name = "RebaseClientError";
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/index.ts
CHANGED
package/src/rebase_context.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import type { UserConfigurationPersistence } from "./controllers/local_config_pe
|
|
|
5
5
|
import type { DatabaseAdmin } from "./types/backend";
|
|
6
6
|
import type { RebaseClient } from "./controllers/client";
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { RebaseSdkData } from "./controllers/data";
|
|
9
9
|
import type { User } from "./users";
|
|
10
10
|
|
|
11
11
|
|
|
@@ -36,8 +36,12 @@ export type RebaseCallContext<USER extends User = User> = {
|
|
|
36
36
|
/**
|
|
37
37
|
* Unified data access — `context.data.products.create(...)`.
|
|
38
38
|
* Access any collection as a dynamic property.
|
|
39
|
+
*
|
|
40
|
+
* Returns flat rows (`{ id, ...columns }`), identical to the frontend SDK
|
|
41
|
+
* client — so `context.data` in a backend callback and `client.data` in the
|
|
42
|
+
* frontend behave the same way (`row.title`, never `row.values.title`).
|
|
39
43
|
*/
|
|
40
|
-
data:
|
|
44
|
+
data: RebaseSdkData;
|
|
41
45
|
|
|
42
46
|
/**
|
|
43
47
|
* Used storage implementation
|
|
@@ -77,9 +81,9 @@ export type RebaseContext<USER extends User = User, AuthControllerType extends A
|
|
|
77
81
|
sideDialogsController?: import("./controllers/side_dialogs_controller").SideDialogsController;
|
|
78
82
|
|
|
79
83
|
/**
|
|
80
|
-
* Controller to open the side
|
|
84
|
+
* Controller to open the side panel displaying entity forms
|
|
81
85
|
*/
|
|
82
|
-
|
|
86
|
+
sidePanelController?: import("./controllers/side_panel_controller").SidePanelController;
|
|
83
87
|
|
|
84
88
|
/**
|
|
85
89
|
* Controller resolving URLs in the CMS
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Pluggable authentication abstraction for Rebase.
|
|
5
5
|
*
|
|
6
6
|
* An `AuthAdapter` decouples authentication from the database layer,
|
|
7
|
-
* allowing users to bring their own auth system (Clerk, Auth0,
|
|
8
|
-
*
|
|
7
|
+
* allowing users to bring their own auth system (Clerk, Auth0, or other
|
|
8
|
+
* external providers) while keeping the Rebase admin frontend fully functional.
|
|
9
9
|
*
|
|
10
10
|
* @example Built-in auth (default — zero config change)
|
|
11
11
|
* ```ts
|
|
@@ -237,6 +237,9 @@ export interface AuthResponsePayload {
|
|
|
237
237
|
email: string;
|
|
238
238
|
displayName: string | null;
|
|
239
239
|
photoURL: string | null;
|
|
240
|
+
providerId?: string;
|
|
241
|
+
isAnonymous?: boolean;
|
|
242
|
+
emailVerified?: boolean;
|
|
240
243
|
roles: string[];
|
|
241
244
|
metadata: Record<string, unknown>;
|
|
242
245
|
};
|
|
@@ -277,7 +280,7 @@ export interface TransformAuthResponseContext {
|
|
|
277
280
|
* 4. Advertise its capabilities so the frontend can adapt
|
|
278
281
|
*
|
|
279
282
|
* The built-in Rebase auth implements this interface internally.
|
|
280
|
-
* External providers (Clerk, Auth0,
|
|
283
|
+
* External providers (Clerk, Auth0, or others) provide their own adapters.
|
|
281
284
|
* Users with custom auth can use `createCustomAuthAdapter()` for a minimal setup.
|
|
282
285
|
*
|
|
283
286
|
* @group Auth
|
|
@@ -286,7 +289,7 @@ export interface AuthAdapter {
|
|
|
286
289
|
/**
|
|
287
290
|
* Unique identifier for this auth adapter.
|
|
288
291
|
*
|
|
289
|
-
* @example "rebase-builtin", "clerk", "auth0", "
|
|
292
|
+
* @example "rebase-builtin", "clerk", "auth0", "external-provider", "custom"
|
|
290
293
|
*/
|
|
291
294
|
readonly id: string;
|
|
292
295
|
|
|
@@ -393,7 +396,7 @@ export interface AuthAdapter {
|
|
|
393
396
|
*
|
|
394
397
|
* @param values - Raw request body from the client.
|
|
395
398
|
* @param collectionAuth - The parsed `AuthCollectionConfig` from the collection (if `auth` is an object).
|
|
396
|
-
* @returns Processed values ready for `driver.
|
|
399
|
+
* @returns Processed values ready for `driver.save()`, plus metadata for the post-save step.
|
|
397
400
|
*/
|
|
398
401
|
prepareUserCreation?(
|
|
399
402
|
values: Record<string, unknown>,
|
|
@@ -435,7 +438,7 @@ export interface AuthAdapter {
|
|
|
435
438
|
* response and returns a (potentially enriched) response.
|
|
436
439
|
*
|
|
437
440
|
* Use cases:
|
|
438
|
-
* - Inject tokens from external auth systems (
|
|
441
|
+
* - Inject tokens from external auth systems (custom provider tokens, etc.)
|
|
439
442
|
* - Add project-specific metadata to the response
|
|
440
443
|
* - Enrich the user object with data from external sources
|
|
441
444
|
*
|