@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.
- package/README.md +4 -0
- package/dist/call_context.d.ts +20 -0
- package/dist/controllers/client.d.ts +36 -4
- package/dist/controllers/data.d.ts +120 -10
- package/dist/errors.d.ts +83 -4
- package/dist/index.es.js +522 -160
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +2 -2
- package/dist/types/auth_adapter.d.ts +41 -6
- package/dist/types/backend.d.ts +48 -0
- package/dist/types/collections.d.ts +25 -1
- package/dist/types/cron.d.ts +34 -0
- package/dist/types/database_adapter.d.ts +39 -0
- package/dist/types/entity_callbacks.d.ts +14 -1
- package/dist/types/filter-operators.d.ts +24 -1
- package/dist/types/policy.d.ts +29 -1
- package/dist/types/properties.d.ts +216 -3
- package/dist/types/relations.d.ts +65 -7
- package/dist/types/resource_kinds.d.ts +173 -17
- package/dist/types/resources.d.ts +108 -7
- package/dist/types/rls-functions.d.ts +11 -0
- package/dist/types/storage_source.d.ts +12 -23
- package/package.json +24 -23
- package/src/call_context.ts +0 -120
- package/src/controllers/auth_state.ts +0 -24
- package/src/controllers/client.ts +0 -494
- package/src/controllers/collection_registry.ts +0 -62
- package/src/controllers/data.ts +0 -1012
- package/src/controllers/data_driver.ts +0 -576
- package/src/controllers/effective_role.ts +0 -4
- package/src/controllers/email.ts +0 -91
- package/src/controllers/index.ts +0 -11
- package/src/controllers/storage.ts +0 -252
- package/src/errors.ts +0 -119
- package/src/index.ts +0 -5
- package/src/types/admin_block.ts +0 -209
- package/src/types/api_keys.ts +0 -108
- package/src/types/auth_adapter.ts +0 -580
- package/src/types/backend.ts +0 -987
- package/src/types/backup.ts +0 -26
- package/src/types/channel_bus.ts +0 -202
- package/src/types/chips.ts +0 -34
- package/src/types/collection_contract.ts +0 -278
- package/src/types/collections.ts +0 -763
- package/src/types/component_ref.ts +0 -92
- package/src/types/cron.ts +0 -213
- package/src/types/data_source.ts +0 -357
- package/src/types/database_adapter.ts +0 -267
- package/src/types/entities.ts +0 -226
- package/src/types/entity_callbacks.ts +0 -229
- package/src/types/filter-operators.ts +0 -444
- package/src/types/history.ts +0 -66
- package/src/types/index.ts +0 -36
- package/src/types/indexes.ts +0 -180
- package/src/types/policy.ts +0 -328
- package/src/types/postgres_introspection.ts +0 -101
- package/src/types/project_manifest.ts +0 -598
- package/src/types/properties.ts +0 -1368
- package/src/types/relations.ts +0 -417
- package/src/types/resource_kinds.ts +0 -390
- package/src/types/resources.ts +0 -368
- package/src/types/rls-functions.ts +0 -98
- package/src/types/schema_editing.ts +0 -157
- package/src/types/schema_version.ts +0 -112
- package/src/types/search.ts +0 -247
- package/src/types/security_rules.ts +0 -344
- package/src/types/storage_authorize.ts +0 -77
- package/src/types/storage_source.ts +0 -248
- package/src/types/websockets.ts +0 -117
- package/src/users/index.ts +0 -2
- package/src/users/user.ts +0 -69
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ResourceRef } from "./resources.js";
|
|
1
2
|
import type { Entity, EntityReference, EntityRelation, EntityValues, GeoPoint, Vector } from "./entities.js";
|
|
2
3
|
import type { Relation, ResolvedRelation } from "./relations.js";
|
|
3
4
|
import type { ColorKey, ColorScheme } from "./chips.js";
|
|
@@ -77,6 +78,129 @@ export type MongoProperties = {
|
|
|
77
78
|
* unknown but the narrowed property constraint must be satisfied.
|
|
78
79
|
*/
|
|
79
80
|
export type EngineProperties = PostgresProperties | FirebaseProperties | MongoProperties;
|
|
81
|
+
/**
|
|
82
|
+
* What a key the surrounding shape does not declare resolves to.
|
|
83
|
+
*
|
|
84
|
+
* Nothing is assignable to it — it has required members nobody can spell — so
|
|
85
|
+
* the key errors. It is a *named* type rather than `never` purely for the
|
|
86
|
+
* message: TypeScript prints the target, so the compiler reads back the key that
|
|
87
|
+
* is wrong and the keys that would have been right, instead of saying "not
|
|
88
|
+
* assignable to type 'never'".
|
|
89
|
+
*
|
|
90
|
+
* ```
|
|
91
|
+
* Type '{ required: true }' is not assignable to type
|
|
92
|
+
* '{ readonly required: true } & NoSuchKey<"validaton", "name" | "type" | "validation" | …>'.
|
|
93
|
+
* Property 'didYouMean' is missing …
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* `Known` is the set of keys that *were* available. TypeScript elides a long
|
|
97
|
+
* union after a few members, so this is a hint and not an exhaustive listing —
|
|
98
|
+
* which is the right trade: the near-miss is usually alphabetically adjacent to
|
|
99
|
+
* the key that was meant, and a wall of 25 names would be read by nobody.
|
|
100
|
+
*/
|
|
101
|
+
export type NoSuchKey<K extends PropertyKey, Known extends PropertyKey = never> = {
|
|
102
|
+
/** The key that was written, so the compiler reads it back verbatim. */
|
|
103
|
+
readonly noSuchKey: K;
|
|
104
|
+
/** The keys that were available. Required, so the type is unsatisfiable. */
|
|
105
|
+
readonly didYouMean: Known;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* What a property whose `type` the engine does not have resolves to.
|
|
109
|
+
*
|
|
110
|
+
* Same trick as {@link NoSuchKey}, for a different mistake: a `relation` on a
|
|
111
|
+
* Firestore collection, a `vector` on MongoDB.
|
|
112
|
+
*
|
|
113
|
+
* Without it, `ExactProperty<V, never>` is `V & {}` — which is `V`, and
|
|
114
|
+
* therefore no check at all. The gate is normally caught one level up, by the
|
|
115
|
+
* builder's `P extends FirebaseProperties` constraint; this is what catches it
|
|
116
|
+
* when `StrictProperties` is applied to a property map that carries no such
|
|
117
|
+
* constraint, and it reports on the property rather than on the whole map.
|
|
118
|
+
*/
|
|
119
|
+
export type PropertyTypeNotOnThisEngine<T> = {
|
|
120
|
+
/** The `type` tag that has no home on this engine. Required, so nothing fits. */
|
|
121
|
+
readonly __rebasePropertyTypeNotOnThisEngine: T;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* A relation checked against the concrete member of the union its own `kind`
|
|
125
|
+
* selects, rather than against the union as a whole.
|
|
126
|
+
*
|
|
127
|
+
* `Relation` is closed — `BelongsToRelation` has `localKey` and no
|
|
128
|
+
* `foreignKeyOnTarget`, `HasManyRelation` the reverse — but excess-property
|
|
129
|
+
* checking against a *union* passes any key that any member declares. So
|
|
130
|
+
* `{ kind: "belongsTo", foreignKeyOnTarget: "author_id" }` typechecked, and
|
|
131
|
+
* described a link that cannot exist: the generator reads `localKey`, defaults
|
|
132
|
+
* it to `<relationName>_id`, and the column the author actually named is never
|
|
133
|
+
* looked at. The relation resolves to a different link than the one written.
|
|
134
|
+
*
|
|
135
|
+
* The runtime already refuses this — `validate-config` rejects a link field that
|
|
136
|
+
* does not belong to the kind — so this is the same rule one stage earlier,
|
|
137
|
+
* where it costs a red squiggle instead of a failed boot.
|
|
138
|
+
*/
|
|
139
|
+
type StrictRelation<R> = R extends {
|
|
140
|
+
kind: infer K;
|
|
141
|
+
} ? R & {
|
|
142
|
+
[Key in Exclude<keyof R, keyof Extract<Relation, {
|
|
143
|
+
kind: K;
|
|
144
|
+
}>>]: NoSuchKey<Key, keyof Extract<Relation, {
|
|
145
|
+
kind: K;
|
|
146
|
+
}>>;
|
|
147
|
+
} : R;
|
|
148
|
+
/**
|
|
149
|
+
* `V`, plus every key it carries that `Shape` does not declare, typed so it
|
|
150
|
+
* cannot be satisfied.
|
|
151
|
+
*
|
|
152
|
+
* The `relation` block is descended into, because it is the one nested shape
|
|
153
|
+
* that is a closed union rather than a single interface — see
|
|
154
|
+
* {@link StrictRelation}. The rest (`array.of`, `map.properties`, the `admin`
|
|
155
|
+
* options) are left to the weak-type check and the boot validator.
|
|
156
|
+
*/
|
|
157
|
+
type ExactProperty<V, Shape> = [Shape] extends [never] ? PropertyTypeNotOnThisEngine<V extends {
|
|
158
|
+
type: infer T;
|
|
159
|
+
} ? T : never> : V & {
|
|
160
|
+
[K in Exclude<keyof V, keyof Shape>]: NoSuchKey<K, keyof Shape>;
|
|
161
|
+
} & (V extends {
|
|
162
|
+
relation: infer R;
|
|
163
|
+
} ? {
|
|
164
|
+
relation: StrictRelation<R>;
|
|
165
|
+
} : unknown);
|
|
166
|
+
/**
|
|
167
|
+
* A property map in which each value is checked against the *concrete* member of
|
|
168
|
+
* the property union that its own `type` tag selects.
|
|
169
|
+
*
|
|
170
|
+
* ### Why this type has to exist
|
|
171
|
+
*
|
|
172
|
+
* `defineCollection` takes `properties: P` where `const P extends Properties`.
|
|
173
|
+
* `Properties` is an index signature, and **every object literal is assignable
|
|
174
|
+
* to an index signature** — extra keys included — so TypeScript's
|
|
175
|
+
* excess-property check never ran inside a property. The consequences were not
|
|
176
|
+
* theoretical:
|
|
177
|
+
*
|
|
178
|
+
* - `validation` misspelled `validaton` compiled, and the field was quietly not
|
|
179
|
+
* required.
|
|
180
|
+
* - `multiline: true` and `markdown: true` written flat — the shape the docs
|
|
181
|
+
* themselves showed — compiled, and then the backend refused to boot with a
|
|
182
|
+
* migration hint pointing at `admin: { … }`.
|
|
183
|
+
* - `multiSelect: true`, a key that exists nowhere in the codebase, compiled.
|
|
184
|
+
*
|
|
185
|
+
* Annotating `const c: PostgresCollectionConfig = { … }` *did* catch all three,
|
|
186
|
+
* which is the tell: the checking was never missing, only bypassed by the
|
|
187
|
+
* inference the builder exists to provide.
|
|
188
|
+
*
|
|
189
|
+
* The map is homomorphic (`[K in keyof P]`), so it stays invertible and `const P`
|
|
190
|
+
* inference is unaffected — `admin.display.title` still completes over the
|
|
191
|
+
* collection's own keys. Verified against the full probe suite before landing.
|
|
192
|
+
*
|
|
193
|
+
* Nested shapes (`array.of`, `map.properties`, and the `admin` block's own
|
|
194
|
+
* options) are not reached by this type; the weak-type check covers an `admin`
|
|
195
|
+
* block whose keys are *all* unknown, and the boot validator covers the rest.
|
|
196
|
+
*/
|
|
197
|
+
export type StrictProperties<P, AllowedProperty> = {
|
|
198
|
+
[K in keyof P]: P[K] extends {
|
|
199
|
+
type: infer T;
|
|
200
|
+
} ? ExactProperty<P[K], Extract<AllowedProperty, {
|
|
201
|
+
type: T;
|
|
202
|
+
}>> : P[K];
|
|
203
|
+
};
|
|
80
204
|
/**
|
|
81
205
|
* A helper type to infer the underlying data type from a Property definition.
|
|
82
206
|
* This is the core of the type inference system.
|
|
@@ -128,9 +252,20 @@ export type InferEntityType<P extends Properties> = {
|
|
|
128
252
|
};
|
|
129
253
|
export interface BaseProperty<CustomProps = unknown> {
|
|
130
254
|
/**
|
|
131
|
-
*
|
|
255
|
+
* The label the admin panel shows for this field — a column header, a form
|
|
256
|
+
* label, a card caption.
|
|
257
|
+
*
|
|
258
|
+
* Optional, and derived from the property key when absent
|
|
259
|
+
* (`publishDate` -> "Publish Date", via `prettifyIdentifier`, which is the
|
|
260
|
+
* same derivation the collection editor already uses when it suggests one).
|
|
261
|
+
*
|
|
262
|
+
* It was required, and that was a UI concern levied on everyone: a headless
|
|
263
|
+
* project has no panel and no reason to invent display names, yet could not
|
|
264
|
+
* declare a property without one. Set it when the derived label is wrong —
|
|
265
|
+
* `"URL"` rather than "Url", `"Postcode"` rather than "Zip" — which is the
|
|
266
|
+
* only time it earns the line.
|
|
132
267
|
*/
|
|
133
|
-
name
|
|
268
|
+
name?: string;
|
|
134
269
|
/**
|
|
135
270
|
* Property description, always displayed under the field
|
|
136
271
|
*/
|
|
@@ -370,6 +505,15 @@ export interface VectorProperty extends BaseProperty {
|
|
|
370
505
|
* Default value for new entities.
|
|
371
506
|
*/
|
|
372
507
|
defaultValue?: Vector;
|
|
508
|
+
/**
|
|
509
|
+
* How many numbers each embedding has — 1536 for OpenAI's
|
|
510
|
+
* `text-embedding-3-small`, 768 for many sentence transformers.
|
|
511
|
+
*
|
|
512
|
+
* **Required, and effectively frozen.** It is the column's width
|
|
513
|
+
* (`vector(1536)`), so changing it is a rewrite of every row, and every
|
|
514
|
+
* stored embedding was produced by a model that no longer matches. Take the
|
|
515
|
+
* number from the model you are actually going to use.
|
|
516
|
+
*/
|
|
373
517
|
dimensions: number;
|
|
374
518
|
/**
|
|
375
519
|
* ANN index configuration for this column.
|
|
@@ -383,6 +527,11 @@ export interface VectorProperty extends BaseProperty {
|
|
|
383
527
|
* embedding is left unindexed rather than failing the boot.
|
|
384
528
|
*/
|
|
385
529
|
index?: VectorIndexConfig | false;
|
|
530
|
+
/**
|
|
531
|
+
* The rules every property has: `required`, `unique`. A vector has no
|
|
532
|
+
* length or range rules of its own — {@link dimensions} is the column's
|
|
533
|
+
* width, and the database enforces it.
|
|
534
|
+
*/
|
|
386
535
|
validation?: PropertyValidationSchema;
|
|
387
536
|
}
|
|
388
537
|
/**
|
|
@@ -394,6 +543,10 @@ export interface BinaryProperty extends BaseProperty {
|
|
|
394
543
|
* Default value for new entities. Must be a base64-encoded string.
|
|
395
544
|
*/
|
|
396
545
|
defaultValue?: string;
|
|
546
|
+
/**
|
|
547
|
+
* The rules every property has: `required`, `unique`. Size limits belong to
|
|
548
|
+
* the upload path, not here.
|
|
549
|
+
*/
|
|
397
550
|
validation?: PropertyValidationSchema;
|
|
398
551
|
}
|
|
399
552
|
export interface DateProperty extends BaseProperty {
|
|
@@ -530,6 +683,12 @@ export interface RelationProperty extends BaseProperty {
|
|
|
530
683
|
* relation: { kind: "manyToMany", target: () => tagsCollection }
|
|
531
684
|
* }
|
|
532
685
|
* ```
|
|
686
|
+
*
|
|
687
|
+
* Optional because there is a second way to say the same thing: an entry in
|
|
688
|
+
* the collection's `relations` array whose `relationName` is this
|
|
689
|
+
* property's key. One of the two is required, and boot refuses a
|
|
690
|
+
* `type: "relation"` property that has neither — a field with no link is a
|
|
691
|
+
* relation in name only.
|
|
533
692
|
*/
|
|
534
693
|
relation?: Relation;
|
|
535
694
|
/**
|
|
@@ -645,15 +804,29 @@ export interface MapProperty extends BaseProperty {
|
|
|
645
804
|
keyValue?: boolean;
|
|
646
805
|
}
|
|
647
806
|
/**
|
|
807
|
+
* What a `dynamicProps` builder is handed when it computes a property.
|
|
808
|
+
*
|
|
809
|
+
* Called on every render of the form, for one field, so it is a pure function of
|
|
810
|
+
* these arguments: the entity being edited, the value in this field, and who is
|
|
811
|
+
* editing. It runs **in the browser** and shapes what is offered — it is not a
|
|
812
|
+
* security boundary, and a rule that must hold has to be a security rule as well.
|
|
813
|
+
*
|
|
648
814
|
* @group Entity properties
|
|
649
815
|
*/
|
|
650
816
|
export type PropertyBuilderProps<M extends Record<string, unknown> = Record<string, unknown>> = {
|
|
817
|
+
/** The entity's values as they stand right now, including unsaved edits. */
|
|
651
818
|
values: Partial<M>;
|
|
819
|
+
/** The values as last saved, or `undefined` for an entity being created. */
|
|
652
820
|
previousValues?: Partial<M>;
|
|
821
|
+
/** The value in *this* field. `undefined` before anything is typed. */
|
|
653
822
|
propertyValue?: unknown;
|
|
823
|
+
/** Position within the parent array, when this property is an array element. */
|
|
654
824
|
index?: number;
|
|
825
|
+
/** The collection path this entity belongs to. */
|
|
655
826
|
path: string;
|
|
827
|
+
/** The entity's id, or `undefined` while it is being created. */
|
|
656
828
|
entityId?: string | number;
|
|
829
|
+
/** Who is editing — the signed-in user and their roles. */
|
|
657
830
|
authController: AuthState;
|
|
658
831
|
};
|
|
659
832
|
/**
|
|
@@ -723,12 +896,19 @@ export interface PropertyValidationSchema {
|
|
|
723
896
|
* @group Entity properties
|
|
724
897
|
*/
|
|
725
898
|
export interface NumberPropertyValidationSchema extends PropertyValidationSchema {
|
|
899
|
+
/** Smallest accepted value, **inclusive**. `min: 0` accepts `0`. */
|
|
726
900
|
min?: number;
|
|
901
|
+
/** Largest accepted value, **inclusive**. `max: 100` accepts `100`. */
|
|
727
902
|
max?: number;
|
|
903
|
+
/** Must be strictly below this. The exclusive twin of {@link max}. */
|
|
728
904
|
lessThan?: number;
|
|
905
|
+
/** Must be strictly above this. The exclusive twin of {@link min}. */
|
|
729
906
|
moreThan?: number;
|
|
907
|
+
/** Must be greater than zero. `0` is rejected — use `min: 0` to allow it. */
|
|
730
908
|
positive?: boolean;
|
|
909
|
+
/** Must be less than zero. `0` is rejected. */
|
|
731
910
|
negative?: boolean;
|
|
911
|
+
/** No fractional part. Does not change the column type; see `columnType`. */
|
|
732
912
|
integer?: boolean;
|
|
733
913
|
}
|
|
734
914
|
/**
|
|
@@ -736,16 +916,42 @@ export interface NumberPropertyValidationSchema extends PropertyValidationSchema
|
|
|
736
916
|
* @group Entity properties
|
|
737
917
|
*/
|
|
738
918
|
export interface StringPropertyValidationSchema extends PropertyValidationSchema {
|
|
919
|
+
/** Exactly this many characters — a country code, a fixed-width reference. */
|
|
739
920
|
length?: number;
|
|
921
|
+
/** Fewest characters accepted, inclusive. */
|
|
740
922
|
min?: number;
|
|
923
|
+
/**
|
|
924
|
+
* Most characters accepted, inclusive.
|
|
925
|
+
*
|
|
926
|
+
* Also sizes the column: a `max` turns `TEXT` into `VARCHAR(max)`, so
|
|
927
|
+
* lowering it on a table that already has longer rows is a migration the
|
|
928
|
+
* database will refuse, not just a stricter form.
|
|
929
|
+
*/
|
|
741
930
|
max?: number;
|
|
931
|
+
/**
|
|
932
|
+
* A pattern the whole value must match.
|
|
933
|
+
*
|
|
934
|
+
* A `string` is compiled per request, so it must be a valid regular
|
|
935
|
+
* expression — one that will not compile is rejected at boot, because
|
|
936
|
+
* `toPattern` answers `undefined` for it and the caller reads
|
|
937
|
+
* `if (pattern && !pattern.test(value))`: the rule would silently become no
|
|
938
|
+
* rule. A `RegExp` literal has already been compiled by the engine.
|
|
939
|
+
*/
|
|
742
940
|
matches?: string | RegExp;
|
|
743
941
|
/**
|
|
744
942
|
* Message displayed when the input does not satisfy the regex in `matches`
|
|
745
943
|
*/
|
|
746
944
|
matchesMessage?: string;
|
|
945
|
+
/**
|
|
946
|
+
* Strip leading and trailing whitespace **before** saving.
|
|
947
|
+
*
|
|
948
|
+
* A transform, not a check: it changes the value that is written, which is
|
|
949
|
+
* what makes it the fix for "the same tag twice, one with a trailing space".
|
|
950
|
+
*/
|
|
747
951
|
trim?: boolean;
|
|
952
|
+
/** Lowercase the value before saving. A transform, like {@link trim}. */
|
|
748
953
|
lowercase?: boolean;
|
|
954
|
+
/** Uppercase the value before saving. A transform, like {@link trim}. */
|
|
749
955
|
uppercase?: boolean;
|
|
750
956
|
}
|
|
751
957
|
/**
|
|
@@ -753,7 +959,9 @@ export interface StringPropertyValidationSchema extends PropertyValidationSchema
|
|
|
753
959
|
* @group Entity properties
|
|
754
960
|
*/
|
|
755
961
|
export interface DatePropertyValidationSchema extends PropertyValidationSchema {
|
|
962
|
+
/** Earliest accepted date, inclusive. A fixed instant, not "today". */
|
|
756
963
|
min?: Date;
|
|
964
|
+
/** Latest accepted date, inclusive. A fixed instant, not "today". */
|
|
757
965
|
max?: Date;
|
|
758
966
|
}
|
|
759
967
|
/**
|
|
@@ -761,7 +969,9 @@ export interface DatePropertyValidationSchema extends PropertyValidationSchema {
|
|
|
761
969
|
* @group Entity properties
|
|
762
970
|
*/
|
|
763
971
|
export interface ArrayPropertyValidationSchema extends PropertyValidationSchema {
|
|
972
|
+
/** Fewest elements accepted, inclusive. Counts elements, not characters. */
|
|
764
973
|
min?: number;
|
|
974
|
+
/** Most elements accepted, inclusive. Counts elements, not characters. */
|
|
765
975
|
max?: number;
|
|
766
976
|
}
|
|
767
977
|
/**
|
|
@@ -775,8 +985,11 @@ export type StorageConfig = {
|
|
|
775
985
|
* in `initializeRebaseBackend({ storage: { ... } })`.
|
|
776
986
|
*
|
|
777
987
|
* When omitted, the default storage source is used.
|
|
988
|
+
*
|
|
989
|
+
* A string key, or the handle `bucket("media")` returned — the handle is
|
|
990
|
+
* the same name spelled once, and `defineCollection` records its key.
|
|
778
991
|
*/
|
|
779
|
-
storageSource?:
|
|
992
|
+
storageSource?: ResourceRef;
|
|
780
993
|
/**
|
|
781
994
|
* Store files for this property as **public**: they are placed under the
|
|
782
995
|
* public prefix and served via stable, token-less, permanent, CDN-cacheable
|
|
@@ -34,13 +34,45 @@ export interface RelationBase {
|
|
|
34
34
|
relationName?: string;
|
|
35
35
|
/** The collection on the other end. */
|
|
36
36
|
target: () => AnyCollectionConfig;
|
|
37
|
+
/**
|
|
38
|
+
* What the database does to this side's foreign key when the target row's
|
|
39
|
+
* key changes. Emitted as the constraint's `ON UPDATE`.
|
|
40
|
+
*
|
|
41
|
+
* Unset means no clause, which Postgres reads as `NO ACTION`. Set
|
|
42
|
+
* `"cascade"` when the target's key is a natural key that can be edited —
|
|
43
|
+
* a slug, a SKU — so the pointers follow it.
|
|
44
|
+
*
|
|
45
|
+
* Only a `belongsTo` puts the key on this table, so this is the only kind
|
|
46
|
+
* where the clause is written here; on the other kinds it describes the
|
|
47
|
+
* constraint the target's own column carries.
|
|
48
|
+
*/
|
|
37
49
|
onUpdate?: OnAction;
|
|
50
|
+
/**
|
|
51
|
+
* What the database does to this side's rows when the target row is
|
|
52
|
+
* deleted. Emitted as the constraint's `ON DELETE`.
|
|
53
|
+
*
|
|
54
|
+
* Defaults, when unset, to `"set null"` for an optional relation and
|
|
55
|
+
* **`"restrict"`** for a required one. `NOT NULL` says a child cannot exist
|
|
56
|
+
* without a parent; it does not say deleting the parent should delete the
|
|
57
|
+
* child. Ask for `"cascade"` when that is what you mean — it is the one
|
|
58
|
+
* value that destroys rows you did not name.
|
|
59
|
+
*
|
|
60
|
+
* A `manyToMany` is the exception: its junction rows default to
|
|
61
|
+
* `"cascade"`, because the row deleted there is the link and not the target.
|
|
62
|
+
*/
|
|
38
63
|
onDelete?: OnAction;
|
|
39
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Presentation overrides applied when this relation is rendered as a tab.
|
|
66
|
+
*
|
|
67
|
+
* Whether the link is *required* is not here: it is
|
|
68
|
+
* `validation: { required: true }` on the declaring property, the same key
|
|
69
|
+
* every other field uses. A relation carried its own copy until 0.18, and
|
|
70
|
+
* the two disagreed by construction — the DDL generator read the property
|
|
71
|
+
* (so the column was `NOT NULL`) while codegen read the relation (so the
|
|
72
|
+
* generated `Insert` type made it optional), and a `create()` that
|
|
73
|
+
* typechecked failed at the database.
|
|
74
|
+
*/
|
|
40
75
|
overrides?: Partial<AnyCollectionConfig>;
|
|
41
|
-
validation?: {
|
|
42
|
-
required?: boolean;
|
|
43
|
-
};
|
|
44
76
|
}
|
|
45
77
|
/**
|
|
46
78
|
* This collection holds the foreign key. One target row per source row.
|
|
@@ -179,6 +211,14 @@ export interface ViaRelation extends RelationBase {
|
|
|
179
211
|
kind: "via";
|
|
180
212
|
/** Whether the chain yields one row or many. Cannot be derived from a join chain. */
|
|
181
213
|
cardinality: "one" | "many";
|
|
214
|
+
/**
|
|
215
|
+
* The joins, in order, from this collection's table to the target's.
|
|
216
|
+
*
|
|
217
|
+
* Each step names a table and the columns to join it on; the last step's
|
|
218
|
+
* table is the target. Read-only, because Rebase will not work out how to
|
|
219
|
+
* write through an arbitrary chain, and guessing is what this kind exists to
|
|
220
|
+
* stop.
|
|
221
|
+
*/
|
|
182
222
|
joinPath: JoinStep[];
|
|
183
223
|
}
|
|
184
224
|
/**
|
|
@@ -212,15 +252,27 @@ export type ResolvedRelation = ResolvedBelongsTo | ResolvedHasOne | ResolvedHasM
|
|
|
212
252
|
export interface ResolvedRelationBase {
|
|
213
253
|
/** Always set: defaulted during resolution if the author omitted it. */
|
|
214
254
|
relationName: string;
|
|
255
|
+
/**
|
|
256
|
+
* The collection on the other end.
|
|
257
|
+
*
|
|
258
|
+
* Still a thunk — a relation between two collections that import each other
|
|
259
|
+
* has to be — but normalised: resolution unwraps the module namespace the
|
|
260
|
+
* author's `() => import(…)` may hand back, so every consumer gets the
|
|
261
|
+
* config and not a `{ default: … }` wrapper.
|
|
262
|
+
*/
|
|
215
263
|
target: () => AnyCollectionConfig;
|
|
216
264
|
/** The target's slug, resolved once so consumers need not call `target()`. */
|
|
217
265
|
targetSlug: string;
|
|
266
|
+
/** As authored — see {@link RelationBase.onUpdate}. Defaults are not filled in. */
|
|
218
267
|
onUpdate?: OnAction;
|
|
268
|
+
/**
|
|
269
|
+
* As authored — see {@link RelationBase.onDelete}. `undefined` here means
|
|
270
|
+
* the author said nothing, and the DDL generator picks the default; it does
|
|
271
|
+
* **not** mean "no action".
|
|
272
|
+
*/
|
|
219
273
|
onDelete?: OnAction;
|
|
274
|
+
/** Presentation overrides applied when this relation is rendered as a tab. */
|
|
220
275
|
overrides?: Partial<AnyCollectionConfig>;
|
|
221
|
-
validation?: {
|
|
222
|
-
required?: boolean;
|
|
223
|
-
};
|
|
224
276
|
/**
|
|
225
277
|
* Whether one row or many come back. Derived from `kind` — kept because it
|
|
226
278
|
* is what most consumers actually branch on, and because `via` is the one
|
|
@@ -290,6 +342,11 @@ export interface ResolvedManyToMany extends ResolvedRelationBase {
|
|
|
290
342
|
cardinality: "many";
|
|
291
343
|
writable: true;
|
|
292
344
|
shared: true;
|
|
345
|
+
/**
|
|
346
|
+
* The junction table and its two key columns, with every default filled in:
|
|
347
|
+
* the table from both table names sorted and joined, the columns from each
|
|
348
|
+
* endpoint's slug.
|
|
349
|
+
*/
|
|
293
350
|
through: {
|
|
294
351
|
table: string;
|
|
295
352
|
sourceColumn: string;
|
|
@@ -300,6 +357,7 @@ export interface ResolvedManyToMany extends ResolvedRelationBase {
|
|
|
300
357
|
export interface ResolvedVia extends ResolvedRelationBase {
|
|
301
358
|
kind: "via";
|
|
302
359
|
writable: false;
|
|
360
|
+
/** The chain as authored — see {@link ViaRelation.joinPath}. Nothing to default. */
|
|
303
361
|
joinPath: JoinStep[];
|
|
304
362
|
}
|
|
305
363
|
/** Relations whose target row carries this collection's key. @group Models */
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* that ships an engine this package has never heard of says so at the call site
|
|
12
12
|
* instead of looking like a typo of one that exists.
|
|
13
13
|
*/
|
|
14
|
-
import { type DeclareOptions, type
|
|
14
|
+
import { type DeclareOptions, type ResourceDeclaration, type ResourceHandle } from "./resources.js";
|
|
15
|
+
import { type DataSourceDefinition } from "./data_source.js";
|
|
16
|
+
import { type StorageSourceDefinition } from "./storage_source.js";
|
|
15
17
|
/** Options a database accepts beyond the common ones. */
|
|
16
18
|
export interface DatabaseOptions extends DeclareOptions {
|
|
17
19
|
/**
|
|
@@ -94,6 +96,20 @@ export interface BucketOptions extends DeclareOptions {
|
|
|
94
96
|
publicRead?: boolean;
|
|
95
97
|
/** Key prefix within the bucket, for sharing one bucket between sources. */
|
|
96
98
|
prefix?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Serve unqualified uploads — a storage property with no `storageSource` —
|
|
101
|
+
* from this bucket.
|
|
102
|
+
*
|
|
103
|
+
* A project that declares only `bucket("media")` has no default bucket, and
|
|
104
|
+
* the registry used to promote the one it found with a warning. That is a
|
|
105
|
+
* decision about where a user's files land, made by the framework, on the
|
|
106
|
+
* strength of declaration order; it also produced two different
|
|
107
|
+
* destinations either side of a deploy, because the synthesized local
|
|
108
|
+
* default is dropped in production and the promotion is not. So it is now
|
|
109
|
+
* a boot error, and this is one of the two ways to answer it — the other
|
|
110
|
+
* being `bucket()`, which declares the default bucket itself.
|
|
111
|
+
*/
|
|
112
|
+
default?: boolean;
|
|
97
113
|
/**
|
|
98
114
|
* The credential set this bucket signs with, when several share one.
|
|
99
115
|
*
|
|
@@ -116,12 +132,20 @@ export type BucketHandle = ResourceHandle;
|
|
|
116
132
|
* Declare a bucket.
|
|
117
133
|
*
|
|
118
134
|
* ```ts
|
|
119
|
-
* export const
|
|
135
|
+
* export const uploads = bucket({ engine: "s3" }); // the default one
|
|
136
|
+
* export const media = bucket("media", { transport: "direct" });
|
|
120
137
|
* ```
|
|
121
138
|
*
|
|
122
139
|
* `transport: "direct"` means a provider SDK talks to the bucket and the
|
|
123
140
|
* backend is not in the upload path.
|
|
141
|
+
*
|
|
142
|
+
* The options-only form exists for the same reason `database`'s does: the
|
|
143
|
+
* default bucket has no name to pass, and without it the only way to configure
|
|
144
|
+
* one was `bucket("(default)", { … })` — writing out an internal sentinel to
|
|
145
|
+
* reach the options. Passing options where a key belongs used to throw "a
|
|
146
|
+
* bucket needs a non-empty key", which names neither the mistake nor the fix.
|
|
124
147
|
*/
|
|
148
|
+
export declare function bucket(options?: BucketOptions): BucketHandle;
|
|
125
149
|
export declare function bucket(key?: string, options?: BucketOptions): BucketHandle;
|
|
126
150
|
/**
|
|
127
151
|
* How hard the runtime tries to deliver.
|
|
@@ -203,10 +227,152 @@ export interface TopicHandle<T> extends ResourceHandle {
|
|
|
203
227
|
* ```
|
|
204
228
|
*/
|
|
205
229
|
export declare function topic<T = unknown>(key: string, options?: TopicOptions): TopicHandle<T>;
|
|
230
|
+
/** What a cron declaration records, beyond its handler. */
|
|
231
|
+
export interface CronResourceOptions extends DeclareOptions {
|
|
232
|
+
/** Five-field cron expression, e.g. `0 3 * * *`. */
|
|
233
|
+
schedule: string;
|
|
234
|
+
/**
|
|
235
|
+
* IANA zone the schedule is read in, e.g. `Europe/Madrid`.
|
|
236
|
+
*
|
|
237
|
+
* Without it the schedule is read in the process's own zone, which is
|
|
238
|
+
* whatever the host happens to be set to — UTC in nearly every container,
|
|
239
|
+
* the developer's own on a laptop. "3 AM" then means two different hours
|
|
240
|
+
* either side of a deploy. Naming the zone makes the declaration mean one
|
|
241
|
+
* thing everywhere.
|
|
242
|
+
*/
|
|
243
|
+
timezone?: string;
|
|
244
|
+
description?: string;
|
|
245
|
+
enabled?: boolean;
|
|
246
|
+
timeoutSeconds?: number;
|
|
247
|
+
catchUpWindowSeconds?: number;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Declare a cron, as the scheduler's `defineCron` does on its way through.
|
|
251
|
+
*
|
|
252
|
+
* Projects do not call this: `defineCron` in `@rebasepro/server` does, so a
|
|
253
|
+
* cron file is both the handler and the declaration — one file, one name, and
|
|
254
|
+
* the graph derived from it says what a host needs to know without evaluating
|
|
255
|
+
* the handler. Exported so the derive step and the scheduler spell the
|
|
256
|
+
* declaration identically.
|
|
257
|
+
*/
|
|
258
|
+
export declare function declareCron(name: string, options: CronResourceOptions): ResourceHandle;
|
|
259
|
+
/**
|
|
260
|
+
* What a function declaration records.
|
|
261
|
+
*
|
|
262
|
+
* Recorded by the derive step from the bundler's static analysis rather than
|
|
263
|
+
* by evaluating the function module: a function's handler is a Hono app that
|
|
264
|
+
* only needs to exist at request time, and evaluating it at build time would
|
|
265
|
+
* run its module-scope code in a process with none of its environment.
|
|
266
|
+
*/
|
|
267
|
+
export interface FunctionResourceOptions extends DeclareOptions {
|
|
268
|
+
/** Path inside the project, so a host can point at the file. */
|
|
269
|
+
file?: string;
|
|
270
|
+
/** `false` when the source imports a Node built-in or a package that needs one. */
|
|
271
|
+
portable?: boolean;
|
|
272
|
+
/** Why it is not portable — one short phrase per reason. */
|
|
273
|
+
requires?: string[];
|
|
274
|
+
}
|
|
275
|
+
/** Declare a function. Called by the derive step, not by projects. */
|
|
276
|
+
export declare function declareFunction(name: string, options?: FunctionResourceOptions): ResourceHandle;
|
|
277
|
+
/** Options a queue accepts beyond the common ones. */
|
|
278
|
+
export interface QueueOptions extends DeclareOptions {
|
|
279
|
+
/** Attempts before a job is left failed. Default 5. */
|
|
280
|
+
maxAttempts?: number;
|
|
281
|
+
}
|
|
282
|
+
/** What a queue's handler receives. `attempt` counts from 1. */
|
|
283
|
+
export type QueueHandler<T> = (payload: T, context: {
|
|
284
|
+
attempt: number;
|
|
285
|
+
queue: string;
|
|
286
|
+
jobId: string;
|
|
287
|
+
}) => Promise<void> | void;
|
|
288
|
+
/** Per-job options at enqueue time. */
|
|
289
|
+
export interface QueueEnqueueOptions {
|
|
290
|
+
/** Earliest time the job may run. Defaults to now. */
|
|
291
|
+
runAt?: Date;
|
|
292
|
+
/** Attempts for this job, overriding the queue's. */
|
|
293
|
+
maxAttempts?: number;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* What a queue enqueues through.
|
|
297
|
+
*
|
|
298
|
+
* Installed by `@rebasepro/server` at boot, alongside the topic runtime.
|
|
299
|
+
* Absent — config evaluated by the CLI, a unit test — enqueueing throws with
|
|
300
|
+
* the cause named, rather than resolving and dropping the job.
|
|
301
|
+
*/
|
|
302
|
+
export interface QueueRuntime {
|
|
303
|
+
enqueue(queue: string, payload: unknown, options?: QueueEnqueueOptions): Promise<{
|
|
304
|
+
id: string;
|
|
305
|
+
}>;
|
|
306
|
+
}
|
|
307
|
+
/** Install the transport queues enqueue through. Called by the server at boot. */
|
|
308
|
+
export declare function setQueueRuntime(runtime: QueueRuntime | null): void;
|
|
309
|
+
/** A queue's handler, as recorded for the worker to wire. */
|
|
310
|
+
export interface QueueConsumer<T = unknown> {
|
|
311
|
+
queue: string;
|
|
312
|
+
handler: QueueHandler<T>;
|
|
313
|
+
}
|
|
314
|
+
/** Every declared queue handler, for the worker to wire. */
|
|
315
|
+
export declare function declaredQueueConsumers(): QueueConsumer[];
|
|
316
|
+
/** Forget declared queue handlers. For tests, alongside `resetDeclaredResources`. */
|
|
317
|
+
export declare function resetDeclaredQueueConsumers(): void;
|
|
318
|
+
/** A queue handle, carrying its payload type. */
|
|
319
|
+
export interface QueueHandle<T> extends ResourceHandle {
|
|
320
|
+
/**
|
|
321
|
+
* Put a job on the queue.
|
|
322
|
+
*
|
|
323
|
+
* Resolves once the job is durably recorded, not once it has run. A row
|
|
324
|
+
* insert, so enqueued inside a transaction that rolls back it was never
|
|
325
|
+
* enqueued.
|
|
326
|
+
*/
|
|
327
|
+
enqueue(payload: T, options?: QueueEnqueueOptions): Promise<{
|
|
328
|
+
id: string;
|
|
329
|
+
}>;
|
|
330
|
+
/**
|
|
331
|
+
* Declare the handler.
|
|
332
|
+
*
|
|
333
|
+
* One per queue: a queue is a work list with one consumer, which is what
|
|
334
|
+
* separates it from a topic. Work that several things must react to is a
|
|
335
|
+
* topic with several subscriptions.
|
|
336
|
+
*/
|
|
337
|
+
handler(fn: QueueHandler<T>): void;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Declare a queue.
|
|
341
|
+
*
|
|
342
|
+
* ```ts
|
|
343
|
+
* export const thumbnails = queue<{ key: string }>("thumbnails");
|
|
344
|
+
* thumbnails.handler(async ({ key }) => { … });
|
|
345
|
+
* await thumbnails.enqueue({ key }, { runAt: new Date(Date.now() + 60_000) });
|
|
346
|
+
* ```
|
|
347
|
+
*
|
|
348
|
+
* The difference from a topic is the number of consumers: a queue has one, a
|
|
349
|
+
* topic fans out to every subscription. Both ride on the durable job queue, so
|
|
350
|
+
* declaring either turns it on.
|
|
351
|
+
*/
|
|
352
|
+
export declare function queue<T = unknown>(key: string, options?: QueueOptions): QueueHandle<T>;
|
|
353
|
+
/**
|
|
354
|
+
* One declaration, as the data layer's definition.
|
|
355
|
+
*
|
|
356
|
+
* There is exactly one of these per kind, and everything that needs a
|
|
357
|
+
* definition goes through it — the frontend, the managed runtime's boot path,
|
|
358
|
+
* and an ejected project's own entrypoint. That is not tidiness: the mapping
|
|
359
|
+
* used to exist twice, once here and once in `@rebasepro/server`'s
|
|
360
|
+
* `graphToStorageSources`, and the two disagreed. The server's copy carried a
|
|
361
|
+
* bucket's `account`; this one dropped it, so a bucket declared with shared
|
|
362
|
+
* credentials resolved them on the managed runtime and resolved *nothing* in an
|
|
363
|
+
* ejected backend — the source was skipped and every upload to it answered 501.
|
|
364
|
+
*
|
|
365
|
+
* A field-by-field map is one line away from that failure at all times, so
|
|
366
|
+
* there is now one line to keep right instead of two to keep equal.
|
|
367
|
+
*/
|
|
368
|
+
export declare function resourceToDataSource(declaration: ResourceDeclaration): DataSourceDefinition;
|
|
369
|
+
/** One declaration, as the storage layer's definition. See {@link resourceToDataSource}. */
|
|
370
|
+
export declare function resourceToStorageSource(declaration: ResourceDeclaration): StorageSourceDefinition;
|
|
206
371
|
/**
|
|
207
|
-
* The declared databases,
|
|
372
|
+
* The declared databases, as definitions.
|
|
208
373
|
*
|
|
209
|
-
*
|
|
374
|
+
* Both the frontend and a project's own backend entrypoint read this. The
|
|
375
|
+
* frontend needs to know which sources exist and how they are reached — a
|
|
210
376
|
* `direct`-transport source is one the browser talks to itself — and it imports
|
|
211
377
|
* the same config package the backend does. Without these it would mean writing
|
|
212
378
|
* the list a second time, by hand, next to the declarations, which is precisely
|
|
@@ -223,16 +389,6 @@ export declare function topic<T = unknown>(key: string, options?: TopicOptions):
|
|
|
223
389
|
* would leave this empty — hence the side-effect import above rather than a
|
|
224
390
|
* bare re-export.
|
|
225
391
|
*/
|
|
226
|
-
export declare function declaredDataSources():
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
transport: ResourceTransport;
|
|
230
|
-
label?: string;
|
|
231
|
-
}[];
|
|
232
|
-
/** The declared buckets, in the shape `<Rebase storageSources>` takes. */
|
|
233
|
-
export declare function declaredStorageSources(): {
|
|
234
|
-
key: string;
|
|
235
|
-
engine: string;
|
|
236
|
-
transport: ResourceTransport;
|
|
237
|
-
label?: string;
|
|
238
|
-
}[];
|
|
392
|
+
export declare function declaredDataSources(): DataSourceDefinition[];
|
|
393
|
+
/** The declared buckets, as definitions. */
|
|
394
|
+
export declare function declaredStorageSources(): StorageSourceDefinition[];
|