@rebasepro/types 0.16.0 → 0.16.1-canary.g041c925
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 +429 -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 +16 -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 +32 -29
- 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 +174 -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/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 +9 -2
- package/src/types/component_ref.ts +3 -2
- package/src/types/cron.ts +0 -24
- package/src/types/index.ts +3 -0
- package/src/types/project_manifest.ts +139 -26
- package/src/types/properties.ts +54 -0
- package/src/types/resource_kinds.ts +309 -0
- package/src/types/resources.ts +368 -0
- package/src/types/schema_editing.ts +154 -0
- package/dist/controllers/database_admin.d.ts +0 -11
- package/src/controllers/database_admin.ts +0 -22
|
@@ -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,174 @@
|
|
|
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
|
+
/** A bucket handle. Storage properties point at it via `storageSource`. */
|
|
50
|
+
export type BucketHandle = ResourceHandle;
|
|
51
|
+
/**
|
|
52
|
+
* Declare a bucket.
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* export const media = bucket("media", { transport: "direct" });
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* `transport: "direct"` means a provider SDK talks to the bucket and the
|
|
59
|
+
* backend is not in the upload path.
|
|
60
|
+
*/
|
|
61
|
+
export declare function bucket(key?: string, options?: BucketOptions): BucketHandle;
|
|
62
|
+
/**
|
|
63
|
+
* How hard the runtime tries to deliver.
|
|
64
|
+
*
|
|
65
|
+
* Only `at-least-once` is implemented, and it is the honest name for what a
|
|
66
|
+
* retrying queue does: a handler must tolerate seeing the same event twice.
|
|
67
|
+
* `at-most-once` is listed so a future transport can offer it without the
|
|
68
|
+
* option changing shape, and is refused today rather than silently upgraded.
|
|
69
|
+
*/
|
|
70
|
+
export type TopicDelivery = "at-least-once" | "at-most-once";
|
|
71
|
+
/** Options a topic accepts beyond the common ones. */
|
|
72
|
+
export interface TopicOptions extends DeclareOptions {
|
|
73
|
+
delivery?: TopicDelivery;
|
|
74
|
+
/** Attempts per subscription before a message is left failed. Default 5. */
|
|
75
|
+
maxAttempts?: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* What a subscription does with an event.
|
|
79
|
+
*
|
|
80
|
+
* `attempt` counts from 1. Worth branching on: the first delivery and the
|
|
81
|
+
* fourth are the same call, but the fourth is where it is worth logging loudly.
|
|
82
|
+
*/
|
|
83
|
+
export type TopicHandler<T> = (event: T, context: {
|
|
84
|
+
attempt: number;
|
|
85
|
+
topic: string;
|
|
86
|
+
subscription: string;
|
|
87
|
+
}) => Promise<void> | void;
|
|
88
|
+
/** A declared subscription, as recorded in the graph and wired at boot. */
|
|
89
|
+
export interface TopicSubscription<T = unknown> {
|
|
90
|
+
topic: string;
|
|
91
|
+
name: string;
|
|
92
|
+
handler: TopicHandler<T>;
|
|
93
|
+
maxAttempts?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* What a topic publishes through.
|
|
97
|
+
*
|
|
98
|
+
* Installed by `@rebasepro/server` at boot. Absent — in the CLI evaluating
|
|
99
|
+
* config to derive the graph, or in a unit test — publishing throws a message
|
|
100
|
+
* naming the cause, rather than resolving and dropping the event. A publish
|
|
101
|
+
* that silently does nothing is the failure mode a queue exists to prevent.
|
|
102
|
+
*/
|
|
103
|
+
export interface TopicRuntime {
|
|
104
|
+
publish(topic: string, event: unknown): Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
/** Install the transport topics publish through. Called by the server at boot. */
|
|
107
|
+
export declare function setTopicRuntime(runtime: TopicRuntime | null): void;
|
|
108
|
+
/** Every declared subscription, for the worker to wire and the graph to record. */
|
|
109
|
+
export declare function declaredSubscriptions(topic?: string): TopicSubscription[];
|
|
110
|
+
/** Forget declared subscriptions. For tests, alongside `resetDeclaredResources`. */
|
|
111
|
+
export declare function resetDeclaredSubscriptions(): void;
|
|
112
|
+
/** A topic handle, carrying its payload type. */
|
|
113
|
+
export interface TopicHandle<T> extends ResourceHandle {
|
|
114
|
+
/**
|
|
115
|
+
* Publish an event.
|
|
116
|
+
*
|
|
117
|
+
* Resolves once the event is durably recorded for every subscription, not
|
|
118
|
+
* once they have run. Enqueued inside a transaction that rolls back, it was
|
|
119
|
+
* never published.
|
|
120
|
+
*/
|
|
121
|
+
publish(event: T): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Declare a subscription.
|
|
124
|
+
*
|
|
125
|
+
* The name is its identity: it is what the job row records, what a retry
|
|
126
|
+
* counts against, and what a second subscription must not collide with.
|
|
127
|
+
*/
|
|
128
|
+
subscription(name: string, handler: TopicHandler<T>, options?: {
|
|
129
|
+
maxAttempts?: number;
|
|
130
|
+
}): void;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Declare a topic.
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* export const signups = topic<{ userId: string }>("signups");
|
|
137
|
+
* signups.subscription("send-welcome", async (event) => { … });
|
|
138
|
+
* await signups.publish({ userId });
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export declare function topic<T = unknown>(key: string, options?: TopicOptions): TopicHandle<T>;
|
|
142
|
+
/**
|
|
143
|
+
* The declared databases, in the shape `<Rebase dataSources>` takes.
|
|
144
|
+
*
|
|
145
|
+
* The frontend needs to know which sources exist and how they are reached — a
|
|
146
|
+
* `direct`-transport source is one the browser talks to itself — and it imports
|
|
147
|
+
* the same config package the backend does. Without these it would mean writing
|
|
148
|
+
* the list a second time, by hand, next to the declarations, which is precisely
|
|
149
|
+
* the two-homes problem this model removed everywhere else.
|
|
150
|
+
*
|
|
151
|
+
* ```tsx
|
|
152
|
+
* import "../config/resources"; // registers them
|
|
153
|
+
* import { declaredDataSources, declaredStorageSources } from "@rebasepro/types";
|
|
154
|
+
*
|
|
155
|
+
* <Rebase dataSources={declaredDataSources()} storageSources={declaredStorageSources()} />
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* The import is what registers them, so a bundler that drops an unused module
|
|
159
|
+
* would leave this empty — hence the side-effect import above rather than a
|
|
160
|
+
* bare re-export.
|
|
161
|
+
*/
|
|
162
|
+
export declare function declaredDataSources(): {
|
|
163
|
+
key: string;
|
|
164
|
+
engine: string;
|
|
165
|
+
transport: ResourceTransport;
|
|
166
|
+
label?: string;
|
|
167
|
+
}[];
|
|
168
|
+
/** The declared buckets, in the shape `<Rebase storageSources>` takes. */
|
|
169
|
+
export declare function declaredStorageSources(): {
|
|
170
|
+
key: string;
|
|
171
|
+
engine: string;
|
|
172
|
+
transport: ResourceTransport;
|
|
173
|
+
label?: string;
|
|
174
|
+
}[];
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The resource graph: one declaration site for every named thing a project needs.
|
|
3
|
+
*
|
|
4
|
+
* ## The rule
|
|
5
|
+
*
|
|
6
|
+
* **Every named resource is declared with a constructor in config code.** A
|
|
7
|
+
* database, a bucket, a topic and whatever kind comes next are all spelled the
|
|
8
|
+
* same way, so "where do I declare my second one" has one answer instead of one
|
|
9
|
+
* answer per kind.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* export const main = database("main");
|
|
13
|
+
* export const media = bucket("media", { transport: "direct" });
|
|
14
|
+
* export const signups = topic<SignupEvent>("signups");
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## Declaration is not binding
|
|
18
|
+
*
|
|
19
|
+
* A declaration says a resource *exists* and what shape it has. It never says
|
|
20
|
+
* how to reach it — that is a property of the environment, not of the project,
|
|
21
|
+
* and it differs between a laptop, a self-hosted box and a tenant in the cloud.
|
|
22
|
+
* Binding lives in `@rebasepro/server`'s boot path, reading environment
|
|
23
|
+
* variables or an infrastructure config file, and it keys off the logical name
|
|
24
|
+
* declared here.
|
|
25
|
+
*
|
|
26
|
+
* This split is the whole point. Before it, storage topology was hand-written
|
|
27
|
+
* into `rebase.json` while database topology lived in TypeScript, and the
|
|
28
|
+
* boundary between them was a fact about what the control plane could read
|
|
29
|
+
* before a build — a platform implementation detail that a developer had no way
|
|
30
|
+
* to derive. Worse, storage could be declared in *both* places, and the merge
|
|
31
|
+
* silently kept the JSON's engine and discarded the code's.
|
|
32
|
+
*
|
|
33
|
+
* ## Why a registry rather than a fixed union
|
|
34
|
+
*
|
|
35
|
+
* Kinds register themselves. Adding pub/sub, a cache or a search index must not
|
|
36
|
+
* require editing a manifest schema, a validator and three switch statements —
|
|
37
|
+
* that cost is exactly why the last two kinds ended up in different homes.
|
|
38
|
+
*/
|
|
39
|
+
/** How a client reaches a resource. */
|
|
40
|
+
export type ResourceTransport =
|
|
41
|
+
/** Through the backend. The default, and the only one that needs no client SDK. */
|
|
42
|
+
"server"
|
|
43
|
+
/** A provider SDK talks to the resource directly; the backend is not in the path. */
|
|
44
|
+
| "direct";
|
|
45
|
+
/**
|
|
46
|
+
* A resource kind, as registered.
|
|
47
|
+
*
|
|
48
|
+
* `engines` is an allowlist rather than documentation. An unrecognised engine
|
|
49
|
+
* used to be a free string that passed every check and failed later, further
|
|
50
|
+
* from the typo that caused it — `"s2"` for `"s3"` reached the runtime. Anything
|
|
51
|
+
* genuinely outside the list is spelled `custom:<id>`, which says so at the call
|
|
52
|
+
* site instead of looking like a typo.
|
|
53
|
+
*/
|
|
54
|
+
export interface ResourceKindSpec {
|
|
55
|
+
/** The kind's name, as it appears in a declaration and in the graph. */
|
|
56
|
+
kind: string;
|
|
57
|
+
/** Engines this kind ships with. `custom:<id>` is always additionally valid. */
|
|
58
|
+
engines: readonly string[];
|
|
59
|
+
/** Used when a declaration names none. */
|
|
60
|
+
defaultEngine: string;
|
|
61
|
+
/**
|
|
62
|
+
* Environment variable base names this kind binds from, in the order a
|
|
63
|
+
* binder should try them. A resource keyed `analytics` reads
|
|
64
|
+
* `<BASE>__ANALYTICS`; the default-keyed resource reads `<BASE>` unsuffixed,
|
|
65
|
+
* so a single-resource project configured the obvious way declares nothing.
|
|
66
|
+
*/
|
|
67
|
+
envBases: readonly string[];
|
|
68
|
+
/**
|
|
69
|
+
* The subset of `envBases` that matters for a given engine.
|
|
70
|
+
*
|
|
71
|
+
* The binder reads every base and takes whichever is set — harmless, and it
|
|
72
|
+
* keeps binding tolerant. A GENERATOR cannot be that relaxed: `rebase eject
|
|
73
|
+
* infra` writing S3_BUCKET, GCS_BUCKET, STORAGE_BUCKET and
|
|
74
|
+
* STORAGE_PUBLIC_URL for a `local` bucket hands somebody four variables of
|
|
75
|
+
* which three are noise, and a config file full of irrelevant keys is one
|
|
76
|
+
* nobody reads carefully.
|
|
77
|
+
*
|
|
78
|
+
* Keyed by engine; an engine with no entry falls back to all of them, which
|
|
79
|
+
* is the honest answer for one this package has never heard of.
|
|
80
|
+
*/
|
|
81
|
+
envBasesByEngine?: Readonly<Record<string, readonly string[]>>;
|
|
82
|
+
/** Option keys this kind accepts beyond the common ones, for validation. */
|
|
83
|
+
optionKeys?: readonly string[];
|
|
84
|
+
/**
|
|
85
|
+
* Whether a project implicitly has one of these even when it declares
|
|
86
|
+
* nothing. True for databases — a backend without one is not a backend —
|
|
87
|
+
* and false for topics, where zero is the normal number.
|
|
88
|
+
*/
|
|
89
|
+
implicitDefault?: boolean;
|
|
90
|
+
}
|
|
91
|
+
/** The key a resource takes when a project declares only one of its kind. */
|
|
92
|
+
export declare const DEFAULT_RESOURCE_KEY = "(default)";
|
|
93
|
+
/** A declared resource, as it appears in the graph. */
|
|
94
|
+
export interface ResourceDeclaration {
|
|
95
|
+
kind: string;
|
|
96
|
+
/** Unique within its kind. What a binder looks up and what an env suffix is built from. */
|
|
97
|
+
key: string;
|
|
98
|
+
engine: string;
|
|
99
|
+
transport: ResourceTransport;
|
|
100
|
+
label?: string;
|
|
101
|
+
/** Kind-specific options, validated against the kind's `optionKeys`. */
|
|
102
|
+
options: Readonly<Record<string, unknown>>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The value a constructor returns.
|
|
106
|
+
*
|
|
107
|
+
* Carries its own declaration so config code can hold it and pass it around,
|
|
108
|
+
* and stringifies to its key so it drops into the places that still take one.
|
|
109
|
+
* Collections name a data source by string today; a handle works there without
|
|
110
|
+
* the collection API having to change, which keeps this a config redesign
|
|
111
|
+
* rather than a rewrite of the data layer.
|
|
112
|
+
*/
|
|
113
|
+
export interface ResourceHandle extends ResourceDeclaration {
|
|
114
|
+
toString(): string;
|
|
115
|
+
}
|
|
116
|
+
/** Whether a value is a resource handle rather than a plain string key. */
|
|
117
|
+
export declare function isResourceHandle(value: unknown): value is ResourceHandle;
|
|
118
|
+
/** The key a resource reference names, whether it is a handle or already a key. */
|
|
119
|
+
export declare function resourceKeyOf(ref: string | ResourceHandle): string;
|
|
120
|
+
/** Register a resource kind. Idempotent for an identical spec; throws on a conflicting one. */
|
|
121
|
+
export declare function registerResourceKind(spec: ResourceKindSpec): void;
|
|
122
|
+
/** Every registered kind, for validators and for `rebase doctor`. */
|
|
123
|
+
export declare function resourceKinds(): ResourceKindSpec[];
|
|
124
|
+
/** One registered kind, or undefined. */
|
|
125
|
+
export declare function resourceKind(kind: string): ResourceKindSpec | undefined;
|
|
126
|
+
/** Options every kind accepts. */
|
|
127
|
+
export interface DeclareOptions {
|
|
128
|
+
engine?: string;
|
|
129
|
+
transport?: ResourceTransport;
|
|
130
|
+
label?: string;
|
|
131
|
+
[option: string]: unknown;
|
|
132
|
+
}
|
|
133
|
+
/** Whether an engine is one the kind knows, or an explicit `custom:` opt-out. */
|
|
134
|
+
export declare function isValidEngine(spec: ResourceKindSpec, engine: string): boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Declare a resource. The primitive every kind's constructor is built from.
|
|
137
|
+
*
|
|
138
|
+
* Redeclaring the same `kind:key` with a *different* shape throws rather than
|
|
139
|
+
* merging. Merging is what the old storage path did, and it silently discarded
|
|
140
|
+
* one of the two engines — a declaration accepted and then ignored, which is
|
|
141
|
+
* the failure this whole model exists to remove. Redeclaring it identically is
|
|
142
|
+
* fine: a config module evaluated twice must not be an error.
|
|
143
|
+
*/
|
|
144
|
+
export declare function declareResource(kind: string, key?: string, options?: DeclareOptions): ResourceHandle;
|
|
145
|
+
/** Every declared resource, in declaration order, optionally filtered by kind. */
|
|
146
|
+
export declare function declaredResources(kind?: string): ResourceDeclaration[];
|
|
147
|
+
/**
|
|
148
|
+
* Forget every declaration, keeping registered kinds.
|
|
149
|
+
*
|
|
150
|
+
* For tests and for a CLI that evaluates more than one project in a process.
|
|
151
|
+
* Kinds survive because they are registered by module import, which will not
|
|
152
|
+
* happen a second time.
|
|
153
|
+
*/
|
|
154
|
+
export declare function resetDeclaredResources(): void;
|
|
155
|
+
/**
|
|
156
|
+
* The env-var suffix a resource's bindings use: `__ANALYTICS` for `analytics`,
|
|
157
|
+
* and nothing at all for the default-keyed one.
|
|
158
|
+
*
|
|
159
|
+
* The default takes no suffix so that a project with one database configured
|
|
160
|
+
* through plain `DATABASE_URL` keeps working having declared nothing — the
|
|
161
|
+
* overwhelmingly common project must not have to say so.
|
|
162
|
+
*/
|
|
163
|
+
export declare function resourceEnvSuffix(key: string): string;
|
|
164
|
+
/**
|
|
165
|
+
* Two resources of a kind whose keys differ but whose env suffixes do not.
|
|
166
|
+
*
|
|
167
|
+
* `media-files` and `media_files` both become `__MEDIA_FILES`, so one would
|
|
168
|
+
* silently read the other's configuration. Returned rather than thrown so the
|
|
169
|
+
* caller can report it with the rest of a validation pass.
|
|
170
|
+
*/
|
|
171
|
+
export declare function findEnvSuffixCollision(keys: readonly string[]): {
|
|
172
|
+
a: string;
|
|
173
|
+
b: string;
|
|
174
|
+
suffix: string;
|
|
175
|
+
} | null;
|
|
176
|
+
/**
|
|
177
|
+
* The whole graph, as recorded in a manifest and read by a host.
|
|
178
|
+
*
|
|
179
|
+
* `version` is the graph format, not the project's. A host reading a graph it
|
|
180
|
+
* does not understand must say so rather than provision half of it.
|
|
181
|
+
*/
|
|
182
|
+
export interface ResourceGraph {
|
|
183
|
+
version: 1;
|
|
184
|
+
resources: ResourceDeclaration[];
|
|
185
|
+
}
|
|
186
|
+
/** The current graph format version. */
|
|
187
|
+
export declare const RESOURCE_GRAPH_VERSION: 1;
|
|
188
|
+
/** Build a graph from the current declarations, sorted for a stable diff. */
|
|
189
|
+
export declare function buildResourceGraph(): ResourceGraph;
|
|
190
|
+
/**
|
|
191
|
+
* The environment variables worth writing for a resource, given its engine.
|
|
192
|
+
*
|
|
193
|
+
* Falls back to every base the kind reads when the engine is unknown — a
|
|
194
|
+
* `custom:` engine gets the full list rather than an empty one, because
|
|
195
|
+
* guessing narrow would silently omit the variable it actually needs.
|
|
196
|
+
*/
|
|
197
|
+
export declare function envBasesForResource(declaration: ResourceDeclaration): readonly string[];
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary a live schema change is described in.
|
|
3
|
+
*
|
|
4
|
+
* Declared here, and nowhere else, because two packages that must not import
|
|
5
|
+
* each other both need it: `@rebasepro/server-postgres` decides what a change
|
|
6
|
+
* means and renders the files it needs, while `@rebasepro/server` commits those
|
|
7
|
+
* files and serves the routes. Neither can reach the other — the server is
|
|
8
|
+
* engine-agnostic by design — so the shared kernel holds the shapes and the
|
|
9
|
+
* driver is detected structurally through {@link SchemaEditingAdmin}.
|
|
10
|
+
*
|
|
11
|
+
* Nothing here executes anything. These are the nouns.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* What a change will do to a live database.
|
|
15
|
+
*
|
|
16
|
+
* - `safe` — the boot-time ensure path expresses it, and the result matches the
|
|
17
|
+
* configuration.
|
|
18
|
+
* - `diverges` — the ensure path applies *something*, but the database will not
|
|
19
|
+
* match what the configuration declares, and nothing reports it. This is the
|
|
20
|
+
* category worth having: adding a required property to a populated table
|
|
21
|
+
* yields a nullable column, and adding a value to an existing enum yields
|
|
22
|
+
* nothing at all. Both read as success.
|
|
23
|
+
* - `needs-migration` — the ensure path cannot express it. Dropping anything,
|
|
24
|
+
* changing a type, moving a primary key.
|
|
25
|
+
*/
|
|
26
|
+
export type SchemaChangeVerdict = "safe" | "diverges" | "needs-migration";
|
|
27
|
+
export type SchemaChangeKind = "add-collection" | "remove-collection" | "add-property" | "remove-property" | "change-property-type" | "rename-column" | "add-enum-value" | "remove-enum-value" | "change-required" | "change-primary-key";
|
|
28
|
+
export interface SchemaChange {
|
|
29
|
+
kind: SchemaChangeKind;
|
|
30
|
+
verdict: SchemaChangeVerdict;
|
|
31
|
+
/** Collection slug. */
|
|
32
|
+
collection: string;
|
|
33
|
+
/** Property name, where the change is to one. */
|
|
34
|
+
property?: string;
|
|
35
|
+
/** One line, specific: what changed and what it will do. */
|
|
36
|
+
detail: string;
|
|
37
|
+
/** What to do instead, when the verdict is not `safe`. */
|
|
38
|
+
remedy?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ClassifiedSchemaChanges {
|
|
41
|
+
changes: SchemaChange[];
|
|
42
|
+
/** The worst verdict present, or `safe` for an empty diff. */
|
|
43
|
+
verdict: SchemaChangeVerdict;
|
|
44
|
+
/** True only when every change is `safe` — the one case an editor may apply. */
|
|
45
|
+
applicable: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Where a project's generated schema artifacts live, relative to the **project**
|
|
49
|
+
* root — which is the repository root only when the project is the whole
|
|
50
|
+
* repository.
|
|
51
|
+
*
|
|
52
|
+
* Here rather than in the Postgres package because it is a contract, not an
|
|
53
|
+
* engine detail: `@rebasepro/server` has to derive these for a project in a
|
|
54
|
+
* subdirectory, and it cannot import a driver to do it.
|
|
55
|
+
*/
|
|
56
|
+
export interface SchemaCommitPaths {
|
|
57
|
+
/** Drizzle schema, imported by the backend. */
|
|
58
|
+
schemaFile: string;
|
|
59
|
+
/** Declarative DDL, what `db push` applies and Atlas diffs against. */
|
|
60
|
+
ddlFile: string;
|
|
61
|
+
policiesFile: string;
|
|
62
|
+
searchFile: string;
|
|
63
|
+
}
|
|
64
|
+
export declare const DEFAULT_COMMIT_PATHS: SchemaCommitPaths;
|
|
65
|
+
/** One file the commit writes, as content rather than as a path on a disk. */
|
|
66
|
+
export interface SchemaChangeFile {
|
|
67
|
+
path: string;
|
|
68
|
+
contents: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Everything a change needs written and run.
|
|
72
|
+
*
|
|
73
|
+
* Computed without touching a disk or a network. The database is *read* — what
|
|
74
|
+
* a change means depends on what is already there, and a plan that guessed
|
|
75
|
+
* would be guessing about whether the statements it returns will be accepted.
|
|
76
|
+
*/
|
|
77
|
+
export interface SchemaChangePlan {
|
|
78
|
+
/** Every file the commit writes — collection source and generated artifacts. */
|
|
79
|
+
files: SchemaChangeFile[];
|
|
80
|
+
/** The additive DDL this change adds, in dependency order. */
|
|
81
|
+
statements: string[];
|
|
82
|
+
classified: ClassifiedSchemaChanges;
|
|
83
|
+
/** A commit message describing the change rather than announcing one. */
|
|
84
|
+
message: string;
|
|
85
|
+
/**
|
|
86
|
+
* Constraints the configuration asks for that these statements do not
|
|
87
|
+
* carry, and why.
|
|
88
|
+
*
|
|
89
|
+
* Almost always empty. When it is not, it is the part the person confirming
|
|
90
|
+
* needs to read: the change will apply, and the database will still not
|
|
91
|
+
* enforce something the configuration says — a required property over a
|
|
92
|
+
* table that already holds rows with no value for it. Optional so a plan
|
|
93
|
+
* from an engine that does not distinguish these cases stays valid.
|
|
94
|
+
*/
|
|
95
|
+
withheldConstraints?: WithheldSchemaConstraint[];
|
|
96
|
+
}
|
|
97
|
+
/** A constraint a plan asks for and does not apply. */
|
|
98
|
+
export interface WithheldSchemaConstraint {
|
|
99
|
+
/** `schema.table.column`. */
|
|
100
|
+
target: string;
|
|
101
|
+
kind: "not-null";
|
|
102
|
+
/** What is in the way, naming the obstacle rather than the rule. */
|
|
103
|
+
reason: string;
|
|
104
|
+
/** What would make it applicable. */
|
|
105
|
+
remedy: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* An admin that can plan a schema change.
|
|
109
|
+
*
|
|
110
|
+
* Planning only. Applying is `executeSql`, which every SQL admin already has,
|
|
111
|
+
* and committing belongs to whatever holds the repository — keeping those three
|
|
112
|
+
* apart is what lets the same plan be committed locally on a developer's machine
|
|
113
|
+
* and through a GitHub App from a cloud tenant.
|
|
114
|
+
*
|
|
115
|
+
* @group Admin
|
|
116
|
+
*/
|
|
117
|
+
export interface SchemaEditingAdmin {
|
|
118
|
+
/**
|
|
119
|
+
* Decide what the change means and render everything it needs.
|
|
120
|
+
*
|
|
121
|
+
* Rejects when the change is not applicable, carrying the classification so
|
|
122
|
+
* a caller can say which change was the problem.
|
|
123
|
+
*/
|
|
124
|
+
planSchemaChange(before: unknown[], after: unknown[], options?: {
|
|
125
|
+
paths?: Partial<SchemaCommitPaths>;
|
|
126
|
+
}): Promise<SchemaChangePlan>;
|
|
127
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* them with `getPolicyNamesForRule`/`getEffectiveSecurityRules` rather than
|
|
16
16
|
* matching on `rule.name`.
|
|
17
17
|
*/
|
|
18
|
-
import type { PolicyExpression } from "./policy";
|
|
18
|
+
import type { PolicyExpression } from "./policy.js";
|
|
19
19
|
/**
|
|
20
20
|
* SQL operation that a policy applies to.
|
|
21
21
|
* @group Models
|
package/dist/users/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "./user";
|
|
1
|
+
export * from "./user.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/types",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.16.
|
|
4
|
+
"version": "0.16.1-canary.g041c925",
|
|
5
5
|
"description": "Rebase type definitions — shared interfaces and controller types",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
},
|
|
89
89
|
"scripts": {
|
|
90
90
|
"watch": "vite build --watch",
|
|
91
|
-
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../scripts/assert-build-output.mjs",
|
|
91
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../tooling/scripts/add-dts-extensions.mjs dist && node ../../tooling/scripts/assert-build-output.mjs",
|
|
92
92
|
"test:lint": "eslint \"src/**\" --quiet",
|
|
93
93
|
"test": "jest --passWithNoTests",
|
|
94
94
|
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|
|
@@ -300,7 +300,7 @@ export interface RebaseClient<DB = unknown> {
|
|
|
300
300
|
/** Unified Authentication layer */
|
|
301
301
|
auth: AuthClient;
|
|
302
302
|
|
|
303
|
-
/** Unified Storage layer
|
|
303
|
+
/** Unified Storage layer — the default storage source. */
|
|
304
304
|
storage?: StorageSource;
|
|
305
305
|
|
|
306
306
|
/** Registry of all named storage sources for multi-backend support */
|
|
@@ -437,6 +437,19 @@ export interface RebaseServerClient<DB = unknown> extends Omit<RebaseClient<DB>,
|
|
|
437
437
|
* Execute raw SQL against the database. Always present server-side for SQL
|
|
438
438
|
* engines. Values interpolated into the query should be passed via
|
|
439
439
|
* `params`, referenced as `$1`, `$2`, … placeholders in the query text.
|
|
440
|
+
*
|
|
441
|
+
* **Runtime note.** This is the one accessor on this object that is not
|
|
442
|
+
* portable. It runs on the database owner connection over a TCP socket, so
|
|
443
|
+
* it is available wherever the framework holds that connection — every Node
|
|
444
|
+
* deployment, self-hosted or managed — and not on a host that has no
|
|
445
|
+
* sockets and no business holding owner credentials.
|
|
446
|
+
*
|
|
447
|
+
* Nothing about that is a problem for a Node deployment, and it is not a
|
|
448
|
+
* reason to avoid it there. It is a reason not to build a function's *only*
|
|
449
|
+
* data path on it if that function may later move: `c.get("driver")` and
|
|
450
|
+
* `rebase.dataAsAdmin` go over the same wire wherever they run. A function
|
|
451
|
+
* that genuinely needs raw SQL can ask `runtimeKey()` and degrade, rather
|
|
452
|
+
* than discovering it at the call.
|
|
440
453
|
*/
|
|
441
454
|
sql(query: string, options?: { database?: string; role?: string; params?: unknown[] }): Promise<Record<string, unknown>[]>;
|
|
442
455
|
}
|
package/src/controllers/data.ts
CHANGED
|
@@ -3,15 +3,6 @@ import type { ComputedSortField, SearchMatch } from "../types/search";
|
|
|
3
3
|
import { Entity, EntityValues } from "../types/entities";
|
|
4
4
|
import { WhereFilterOp, FieldPath, FilterValues, OrderBySpec } from "../types/filter-operators";
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Operator-blind filter value: whatever the column holds, a list of it, or null.
|
|
8
|
-
*
|
|
9
|
-
* @deprecated Superseded by {@link WhereValueFor}, which correlates the value
|
|
10
|
-
* with the operator. Kept exported because it is public API and downstream code
|
|
11
|
-
* annotates with it; every `where()` overload in this file uses `WhereValueFor`.
|
|
12
|
-
*/
|
|
13
|
-
export type WhereValue<T> = T | T[] | null;
|
|
14
|
-
|
|
15
6
|
/**
|
|
16
7
|
* The element type of an array column, and the column's own type otherwise.
|
|
17
8
|
*
|