@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.
Files changed (88) hide show
  1. package/README.md +10 -10
  2. package/dist/controllers/auth.d.ts +1 -1
  3. package/dist/controllers/client.d.ts +237 -7
  4. package/dist/controllers/collection_registry.d.ts +3 -3
  5. package/dist/controllers/customization_controller.d.ts +1 -1
  6. package/dist/controllers/data.d.ts +285 -81
  7. package/dist/controllers/data_driver.d.ts +50 -37
  8. package/dist/controllers/index.d.ts +1 -1
  9. package/dist/controllers/local_config_persistence.d.ts +4 -4
  10. package/dist/controllers/navigation.d.ts +2 -2
  11. package/dist/controllers/registry.d.ts +17 -6
  12. package/dist/controllers/{side_entity_controller.d.ts → side_panel_controller.d.ts} +7 -7
  13. package/dist/controllers/storage.d.ts +39 -0
  14. package/dist/errors.d.ts +64 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.es.js +290 -16
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/index.umd.js +305 -18
  19. package/dist/index.umd.js.map +1 -1
  20. package/dist/rebase_context.d.ts +8 -4
  21. package/dist/types/auth_adapter.d.ts +9 -6
  22. package/dist/types/backend.d.ts +30 -26
  23. package/dist/types/builders.d.ts +2 -2
  24. package/dist/types/collections.d.ts +211 -136
  25. package/dist/types/component_overrides.d.ts +61 -3
  26. package/dist/types/cron.d.ts +10 -1
  27. package/dist/types/data_source.d.ts +18 -5
  28. package/dist/types/database_adapter.d.ts +4 -3
  29. package/dist/types/entities.d.ts +7 -7
  30. package/dist/types/entity_actions.d.ts +7 -7
  31. package/dist/types/entity_callbacks.d.ts +55 -43
  32. package/dist/types/entity_views.d.ts +3 -3
  33. package/dist/types/filter-operators.d.ts +153 -0
  34. package/dist/types/index.d.ts +3 -2
  35. package/dist/types/modify_collections.d.ts +2 -2
  36. package/dist/types/plugins.d.ts +9 -9
  37. package/dist/types/policy.d.ts +191 -0
  38. package/dist/types/properties.d.ts +153 -43
  39. package/dist/types/property_config.d.ts +1 -1
  40. package/dist/types/relations.d.ts +3 -3
  41. package/dist/types/slots.d.ts +14 -14
  42. package/dist/types/storage_source.d.ts +83 -0
  43. package/dist/types/websockets.d.ts +12 -13
  44. package/dist/users/user.d.ts +21 -9
  45. package/package.json +1 -1
  46. package/src/controllers/auth.tsx +1 -1
  47. package/src/controllers/client.ts +275 -7
  48. package/src/controllers/collection_registry.ts +3 -3
  49. package/src/controllers/customization_controller.tsx +1 -1
  50. package/src/controllers/data.ts +309 -97
  51. package/src/controllers/data_driver.ts +49 -40
  52. package/src/controllers/index.ts +1 -1
  53. package/src/controllers/local_config_persistence.tsx +4 -4
  54. package/src/controllers/navigation.ts +2 -2
  55. package/src/controllers/registry.ts +18 -6
  56. package/src/controllers/{side_entity_controller.tsx → side_panel_controller.tsx} +7 -7
  57. package/src/controllers/storage.ts +60 -1
  58. package/src/errors.ts +80 -0
  59. package/src/index.ts +1 -0
  60. package/src/rebase_context.tsx +8 -4
  61. package/src/types/auth_adapter.ts +9 -6
  62. package/src/types/backend.ts +41 -36
  63. package/src/types/builders.ts +2 -2
  64. package/src/types/collections.ts +256 -172
  65. package/src/types/component_overrides.ts +72 -5
  66. package/src/types/cron.ts +10 -1
  67. package/src/types/data_source.ts +29 -7
  68. package/src/types/database_adapter.ts +4 -3
  69. package/src/types/entities.ts +7 -7
  70. package/src/types/entity_actions.tsx +7 -7
  71. package/src/types/entity_callbacks.ts +58 -47
  72. package/src/types/entity_views.tsx +3 -3
  73. package/src/types/filter-operators.ts +240 -0
  74. package/src/types/index.ts +3 -2
  75. package/src/types/modify_collections.tsx +2 -2
  76. package/src/types/plugins.tsx +9 -9
  77. package/src/types/policy.ts +229 -0
  78. package/src/types/properties.ts +164 -44
  79. package/src/types/property_config.tsx +0 -1
  80. package/src/types/relations.ts +3 -3
  81. package/src/types/slots.tsx +14 -14
  82. package/src/types/storage_source.ts +90 -0
  83. package/src/types/websockets.ts +12 -14
  84. package/src/users/user.ts +22 -9
  85. package/dist/types/backend_hooks.d.ts +0 -109
  86. package/dist/types/entity_overrides.d.ts +0 -10
  87. package/src/types/backend_hooks.ts +0 -114
  88. package/src/types/entity_overrides.tsx +0 -11
