@rebasepro/types 0.16.0 → 0.16.1-canary.g0d7af95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/call_context.d.ts +5 -5
- package/dist/controllers/auth_state.d.ts +1 -1
- package/dist/controllers/client.d.ts +22 -9
- package/dist/controllers/collection_registry.d.ts +2 -2
- package/dist/controllers/data.d.ts +4 -12
- package/dist/controllers/data_driver.d.ts +7 -7
- package/dist/controllers/email.d.ts +54 -2
- package/dist/controllers/index.d.ts +8 -9
- package/dist/controllers/storage.d.ts +4 -4
- package/dist/index.d.ts +5 -5
- package/dist/index.es.js +433 -3
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +1 -1
- package/dist/types/auth_adapter.d.ts +18 -9
- package/dist/types/backend.d.ts +23 -10
- package/dist/types/collection_contract.d.ts +1 -1
- package/dist/types/collections.d.ts +34 -9
- package/dist/types/component_ref.d.ts +3 -2
- package/dist/types/cron.d.ts +1 -25
- package/dist/types/data_source.d.ts +1 -1
- package/dist/types/database_adapter.d.ts +5 -5
- package/dist/types/entities.d.ts +1 -1
- package/dist/types/entity_callbacks.d.ts +4 -4
- package/dist/types/index.d.ts +33 -29
- package/dist/types/indexes.d.ts +179 -0
- package/dist/types/project_manifest.d.ts +132 -27
- package/dist/types/properties.d.ts +58 -6
- package/dist/types/relations.d.ts +1 -1
- package/dist/types/resource_kinds.d.ts +189 -0
- package/dist/types/resources.d.ts +197 -0
- package/dist/types/schema_editing.d.ts +127 -0
- package/dist/types/schema_version.d.ts +1 -1
- package/dist/types/security_rules.d.ts +1 -1
- package/dist/types/storage_source.d.ts +27 -0
- package/dist/users/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/controllers/client.ts +14 -1
- package/src/controllers/data.ts +0 -9
- package/src/controllers/email.ts +55 -2
- package/src/controllers/index.ts +0 -1
- package/src/controllers/storage.ts +4 -4
- package/src/types/admin_block.ts +1 -2
- package/src/types/auth_adapter.ts +18 -10
- package/src/types/backend.ts +18 -1
- package/src/types/collections.ts +28 -2
- package/src/types/component_ref.ts +3 -2
- package/src/types/cron.ts +0 -24
- package/src/types/index.ts +4 -0
- package/src/types/indexes.ts +180 -0
- package/src/types/project_manifest.ts +139 -26
- package/src/types/properties.ts +54 -0
- package/src/types/resource_kinds.ts +324 -0
- package/src/types/resources.ts +368 -0
- package/src/types/schema_editing.ts +154 -0
- package/src/types/storage_source.ts +28 -0
- package/dist/controllers/database_admin.d.ts +0 -11
- package/src/controllers/database_admin.ts +0 -22
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
* work: two repositories never need to know about each other, only about the
|
|
25
25
|
* project.
|
|
26
26
|
*/
|
|
27
|
-
import type { StorageSourceDefinition } from "./storage_source";
|
|
27
|
+
import type { StorageSourceDefinition } from "./storage_source.js";
|
|
28
|
+
import type { ResourceGraph } from "./resources.js";
|
|
28
29
|
/**
|
|
29
30
|
* Which kind of thing an app is.
|
|
30
31
|
*
|
|
@@ -58,7 +59,7 @@ export interface RebaseBackendAppConfig {
|
|
|
58
59
|
*
|
|
59
60
|
* Independent of *where* it runs. Both run on Rebase Cloud and both
|
|
60
61
|
* self-host — the destination lives in `.rebase/cloud.json`, not here. See
|
|
61
|
-
* `docker/docker-compose.selfhost.yml`, which boots a managed bundle on a
|
|
62
|
+
* `infra/docker/docker-compose.selfhost.yml`, which boots a managed bundle on a
|
|
62
63
|
* developer's own Docker host.
|
|
63
64
|
*
|
|
64
65
|
* This is authored rather than inferred on purpose. It is the single most
|
|
@@ -125,6 +126,31 @@ export interface RebaseStaticAppConfig {
|
|
|
125
126
|
spa?: boolean;
|
|
126
127
|
}
|
|
127
128
|
export type RebaseAppConfig = RebaseBackendAppConfig | RebaseStaticAppConfig;
|
|
129
|
+
/**
|
|
130
|
+
* Path prefixes the backend owns, which no static app may claim.
|
|
131
|
+
*
|
|
132
|
+
* One process — and, on the platform, one hostname — serves both the API and
|
|
133
|
+
* however many static apps a project has. Mounting is longest-path-first, so an
|
|
134
|
+
* app declaring `/api` would win against the API itself and every request to it
|
|
135
|
+
* would be answered with that app's `index.html`: a 200 carrying HTML where the
|
|
136
|
+
* caller expected JSON, from a project that looks deployed and healthy.
|
|
137
|
+
*
|
|
138
|
+
* Declared here rather than in either enforcer because both must agree. The CLI
|
|
139
|
+
* checks it so a developer finds out while editing `rebase.json`; the control
|
|
140
|
+
* plane checks it again at deploy intake, because the front door's correctness
|
|
141
|
+
* cannot rest on a check that ran in somebody else's CLI — and a repository can
|
|
142
|
+
* be deployed by a CLI older than this rule.
|
|
143
|
+
*/
|
|
144
|
+
export declare const RESERVED_BACKEND_PREFIXES: readonly ["/api", "/health", "/healthz", "/livez", "/readyz", "/metrics"];
|
|
145
|
+
/**
|
|
146
|
+
* Whether `path` collides with a prefix the backend owns.
|
|
147
|
+
*
|
|
148
|
+
* Compares at segment boundaries, so `/api` and `/api/v2` collide while
|
|
149
|
+
* `/apidocs` does not — the same rule the router matches with, because a check
|
|
150
|
+
* that is stricter than the router rejects paths that would have worked, and one
|
|
151
|
+
* that is looser admits paths that will not.
|
|
152
|
+
*/
|
|
153
|
+
export declare function reservedPrefixFor(path: string): string | undefined;
|
|
128
154
|
/**
|
|
129
155
|
* One declared storage source, as authored in `rebase.json`.
|
|
130
156
|
*
|
|
@@ -171,27 +197,20 @@ export interface RebaseProjectManifest {
|
|
|
171
197
|
*/
|
|
172
198
|
apps: Record<string, RebaseAppConfig>;
|
|
173
199
|
/**
|
|
174
|
-
*
|
|
200
|
+
* Buckets are NOT declared here any more.
|
|
175
201
|
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* default source takes no suffix, so a single-bucket project configured with
|
|
181
|
-
* plain `S3_BUCKET` keeps working having declared nothing at all.
|
|
202
|
+
* They were, and the runtime merged this block with the declarations in
|
|
203
|
+
* config code — a bucket named in both had one engine kept and the other
|
|
204
|
+
* silently discarded. Two homes for one concept, with a merge to decide
|
|
205
|
+
* between them, is the shape this whole model replaced.
|
|
182
206
|
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* project invisible.
|
|
190
|
-
*
|
|
191
|
-
* Omitted entirely means one default source, which is the overwhelmingly
|
|
192
|
-
* common project and must not be required to say so.
|
|
207
|
+
* `bucket("media", { engine: "s3" })` in the project's config declares one
|
|
208
|
+
* now, and `rebase resources --write` generates `rebase.resources.json`,
|
|
209
|
+
* which is what a host reads before a build. A `storage` block left in this
|
|
210
|
+
* file is refused by the validator, by name, with the replacement in the
|
|
211
|
+
* message — not ignored, because a key that still parses and does nothing
|
|
212
|
+
* is the failure this removed.
|
|
193
213
|
*/
|
|
194
|
-
storage?: Record<string, RebaseStorageSourceConfig>;
|
|
195
214
|
/**
|
|
196
215
|
* Repository-wide opt-out from anonymous CLI usage sharing.
|
|
197
216
|
*
|
|
@@ -263,6 +282,31 @@ export declare const BUNDLE_FORMAT_VERSION = 2;
|
|
|
263
282
|
* any number of minors and patches while this stays put. It changes only when
|
|
264
283
|
* the bundle/runtime contract breaks compatibility, and a project's
|
|
265
284
|
* `manifest.runtime` range is matched against *this*.
|
|
285
|
+
*
|
|
286
|
+
* ## v2 — resources are declared, not configured
|
|
287
|
+
*
|
|
288
|
+
* `RebaseBackendConfig.dataSources` and `.storageSources` are gone. A project
|
|
289
|
+
* declares its databases and buckets with `database()` / `bucket()` in its
|
|
290
|
+
* config, and the runtime reads those declarations.
|
|
291
|
+
*
|
|
292
|
+
* This had to be a major, and the reason is the managed tier: it moves projects
|
|
293
|
+
* onto new images WITHOUT rebuilding them. A bundle built against v1 exports
|
|
294
|
+
* those keys, and a v2 runtime refuses them at boot — so without this bump, one
|
|
295
|
+
* image rollout would crash-loop every tenant that had ever declared a second
|
|
296
|
+
* database or bucket, in a wave, with the cause in a container log nobody is
|
|
297
|
+
* watching.
|
|
298
|
+
*
|
|
299
|
+
* With the bump, a v1 bundle on a v2 runtime is refused by
|
|
300
|
+
* `assertBundleCompatibility` with the remedy in the message, and the platform
|
|
301
|
+
* keeps it on a v1 image until it is rebuilt. That is the whole purpose of this
|
|
302
|
+
* number.
|
|
303
|
+
*
|
|
304
|
+
* **Release order matters and is not optional.** The control plane is the side
|
|
305
|
+
* that rejects, so it ships FIRST: raise `SUPPORTED_RUNTIME_CONTRACT` in the
|
|
306
|
+
* saas repo (it rejects only `contract >` its own, so it then accepts both),
|
|
307
|
+
* deploy that, and only then release a runtime implementing v2. Shipping the
|
|
308
|
+
* runtime first turns every deploy into a rejected intake blaming the tenant's
|
|
309
|
+
* bundle.
|
|
266
310
|
*/
|
|
267
311
|
export declare const RUNTIME_CONTRACT_VERSION = 1;
|
|
268
312
|
/** Where the runtime finds each part of the bundle. Paths are bundle-relative. */
|
|
@@ -313,6 +357,35 @@ export interface NativeDependency {
|
|
|
313
357
|
* `manifest.json` — generated, and the document the runtime and control plane
|
|
314
358
|
* both validate against.
|
|
315
359
|
*/
|
|
360
|
+
/**
|
|
361
|
+
* One custom function, as recorded in a built bundle.
|
|
362
|
+
*
|
|
363
|
+
* @see RebaseBundleManifest.functions
|
|
364
|
+
*/
|
|
365
|
+
export interface RebaseBundleFunction {
|
|
366
|
+
/**
|
|
367
|
+
* The filename without its extension — which is also the URL segment it
|
|
368
|
+
* mounts at (`/api/functions/<name>`), the API-key permission that grants
|
|
369
|
+
* it, and the name `REBASE_FUNCTIONS_ONLY` selects by. One identity, used
|
|
370
|
+
* everywhere.
|
|
371
|
+
*/
|
|
372
|
+
name: string;
|
|
373
|
+
/** Path inside the bundle, so a host can point at the file. */
|
|
374
|
+
file: string;
|
|
375
|
+
/**
|
|
376
|
+
* `false` when the function's own source imports a Node built-in or a
|
|
377
|
+
* package that needs one.
|
|
378
|
+
*
|
|
379
|
+
* Descriptive, never a gate: nothing refuses to build or deploy on this. It
|
|
380
|
+
* says where this function *could* run, not where it should.
|
|
381
|
+
*/
|
|
382
|
+
portable: boolean;
|
|
383
|
+
/**
|
|
384
|
+
* Why it is not portable — one short phrase per reason, deduplicated.
|
|
385
|
+
* Absent when it is.
|
|
386
|
+
*/
|
|
387
|
+
requires?: string[];
|
|
388
|
+
}
|
|
316
389
|
export interface RebaseBundleManifest {
|
|
317
390
|
/** @see BUNDLE_FORMAT_VERSION */
|
|
318
391
|
bundleFormat: number;
|
|
@@ -353,6 +426,28 @@ export interface RebaseBundleManifest {
|
|
|
353
426
|
entry: RebaseBundleEntrypoints;
|
|
354
427
|
/** Collection slugs contained in the bundle, for quick inspection. */
|
|
355
428
|
collections?: string[];
|
|
429
|
+
/**
|
|
430
|
+
* Every custom function in the bundle, named and classified.
|
|
431
|
+
*
|
|
432
|
+
* Two things are recorded per function, and both are answers a host would
|
|
433
|
+
* otherwise have to get by importing user code:
|
|
434
|
+
*
|
|
435
|
+
* - **What it is called.** That name is the function's identity everywhere —
|
|
436
|
+
* the URL segment it mounts at, the `functions/<name>` API-key
|
|
437
|
+
* permission, the value `REBASE_FUNCTIONS_ONLY` selects by. A host that
|
|
438
|
+
* wants to give one slow function its own replica count currently has to
|
|
439
|
+
* boot the bundle to discover what is in it.
|
|
440
|
+
* - **Whether it needs Node.** Purely descriptive: a function that opens a
|
|
441
|
+
* file or runs raw SQL is a fine function, and every deployment today is
|
|
442
|
+
* a Node process. It is recorded because the question "which of these
|
|
443
|
+
* could run somewhere else" has to be answerable from the artifact, and
|
|
444
|
+
* because answering it per-file after the fact — across a codebase
|
|
445
|
+
* already written — is the expensive version of the same question.
|
|
446
|
+
*
|
|
447
|
+
* Absent on a bundle built before this field existed, which is why every
|
|
448
|
+
* consumer must treat it as optional rather than as an empty list.
|
|
449
|
+
*/
|
|
450
|
+
functions?: RebaseBundleFunction[];
|
|
356
451
|
hooks: {
|
|
357
452
|
/**
|
|
358
453
|
* Whether the dependency closure contains native code.
|
|
@@ -381,17 +476,27 @@ export interface RebaseBundleManifest {
|
|
|
381
476
|
/** Whether the config package exports a `storageAuthorize` hook. */
|
|
382
477
|
authorize: boolean;
|
|
383
478
|
/**
|
|
384
|
-
*
|
|
385
|
-
* `rebase.json`'s `storage` block merged with any `storageSources` the
|
|
386
|
-
* config package exports.
|
|
479
|
+
* Buckets, on bundles built before {@link RebaseBundleManifest.resources}.
|
|
387
480
|
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* built before this field existed, which means one default source.
|
|
481
|
+
* No longer written. A host reads `resources`, which carries every kind
|
|
482
|
+
* in one list; this stays declared so a control plane can keep reading
|
|
483
|
+
* the bundles a project shipped before it was rebuilt.
|
|
392
484
|
*/
|
|
393
485
|
sources?: StorageSourceDefinition[];
|
|
394
486
|
};
|
|
487
|
+
/**
|
|
488
|
+
* Everything the project declares it needs — databases, buckets, topics,
|
|
489
|
+
* and whatever kind is registered next.
|
|
490
|
+
*
|
|
491
|
+
* Recorded so a host can tell, from the artifact alone and before starting
|
|
492
|
+
* anything, what a deploy will need provisioned. That question used to be
|
|
493
|
+
* answerable for buckets and for nothing else, because buckets were the
|
|
494
|
+
* only kind written into an artifact — which is how a project's databases
|
|
495
|
+
* became invisible to the platform that runs them.
|
|
496
|
+
*
|
|
497
|
+
* Absent on bundles built before this field existed.
|
|
498
|
+
*/
|
|
499
|
+
resources?: ResourceGraph;
|
|
395
500
|
deps: {
|
|
396
501
|
/** Runtime dependencies of user code, as declared. */
|
|
397
502
|
declared: Record<string, string>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Entity, EntityReference, EntityRelation, EntityValues, GeoPoint, Vector } from "./entities";
|
|
2
|
-
import type { Relation, ResolvedRelation } from "./relations";
|
|
3
|
-
import type { ColorKey, ColorScheme } from "./chips";
|
|
4
|
-
import type { AuthState } from "../controllers/auth_state";
|
|
5
|
-
import type { AfterReadProps, BeforeSaveProps } from "./entity_callbacks";
|
|
6
|
-
import type { User } from "../users";
|
|
1
|
+
import type { Entity, EntityReference, EntityRelation, EntityValues, GeoPoint, Vector } from "./entities.js";
|
|
2
|
+
import type { Relation, ResolvedRelation } from "./relations.js";
|
|
3
|
+
import type { ColorKey, ColorScheme } from "./chips.js";
|
|
4
|
+
import type { AuthState } from "../controllers/auth_state.js";
|
|
5
|
+
import type { AfterReadProps, BeforeSaveProps } from "./entity_callbacks.js";
|
|
6
|
+
import type { User } from "../users/index.js";
|
|
7
7
|
/**
|
|
8
8
|
* Callbacks/Hooks for individual property fields
|
|
9
9
|
* @group Entity properties
|
|
@@ -324,6 +324,46 @@ export interface BooleanProperty extends BaseProperty {
|
|
|
324
324
|
*/
|
|
325
325
|
validation?: PropertyValidationSchema;
|
|
326
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Which pgvector distance a query measures with, and therefore which operator
|
|
329
|
+
* class an index has to be built for. The names match the `distance` option on
|
|
330
|
+
* `vectorSearch`, because an index built for one operator is not used by a
|
|
331
|
+
* query that asks for another.
|
|
332
|
+
*
|
|
333
|
+
* @group Entity properties
|
|
334
|
+
*/
|
|
335
|
+
export type VectorDistance = "cosine" | "l2" | "inner_product";
|
|
336
|
+
/**
|
|
337
|
+
* How the ANN index over a vector column is built.
|
|
338
|
+
*
|
|
339
|
+
* Without an index, `vectorSearch` is an exact scan: correct at any size,
|
|
340
|
+
* and linear in the number of rows. With one, it is approximate and fast.
|
|
341
|
+
* That trade is why this is configurable rather than implied.
|
|
342
|
+
*
|
|
343
|
+
* @group Entity properties
|
|
344
|
+
*/
|
|
345
|
+
export interface VectorIndexConfig {
|
|
346
|
+
/**
|
|
347
|
+
* `hnsw` (the default) builds a navigable-graph index: slower to build,
|
|
348
|
+
* better recall, and it needs no training data, so it works on an empty
|
|
349
|
+
* table. `ivfflat` is cheaper to build but partitions by centroid, so an
|
|
350
|
+
* index built on an empty or tiny table has useless partitions — build it
|
|
351
|
+
* after the data is loaded, and set {@link lists}.
|
|
352
|
+
*/
|
|
353
|
+
method?: "hnsw" | "ivfflat";
|
|
354
|
+
/**
|
|
355
|
+
* Which distance operators to index, defaulting to `cosine` — the default
|
|
356
|
+
* `vectorSearch` measures with. Name several to index several; each one is
|
|
357
|
+
* a separate index with its own build cost and its own storage.
|
|
358
|
+
*/
|
|
359
|
+
distance?: VectorDistance | VectorDistance[];
|
|
360
|
+
/** HNSW: connections per node. Postgres defaults to 16. */
|
|
361
|
+
m?: number;
|
|
362
|
+
/** HNSW: candidate-list size while building. Postgres defaults to 64. */
|
|
363
|
+
efConstruction?: number;
|
|
364
|
+
/** IVFFlat: number of partitions. Postgres defaults to 100. */
|
|
365
|
+
lists?: number;
|
|
366
|
+
}
|
|
327
367
|
export interface VectorProperty extends BaseProperty {
|
|
328
368
|
type: "vector";
|
|
329
369
|
/**
|
|
@@ -331,6 +371,18 @@ export interface VectorProperty extends BaseProperty {
|
|
|
331
371
|
*/
|
|
332
372
|
defaultValue?: Vector;
|
|
333
373
|
dimensions: number;
|
|
374
|
+
/**
|
|
375
|
+
* ANN index configuration for this column.
|
|
376
|
+
*
|
|
377
|
+
* Omitted, a single HNSW index for cosine distance is created — which is
|
|
378
|
+
* what the default `vectorSearch` uses. `false` creates none, leaving
|
|
379
|
+
* `vectorSearch` an exact scan.
|
|
380
|
+
*
|
|
381
|
+
* Indexes are only created when {@link dimensions} is at most 2000:
|
|
382
|
+
* pgvector cannot index a wider `vector` column, so a 3072-dimension
|
|
383
|
+
* embedding is left unindexed rather than failing the boot.
|
|
384
|
+
*/
|
|
385
|
+
index?: VectorIndexConfig | false;
|
|
334
386
|
validation?: PropertyValidationSchema;
|
|
335
387
|
}
|
|
336
388
|
/**
|
|
@@ -0,0 +1,189 @@
|
|
|
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 { type DeclareOptions, type ResourceHandle, type ResourceTransport } from "./resources.js";
|
|
15
|
+
/** Options a database accepts beyond the common ones. */
|
|
16
|
+
export interface DatabaseOptions extends DeclareOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The physical database or schema within the engine, when it differs from
|
|
19
|
+
* the engine's own default. Threaded to drivers as `databaseId`.
|
|
20
|
+
*/
|
|
21
|
+
databaseId?: string;
|
|
22
|
+
/** Directory of migration files, relative to the config directory. */
|
|
23
|
+
migrations?: string;
|
|
24
|
+
}
|
|
25
|
+
/** A database handle. Collections point at it via `dataSource`. */
|
|
26
|
+
export type DatabaseHandle = ResourceHandle;
|
|
27
|
+
/**
|
|
28
|
+
* Declare a database.
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* export const main = database(); // the default one
|
|
32
|
+
* export const analytics = database("analytics"); // reads DATABASE_URL__ANALYTICS
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function database(key?: string, options?: DatabaseOptions): DatabaseHandle;
|
|
36
|
+
/** Options a bucket accepts beyond the common ones. */
|
|
37
|
+
export interface BucketOptions extends DeclareOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Whether objects are world-readable by default.
|
|
40
|
+
*
|
|
41
|
+
* Declared rather than inferred from the engine, because the two have
|
|
42
|
+
* disagreed before: a private object served through a cacheable public URL
|
|
43
|
+
* is a data leak that nothing errors on.
|
|
44
|
+
*/
|
|
45
|
+
publicRead?: boolean;
|
|
46
|
+
/** Key prefix within the bucket, for sharing one bucket between sources. */
|
|
47
|
+
prefix?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The credential set this bucket signs with, when several share one.
|
|
50
|
+
*
|
|
51
|
+
* `bucket("media", { engine: "s3", account: "minio" })` keeps reading its own
|
|
52
|
+
* `S3_BUCKET__MEDIA` — the bucket name is what distinguishes one source from
|
|
53
|
+
* another and never falls back — while the provider-level variables
|
|
54
|
+
* (`S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_ENDPOINT`, `S3_REGION`,
|
|
55
|
+
* `S3_FORCE_PATH_STYLE`) fall back to `__MINIO` when no per-key value is set.
|
|
56
|
+
*
|
|
57
|
+
* Fifteen buckets on one install go from ninety variables to eighteen, and
|
|
58
|
+
* rotating the key becomes one edit. A per-bucket value still wins, so a
|
|
59
|
+
* single source can move to another provider without breaking the rest off
|
|
60
|
+
* their shared account.
|
|
61
|
+
*/
|
|
62
|
+
account?: string;
|
|
63
|
+
}
|
|
64
|
+
/** A bucket handle. Storage properties point at it via `storageSource`. */
|
|
65
|
+
export type BucketHandle = ResourceHandle;
|
|
66
|
+
/**
|
|
67
|
+
* Declare a bucket.
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* export const media = bucket("media", { transport: "direct" });
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* `transport: "direct"` means a provider SDK talks to the bucket and the
|
|
74
|
+
* backend is not in the upload path.
|
|
75
|
+
*/
|
|
76
|
+
export declare function bucket(key?: string, options?: BucketOptions): BucketHandle;
|
|
77
|
+
/**
|
|
78
|
+
* How hard the runtime tries to deliver.
|
|
79
|
+
*
|
|
80
|
+
* Only `at-least-once` is implemented, and it is the honest name for what a
|
|
81
|
+
* retrying queue does: a handler must tolerate seeing the same event twice.
|
|
82
|
+
* `at-most-once` is listed so a future transport can offer it without the
|
|
83
|
+
* option changing shape, and is refused today rather than silently upgraded.
|
|
84
|
+
*/
|
|
85
|
+
export type TopicDelivery = "at-least-once" | "at-most-once";
|
|
86
|
+
/** Options a topic accepts beyond the common ones. */
|
|
87
|
+
export interface TopicOptions extends DeclareOptions {
|
|
88
|
+
delivery?: TopicDelivery;
|
|
89
|
+
/** Attempts per subscription before a message is left failed. Default 5. */
|
|
90
|
+
maxAttempts?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* What a subscription does with an event.
|
|
94
|
+
*
|
|
95
|
+
* `attempt` counts from 1. Worth branching on: the first delivery and the
|
|
96
|
+
* fourth are the same call, but the fourth is where it is worth logging loudly.
|
|
97
|
+
*/
|
|
98
|
+
export type TopicHandler<T> = (event: T, context: {
|
|
99
|
+
attempt: number;
|
|
100
|
+
topic: string;
|
|
101
|
+
subscription: string;
|
|
102
|
+
}) => Promise<void> | void;
|
|
103
|
+
/** A declared subscription, as recorded in the graph and wired at boot. */
|
|
104
|
+
export interface TopicSubscription<T = unknown> {
|
|
105
|
+
topic: string;
|
|
106
|
+
name: string;
|
|
107
|
+
handler: TopicHandler<T>;
|
|
108
|
+
maxAttempts?: number;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* What a topic publishes through.
|
|
112
|
+
*
|
|
113
|
+
* Installed by `@rebasepro/server` at boot. Absent — in the CLI evaluating
|
|
114
|
+
* config to derive the graph, or in a unit test — publishing throws a message
|
|
115
|
+
* naming the cause, rather than resolving and dropping the event. A publish
|
|
116
|
+
* that silently does nothing is the failure mode a queue exists to prevent.
|
|
117
|
+
*/
|
|
118
|
+
export interface TopicRuntime {
|
|
119
|
+
publish(topic: string, event: unknown): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
/** Install the transport topics publish through. Called by the server at boot. */
|
|
122
|
+
export declare function setTopicRuntime(runtime: TopicRuntime | null): void;
|
|
123
|
+
/** Every declared subscription, for the worker to wire and the graph to record. */
|
|
124
|
+
export declare function declaredSubscriptions(topic?: string): TopicSubscription[];
|
|
125
|
+
/** Forget declared subscriptions. For tests, alongside `resetDeclaredResources`. */
|
|
126
|
+
export declare function resetDeclaredSubscriptions(): void;
|
|
127
|
+
/** A topic handle, carrying its payload type. */
|
|
128
|
+
export interface TopicHandle<T> extends ResourceHandle {
|
|
129
|
+
/**
|
|
130
|
+
* Publish an event.
|
|
131
|
+
*
|
|
132
|
+
* Resolves once the event is durably recorded for every subscription, not
|
|
133
|
+
* once they have run. Enqueued inside a transaction that rolls back, it was
|
|
134
|
+
* never published.
|
|
135
|
+
*/
|
|
136
|
+
publish(event: T): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Declare a subscription.
|
|
139
|
+
*
|
|
140
|
+
* The name is its identity: it is what the job row records, what a retry
|
|
141
|
+
* counts against, and what a second subscription must not collide with.
|
|
142
|
+
*/
|
|
143
|
+
subscription(name: string, handler: TopicHandler<T>, options?: {
|
|
144
|
+
maxAttempts?: number;
|
|
145
|
+
}): void;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Declare a topic.
|
|
149
|
+
*
|
|
150
|
+
* ```ts
|
|
151
|
+
* export const signups = topic<{ userId: string }>("signups");
|
|
152
|
+
* signups.subscription("send-welcome", async (event) => { … });
|
|
153
|
+
* await signups.publish({ userId });
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare function topic<T = unknown>(key: string, options?: TopicOptions): TopicHandle<T>;
|
|
157
|
+
/**
|
|
158
|
+
* The declared databases, in the shape `<Rebase dataSources>` takes.
|
|
159
|
+
*
|
|
160
|
+
* The frontend needs to know which sources exist and how they are reached — a
|
|
161
|
+
* `direct`-transport source is one the browser talks to itself — and it imports
|
|
162
|
+
* the same config package the backend does. Without these it would mean writing
|
|
163
|
+
* the list a second time, by hand, next to the declarations, which is precisely
|
|
164
|
+
* the two-homes problem this model removed everywhere else.
|
|
165
|
+
*
|
|
166
|
+
* ```tsx
|
|
167
|
+
* import "../config/resources"; // registers them
|
|
168
|
+
* import { declaredDataSources, declaredStorageSources } from "@rebasepro/types";
|
|
169
|
+
*
|
|
170
|
+
* <Rebase dataSources={declaredDataSources()} storageSources={declaredStorageSources()} />
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* The import is what registers them, so a bundler that drops an unused module
|
|
174
|
+
* would leave this empty — hence the side-effect import above rather than a
|
|
175
|
+
* bare re-export.
|
|
176
|
+
*/
|
|
177
|
+
export declare function declaredDataSources(): {
|
|
178
|
+
key: string;
|
|
179
|
+
engine: string;
|
|
180
|
+
transport: ResourceTransport;
|
|
181
|
+
label?: string;
|
|
182
|
+
}[];
|
|
183
|
+
/** The declared buckets, in the shape `<Rebase storageSources>` takes. */
|
|
184
|
+
export declare function declaredStorageSources(): {
|
|
185
|
+
key: string;
|
|
186
|
+
engine: string;
|
|
187
|
+
transport: ResourceTransport;
|
|
188
|
+
label?: string;
|
|
189
|
+
}[];
|