@rebasepro/types 0.17.3 → 0.18.1

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 (71) hide show
  1. package/README.md +4 -0
  2. package/dist/call_context.d.ts +20 -0
  3. package/dist/controllers/client.d.ts +36 -4
  4. package/dist/controllers/data.d.ts +120 -10
  5. package/dist/errors.d.ts +83 -4
  6. package/dist/index.es.js +522 -160
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/types/admin_block.d.ts +2 -2
  9. package/dist/types/auth_adapter.d.ts +41 -6
  10. package/dist/types/backend.d.ts +48 -0
  11. package/dist/types/collections.d.ts +25 -1
  12. package/dist/types/cron.d.ts +34 -0
  13. package/dist/types/database_adapter.d.ts +39 -0
  14. package/dist/types/entity_callbacks.d.ts +14 -1
  15. package/dist/types/filter-operators.d.ts +24 -1
  16. package/dist/types/policy.d.ts +29 -1
  17. package/dist/types/properties.d.ts +216 -3
  18. package/dist/types/relations.d.ts +65 -7
  19. package/dist/types/resource_kinds.d.ts +173 -17
  20. package/dist/types/resources.d.ts +108 -7
  21. package/dist/types/rls-functions.d.ts +11 -0
  22. package/dist/types/storage_source.d.ts +12 -23
  23. package/package.json +24 -23
  24. package/src/call_context.ts +0 -120
  25. package/src/controllers/auth_state.ts +0 -24
  26. package/src/controllers/client.ts +0 -494
  27. package/src/controllers/collection_registry.ts +0 -62
  28. package/src/controllers/data.ts +0 -1012
  29. package/src/controllers/data_driver.ts +0 -576
  30. package/src/controllers/effective_role.ts +0 -4
  31. package/src/controllers/email.ts +0 -91
  32. package/src/controllers/index.ts +0 -11
  33. package/src/controllers/storage.ts +0 -252
  34. package/src/errors.ts +0 -119
  35. package/src/index.ts +0 -5
  36. package/src/types/admin_block.ts +0 -209
  37. package/src/types/api_keys.ts +0 -108
  38. package/src/types/auth_adapter.ts +0 -580
  39. package/src/types/backend.ts +0 -987
  40. package/src/types/backup.ts +0 -26
  41. package/src/types/channel_bus.ts +0 -202
  42. package/src/types/chips.ts +0 -34
  43. package/src/types/collection_contract.ts +0 -278
  44. package/src/types/collections.ts +0 -763
  45. package/src/types/component_ref.ts +0 -92
  46. package/src/types/cron.ts +0 -213
  47. package/src/types/data_source.ts +0 -357
  48. package/src/types/database_adapter.ts +0 -267
  49. package/src/types/entities.ts +0 -226
  50. package/src/types/entity_callbacks.ts +0 -229
  51. package/src/types/filter-operators.ts +0 -444
  52. package/src/types/history.ts +0 -66
  53. package/src/types/index.ts +0 -36
  54. package/src/types/indexes.ts +0 -180
  55. package/src/types/policy.ts +0 -328
  56. package/src/types/postgres_introspection.ts +0 -101
  57. package/src/types/project_manifest.ts +0 -598
  58. package/src/types/properties.ts +0 -1368
  59. package/src/types/relations.ts +0 -417
  60. package/src/types/resource_kinds.ts +0 -390
  61. package/src/types/resources.ts +0 -368
  62. package/src/types/rls-functions.ts +0 -98
  63. package/src/types/schema_editing.ts +0 -157
  64. package/src/types/schema_version.ts +0 -112
  65. package/src/types/search.ts +0 -247
  66. package/src/types/security_rules.ts +0 -344
  67. package/src/types/storage_authorize.ts +0 -77
  68. package/src/types/storage_source.ts +0 -248
  69. package/src/types/websockets.ts +0 -117
  70. package/src/users/index.ts +0 -2
  71. package/src/users/user.ts +0 -69