@@ -1,29 +1,5 @@
1
1
  import { Entity, EntityValues } from "../types/entities";
2
-
3
- /**
4
- * Parameters for querying a collection.
5
- * Uses PostgREST-style filter syntax for consistency between
6
- * the SDK (HTTP) and framework (in-process) contexts.
7
- *
8
- * @group Data
9
- */
10
- /**
11
- * A where-clause value for a single field.
12
- *
13
- * Supports three syntaxes:
14
- * 1. **Equality shorthand**: raw JS values — `null`, `"active"`, `42`, `true`
15
- * 2. **Tuple syntax**: `[operator, value]` — `[">", 18]`, `["in", ["a","b"]]`
16
- * 3. **PostgREST string**: `"eq.published"`, `"gte.18"`, `"in.(a,b)"`
17
- *
18
- * @group Data
19
- */
20
- export type WhereFieldValue =
21
- | string
22
- | number
23
- | boolean
24
- | null
25
- | [WhereFilterOpShort, any]
26
- | [WhereFilterOpShort, any][];
2
+ import { WhereFilterOp, FilterValues, OrderByTuple } from "../types/filter-operators";
27
3
 
28
4
  export type WhereValue<T> = T | T[] | null;
29
5
 
@@ -34,59 +10,84 @@ export interface LogicalCondition {
34
10
 
35
11
  export interface FilterCondition {
36
12
  column: string;
37
- operator: FilterOperator;
13
+ operator: WhereFilterOp;
38
14
  value: unknown;
39
15
  }
40
16
 
41
- /** Short operator strings accepted in the tuple syntax. */
42
- export type WhereFilterOpShort =
43
- | "==" | "!=" | ">" | ">=" | "<" | "<="
44
- | "eq" | "neq" | "gt" | "gte" | "lt" | "lte"
45
- | "in" | "nin" | "not-in"
46
- | "array-contains" | "array-contains-any" | "cs" | "csa";
47
-
17
+ /**
18
+ * Parameters for querying a collection.
19
+ *
20
+ * ## How the filter parameters combine
21
+ *
22
+ * `where`, `logical`, and `searchString` are **independent** and, when more
23
+ * than one is present, are combined with **AND** — every clause must match.
24
+ * Concretely the backend builds:
25
+ *
26
+ * ```text
27
+ * (where filters, AND-ed together)
28
+ * AND (logical group)
29
+ * AND (searchString matches, OR-ed across searchable columns)
30
+ * ```
31
+ *
32
+ * So `where` does **not** conflict with or override `logical` — they stack.
33
+ * If you need `where` fields OR-ed with each other, move them into `logical`
34
+ * instead. There is no way to OR `where` against `logical`; express anything
35
+ * that isn't a plain AND of the three groups inside a single `logical` tree.
36
+ *
37
+ * ## Pagination precedence
38
+ *
39
+ * `limit`/`offset` and `page` describe the same window two ways. If **both
40
+ * `offset` and `page` are provided, `page` wins** — the backend computes
41
+ * `offset = (page - 1) * (limit ?? 20)` and ignores the explicit `offset`.
42
+ * Pick one style per query.
43
+ *
44
+ * @group Data
45
+ */
48
46
  export interface FindParams {
49
- /** Maximum number of items to return (default: 20) */
47
+ /** Maximum number of items to return (default: 20). */
50
48
  limit?: number;
51
- /** Number of items to skip */
49
+ /**
50
+ * Number of items to skip. Ignored when {@link FindParams.page} is also
51
+ * set — `page` takes precedence.
52
+ */
52
53
  offset?: number;
53
- /** Page number (1-indexed), alternative to offset */
54
+ /**
55
+ * Page number (1-indexed), alternative to {@link FindParams.offset}.
56
+ * When set, overrides `offset` as `(page - 1) * (limit ?? 20)`.
57
+ */
54
58
  page?: number;
55
59
  /**
56
- * Filter object. Supports multiple syntaxes per field:
60
+ * Filter conditions keyed by field name.
61
+ * Each value is a `[WhereFilterOp, value]` tuple or an array of tuples
62
+ * for multiple conditions on the same field. Multiple fields, and multiple
63
+ * tuples on one field, are **AND-ed**; also AND-ed with `logical` and
64
+ * `searchString` when present (see the interface docs).
57
65
  *
58
- * **Equality shorthand** — raw JS values (null, string, number, boolean):
59
- * ```ts
60
- * { company_profile_id: null }
61
- * { status: "active" }
62
- * { age: 18 }
63
- * ```
64
- *
65
- * **Tuple syntax** — `[operator, value]`:
66
- * ```ts
66
+ * @example
67
+ * { status: ["==", "active"] }
67
68
  * { age: [">=", 18] }
68
69
  * { role: ["in", ["admin", "editor"]] }
69
- * { deleted_at: ["!=", null] }
70
- * ```
71
- *
72
- * **PostgREST string syntax** (original format):
73
- * ```ts
74
- * { status: "eq.published" }
75
- * { age: "gte.18" }
76
- * { role: "in.(admin,editor)" }
77
- * ```
78
- */
79
- where?: Record<string, WhereFieldValue>;
80
- /** Logical grouping conditions (AND/OR) */
70
+ * { age: [[">=", 18], ["<", 65]] }
71
+ */
72
+ where?: FilterValues<string>;
73
+ /**
74
+ * Logical grouping conditions (AND/OR). Use this for anything `where`
75
+ * can't express — notably OR-ing conditions. AND-ed with `where` and
76
+ * `searchString` when present (see the interface docs).
77
+ */
81
78
  logical?: LogicalCondition;
82
79
  /**
83
- * Sort order. Format: "field:direction".
84
- * @example "created_at:desc", "name:asc"
80
+ * Sort order as a `[field, direction]` tuple.
81
+ * @example orderBy: ["created_at", "desc"]
85
82
  */
86
- orderBy?: string;
83
+ orderBy?: OrderByTuple;
87
84
  /** Relations to include in the response */
88
85
  include?: string[];
89
- /** Full-text search string */
86
+ /**
87
+ * Full-text search string. Matched (OR-ed) across the collection's
88
+ * searchable columns, then AND-ed with `where`/`logical`. This is the
89
+ * value behind the query builder's `.search()` method.
90
+ */
90
91
  searchString?: string;
91
92
  }
92
93
 
@@ -106,16 +107,22 @@ export interface FindResponse<M extends Record<string, unknown> = Record<string,
106
107
  };
