@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,390 +0,0 @@
1
- /**
2
- * The kinds Rebase ships, and the constructors a project declares them with.
3
- *
4
- * Each kind is registered rather than hardcoded, so a fourth one arrives
5
- * without editing a manifest schema, a validator and a switch statement. That
6
- * cost is precisely why databases and buckets ended up declared in different
7
- * files with different rules — the cheapest thing to do was always to bolt the
8
- * new kind onto whichever home was nearest.
9
- *
10
- * A kind owns its engine list. `custom:<id>` is always accepted, so a build
11
- * that ships an engine this package has never heard of says so at the call site
12
- * instead of looking like a typo of one that exists.
13
- */
14
- import {
15
- DEFAULT_RESOURCE_KEY,
16
- declareResource,
17
- declaredResources,
18
- registerResourceKind,
19
- type DeclareOptions,
20
- type ResourceHandle,
21
- type ResourceTransport
22
- } from "./resources";
23
-
24
- // ── database ─────────────────────────────────────────────────────────────────
25
-
26
- registerResourceKind({
27
- kind: "database",
28
- engines: ["postgres", "mongodb", "firestore", "sqlite"],
29
- defaultEngine: "postgres",
30
- // REBASE_DRIVER overrides the engine's default driver package; the pool
31
- // ceiling is per-source because one source can be a single-session PGlite
32
- // and another a real server.
33
- envBases: ["DATABASE_URL", "REBASE_DRIVER", "REBASE_DB_POOL_MAX"],
34
- // No per-engine narrowing: every engine binds from the same three, and the
35
- // driver package that differs between them is named by REBASE_DRIVER either
36
- // way.
37
- optionKeys: ["databaseId", "migrations", "extensions"],
38
- // A backend without a database is not a backend, so one exists whether or
39
- // not a project says so.
40
- implicitDefault: true
41
- });
42
-
43
- /** Options a database accepts beyond the common ones. */
44
- export interface DatabaseOptions extends DeclareOptions {
45
- /**
46
- * The physical database or schema within the engine, when it differs from
47
- * the engine's own default. Threaded to drivers as `databaseId`.
48
- */
49
- databaseId?: string;
50
- /** Directory of migration files, relative to the config directory. */
51
- migrations?: string;
52
- /**
53
- * Server extensions Rebase may install on this database.
54
- *
55
- * A permission, not a request: naming one grants leave to run
56
- * `CREATE EXTENSION IF NOT EXISTS <name>`, and Rebase issues it only when
57
- * something in the schema actually needs it. Naming an extension nothing
58
- * needs installs nothing.
59
- *
60
- * It has to be said out loud because installing an extension is a decision
61
- * with a deployment behind it — the image has to ship the library, the role
62
- * has to be allowed to install it, and a managed provider has to have it on
63
- * an allow-list. Rebase cannot see any of that from inside the connection,
64
- * so the answer comes from whoever chose the database.
65
- *
66
- * Today `vector` is the one that matters: a `{ type: "vector" }` property
67
- * compiles to a `VECTOR(n)` column, which does not exist until pgvector is
68
- * installed. Without this, Rebase creates the column and lets Postgres
69
- * refuse, naming the option.
70
- *
71
- * ```ts
72
- * export const main = database({ extensions: ["vector"] });
73
- * ```
74
- *
75
- * `pg_trgm` and `unaccent` are not on this list and need no permission: a
76
- * `search` block installs them unasked, because they are contrib modules
77
- * present in every Postgres distribution. pgvector is a separate build that
78
- * a stock `postgres:18` does not carry.
79
- */
80
- extensions?: string[];
81
- }
82
-
83
- /** A database handle. Collections point at it via `dataSource`. */
84
- export type DatabaseHandle = ResourceHandle;
85
-
86
- /**
87
- * Declare a database.
88
- *
89
- * ```ts
90
- * export const main = database(); // the default one
91
- * export const analytics = database("analytics"); // reads DATABASE_URL__ANALYTICS
92
- * export const withPgv = database({ extensions: ["vector"] }); // the default one, configured
93
- * ```
94
- *
95
- * The third form exists because the default database has no name to pass, and
96
- * the alternative was `database("(default)", { … })` — writing out an internal
97
- * sentinel to reach the options. A key is a string and options are an object,
98
- * so the two can never be confused for one another.
99
- */
100
- export function database(options?: DatabaseOptions): DatabaseHandle;
101
- export function database(key?: string, options?: DatabaseOptions): DatabaseHandle;
102
- export function database(
103
- keyOrOptions: string | DatabaseOptions = DEFAULT_RESOURCE_KEY,
104
- options: DatabaseOptions = {}
105
- ): DatabaseHandle {
106
- return typeof keyOrOptions === "string"
107
- ? declareResource("database", keyOrOptions, options)
108
- : declareResource("database", DEFAULT_RESOURCE_KEY, keyOrOptions);
109
- }
110
-
111
- /**
112
- * The extensions the project's databases gave Rebase leave to install.
113
- *
114
- * A flat union rather than a per-database answer, because the surfaces that ask
115
- * — `rebase db push` and the boot schema-ensure — drive one connection and
116
- * generate one `schema.sql` for every collection regardless of `dataSource`.
117
- * Splitting the permission by data source would be a distinction the rest of
118
- * that pipeline does not make, and a false precision is worse than none.
119
- *
120
- * Empty for a project that declared nothing, which is every project that has
121
- * not opted in — so this reads as a refusal by default, on purpose.
122
- */
123
- export function declaredDatabaseExtensions(): readonly string[] {
124
- const names = new Set<string>();
125
- for (const declaration of declaredResources("database")) {
126
- const declared = declaration.options.extensions;
127
- if (!Array.isArray(declared)) continue;
128
- for (const name of declared) {
129
- if (typeof name === "string" && name.trim()) names.add(name.trim());
130
- }
131
- }
132
- return [...names].sort();
133
- }
134
-
135
- // ── bucket ───────────────────────────────────────────────────────────────────
136
-
137
- registerResourceKind({
138
- kind: "bucket",
139
- engines: ["local", "s3", "gcs", "azure", "firebase"],
140
- defaultEngine: "local",
141
- envBases: ["S3_BUCKET", "GCS_BUCKET", "STORAGE_BUCKET", "STORAGE_PUBLIC_URL"],
142
- envBasesByEngine: {
143
- local: ["STORAGE_BUCKET"],
144
- s3: ["S3_BUCKET", "STORAGE_ENDPOINT", "STORAGE_REGION", "STORAGE_PUBLIC_URL"],
145
- gcs: ["GCS_BUCKET", "STORAGE_PUBLIC_URL"],
146
- azure: ["STORAGE_BUCKET", "STORAGE_PUBLIC_URL"],
147
- firebase: ["STORAGE_BUCKET", "STORAGE_PUBLIC_URL"]
148
- },
149
- optionKeys: ["publicRead", "prefix", "account"],
150
- // Storage is genuinely optional: plenty of projects store nothing.
151
- implicitDefault: false
152
- });
153
-
154
- /** Options a bucket accepts beyond the common ones. */
155
- export interface BucketOptions extends DeclareOptions {
156
- /**
157
- * Whether objects are world-readable by default.
158
- *
159
- * Declared rather than inferred from the engine, because the two have
160
- * disagreed before: a private object served through a cacheable public URL
161
- * is a data leak that nothing errors on.
162
- */
163
- publicRead?: boolean;
164
- /** Key prefix within the bucket, for sharing one bucket between sources. */
165
- prefix?: string;
166
- /**
167
- * The credential set this bucket signs with, when several share one.
168
- *
169
- * `bucket("media", { engine: "s3", account: "minio" })` keeps reading its own
170
- * `S3_BUCKET__MEDIA` — the bucket name is what distinguishes one source from
171
- * another and never falls back — while the provider-level variables
172
- * (`S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_ENDPOINT`, `S3_REGION`,
173
- * `S3_FORCE_PATH_STYLE`) fall back to `__MINIO` when no per-key value is set.
174
- *
175
- * Fifteen buckets on one install go from ninety variables to eighteen, and
176
- * rotating the key becomes one edit. A per-bucket value still wins, so a
177
- * single source can move to another provider without breaking the rest off
178
- * their shared account.
179
- */
180
- account?: string;
181
- }
182
-
183
- /** A bucket handle. Storage properties point at it via `storageSource`. */
184
- export type BucketHandle = ResourceHandle;
185
-
186
- /**
187
- * Declare a bucket.
188
- *
189
- * ```ts
190
- * export const media = bucket("media", { transport: "direct" });
191
- * ```
192
- *
193
- * `transport: "direct"` means a provider SDK talks to the bucket and the
194
- * backend is not in the upload path.
195
- */
196
- export function bucket(key: string = DEFAULT_RESOURCE_KEY, options: BucketOptions = {}): BucketHandle {
197
- return declareResource("bucket", key, options);
198
- }
199
-
200
- // ── topic ────────────────────────────────────────────────────────────────────
201
-
202
- registerResourceKind({
203
- kind: "topic",
204
- // `jobs` is the durable local implementation: a topic fans out to one job
205
- // row per subscription, so each subscriber retries on its own schedule and
206
- // a failure is a row somebody can look at rather than a lost message.
207
- engines: ["jobs"],
208
- defaultEngine: "jobs",
209
- envBases: ["REBASE_TOPIC_URL"],
210
- optionKeys: ["delivery", "maxAttempts"],
211
- implicitDefault: false
212
- });
213
-
214
- /**
215
- * How hard the runtime tries to deliver.
216
- *
217
- * Only `at-least-once` is implemented, and it is the honest name for what a
218
- * retrying queue does: a handler must tolerate seeing the same event twice.
219
- * `at-most-once` is listed so a future transport can offer it without the
220
- * option changing shape, and is refused today rather than silently upgraded.
221
- */
222
- export type TopicDelivery = "at-least-once" | "at-most-once";
223
-
224
- /** Options a topic accepts beyond the common ones. */
225
- export interface TopicOptions extends DeclareOptions {
226
- delivery?: TopicDelivery;
227
- /** Attempts per subscription before a message is left failed. Default 5. */
228
- maxAttempts?: number;
229
- }
230
-
231
- /**
232
- * What a subscription does with an event.
233
- *
234
- * `attempt` counts from 1. Worth branching on: the first delivery and the
235
- * fourth are the same call, but the fourth is where it is worth logging loudly.
236
- */
237
- export type TopicHandler<T> = (event: T, context: { attempt: number; topic: string; subscription: string }) => Promise<void> | void;
238
-
239
- /** A declared subscription, as recorded in the graph and wired at boot. */
240
- export interface TopicSubscription<T = unknown> {
241
- topic: string;
242
- name: string;
243
- handler: TopicHandler<T>;
244
- maxAttempts?: number;
245
- }
246
-
247
- /**
248
- * What a topic publishes through.
249
- *
250
- * Installed by `@rebasepro/server` at boot. Absent — in the CLI evaluating
251
- * config to derive the graph, or in a unit test — publishing throws a message
252
- * naming the cause, rather than resolving and dropping the event. A publish
253
- * that silently does nothing is the failure mode a queue exists to prevent.
254
- */
255
- export interface TopicRuntime {
256
- publish(topic: string, event: unknown): Promise<void>;
257
- }
258
-
259
- const runtimeHolder: { current: TopicRuntime | null } = { current: null };
260
-
261
- /** Install the transport topics publish through. Called by the server at boot. */
262
- export function setTopicRuntime(runtime: TopicRuntime | null): void {
263
- runtimeHolder.current = runtime;
264
- }
265
-
266
- const subscriptions: TopicSubscription[] = [];
267
-
268
- /** Every declared subscription, for the worker to wire and the graph to record. */
269
- export function declaredSubscriptions(topic?: string): TopicSubscription[] {
270
- return topic ? subscriptions.filter(s => s.topic === topic) : subscriptions.slice();
271
- }
272
-
273
- /** Forget declared subscriptions. For tests, alongside `resetDeclaredResources`. */
274
- export function resetDeclaredSubscriptions(): void {
275
- subscriptions.length = 0;
276
- }
277
-
278
- /** A topic handle, carrying its payload type. */
279
- export interface TopicHandle<T> extends ResourceHandle {
280
- /**
281
- * Publish an event.
282
- *
283
- * Resolves once the event is durably recorded for every subscription, not
284
- * once they have run. Enqueued inside a transaction that rolls back, it was
285
- * never published.
286
- */
287
- publish(event: T): Promise<void>;
288
- /**
289
- * Declare a subscription.
290
- *
291
- * The name is its identity: it is what the job row records, what a retry
292
- * counts against, and what a second subscription must not collide with.
293
- */
294
- subscription(name: string, handler: TopicHandler<T>, options?: { maxAttempts?: number }): void;
295
- }
296
-
297
- /**
298
- * Declare a topic.
299
- *
300
- * ```ts
301
- * export const signups = topic<{ userId: string }>("signups");
302
- * signups.subscription("send-welcome", async (event) => { … });
303
- * await signups.publish({ userId });
304
- * ```
305
- */
306
- export function topic<T = unknown>(key: string, options: TopicOptions = {}): TopicHandle<T> {
307
- if (options.delivery === "at-most-once") {
308
- throw new Error(
309
- `Topic "${key}" asks for at-most-once delivery, which no shipped transport implements. ` +
310
- "The durable queue behind topics retries, so it is at-least-once and a handler must " +
311
- "tolerate seeing an event twice. Refused rather than quietly given the other guarantee."
312
- );
313
- }
314
- const handle = declareResource("topic", key, options);
315
-
316
- return {
317
- ...handle,
318
- toString() { return key; },
319
- async publish(event: T): Promise<void> {
320
- const runtime = runtimeHolder.current;
321
- if (!runtime) {
322
- throw new Error(
323
- `Cannot publish to topic "${key}": no topic runtime is installed. ` +
324
- "Publishing works inside a running Rebase backend; this looks like config " +
325
- "being evaluated outside one (a build, a script, or a test without a harness)."
326
- );
327
- }
328
- await runtime.publish(key, event);
329
- },
330
- subscription(name: string, handler: TopicHandler<T>, subOptions: { maxAttempts?: number } = {}): void {
331
- if (!name || name.trim() === "") {
332
- throw new Error(`A subscription on topic "${key}" needs a non-empty name.`);
333
- }
334
- if (subscriptions.some(s => s.topic === key && s.name === name)) {
335
- throw new Error(
336
- `Topic "${key}" already has a subscription named "${name}". ` +
337
- "The name is what a job row records and what a retry counts against, so two " +
338
- "cannot share one."
339
- );
340
- }
341
- subscriptions.push({
342
- topic: key,
343
- name,
344
- handler: handler as TopicHandler<unknown>,
345
- ...(subOptions.maxAttempts !== undefined ? { maxAttempts: subOptions.maxAttempts } : {})
346
- });
347
- }
348
- } as TopicHandle<T>;
349
- }
350
-
351
- // ── Handing declarations to the frontend ─────────────────────────────────────
352
-
353
- /**
354
- * The declared databases, in the shape `<Rebase dataSources>` takes.
355
- *
356
- * The frontend needs to know which sources exist and how they are reached — a
357
- * `direct`-transport source is one the browser talks to itself — and it imports
358
- * the same config package the backend does. Without these it would mean writing
359
- * the list a second time, by hand, next to the declarations, which is precisely
360
- * the two-homes problem this model removed everywhere else.
361
- *
362
- * ```tsx
363
- * import "../config/resources"; // registers them
364
- * import { declaredDataSources, declaredStorageSources } from "@rebasepro/types";
365
- *
366
- * <Rebase dataSources={declaredDataSources()} storageSources={declaredStorageSources()} />
367
- * ```
368
- *
369
- * The import is what registers them, so a bundler that drops an unused module
370
- * would leave this empty — hence the side-effect import above rather than a
371
- * bare re-export.
372
- */
373
- export function declaredDataSources(): { key: string; engine: string; transport: ResourceTransport; label?: string }[] {
374
- return declaredResources("database").map(r => ({
375
- key: r.key,
376
- engine: r.engine,
377
- transport: r.transport,
378
- ...(r.label !== undefined ? { label: r.label } : {})
379
- }));
380
- }
381
-
382
- /** The declared buckets, in the shape `<Rebase storageSources>` takes. */
383
- export function declaredStorageSources(): { key: string; engine: string; transport: ResourceTransport; label?: string }[] {
384
- return declaredResources("bucket").map(r => ({
385
- key: r.key,
386
- engine: r.engine,
387
- transport: r.transport,
388
- ...(r.label !== undefined ? { label: r.label } : {})
389
- }));
390
- }