@rebasepro/common 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 (63) hide show
  1. package/README.md +4 -4
  2. package/dist/collections/CollectionRegistry.d.ts +30 -15
  3. package/dist/collections/default-collections.d.ts +255 -2
  4. package/dist/data/buildRebaseData.d.ts +30 -2
  5. package/dist/data/buildRoutedRebaseData.d.ts +14 -9
  6. package/dist/data/filter-dialect.d.ts +75 -0
  7. package/dist/data/query_builder.d.ts +4 -4
  8. package/dist/data/resolveDataSource.d.ts +8 -8
  9. package/dist/data/sort-dialect.d.ts +41 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.es.js +1125 -299
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.umd.js +1138 -303
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/util/builders.d.ts +52 -42
  16. package/dist/util/callbacks.d.ts +8 -3
  17. package/dist/util/collections.d.ts +4 -4
  18. package/dist/util/entities.d.ts +2 -2
  19. package/dist/util/filter-operator-resolution.d.ts +32 -0
  20. package/dist/util/index.d.ts +2 -0
  21. package/dist/util/navigation_from_path.d.ts +4 -4
  22. package/dist/util/navigation_utils.d.ts +3 -3
  23. package/dist/util/parent_references_from_path.d.ts +2 -2
  24. package/dist/util/permissions.d.ts +30 -6
  25. package/dist/util/policy/evaluatePolicy.d.ts +31 -0
  26. package/dist/util/policy/index.d.ts +3 -0
  27. package/dist/util/policy/policyToPostgres.d.ts +22 -0
  28. package/dist/util/policy/securityRuleToConditions.d.ts +24 -0
  29. package/dist/util/policy/sqlToPolicy.d.ts +20 -0
  30. package/dist/util/references.d.ts +2 -2
  31. package/dist/util/relations.d.ts +5 -5
  32. package/dist/util/resolutions.d.ts +2 -2
  33. package/dist/util/storage.d.ts +26 -1
  34. package/package.json +13 -13
  35. package/src/collections/CollectionRegistry.ts +92 -61
  36. package/src/collections/default-collections.ts +4 -4
  37. package/src/data/buildRebaseData.ts +336 -172
  38. package/src/data/buildRoutedRebaseData.ts +22 -16
  39. package/src/data/filter-dialect.ts +403 -0
  40. package/src/data/query_builder.ts +19 -10
  41. package/src/data/resolveDataSource.ts +10 -10
  42. package/src/data/sort-dialect.ts +56 -0
  43. package/src/index.ts +2 -0
  44. package/src/util/builders.ts +87 -84
  45. package/src/util/callbacks.ts +15 -8
  46. package/src/util/collections.ts +4 -4
  47. package/src/util/entities.ts +4 -4
  48. package/src/util/filter-operator-resolution.ts +81 -0
  49. package/src/util/index.ts +2 -0
  50. package/src/util/navigation_from_path.ts +4 -4
  51. package/src/util/navigation_utils.ts +8 -8
  52. package/src/util/parent_references_from_path.ts +3 -3
  53. package/src/util/permissions.test.ts +7 -5
  54. package/src/util/permissions.ts +90 -163
  55. package/src/util/policy/evaluatePolicy.ts +152 -0
  56. package/src/util/policy/index.ts +3 -0
  57. package/src/util/policy/policyToPostgres.ts +165 -0
  58. package/src/util/policy/securityRuleToConditions.ts +67 -0
  59. package/src/util/policy/sqlToPolicy.ts +88 -0
  60. package/src/util/references.ts +3 -3
  61. package/src/util/relations.ts +19 -20
  62. package/src/util/resolutions.ts +11 -11
  63. package/src/util/storage.ts +34 -1
package/README.md CHANGED
@@ -15,7 +15,7 @@ pnpm add @rebasepro/common
15
15
  - **Collection utilities** — collection registry, default collection definitions, path resolution, navigation helpers
16
16
  - **Data driver adapter** — `buildRebaseData()` bridges any `DataDriver` implementation into a `RebaseData` proxy with typed collection accessors
17
17
  - **Query builder** — fluent `QueryBuilder` class plus `or()`, `and()`, `cond()` helpers for composing complex queries