@@ -1,92 +0,0 @@
1
- /**
2
- * How a collection points at a UI component without the backend learning about React.
3
- *
4
- * This file is the hinge the BaaS/admin split turns on. `ComponentRef` is named
5
- * by a property's `admin` block (`admin.Field`, `admin.Preview`, `admin.Filter`)
6
- * and imported by `properties.ts`, which must stay in the React-free core
7
- * because every backend subsystem — validation,
8
- * the drizzle schema generator, the OpenAPI generator, the SDK codegen — reads
9
- * property definitions. If `ComponentRef` needed `React.ComponentType`, the whole
10
- * property model would have to move to the admin layer with it.
11
- *
12
- * So the React types are described structurally instead of imported. Every form
13
- * a React component takes is assignable to {@link ComponentLike}:
14
- *
15
- * - a function component is `(props: P) => ReactNode`
16
- * - a class component satisfies the construct signature (`Component` has `render`)
17
- * - `memo` and `forwardRef` return exotic components, which are callable
18
- *
19
- * The cost is that the return type is `unknown` rather than `ReactNode`, so a
20
- * function that returns something React could not render is accepted here.
21
- * `@rebasepro/cms-types` re-exports a `ReactComponentRef<P>` narrowed against
22
- * the real `React.ComponentType` for authoring and for the admin's internals,
23
- * which restores that check where it can be enforced.
24
- */
25
-
26
- /**
27
- * Structural stand-in for `React.ComponentType<P>`.
28
- *
29
- * Deliberately not `Function` or `unknown`: those would accept anything and the
30
- * resolver's runtime heuristics ({@link ComponentRef} form 3) would be all that
31
- * stood between a typo and a blank screen.
32
- */
33
- export type ComponentLike<P = any> =
34
- | ((props: P) => unknown)
35
- | (new (props: P, context?: unknown) => { render(): unknown });
36
-
37
- /**
38
- * Internal marker for a lazily-loaded component reference.
39
- * Created by the Vite transform plugin when converting string paths
40
- * to deferred `import()` calls. Users should NOT create these manually.
41
- *
42
- * @internal
43
- */
44
- export interface LazyComponentRef<P = unknown> {
45
- readonly __rebaseLazy: true;
46
- readonly load: () => Promise<{ default: ComponentLike<P> }>;
47
- }
48
-
49
- /**
50
- * A reference to a UI component that can be provided in three forms:
51
- *
52
- * 1. **String path** (recommended for collection configs):
53
- * ```ts
54
- * Field: "../../frontend/src/components/MyField"
55
- * ```
56
- * The Vite plugin transforms this into a `LazyComponentRef` at build time.
57
- * On the backend, the string stays inert and is never evaluated.
58
- *
59
- * 2. **Lazy import function**:
60
- * ```ts
61
- * Field: () => import("../../frontend/src/components/MyField")
62
- * ```
63
- * Standard ES dynamic import. Backend never calls the function.
64
- *
65
- * 3. **Direct component reference** (use only in frontend-only code):
66
- * ```ts
67
- * Field: MyFieldComponent
68
- * ```
69
- * Importing a component at the top level will pull React into the
70
- * backend runtime — only safe in code that the backend never imports.
71
- * `pnpm check:headless` fails on a collection file that does this.
72
- *
73
- * @group Types
74
- */
75
- export type ComponentRef<P = any> =
76
- | string
77
- | LazyComponentRef<P>
78
- | (() => Promise<{ default: ComponentLike<P> }>)
79
- | ComponentLike<P>;
80
-
81
- /**
82
- * Type guard: checks if a value is a `LazyComponentRef` produced by the
83
- * Vite transform plugin.
84
- */
85
- export function isLazyComponentRef<P = unknown>(ref: unknown): ref is LazyComponentRef<P> {
86
- return (
87
- typeof ref === "object" &&
88
- ref !== null &&
89
- "__rebaseLazy" in ref &&
90
- (ref as Record<string, unknown>).__rebaseLazy === true
91
- );
92
- }
package/src/types/cron.ts DELETED
@@ -1,213 +0,0 @@
1
- import type { RebaseServerClient } from "../controllers/client";
2
-
3
- /**
4
- * Cron Job type definitions for Rebase.
5
- *
6
- * These types define the shape of cron job definitions, their runtime
7
- * status, and execution log entries — used across server, client,
8
- * and studio packages.
9
- */
10
-
11
- // =============================================================================
12
- // CRON JOB DEFINITION (static, declared by the developer)
13
- // =============================================================================
14
-
15
- /**
16
- * A cron job definition file exports this shape as its default export.
17
- * See the example cron files in `app/backend/crons/` for usage.
18
- */
19
- export interface CronJobDefinition {
20
- // Cron schedule expression, e.g. "0 3 * * *" for daily at 3 AM.
21
- schedule: string;
22
-
23
- /** Human-readable name shown in the Studio UI. */
24
- name: string;
25
-
26
- /** Optional description shown in the Studio UI. */
27
- description?: string;
28
-
29
- /**
30
- * Whether the job is enabled at startup. Defaults to `true`.
31
- * Can be toggled at runtime via the Admin API.
32
- */
33
- enabled?: boolean;
34
-
35
- /**
36
- * Maximum number of seconds the handler may run before being
37
- * considered timed-out. Default: 300 (5 min).
38
- */
39
- timeoutSeconds?: number;
40
-
41
- /**
42
- * How far back to look, on startup, for a slot that elapsed while no
43
- * instance was holding a timer for it. Off by default.
44
- *
45
- * The scheduler drives jobs with in-process `setTimeout` and computes the
46
- * next slot from *now* on every boot, so a slot only fires if some instance
47
- * happened to be alive and ticking when it came round. That is not a
48
- * scale-to-zero problem: a platform that recycles containers — Cloud Run
49
- * rotating an instance under `--min-instances 1`, a rolling deploy, a crash
50
- * loop — drops any slot that falls inside the changeover, and the
51
- * replacement schedules the slot *after* it. The run is skipped in silence.
52
- *
53
- * Set this to a window comfortably wider than a restart (a few minutes for
54
- * a frequent job; an hour or more for a daily one) and startup will run a
55
- * slot it finds unclaimed inside that window.
56
- *
57
- * Two deliberate limits:
58
- *
59
- * - **Only the most recent missed slot runs.** Booting after a six-hour
60
- * outage catches an hourly job up once, not six times. Catch-up exists to
61
- * stop a run going missing, not to replay history.
62
- * - **A claims-capable store is required.** Catch-up is skipped entirely
63
- * when the store has no `tryClaimRun` (or no store is attached), because
64
- * the claim is the only thing that distinguishes "this slot never ran"
65
- * from "this slot already ran on the instance I am replacing". Without
66
- * it, an instance recycled every 30 minutes would re-run the same hourly
67
- * job every time it booted.
68
- *
69
- * @example catchUpWindowSeconds: 3600 // daily job: tolerate an hour of downtime
70
- */
71
- catchUpWindowSeconds?: number;
72
-
73
- /**
74
- * The handler function executed on each tick.
75
- * Receives a context object with the data driver and logger.
76
- * May return arbitrary JSON-serialisable data stored in the log.
77
- */
78
- handler: (ctx: CronJobContext) => Promise<unknown> | unknown;
79
- }
80
-
81
-
82
- /**
83
- * Context passed to each cron handler invocation.
84
- */
85
- export interface CronJobContext {
86
- /** The job's unique ID (derived from filename). */
87
- jobId: string;
88
-
89
- /** The current scheduled tick timestamp. */
90
- scheduledAt: Date;
91
-
92
- /** A simple logger scoped to this job run. */
93
- log: (...args: unknown[]) => void;
94
-
95
- /**
96
- * The server-side Rebase singleton — the **same object** `import { rebase }
97
- * from "@rebasepro/server"` returns, and the same one `defineFunction`
98
- * hands its callback. Spelled the same way here so that one thing has one
99
- * name across every server-side authoring surface.
100
- *
101
- * Its data plane is {@link RebaseServerClient.dataAsAdmin}, scoped as
102
- * `{ uid: "service", roles: ["admin"] }` — **admin-scoped, not
103
- * RLS-bypassing**. Statements still run as `rebase_user` with the policies
104
- * evaluated against that identity; the admin role merely clears the default
105
- * policies through their `rolesOverlap(['admin'])` arm, and
106
- * `policy.serverContext()` (`rebase.uid() IS NULL`) is *false* for it.
107
- * `rebase.sql()` is the unconditional bypass. A cron has no per-request
108
- * user, so there is no user-scoped alternative here: scope every query's
109
- * filters yourself.
110
- *
111
- * @example
112
- * export default defineCron({
113
- * name: "Nightly cleanup",
114
- * schedule: "0 3 * * *",
115
- * async handler({ rebase, log }) {
116
- * const expired = await rebase.dataAsAdmin.sessions.findAll({
117
- * where: { expired: ["==", true] }
118
- * });
119
- * for (const session of expired) {
120
- * await rebase.dataAsAdmin.sessions.delete(session.id as string);
121
- * }
122
- * log(`Deleted ${expired.length} expired sessions`);
123
- * }
124
- * });
125
- */
126
- rebase: RebaseServerClient;
127
-
128
- }
129
-
130
- // =============================================================================
131
- // CRON JOB RUNTIME STATUS (what the API returns)
132
- // =============================================================================
133
-
134
- export type CronJobRunState = "idle" | "running" | "success" | "error" | "disabled";
135
-
136
- /**
137
- * Full runtime information about a registered cron job.
138
- */
139
- export interface CronJobStatus {
140
- /** Unique identifier (derived from filename, e.g. "cleanup-sessions"). */
141
- id: string;
142
-
143
- /** Human-readable name from the definition. */
144
- name: string;
145
-
146
- /** Description from the definition. */
147
- description?: string;
148
-
149
- /** The cron schedule expression. */
150
- schedule: string;
151
-
152
- /** Whether the job is currently enabled. */
153
- enabled: boolean;
154
-
155
- /** Current run state. */
156
- state: CronJobRunState;
157
-
158
- /** ISO timestamp of the last execution start. */
159
- lastRunAt?: string;
160
-
161
- /** ISO timestamp of the next scheduled execution. */
162
- nextRunAt?: string;
163
-
164
- /** Duration of the last run in milliseconds. */
165
- lastDurationMs?: number;
166
-
167
- /** Error message from the last failed run. */
168
- lastError?: string;
169
-
170
- /** Total number of executions since server start. */
171
- totalRuns: number;
172
-
173
- /** Total number of failed executions since server start. */
174
- totalFailures: number;
175
- }
176
-
177
- // =============================================================================
178
- // CRON JOB LOG ENTRY
179
- // =============================================================================
180
-
181
- export type CronLogLevel = "info" | "error" | "warn";
182
-
183
- /**
184
- * A single execution log entry stored in the in-memory ring buffer.
185
- */
186
- export interface CronJobLogEntry {
187
- /** The job ID this log belongs to. */
188
- jobId: string;
189
-
190
- /** ISO timestamp when execution started. */
191
- startedAt: string;
192
-
193
- /** ISO timestamp when execution finished. */
194
- finishedAt: string;
195
-
196
- /** Duration in milliseconds. */
197
- durationMs: number;
198
-
199
- /** Whether this run succeeded. */
200
- success: boolean;
201
-
202
- /** Error message if the run failed. */
203
- error?: string;
204
-
205
- /** Arbitrary result data returned by the handler. */
206
- result?: unknown;
207
-
208
- /** Captured log lines. */
209
- logs: string[];
210
-
211
- /** Whether this was a manual trigger. */
212
- manual?: boolean;
213
- }
@@ -1,357 +0,0 @@
1
- import { ALL_WHERE_FILTER_OPS, WhereFilterOp } from "./filter-operators";
2
-
3
- /**
4
- * Describes the capabilities and features supported by a data source (driver).
5
- *
6
- * Each driver (Postgres, Firebase, MongoDB, etc.) declares which features it
7
- * supports. The admin uses this descriptor to:
8
- * - Show/hide editor tabs (e.g. Relations for SQL, Subcollections for Firebase)
9
- * - Filter the property type picker (e.g. `relation` for SQL, `reference` for Firebase)
10
- * - Toggle driver-specific form controls (e.g. `columnType` for SQL)
11
- *
12
- * @group Models
13
- */
14
- export interface DataSourceCapabilities {
15
- /** Unique driver key (e.g. "postgres", "firestore", "mongodb") */
16
- key: string;
17
-
18
- /** Human-readable label for the UI (e.g. "PostgreSQL", "Firebase / Firestore") */
19
- label: string;
20
-
21
- // ── Feature flags ─────────────────────────────────────────────────
22
- /** Does this source support SQL-style relations (JOINs)? */
23
- supportsRelations: boolean;
24
-
25
- /** Does this source support nested subcollections? */
26
- supportsSubcollections: boolean;
27
-
28
- /** Does this source support Row Level Security policies? */
29
- supportsRLS: boolean;
30
-
31
- /** Does this source support document references (Firebase-style)? */
32
- supportsReferences: boolean;
33
-
34
- /** Does this source support SQL column type annotations? */
35
- supportsColumnTypes: boolean;
36
-
37
- /** Does this source support real-time listeners? */
38
- supportsRealtime: boolean;
39
-
40
- /**
41
- * Does this source store vectors natively?
42
- *
43
- * `VectorProperty` carries a `dimensions` and is pgvector-shaped. It was
44
- * the one driver-specific property kind with no flag to gate it, so unlike
45
- * every other field in this descriptor there was not even a runtime answer
46
- * to appeal to — a Firestore collection could declare an embedding column
47
- * and no driver would do anything with it.
48
- */
49
- supportsVectors: boolean;
50
-
51
- /**
52
- * Canonical filter operators this engine can execute.
53
- *
54
- * The admin UI intersects this set with the property-type defaults and
55
- * any per-property narrowing (`property.ui.filterOperators`) to decide
56
- * which operators to offer in filter fields — so an engine that cannot
57
- * run `ilike` (e.g. Firestore) never shows a "Contains" filter that
58
- * would throw at query time.
59
- */
60
- filterOperators: readonly WhereFilterOp[];
61
-
62
- /**
63
- * Relation kinds this engine's driver can compile into a filter.
64
- *
65
- * Only `belongsTo` puts a column on the row being filtered; the others are
66
- * answered with a correlated subquery over the junction or the target
67
- * table, which not every driver can build. An engine with no relations at
68
- * all declares none.
69
- *
70
- * The admin uses this to decide whether a relation column offers a filter
71
- * control. Offering one an engine cannot answer is not cosmetic: a driver
72
- * that drops the key it cannot resolve *widens* the read to every row, and
73
- * one that fails closed answers a control the admin itself put on screen
74
- * with a 400.
75
- *
76
- * Optional, so a third-party driver registered before this existed still
77
- * compiles. Omitted means {@link DEFAULT_FILTERABLE_RELATION_KINDS} — the
78
- * one kind that is a plain column comparison, which every relational
79
- * driver can do. The subquery kinds are a real capability and have to be
80
- * claimed rather than assumed: assuming them wrongly is the widening.
81
- */
82
- filterableRelationKinds?: readonly string[];
83
-
84
- /**
85
- * Can a filter address a *column of the related row* — `applications.status`
86
- * — rather than only the related row's id?
87
- *
88
- * A separate capability from {@link filterableRelationKinds} because it is
89
- * a separate subquery: the id filter stops at the junction, one of these
90
- * reaches the target table and compares one of its columns. A driver can
91
- * do the first and not the second.
92
- *
93
- * Optional and defaulting to **false**, for the reason the relation kinds
94
- * default narrow: an unclaimed capability that the admin assumes is there
95
- * produces a control whose query the driver answers by dropping the key —
96
- * and a dropped filter key widens the read to every row.
97
- *
98
- * Meaningless without {@link supportsRelations}; a driver with no relations
99
- * has nothing to reach through.
100
- */
101
- supportsRelationFieldFilters?: boolean;
102
-
103
- /**
104
- * Can a sort key be an aggregate over a to-many relation — "oldest waiting
105
- * first", "busiest first"?
106
- *
107
- * Compiled as a correlated scalar subquery in `ORDER BY`, which a document
108
- * store cannot express at all. Optional and defaulting to **false**.
109
- *
110
- * A wrongly claimed sort capability fails differently from a wrongly
111
- * claimed filter one, and worse in one respect: a driver that cannot
112
- * resolve the key drops the `ORDER BY` and answers 200 with rows in
113
- * whatever order the database pleased, which reads as a sorted list. Paging
114
- * over that repeats and skips rows.
115
- */
116
- relationAggregateSorts?: boolean;
117
-
118
- // ── Admin capability flags ───────────────────────────────────────
119
- /** Does this source support SQL admin operations (SQL editor, EXPLAIN, etc.)? */
120
- supportsSQLAdmin: boolean;
121
-
122
- /** Does this source support document admin operations (aggregation, stats)? */
123
- supportsDocumentAdmin: boolean;
124
-
125
- /** Does this source support schema admin (unmapped tables, table metadata)? */
126
- supportsSchemaAdmin: boolean;
127
- }
128
-
129
- /**
130
- * Subset of DataSourceCapabilities containing only feature flags.
131
- * Useful when you only need to check capabilities without UI metadata.
132
- * @group Models
133
- */
134
- export type DataSourceFeatures = Omit<DataSourceCapabilities, "key" | "label">;
135
-
136
- /**
137
- * The default data-source key, used when a collection does not name a
138
- * `dataSource`. Shared by the frontend router and the backend driver
139
- * registry so both agree on "the default database".
140
- * @group Models
141
- */
142
- export const DEFAULT_DATA_SOURCE_KEY = "(default)";
143
-
144
- /**
145
- * How the *frontend* reaches a data source.
146
- *
147
- * - `"server"` — through the Rebase backend (the `RebaseClient`). The backend
148
- * holds the actual database adapter and routes by data-source key. This is
149
- * the default and covers Postgres, MongoDB, and any other server-mediated
150
- * engine.
151
- * - `"direct"` — straight from the client to the external backend via its own
152
- * SDK driver (e.g. Firestore). The Rebase backend is not in the data path.
153
- * - `"custom"` — a developer-supplied {@link DataDriver}, transport unspecified.
154
- *
155
- * @group Models
156
- */
157
- export type DataSourceTransport = "server" | "direct" | "custom";
158
-
159
- /**
160
- * Declarative definition of a data source — a named place data lives.
161
- *
162
- * Declared once and shared front and back: the frontend uses it to decide
163
- * transport (client vs direct driver), the backend uses the same `key` to
164
- * resolve a database adapter, and the editor derives capabilities from
165
- * `engine`. Collections reference a definition by its `key` via
166
- * `collection.dataSource`.
167
- *
168
- * @group Models
169
- */
170
- export interface DataSourceDefinition {
171
- /**
172
- * Unique identifier for this data source. Collections point at it via
173
- * `dataSource`. Defaults to {@link DEFAULT_DATA_SOURCE_KEY}.
174
- */
175
- key: string;
176
-
177
- /**
178
- * The engine backing this data source (e.g. `"postgres"`, `"mongodb"`,
179
- * `"firestore"`, or a custom id). Determines the
180
- * {@link DataSourceCapabilities} surfaced in the editor.
181
- */
182
- engine: string;
183
-
184
- /**
185
- * How the frontend reaches this source. Optional — when omitted it is
186
- * inferred: `"direct"` if the definition carries a client-side driver,
187
- * `"server"` otherwise.
188
- */
189
- transport?: DataSourceTransport;
190
-
191
- /**
192
- * The physical database/schema/Firestore-database within the engine.
193
- * Threaded to drivers/adapters as the existing `databaseId` runtime
194
- * parameter. Defaults to the engine's own default.
195
- */
196
- databaseId?: string;
197
-
198
- /** Human-readable label for the UI. */
199
- label?: string;
200
- }
201
-
202
- /**
203
- * The resolved data source for a collection: the single source of truth that
204
- * the frontend router, backend registry, and editor all derive from.
205
- * Produced by `resolveDataSource(collection, registry)`.
206
- *
207
- * @group Models
208
- */
209
- export interface ResolvedDataSource {
210
- /** Data-source key (routing key, shared front + back). */
211
- key: string;
212
- /** Engine backing the source (drives capabilities). */
213
- engine: string;
214
- /** Frontend transport. */
215
- transport: DataSourceTransport;
216
- /** Within-engine instance, if any (the `databaseId` runtime param). */
217
- databaseId?: string;
218
- /** Capabilities derived from {@link engine}. */
219
- capabilities: DataSourceCapabilities;
220
- }
221
-
222
- /**
223
- * Relation kinds assumed filterable when a driver does not say.
224
- *
225
- * `belongsTo` alone: its filter is a comparison on a column of the row being
226
- * filtered, the one shape that needs no query construction a driver might not
227
- * have. Everything else is a correlated subquery over another table.
228
- *
229
- * @group Models
230
- */
231
- export const DEFAULT_FILTERABLE_RELATION_KINDS: readonly string[] = ["belongsTo"];
232
-
233
- // ── Built-in driver capabilities ─────────────────────────────────────
234
-
235
- /** @group Models */
236
- export const POSTGRES_CAPABILITIES: DataSourceCapabilities = {
237
- key: "postgres",
238
- label: "PostgreSQL",
239
- supportsRelations: true,
240
- supportsSubcollections: false,
241
- supportsRLS: true,
242
- supportsReferences: false,
243
- supportsColumnTypes: true,
244
- supportsRealtime: true,
245
- supportsVectors: true,
246
- filterOperators: ALL_WHERE_FILTER_OPS,
247
- // `via` is absent: its join path is authored source → target with no
248
- // stated inverse, so the driver has nothing to reverse into a filter.
249
- filterableRelationKinds: ["belongsTo", "manyToMany", "hasMany", "hasOne"],
250
- supportsRelationFieldFilters: true,
251
- relationAggregateSorts: true,
252
- supportsSQLAdmin: true,
253
- supportsDocumentAdmin: false,
254
- supportsSchemaAdmin: true
255
- };
256
-
257
- /** @group Models */
258
- export const FIREBASE_CAPABILITIES: DataSourceCapabilities = {
259
- key: "firestore",
260
- label: "Firebase / Firestore",
261
- supportsRelations: false,
262
- supportsSubcollections: true,
263
- supportsRLS: false,
264
- supportsReferences: true,
265
- supportsColumnTypes: false,
266
- supportsRealtime: true,
267
- supportsVectors: false,
268
- // Firestore has no SQL pattern matching — the driver throws on the LIKE
269
- // family, so the UI must never offer it.
270
- filterOperators: ALL_WHERE_FILTER_OPS.filter(op =>
271
- op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
272
- // No relations at all — a document store links by reference. Nothing to
273
- // reach through, so neither of the two relation-reaching features either.
274
- filterableRelationKinds: [],
275
- supportsRelationFieldFilters: false,
276
- relationAggregateSorts: false,
277
- supportsSQLAdmin: false,
278
- supportsDocumentAdmin: false,
279
- supportsSchemaAdmin: false
280
- };
281
-
282
- /** @group Models */
283
- export const MONGODB_CAPABILITIES: DataSourceCapabilities = {
284
- key: "mongodb",
285
- label: "MongoDB",
286
- supportsRelations: false,
287
- supportsSubcollections: true,
288
- supportsRLS: false,
289
- supportsReferences: true,
290
- supportsColumnTypes: false,
291
- supportsRealtime: false,
292
- supportsVectors: false,
293
- filterOperators: ALL_WHERE_FILTER_OPS,
294
- filterableRelationKinds: [],
295
- supportsRelationFieldFilters: false,
296
- relationAggregateSorts: false,
297
- supportsSQLAdmin: false,
298
- supportsDocumentAdmin: true,
299
- supportsSchemaAdmin: true
300
- };
301
-
302
- /**
303
- * Fallback capabilities when the driver is unknown.
304
- * Enables everything so nothing is hidden unexpectedly.
305
- * @group Models
306
- */
307
- export const DEFAULT_CAPABILITIES: DataSourceCapabilities = {
308
- key: "(default)",
309
- label: "Default",
310
- supportsRelations: true,
311
- supportsSubcollections: true,
312
- supportsRLS: true,
313
- supportsReferences: true,
314
- supportsColumnTypes: true,
315
- supportsRealtime: true,
316
- supportsVectors: true,
317
- filterOperators: ALL_WHERE_FILTER_OPS,
318
- // The exception to this descriptor's "enable everything" rule. The other
319
- // flags hide a tab or a picker when they are wrong; this one decides
320
- // whether a query is sent that an unknown driver may answer by dropping
321
- // the condition — which returns every row rather than none.
322
- filterableRelationKinds: DEFAULT_FILTERABLE_RELATION_KINDS,
323
- // Narrow for the same reason, and more sharply. An unknown driver that is
324
- // assumed to compile these answers by dropping the key: the filter widens
325
- // the read to every row, and the sort comes back unordered while looking
326
- // sorted. Both have to be claimed.
327
- supportsRelationFieldFilters: false,
328
- relationAggregateSorts: false,
329
- supportsSQLAdmin: true,
330
- supportsDocumentAdmin: true,
331
- supportsSchemaAdmin: true
332
- };
333
-
334
- const CAPABILITIES_REGISTRY: Record<string, DataSourceCapabilities> = {
335
- postgres: POSTGRES_CAPABILITIES,
336
- firestore: FIREBASE_CAPABILITIES,
337
- mongodb: MONGODB_CAPABILITIES,
338
- "(default)": DEFAULT_CAPABILITIES
339
- };
340
-
341
- /**
342
- * Look up capabilities for a given engine key.
343
- * If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
344
- * @group Models
345
- */
346
- export function getDataSourceCapabilities(engine?: string): DataSourceCapabilities {
347
- if (!engine) return POSTGRES_CAPABILITIES; // postgres is the default engine
348
- return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
349
- }
350
-
351
- /**
352
- * Register custom capabilities for a third-party driver.
353
- * @group Models
354
- */
355
- export function registerDataSourceCapabilities(capabilities: DataSourceCapabilities): void {
356
- CAPABILITIES_REGISTRY[capabilities.key] = capabilities;
357
- }