107
108
  }
108
109
 
109
- export type FilterOperator = WhereFilterOpShort;
110
+
110
111
 
111
112
  /**
112
- * Fluent Query Builder Interface supported on both client and server accessors.
113
+ * Fluent query builder for the **admin CMS** resolves to `FindResponse<M>`
114
+ * (Snapshot-wrapped rows).
115
+ *
116
+ * @internal App developers should use {@link SDKQueryBuilderInterface}
117
+ * (flat rows, returned by `client.data.*` / `context.data.*`). This
118
+ * Snapshot-flavored variant backs the admin CMS internals only.
119
+ *
113
120
  * @group Data
114
121
  */
115
122
  export interface QueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {
116
- where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;
123
+ where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): this;
117
124
  where(logicalCondition: LogicalCondition): this;
118
- orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
125
+ orderBy(column: keyof M & string, direction?: "asc" | "desc"): this;
119
126
  limit(count: number): this;
120
127
  offset(count: number): this;
121
128
  search(searchString: string): this;
@@ -125,11 +132,13 @@ export interface QueryBuilderInterface<M extends Record<string, unknown> = Recor
125
132
  }
126
133
 
127
134
  /**
128
- * A single collection's CRUD accessor.
135
+ * A single collection's CRUD accessor for the **admin CMS** — every method
136
+ * resolves to `Snapshot`-wrapped rows (`FindResponse<M>` / `Snapshot<M>`).
129
137
  *
130
- * This is the unified API surface used in both:
131
- * - The generated SDK (`client.data.products.create(...)`)
132
- * - Framework callbacks (`context.data.products.create(...)`)
138
+ * @internal App developers do **not** use this. The public, symmetric surface
139
+ * is {@link SDKCollectionClient} (flat rows), exposed as `client.data.products`
140
+ * in the SDK and `context.data.products` in framework callbacks. This
141
+ * Snapshot-flavored accessor backs the admin CMS view-model only.
133
142
  *
134
143
  * @group Data
135
144
  */