18
- - **Entity/property utilities** — entity resolution, enum helpers, permission checks, reference/relation helpers, storage path utils, callback utilities
18
+ - **Snapshot/property utilities** — snapshot resolution, enum helpers, permission checks, reference/relation helpers, storage path utils, callback utilities
19
19
 
20
20
  This package has no React dependency — it's pure TypeScript and can be used in both client and server contexts.
21
21
 
@@ -44,7 +44,7 @@ This package has no React dependency — it's pure TypeScript and can be used in
44
44
  |---|---|
45
45
  | `collections` | Collection config helpers |
46
46
  | `common` | General-purpose utilities |
47
- | `entities` | Entity value resolution |
47
+ | `snapshots` | Snapshot value resolution |
48
48
  | `enums` | Enum type helpers |
49
49
  | `paths` | Path parsing and manipulation |
50
50
  | `resolutions` | Property and collection resolution |
@@ -69,7 +69,7 @@ const data = buildRebaseData(myDriver);
69
69
 
70
70
  // Access collections by name (camelCase auto-converts to snake_case)
71
71
  const { data: products } = await data.products.find({ limit: 10 });
72
- const entity = await data.products.findById("abc-123");
72
+ const snapshot = await data.products.findById("abc-123");
73
73
 
74
74
  // Fluent query builder
75
75
  const { data: results } = await data.products
@@ -89,7 +89,7 @@ const { data: filtered } = await data.products
89
89
 
90
90
  ## Related Packages
91
91
 
92
- - [`@rebasepro/types`](../types) — `DataDriver`, `RebaseData`, `CollectionAccessor`, `Entity`, `FindResponse`, etc.
92
+ - [`@rebasepro/types`](../types) — `DataDriver`, `RebaseData`, `CollectionAccessor`, `Snapshot`, `FindResponse`, etc.
93
93
  - [`@rebasepro/utils`](../utils) — Low-level utilities (`toSnakeCase`, etc.)
94
94
  - [`@rebasepro/core`](../core) — Runtime layer that consumes `@rebasepro/common`
95
95
  - [`@rebasepro/client`](../client) — HTTP client that re-exports and extends the `QueryBuilder`
@@ -1,12 +1,27 @@
1
- import { EntityCollection } from "@rebasepro/types";
1
+ import { CollectionCallbacks, CollectionConfig } from "@rebasepro/types";
2
2
  import { DataSourceRegistry } from "../data/resolveDataSource";
3
3
  export declare class CollectionRegistry {
4
4
  /**
5
5
  * Declared data sources, used during normalization to resolve each
6
6
  * collection's engine (so `dataSource`-only collections get the right
7
- * capabilities). Empty by default → behaviour keys off `driver` as before.
7
+ * capabilities). Empty by default.
8
8
  */
9
9
  private dataSources;
10
+ /**
11
+ * Global lifecycle callbacks applied to every collection.
12
+ * Runs on all data paths (REST, WebSocket, `rebase.data`).
13
+ * Execution order: global → collection → property callbacks.
14
+ */
15
+ private _globalCallbacks?;
16
+ /**
17
+ * Set global lifecycle callbacks that apply to every collection.
18
+ * Typically called once during backend initialization.
19
+ */
20
+ setGlobalCallbacks(callbacks: CollectionCallbacks): void;
21
+ /**
22
+ * Get the currently registered global callbacks, if any.
23
+ */
24
+ getGlobalCallbacks(): CollectionCallbacks | undefined;
10
25
  private collectionsByTableName;
11
26
  private collectionsBySlug;
12
27
  private rootCollections;
@@ -15,8 +30,8 @@ export declare class CollectionRegistry {
15
30
  private rawCollectionsBySlug;
16
31
  private rawRootCollections;
17
32
  private cachedRawCollectionsList;
18
- private lastRawInputSnapshot;
19
- constructor(collections?: EntityCollection[], dataSources?: DataSourceRegistry);
33
+ private lastRawInputEntity;
34
+ constructor(collections?: CollectionConfig[], dataSources?: DataSourceRegistry);
20
35
  /**
21
36
  * Provide the declared data sources used to resolve each collection's
22
37
  * engine during normalization. Set this before registering collections.
@@ -29,13 +44,13 @@ export declare class CollectionRegistry {
29
44
  * Returns true if the collections have changed, false otherwise.
30
45
  *
31
46
  * Idempotent: compares the raw input (before normalization) against a stored
32
- * snapshot. Only re-normalizes and re-registers when the raw input actually changed.
47
+ * entity. Only re-normalizes and re-registers when the raw input actually changed.
33
48
  * @param collections
34
49
  */
35
- registerMultiple(collections: EntityCollection[]): boolean;
36
- register(collection: EntityCollection, rawCollection?: EntityCollection): void;
50
+ registerMultiple(collections: CollectionConfig[]): boolean;
51
+ register(collection: CollectionConfig, rawCollection?: CollectionConfig): void;
37
52
  private _registerRecursively;
38
- normalizeCollection(collection: EntityCollection): EntityCollection;
53
+ normalizeCollection(collection: CollectionConfig): CollectionConfig;
39
54
  /**
40
55
  * Extract Relation[] from properties that have inline relation config (i.e. `target` is set).
41
56
  * This allows developers to define relations directly on properties without a separate
@@ -44,26 +59,26 @@ export declare class CollectionRegistry {
44
59
  private extractRelationsFromProperties;
45
60
  private normalizeProperties;
46
61
  private normalizeProperty;
47
- get(path: string): EntityCollection | undefined;
62
+ get(path: string): CollectionConfig | undefined;
48
63
  /**
49
64
  * Gets the pristine, un-normalized collection exactly as it was provided.
50
65
  * Useful for the AST editor so it doesn't accidentally serialize injected metadata back to disk.
51
66
  */
52
- getRaw(path: string): EntityCollection | undefined;
67
+ getRaw(path: string): CollectionConfig | undefined;
53
68
  /**
54
69
  * Get collection by resolving multi-segment paths through relations
55
70
  * e.g., "authors/70/posts" resolves to the posts collection
56
71
  */
57
- getCollectionByPath(collectionPath: string): EntityCollection | undefined;
58
- getCollections(): EntityCollection[];
59
- getRawCollections(): EntityCollection[];
72
+ getCollectionByPath(collectionPath: string): CollectionConfig | undefined;
73
+ getCollections(): CollectionConfig[];
74
+ getRawCollections(): CollectionConfig[];
60
75
  /**
61
76
  * Resolves a multi-segment path like "products/123/locales" and returns
62
77
  * information about the collections and entity IDs along the path
63
78
  */
64
79
  resolvePathToCollections(path: string): {
65
- collections: EntityCollection[];
80
+ collections: CollectionConfig[];
66
81
  entityIds: (string | number)[];
67
- finalCollection: EntityCollection;
82
+ finalCollection: CollectionConfig;
68
83
  };
69
84
  }
@@ -1,4 +1,3 @@
1
- import type { PostgresCollection } from "@rebasepro/types";
2
1
  /**
3
2
  * Default users collection.
4
3
  *
@@ -6,4 +5,258 @@ import type { PostgresCollection } from "@rebasepro/types";
6
5
  * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers
7
6
  * override by defining their own collection with `slug: "users"`.
8
7
  */
9
- export declare const defaultUsersCollection: PostgresCollection;
8
+ export declare const defaultUsersCollection: import("@rebasepro/types").PostgresCollectionConfig<import("@rebasepro/types").InferEntityType<{
9
+ readonly id: {
10
+ readonly name: "ID";
11
+ readonly type: "string";
12
+ readonly isId: "uuid";
13
+ readonly ui: {
14
+ readonly readOnly: true;
15
+ };
16
+ };
17
+ readonly email: {
18
+ readonly name: "Email";
19
+ readonly type: "string";
20
+ readonly validation: {
21
+ readonly required: true;
22
+ readonly unique: true;
23
+ };
24
+ };
25
+ readonly displayName: {
26
+ readonly name: "Name";
27
+ readonly type: "string";
28
+ readonly columnName: "display_name";
29
+ readonly validation: {
30
+ readonly required: true;
31
+ };
32
+ };
33
+ readonly photoURL: {
34
+ readonly name: "Photo URL";
35
+ readonly type: "string";
36
+ readonly columnName: "photo_url";
37
+ readonly ui: {
38
+ readonly url: "image";
39
+ };
40
+ };
41
+ readonly roles: {
42
+ readonly name: "Roles";
43
+ readonly type: "array";
44
+ readonly columnType: "text[]";
45
+ readonly of: {
46
+ readonly name: "Role";
47
+ readonly type: "string";
48
+ readonly enum: {
49
+ readonly admin: "Admin";
50
+ readonly editor: "Editor";
51
+ readonly viewer: "Viewer";
52
+ };
53
+ };
54
+ };
55
+ readonly passwordHash: {
56
+ readonly name: "Password Hash";
57
+ readonly type: "string";
58
+ readonly columnName: "password_hash";
59
+ readonly ui: {
60
+ readonly hideFromCollection: true;
61
+ readonly disabled: {
62
+ readonly hidden: true;
63
+ };
64
+ };
65
+ };
66
+ readonly emailVerified: {
67
+ readonly name: "Email Verified";
68
+ readonly type: "boolean";
69
+ readonly columnName: "email_verified";
70
+ readonly defaultValue: false;
71
+ readonly ui: {
72
+ readonly hideFromCollection: true;
73
+ readonly disabled: {
74
+ readonly hidden: true;
75
+ };
76
+ };
77
+ };
78
+ readonly emailVerificationToken: {
79
+ readonly name: "Email Verification Token";
80
+ readonly type: "string";
81
+ readonly columnName: "email_verification_token";
82
+ readonly ui: {
83
+ readonly hideFromCollection: true;
84
+ readonly disabled: {
85
+ readonly hidden: true;
86
+ };
87
+ };
88
+ };
89
+ readonly emailVerificationSentAt: {
90
+ readonly name: "Email Verification Sent At";
91
+ readonly type: "date";
92
+ readonly columnName: "email_verification_sent_at";
93
+ readonly ui: {
94
+ readonly hideFromCollection: true;
95
+ readonly disabled: {
96
+ readonly hidden: true;
97
+ };
98
+ };
99
+ };
100
+ readonly metadata: {
101
+ readonly name: "Metadata";
102
+ readonly type: "map";
103
+ readonly keyValue: true;
104
+ readonly properties: {};
105
+ readonly defaultValue: {};
106
+ readonly ui: {
107
+ readonly hideFromCollection: true;
108
+ readonly disabled: {
109
+ readonly hidden: true;
110
+ };
111
+ };
112
+ };
113
+ readonly createdAt: {
114
+ readonly name: "Created At";
115
+ readonly type: "date";
116
+ readonly columnName: "created_at";
117
+ readonly autoValue: "on_create";
118
+ readonly ui: {
119
+ readonly readOnly: true;
120
+ };
121
+ };
122
+ readonly updatedAt: {
123
+ readonly name: "Updated At";
124
+ readonly type: "date";
125
+ readonly columnName: "updated_at";
126
+ readonly autoValue: "on_update";
127
+ readonly ui: {
128
+ readonly hideFromCollection: true;
129
+ readonly disabled: {
130
+ readonly hidden: true;
131
+ };
132
+ };
133
+ };
134
+ }>, import("@rebasepro/types").User> & {
135
+ properties: {
136
+ readonly id: {
137
+ readonly name: "ID";
138
+ readonly type: "string";
139
+ readonly isId: "uuid";
140
+ readonly ui: {
141
+ readonly readOnly: true;
142
+ };
143
+ };
144
+ readonly email: {
145
+ readonly name: "Email";
146
+ readonly type: "string";
147
+ readonly validation: {
148
+ readonly required: true;
149
+ readonly unique: true;
150
+ };
151
+ };
152
+ readonly displayName: {
153
+ readonly name: "Name";
154
+ readonly type: "string";
155
+ readonly columnName: "display_name";
156
+ readonly validation: {
157
+ readonly required: true;
158
+ };
159
+ };
160
+ readonly photoURL: {
161
+ readonly name: "Photo URL";
162
+ readonly type: "string";
163
+ readonly columnName: "photo_url";
164
+ readonly ui: {
165
+ readonly url: "image";
166
+ };
167
+ };
168
+ readonly roles: {
169
+ readonly name: "Roles";
170
+ readonly type: "array";
171
+ readonly columnType: "text[]";
172
+ readonly of: {
173
+ readonly name: "Role";
174
+ readonly type: "string";
175
+ readonly enum: {
176
+ readonly admin: "Admin";
177
+ readonly editor: "Editor";
178
+ readonly viewer: "Viewer";
179
+ };
180
+ };
181
+ };
182
+ readonly passwordHash: {
183
+ readonly name: "Password Hash";
184
+ readonly type: "string";
185
+ readonly columnName: "password_hash";
186
+ readonly ui: {
187
+ readonly hideFromCollection: true;
188
+ readonly disabled: {
189
+ readonly hidden: true;
190
+ };
191
+ };
192
+ };
193
+ readonly emailVerified: {
194
+ readonly name: "Email Verified";
195
+ readonly type: "boolean";
196
+ readonly columnName: "email_verified";
197
+ readonly defaultValue: false;
198
+ readonly ui: {
199
+ readonly hideFromCollection: true;
200
+ readonly disabled: {
201
+ readonly hidden: true;
202
+ };
203
+ };
204
+ };
205
+ readonly emailVerificationToken: {
206
+ readonly name: "Email Verification Token";
207
+ readonly type: "string";
208
+ readonly columnName: "email_verification_token";
209
+ readonly ui: {
210
+ readonly hideFromCollection: true;
211
+ readonly disabled: {
212
+ readonly hidden: true;
213
+ };
214
+ };
215
+ };
216
+ readonly emailVerificationSentAt: {
217
+ readonly name: "Email Verification Sent At";
218
+ readonly type: "date";
219
+ readonly columnName: "email_verification_sent_at";
220
+ readonly ui: {
221
+ readonly hideFromCollection: true;
222
+ readonly disabled: {
223
+ readonly hidden: true;
224
+ };
225
+ };
226
+ };
227
+ readonly metadata: {
228
+ readonly name: "Metadata";
229
+ readonly type: "map";
230
+ readonly keyValue: true;
231
+ readonly properties: {};
232
+ readonly defaultValue: {};
233
+ readonly ui: {
234
+ readonly hideFromCollection: true;
235
+ readonly disabled: {
236
+ readonly hidden: true;
237
+ };
238
+ };
239
+ };
240
+ readonly createdAt: {
241
+ readonly name: "Created At";
242
+ readonly type: "date";
243
+ readonly columnName: "created_at";
244
+ readonly autoValue: "on_create";
245
+ readonly ui: {
246
+ readonly readOnly: true;
247
+ };
248
+ };
249
+ readonly updatedAt: {
250
+ readonly name: "Updated At";
251
+ readonly type: "date";
252
+ readonly columnName: "updated_at";
253
+ readonly autoValue: "on_update";
254
+ readonly ui: {
255
+ readonly hideFromCollection: true;
256
+ readonly disabled: {
257
+ readonly hidden: true;
258
+ };
259
+ };
260
+ };
261
+ };
262
+ };
@@ -1,4 +1,4 @@
1
- import { DataDriver, RebaseData } from "@rebasepro/types";
1
+ import { DataDriver, RebaseData, RebaseSdkData } from "@rebasepro/types";
2
2
  /**
3
3
  * Build a `RebaseData` object from a `DataDriver` using JavaScript Proxy.
4
4
  *
@@ -9,6 +9,34 @@ import { DataDriver, RebaseData } from "@rebasepro/types";
9
9
  * @example
10
10
  * const data = buildRebaseData(driver);
11
11
  * await data.products.create({ name: "Camera", price: 299 });
12
- * const { data: items } = await data.products.find({ where: { status: "eq.published" } });
12
+ * const { data: items } = await data.products.find({ where: { status: ["==", "published"] } });
13
13
  */
14
14
  export declare function buildRebaseData(driver: DataDriver): RebaseData;
15
+ /**
16
+ * Wrap a flat {@link RebaseSdkData} into a Entity-shaped {@link RebaseData}.
17
+ *
18
+ * This is the **CMS boundary**: the SDK client (`client.data`) returns flat
19
+ * rows, but the admin renders the `Entity` view-model (`entity.values.*`).
20
+ * `core/Rebase.tsx` wraps `client.data` through this before handing it to the
21
+ * CMS `RebaseDataContext` — without it the admin renders rows with only their
22
+ * `id`.
23
+ */
24
+ export declare function wrapAsEntityData(sdkData: RebaseSdkData): RebaseData;
25
+ /**
26
+ * Wrap a Entity-shaped {@link RebaseData} into a flat {@link RebaseSdkData}.
27
+ *
28
+ * Every collection accessor is adapted to return flat rows. Use this to derive
29
+ * the flat SDK data layer (`context.data`) from an existing Entity data layer
30
+ * — e.g. the admin routes its Entity data via `useData()` and exposes the
31
+ * same routing as flat `context.data` for callbacks by wrapping it here.
32
+ */
33
+ export declare function wrapAsSdkData(entityData: RebaseData): RebaseSdkData;
34
+ /**
35
+ * Build a flat {@link RebaseSdkData} from a `DataDriver`.
36
+ *
37
+ * This is the developer-facing SDK data layer used by backend framework
38
+ * callbacks & scripts (`context.data` / `rebase.data`). It returns flat rows —
39
+ * identical in shape to the frontend SDK client — so the API is symmetric
40
+ * across front and back. The admin CMS uses {@link buildRebaseData} (Entity).
41
+ */
42
+ export declare function buildSdkData(driver: DataDriver): RebaseSdkData;
@@ -1,21 +1,26 @@
1
- import { RebaseData } from "@rebasepro/types";
1
+ import { RebaseData, RebaseSdkData } from "@rebasepro/types";
2
+ /**
3
+ * The two data-layer shapes that can be routed: the Entity-shaped admin
4
+ * {@link RebaseData} or the flat SDK {@link RebaseSdkData}. Both expose a
5
+ * `.collection(slug)` accessor, which is all the router needs.
6
+ */
7
+ export type RoutableData = RebaseData | RebaseSdkData;
2
8
  /**
3
9
  * Parameters for {@link buildRoutedRebaseData}.
4
10
  */
5
- export interface RoutedRebaseDataParams {
11
+ export interface RoutedRebaseDataParams<T extends RoutableData = RebaseData> {
6
12
  /**
7
13
  * The default data source. Handles every collection that does not
8
14
  * resolve to an entry in `sources` (i.e. server-transport collections,
9
15
  * which ride the Rebase client).
10
16
  */
11
- defaultData: RebaseData;
17
+ defaultData: T;
12
18
  /**
13
- * Per-data-source {@link RebaseData} instances for direct and custom
14
- * transports, keyed by data-source key (e.g. `"analytics"`). Server-
15
- * mediated sources are not listed here — they fall through to
16
- * `defaultData`.
19
+ * Per-data-source instances for direct and custom transports, keyed by
20
+ * data-source key (e.g. `"analytics"`). Server-mediated sources are not
21
+ * listed here — they fall through to `defaultData`.
17
22
  */
18
- sources: Record<string, RebaseData>;
23
+ sources: Record<string, T>;
19
24
  /**
20
25
  * Resolve the data-source key for a given collection slug or path.
21
26
  * Typically backed by the collection registry + `resolveDataSource`
@@ -50,4 +55,4 @@ export interface RoutedRebaseDataParams {
50
55
  * await data.products.find(); // → default (server / Postgres)
51
56
  * await data.events.find(); // → Firestore, if `events.dataSource === "analytics"`
52
57
  */
53
- export declare function buildRoutedRebaseData({ defaultData, sources, resolveKey }: RoutedRebaseDataParams): RebaseData;
58
+ export declare function buildRoutedRebaseData<T extends RoutableData = RebaseData>({ defaultData, sources, resolveKey }: RoutedRebaseDataParams<T>): T;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * REST wire-format adapter for the unified filter system.
3
+ *
4
+ * This module is the ONLY code in the entire codebase that knows about
5
+ * PostgREST-style dot-syntax strings (`eq.active`, `gt.18`, `in.(a,b)`).
6
+ * Everything else speaks `FilterValues` exclusively.
7
+ *
8
+ * Wire-format values are always strings — the wire format carries no type
9
+ * metadata, so type coercion is the responsibility of the server-side data
10
+ * driver which has access to the collection schema.
11
+ *
12
+ * Commas inside list values are backslash-escaped (`\,`), and literal
13
+ * backslashes are escaped as `\\`.
14
+ *
15
+ * @module
16
+ */
17
+ import { FilterValues, LogicalCondition, FilterCondition } from "@rebasepro/types";
18
+ /**
19
+ * Convert `FilterValues` (or `WireFilterValues`) to a PostgREST-style
20
+ * querystring record.
21
+ *
22
+ * - Canonical `[WhereFilterOp, value]` tuples are serialized strictly.
23
+ * - Pre-serialized PostgREST strings (e.g. `"eq.published"`) are passed through.
24
+ * - Single conditions produce a string value.
25
+ * - Multiple conditions on the same field produce a string array (repeated params).
26
+ *
27
+ * @example
28
+ * serializeFilter({ status: ["==", "active"] })
29
+ * // → { status: "eq.active" }
30
+ *
31
+ * serializeFilter({ age: [[">=", 18], ["<", 65]] })
32
+ * // → { age: ["gte.18", "lt.65"] }
33
+ *
34
+ * // Pre-serialized strings pass through unchanged:
35
+ * serializeFilter({ status: "eq.published" })
36
+ * // → { status: "eq.published" }
37
+ */
38
+ export declare function serializeFilter(filter: FilterValues<string> | Record<string, unknown>): Record<string, string | string[]>;
39
+ /**
40
+ * Convert a PostgREST-style querystring record to `FilterValues`.
41
+ *
42
+ * - String values are parsed as single conditions.
43
+ * - String arrays (repeated query params) become multiple conditions on the same field.
44
+ *
45
+ * @example
46
+ * deserializeFilter({ status: "eq.active" })
47
+ * // → { status: ["==", "active"] }
48
+ *
49
+ * deserializeFilter({ age: ["gte.18", "lt.65"] })
50
+ * // → { age: [[">=", "18"], ["<", "65"]] }
51
+ */
52
+ export declare function deserializeFilter(query: Record<string, unknown>): FilterValues<string>;
53
+ /**
54
+ * Serialize a `LogicalCondition` or `FilterCondition` to its wire-format string.
55
+ *
56
+ * @example
57
+ * serializeLogicalCondition({ column: "status", operator: "==", value: "active" })
58
+ * // → "status.eq.active"
59
+ *
60
+ * serializeLogicalCondition({ type: "or", conditions: [...] })
61
+ * // → "or(status.eq.active,status.eq.pending)"
62
+ */
63
+ export declare function serializeLogicalCondition(cond: LogicalCondition | FilterCondition): string;
64
+ /**
65
+ * Parse a logical condition wire-format string back into a
66
+ * `LogicalCondition` or `FilterCondition`.
67
+ *
68
+ * @example
69
+ * deserializeLogicalCondition("status.eq.active")
70
+ * // → { column: "status", operator: "==", value: "active" }
71
+ *
72
+ * deserializeLogicalCondition("or(status.eq.active,age.gte.18)")
73
+ * // → { type: "or", conditions: [...] }
74
+ */
75
+ export declare function deserializeLogicalCondition(str: string): LogicalCondition | FilterCondition;
@@ -1,7 +1,7 @@
1
- import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator, LogicalCondition, WhereValue, FilterCondition } from "@rebasepro/types";
1
+ import { CollectionAccessor, FilterCondition, FindResponse, LogicalCondition, QueryBuilderInterface, WhereFilterOp, WhereValue } from "@rebasepro/types";
2
2
  export declare function or(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
3
3
  export declare function and(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
4
- export declare function cond(column: string, operator: FilterOperator, value: unknown): FilterCondition;
4
+ export declare function cond(column: string, operator: WhereFilterOp, value: unknown): FilterCondition;
5
5
  export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {
6
6
  private collection;
7
7
  private params;
@@ -11,14 +11,14 @@ export declare class QueryBuilder<M extends Record<string, unknown> = Record<str
11
11
  * @example
12
12
  * client.collection('users').where('age', '>=', 18).find()
13
13
  */
14
- where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;
14
+ where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): this;
15
15
  where(logicalCondition: LogicalCondition): this;
16
16
  /**
17
17
  * Order the results by a specific column.
18
18
  * @example
19
19
  * client.collection('users').orderBy('createdAt', 'desc').find()
20
20
  */
21
- orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
21
+ orderBy(column: keyof M & string, direction?: "asc" | "desc"): this;
22
22
  /**
23
23
  * Limit the number of results returned.
24
24
  */
@@ -1,15 +1,15 @@
1
1
  import { DataSourceDefinition, ResolvedDataSource } from "@rebasepro/types";
2
2
  /**
3
3
  * The subset of a collection needed to resolve its data source. Accepting a
4
- * structural type (rather than the full `EntityCollection`) keeps this usable
4
+ * structural type (rather than the full `CollectionConfig`) keeps this usable
5
5
  * from anywhere — frontend router, backend registry, editor — without coupling
6
6
  * to the collection union.
7
7
  */
8
8
  export interface DataSourceResolvable {
9
9
  /** Preferred routing key. */
10
10
  dataSource?: string;
11
- /** Legacy engine hint / fallback routing key. */
12
- driver?: string;
11
+ /** Engine type discriminant (set on variant collection types). */
12
+ engine?: string;
13
13
  /** Within-engine instance. */
14
14
  databaseId?: string;
15
15
  }
@@ -26,13 +26,13 @@ export declare function createDataSourceRegistry(definitions?: DataSourceDefinit
26
26
  * editor's capability lookups.
27
27
  *
28
28
  * Resolution order:
29
- * 1. The routing **key** is `collection.dataSource`, else the legacy
30
- * `collection.driver`, else {@link DEFAULT_DATA_SOURCE_KEY}.
29
+ * 1. The routing **key** is `collection.dataSource`, else
30
+ * {@link DEFAULT_DATA_SOURCE_KEY}.
31
31
  * 2. If a definition is registered for that key, it provides `engine`,
32
32
  * `transport`, and `databaseId`.
33
- * 3. Otherwise values are synthesized for backward compatibility: `engine`
34
- * from the legacy `driver` (or the key, or `"postgres"`), `transport`
35
- * defaults to `"server"`, and `databaseId` from the collection.
33
+ * 3. Otherwise values are synthesized: `engine` from `collection.engine`
34
+ * (or the key, or `"postgres"`), `transport` defaults to `"server"`,
35
+ * and `databaseId` from the collection.
36
36
  *
37
37
  * `capabilities` are always derived from the resolved `engine`, so two
38
38
  * data sources sharing an engine share capabilities.
@@ -0,0 +1,41 @@
1
+ import type { OrderByTuple } from "@rebasepro/types";
2
+ /**
3
+ * Sort-order wire codec.
4
+ *
5
+ * This is the ONLY module that knows about the colon-delimited wire format
6
+ * (`"field:direction"`) used in HTTP query parameters.
7
+ * Everything else speaks {@link OrderByTuple} exclusively.
8
+ *
9
+ * Mirrors the filter architecture in `filter-dialect.ts`.
10
+ *
11
+ * @module
12
+ */
13
+ /**
14
+ * Serialize an {@link OrderByTuple} to the wire format `"field:direction"`.
15
+ *
16
+ * **Runtime tolerance:** if the input is already a well-formed wire string
17
+ * (from an untyped JS caller), it is returned unchanged.
18
+ * This is undocumented tolerance, not public API — don't rely on it.
19
+ *
20
+ * @param orderBy - A canonical `[field, direction]` tuple, or at runtime
21
+ * possibly a pre-serialized string (undocumented tolerance).
22
+ * @returns The wire-format string, or `undefined` if the input is falsy.
23
+ *
24
+ * @remarks
25
+ * Field names containing `:` are representable in the tuple form but
26
+ * **not** on the wire — this is an inherent limitation of the colon-delimited
27
+ * encoding and is not resolved here.
28
+ */
29
+ export declare function serializeOrderBy(orderBy?: OrderByTuple | string): string | undefined;
30
+ /**
31
+ * Deserialize a wire-format `"field:direction"` string into an {@link OrderByTuple}.
32
+ *
33
+ * Lenient parsing (matches existing server behaviour):
34
+ * - Bare field name (no colon): `"name"` → `["name", "asc"]`
35
+ * - Unknown direction: `"name:foo"` → `["name", "asc"]`
36
+ * - Empty / falsy input: → `undefined`
37
+ *
38
+ * @param raw - The wire-format string from an HTTP query parameter.
39
+ * @returns The canonical tuple, or `undefined` if the input is empty/falsy.
40
+ */
41
+ export declare function deserializeOrderBy(raw?: string): OrderByTuple | undefined;
package/dist/index.d.ts CHANGED
@@ -4,4 +4,6 @@ export * from "./data/buildRebaseData";
4
4
  export * from "./data/buildRoutedRebaseData";
5
5
  export * from "./data/resolveDataSource";
6
6
  export * from "./data/query_builder";
7
+ export * from "./data/filter-dialect";
8
+ export * from "./data/sort-dialect";
7
9
  export * from "./table-classification";