@@ -163,11 +172,6 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
163
172
  */
164
173
  delete(id: string | number): Promise<void>;
165
174
 
166
- /**
167
- * Delete all records in this collection.
168
- */
169
- deleteAll?(): Promise<void>;
170
-
171
175
  /**
172
176
  * Subscribe to a collection for real-time updates.
173
177
  * Optional method, may not be supported by all implementations (like stateless HTTP clients).
@@ -186,37 +190,169 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
186
190
  count?(params?: FindParams): Promise<number>;
187
191
 
188
192
  // Fluent Query Builder
189
- where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): QueryBuilderInterface<M>;
193
+ where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): QueryBuilderInterface<M>;
190
194
  where(logicalCondition: LogicalCondition): QueryBuilderInterface<M>;
191
- orderBy(column: keyof M & string, ascending?: "asc" | "desc"): QueryBuilderInterface<M>;
195
+ orderBy(column: keyof M & string, direction?: "asc" | "desc"): QueryBuilderInterface<M>;
192
196
  limit(count: number): QueryBuilderInterface<M>;
193
197
  offset(count: number): QueryBuilderInterface<M>;
194
198
  search(searchString: string): QueryBuilderInterface<M>;
195
199
  include(...relations: string[]): QueryBuilderInterface<M>;
196
200
  }
197
201
 
202
+ // =============================================================================
203
+ // SDK-facing types — flat rows, no Entity wrapper
204
+ // =============================================================================
205
+
206
+ /**
207
+ * Pagination metadata returned with collection queries.
208
+ * @group Data
209
+ */
210
+ export interface PaginationMeta {
211
+ total: number;
212
+ limit: number;
213
+ offset: number;
214
+ hasMore: boolean;
215
+ }
216
+
198
217
  /**
199
- * The unified data access object.
218
+ * Paginated response from a collection query (SDK-facing).
219
+ * Returns flat rows instead of Entity-wrapped objects.
200
220
  *
201
- * Access collections as dynamic properties: `data.products.find(...)`.
202
- * In the SDK this is backed by HTTP transport (typed, generated per-project).
203
- * In the framework this is backed by a Proxy + in-process database driver (dynamic).
221
+ * @example
222
+ * const { data, meta } = await rebase.data.posts.find();
223
+ * console.log(data[0].title); // direct access no .values
224
+ * console.log(meta.total);
225
+ *
226
+ * @group Data
227
+ */
228
+ export interface FindResult<M extends Record<string, unknown> = Record<string, unknown>> {
229
+ /** Array of flat rows matching the query */
230
+ data: M[];
231
+ /** Pagination metadata */
232
+ meta: PaginationMeta;
233
+ }
234
+
235
+ /**
236
+ * Fluent Query Builder Interface for the SDK client.
237
+ * Returns `FindResult<M>` (flat rows) instead of `FindResponse<M>` (Entity-wrapped).
238
+ *
239
+ * @group Data
240
+ */
241
+ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {
242
+ where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): this;
243
+ where(logicalCondition: LogicalCondition): this;
244
+ orderBy(column: keyof M & string, direction?: "asc" | "desc"): this;
245
+ limit(count: number): this;
246
+ offset(count: number): this;
247
+ search(searchString: string): this;
248
+ include(...relations: string[]): this;
249
+ find(): Promise<FindResult<M>>;
250
+ count(): Promise<number>;
251
+ listen(onUpdate: (data: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
252
+ }
253
+
254
+ /**
255
+ * SDK collection client — returns flat rows, no Entity wrapper.
256
+ *
257
+ * This is the public API surface for app developers using
258
+ * `createRebaseClient()`. CMS internals use `CollectionAccessor` instead.
259
+ *
260
+ * Type parameters:
261
+ * - `M` — the **Row** shape returned by reads (`find`, `findById`, `listen`).
262
+ * - `I` — the **Insert** shape accepted by {@link create}. Defaults to
263
+ * `Partial<M>`; the generated SDK supplies a dedicated `Insert` type where
264
+ * required columns are required and auto-generated / read-only columns are
265
+ * omitted, so `create({})` on a table with required fields is a compile error.
266
+ * - `U` — the **Update** shape accepted by {@link update}. Defaults to
267
+ * `Partial<M>`; the generated SDK supplies a dedicated `Update` type.
204
268
  *
205
269
  * @example
206
- * // SDK
207
- * const client = createRebaseClient({ baseUrl: "..." });
208
- * await client.data.products.create({ name: "Camera", price: 299 });
270
+ * const { data: posts } = await rebase.data.posts.find();
271
+ * console.log(posts[0].title); // flat access
272
+ * console.log(posts[0].id); // id at top level
209
273
  *
210
- * // Framework callback
211
- * callbacks: {
212
- * afterSave({ context }) {
213
- * await context.data.logs.create({ action: "saved", timestamp: new Date() });
214
- * }
215
- * }
274
+ * const post = await rebase.data.posts.findById(1);
275
+ * console.log(post?.title); // no .values needed
216
276
  *
217
277
  * @group Data
218
278
  */
219
- export interface RebaseData {
279
+ export interface SDKCollectionClient<
280
+ M extends Record<string, unknown> = Record<string, unknown>,
281
+ I = Partial<M>,
282
+ U = Partial<M>
283
+ > {
284
+ /**
285
+ * Find multiple records with optional filtering, pagination, and sorting.
286
+ */
287
+ find(params?: FindParams): Promise<FindResult<M>>;
288
+
289
+ /**
290
+ * Find a single record by its ID.
291
+ */
292
+ findById(id: string | number): Promise<M | undefined>;
293
+
294
+ /**
295
+ * Create a new record.
296
+ * @param data The record data to create (the collection's `Insert` shape).
297
+ * @param id Optional specific ID to use for the new record.
298
+ * @returns The created row
299
+ */
300
+ create(data: I, id?: string | number): Promise<M>;
301
+
302
+ /**
303
+ * Update an existing record by ID.
304
+ * @param data The fields to update (the collection's `Update` shape).
305
+ * @returns The updated row.
306
+ * @throws {RebaseApiError} with status 404 when the record does not exist.
307
+ */
308
+ update(id: string | number, data: U): Promise<M>;
309
+
310
+ /**
311
+ * Delete a record by ID.
312
+ * @throws {RebaseApiError} with status 404 when the record does not exist.
313
+ */
314
+ delete(id: string | number): Promise<void>;
315
+
316
+ /**
317
+ * Subscribe to a collection for real-time updates.
318
+ */
319
+ listen?(params: FindParams | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
320
+
321
+ /**
322
+ * Subscribe to a single record for real-time updates.
323
+ */
324
+ listenById?(id: string | number, onUpdate: (row: M | undefined) => void, onError?: (error: Error) => void): () => void;
325
+
326
+ /**
327
+ * Count the number of records matching the given filter.
328
+ */
329
+ count?(params?: FindParams): Promise<number>;
330
+
331
+ // Fluent Query Builder
332
+ where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): SDKQueryBuilderInterface<M>;
333
+ where(logicalCondition: LogicalCondition): SDKQueryBuilderInterface<M>;
334
+ orderBy(column: keyof M & string, direction?: "asc" | "desc"): SDKQueryBuilderInterface<M>;
335
+ limit(count: number): SDKQueryBuilderInterface<M>;
336
+ offset(count: number): SDKQueryBuilderInterface<M>;
337
+ search(searchString: string): SDKQueryBuilderInterface<M>;
338
+ include(...relations: string[]): SDKQueryBuilderInterface<M>;
339
+ }
340
+
341
+ /**
342
+ * The unified data access object for the **admin CMS** (Entity-shaped).
343
+ *
344
+ * Access collections as dynamic properties: `data.products.find(...)`. Each
345
+ * accessor returns `Entity`-wrapped records (`{ id, path, values }`) — the
346
+ * view-model the CMS renders. This is what `useData()` / the admin
347
+ * `RebaseContext.data` are backed by.
348
+ *
349
+ * @internal App developers do **not** use this — they use
350
+ * {@link RebaseSdkData} (flat rows), which is what the SDK client and backend
351
+ * `context.data` expose. This Entity-shaped map backs the admin CMS only.
352
+ *
353
+ * @group Data
354
+ */
355
+ export type RebaseData<DB = unknown> = {
220
356
  /**
221
357
  * Get a collection accessor by slug.
222
358
  * Alternative to dynamic property access for cases where
@@ -226,14 +362,90 @@ export interface RebaseData {
226
362
  * const accessor = data.collection("products");
227
363
  * await accessor.find({ limit: 10 });
228
364
  */
229
- collection(slug: string): CollectionAccessor;
365
+ collection<M extends Record<string, unknown> = Record<string, unknown>>(slug: string): CollectionAccessor<M>;
366
+ } & (
367
+ DB extends Record<string, unknown>
368
+ ? { [K in keyof DB]: CollectionAccessor<DB[K] extends { Row: infer R extends Record<string, unknown> } ? R : Record<string, unknown>> }
369
+ : {
370
+ /**
371
+ * Dynamic collection accessor.
372
+ * Access any collection by its slug as a property.
373
+ *
374
+ * @example
375
+ * data.products.find({ where: { status: ["==", "published"] } })
376
+ */
377
+ [collectionSlug: string]: CollectionAccessor | ((slug: string) => CollectionAccessor);
378
+ }
379
+ );
230
380
 
381
+ /**
382
+ * The unified data access object for the **SDK** — flat rows, no Entity wrapper.
383
+ *
384
+ * This is the symmetric developer-facing data API, identical in shape on both
385
+ * sides of the stack:
386
+ * - The frontend SDK client (`client.data.products.find()`)
387
+ * - Backend framework callbacks & scripts (`context.data.products.find()`)
388
+ *
389
+ * Every accessor returns flat rows (`{ id, ...columns }`) via
390
+ * {@link SDKCollectionClient} — access fields directly (`row.title`), never
391
+ * `row.values.title`. The admin CMS uses {@link RebaseData} (Entity) instead.
392
+ *
393
+ * @example
394
+ * // Frontend SDK
395
+ * const { data: posts } = await client.data.posts.find();
396
+ * console.log(posts[0].title); // flat — no .values
397
+ *
398
+ * // Backend callback — identical shape
399
+ * callbacks: {
400
+ * beforeSave: async ({ context }) => {
401
+ * const product = await context.data.products.findById(id);
402
+ * console.log(product?.price); // flat — no .values
403
+ * }
404
+ * }
405
+ *
406
+ * @group Data
407
+ */
408
+ /**
409
+ * Extract the `Row` shape from a generated `Database[slug]` entry, falling
410
+ * back to an open record when the entry is untyped.
411
+ * @group Data
412
+ */
413
+ export type RowOf<T> = T extends { Row: infer R extends Record<string, unknown> } ? R : Record<string, unknown>;
414
+
415
+ /**
416
+ * Extract the `Insert` shape from a generated `Database[slug]` entry (the
417
+ * input accepted by `create`), falling back to `Partial<Row>`.
418
+ * @group Data
419
+ */
420
+ export type InsertOf<T> = T extends { Insert: infer I extends Record<string, unknown> } ? I : Partial<RowOf<T>>;
421
+
422
+ /**
423
+ * Extract the `Update` shape from a generated `Database[slug]` entry (the
424
+ * input accepted by `update`), falling back to `Partial<Row>`.
425
+ * @group Data
426
+ */
427
+ export type UpdateOf<T> = T extends { Update: infer U extends Record<string, unknown> } ? U : Partial<RowOf<T>>;
428
+
429
+ export type RebaseSdkData<DB = unknown> = {
231
430
  /**
232
- * Dynamic collection accessor.
233
- * Access any collection by its slug as a property.
431
+ * Get a flat collection accessor by slug.
234
432
  *
235
433
  * @example
236
- * data.products.find({ where: { status: "eq.published" } })
434
+ * const accessor = data.collection("products");
435
+ * await accessor.find({ limit: 10 });
237
436
  */
238
- [collectionSlug: string]: CollectionAccessor | ((slug: string) => CollectionAccessor);
239
- }
437
+ collection<M extends Record<string, unknown> = Record<string, unknown>>(slug: string): SDKCollectionClient<M>;
438
+ } & (
439
+ DB extends Record<string, unknown>
440
+ ? { [K in keyof DB]: SDKCollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>> }
441
+ : {
442
+ /**
443
+ * Dynamic flat collection accessor.
444
+ * Access any collection by its slug as a property.
445
+ *
446
+ * @example
447
+ * data.products.find({ where: { status: ["==", "published"] } })
448
+ */
449
+ [collectionSlug: string]: SDKCollectionClient | ((slug: string) => SDKCollectionClient);
450
+ }
451
+ );