@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,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The storage access-control contract.
|
|
3
|
-
*
|
|
4
|
-
* Lives here rather than in `@rebasepro/server` because a project declares its
|
|
5
|
-
* `storageAuthorize` hook from its **config package**, and a config package
|
|
6
|
-
* depends on `@rebasepro/types` alone. A type the contract requires but the
|
|
7
|
-
* contract's author cannot import is not much of a contract.
|
|
8
|
-
*
|
|
9
|
-
* `@rebasepro/server` re-exports all of this, so existing imports keep working.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export type StorageOperation = "read" | "write" | "delete" | "list";
|
|
13
|
-
|
|
14
|
-
/** The caller, as resolved by whichever auth middleware ran. */
|
|
15
|
-
export interface StorageAuthorizeUser {
|
|
16
|
-
uid: string;
|
|
17
|
-
email?: string;
|
|
18
|
-
roles?: string[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface StorageAuthorizeContext {
|
|
22
|
-
/** Object key, bucket prefix stripped and traversal already sanitized. */
|
|
23
|
-
key: string;
|
|
24
|
-
bucket: string;
|
|
25
|
-
operation: StorageOperation;
|
|
26
|
-
/** Null when the route allows unauthenticated access. */
|
|
27
|
-
user: StorageAuthorizeUser | null;
|
|
28
|
-
/** Named backend the request targeted, when one was given. */
|
|
29
|
-
storageId?: string;
|
|
30
|
-
/**
|
|
31
|
-
* Trusted, RLS-bypassing data access, so the hook can answer the question it
|
|
32
|
-
* actually has to answer: *who owns this object?*
|
|
33
|
-
*
|
|
34
|
-
* Without it the hook can only do prefix arithmetic on the key, which
|
|
35
|
-
* expresses no real multi-tenant rule — ownership lives in a row, not in a
|
|
36
|
-
* string. And it cannot simply import the server to get one: a project
|
|
37
|
-
* declares this hook from its **config** package, which depends on
|
|
38
|
-
* `@rebasepro/types` alone and cannot resolve `@rebasepro/server` at
|
|
39
|
-
* runtime. So the accessor is handed in.
|
|
40
|
-
*
|
|
41
|
-
* It bypasses row-level security on purpose. The hook IS the authorization
|
|
42
|
-
* decision; asking it to make that decision through a reader that has
|
|
43
|
-
* already been narrowed by the caller's own permissions is circular.
|
|
44
|
-
*/
|
|
45
|
-
data?: StorageAuthorizeData;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The slice of the data API a storage hook needs: read a collection, in the
|
|
50
|
-
* trusted server context.
|
|
51
|
-
*
|
|
52
|
-
* Deliberately read-only and deliberately tiny. A hook that can write is a hook
|
|
53
|
-
* that can be tricked into writing, and an authorization check has no business
|
|
54
|
-
* mutating anything.
|
|
55
|
-
*/
|
|
56
|
-
export interface StorageAuthorizeData {
|
|
57
|
-
collection(slug: string): {
|
|
58
|
-
find(query?: Record<string, unknown>): Promise<{ data: Record<string, unknown>[] }>;
|
|
59
|
-
findById(id: string): Promise<Record<string, unknown> | null>;
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Per-object access control for storage, the analogue of an RLS policy on a
|
|
65
|
-
* collection.
|
|
66
|
-
*
|
|
67
|
-
* Without it, storage routes authenticate but do not authorize: `requireAuth`
|
|
68
|
-
* and `publicRead` are global switches, so any signed-in user could read any
|
|
69
|
-
* key they could name. That is fine for a single-tenant app and useless for a
|
|
70
|
-
* multi-tenant one, where the only thing separating two tenants' files would be
|
|
71
|
-
* key unguessability — not an access-control model. Multi-tenant apps were
|
|
72
|
-
* left to route every byte through a custom function to get an ownership check
|
|
73
|
-
* in, and each of them had to invent it.
|
|
74
|
-
*
|
|
75
|
-
* Return false (or throw) to deny. Denials surface as 403.
|
|
76
|
-
*/
|
|
77
|
-
export type StorageAuthorize = (ctx: StorageAuthorizeContext) => boolean | Promise<boolean>;
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Describes a named storage backend — a place files live.
|
|
3
|
-
*
|
|
4
|
-
* Declared once and shared front + back: the frontend uses it to decide
|
|
5
|
-
* transport (HTTP proxy vs direct SDK), the backend uses the same `key`
|
|
6
|
-
* to resolve a StorageController, and collection properties reference
|
|
7
|
-
* a definition by its `key` via `StorageConfig.storageSource`.
|
|
8
|
-
*
|
|
9
|
-
* This mirrors the {@link DataSourceDefinition} pattern used for databases.
|
|
10
|
-
*
|
|
11
|
-
* @group Models
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The default storage source key, used when a property does not specify
|
|
16
|
-
* a `storageSource`. Shared by the frontend and backend registries so
|
|
17
|
-
* both agree on "the default storage backend".
|
|
18
|
-
* @group Models
|
|
19
|
-
*/
|
|
20
|
-
export const DEFAULT_STORAGE_SOURCE_KEY = "(default)";
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* How the *frontend* reaches a storage backend.
|
|
24
|
-
*
|
|
25
|
-
* - `"server"` — through the Rebase backend REST API (`/api/storage`).
|
|
26
|
-
* The backend holds the actual `StorageController` and routes by
|
|
27
|
-
* storage-source key. This is the default and covers Local, S3, GCS,
|
|
28
|
-
* and any other server-mediated engine.
|
|
29
|
-
* - `"direct"` — straight from the client to the external backend via
|
|
30
|
-
* its own SDK (e.g. Firebase Storage via `@firebase/storage`).
|
|
31
|
-
* The Rebase backend is **not** in the upload/download path.
|
|
32
|
-
*
|
|
33
|
-
* @group Models
|
|
34
|
-
*/
|
|
35
|
-
export type StorageSourceTransport = "server" | "direct";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Declarative definition of a storage source — a named place files live.
|
|
39
|
-
*
|
|
40
|
-
* Declared once and shared front and back: the frontend uses it to decide
|
|
41
|
-
* transport (client HTTP proxy vs direct provider SDK), the backend uses
|
|
42
|
-
* the same `key` to resolve a `StorageController`, and collection
|
|
43
|
-
* properties reference a definition by its `key` via
|
|
44
|
-
* `StorageConfig.storageSource`.
|
|
45
|
-
*
|
|
46
|
-
* @group Models
|
|
47
|
-
*/
|
|
48
|
-
export interface StorageSourceDefinition {
|
|
49
|
-
/**
|
|
50
|
-
* Unique identifier for this storage source. Collection properties
|
|
51
|
-
* point at it via `StorageConfig.storageSource`.
|
|
52
|
-
* Defaults to {@link DEFAULT_STORAGE_SOURCE_KEY}.
|
|
53
|
-
*/
|
|
54
|
-
key: string;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The engine backing this storage source (e.g. `"local"`, `"s3"`,
|
|
58
|
-
* `"gcs"`, `"firebase"`, `"azure"`, or a custom id).
|
|
59
|
-
*/
|
|
60
|
-
engine: string;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* The credential set this source signs with, when several sources share one.
|
|
64
|
-
*
|
|
65
|
-
* ## What it is for
|
|
66
|
-
*
|
|
67
|
-
* Every binding a bucket needs is read per key — `S3_BUCKET__MEDIA`,
|
|
68
|
-
* `S3_ACCESS_KEY_ID__MEDIA`, and so on. That is right for the bucket *name*,
|
|
69
|
-
* which is different for every source by definition, and wrong for the
|
|
70
|
-
* credentials, which usually are not: fifteen buckets on one MinIO install
|
|
71
|
-
* meant fifteen copies of the same endpoint, access key and secret — ninety
|
|
72
|
-
* variables where eighteen would do, and one key rotation became fifteen
|
|
73
|
-
* paired edits where a single missed one fails at upload time with an opaque
|
|
74
|
-
* signing error.
|
|
75
|
-
*
|
|
76
|
-
* Naming an account here lets the *account-scoped* bindings fall back to
|
|
77
|
-
* `<BASE>__<ACCOUNT>` when no per-key value is set. The bucket name never
|
|
78
|
-
* falls back: it is what distinguishes one source from another.
|
|
79
|
-
*
|
|
80
|
-
* ## Why it does not fall back to the bare variable
|
|
81
|
-
*
|
|
82
|
-
* A source with no `account` reads only its own suffixed names, exactly as
|
|
83
|
-
* before — so every project that predates this is wire-identical. The
|
|
84
|
-
* unsuffixed `S3_ACCESS_KEY_ID` belongs to the *default* source, and letting
|
|
85
|
-
* a named bucket inherit it would mean a typo'd key silently signs with
|
|
86
|
-
* another source's credentials. Two forms, both explicit, opt-in.
|
|
87
|
-
*/
|
|
88
|
-
account?: string;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* How the frontend reaches this storage. Defaults to `"server"`.
|
|
92
|
-
*
|
|
93
|
-
* When `"direct"`, the client uses a provider-specific SDK
|
|
94
|
-
* (e.g. `@firebase/storage`) and the backend does not proxy
|
|
95
|
-
* upload/download traffic for this source.
|
|
96
|
-
*/
|
|
97
|
-
transport: StorageSourceTransport;
|
|
98
|
-
|
|
99
|
-
/** Human-readable label for the UI (e.g. "Firebase Storage", "S3 Media"). */
|
|
100
|
-
label?: string;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* A resolved storage source: the single source of truth that the frontend
|
|
105
|
-
* router and backend registry both derive from.
|
|
106
|
-
*
|
|
107
|
-
* @group Models
|
|
108
|
-
*/
|
|
109
|
-
export interface ResolvedStorageSource {
|
|
110
|
-
/** Storage source key (routing key, shared front + back). */
|
|
111
|
-
key: string;
|
|
112
|
-
/** Engine backing the source. */
|
|
113
|
-
engine: string;
|
|
114
|
-
/** Frontend transport. */
|
|
115
|
-
transport: StorageSourceTransport;
|
|
116
|
-
/** Human-readable label. */
|
|
117
|
-
label?: string;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* The environment-variable suffix for a storage or data source key.
|
|
122
|
-
*
|
|
123
|
-
* `""` for the default source — so a single-bucket project keeps configuring
|
|
124
|
-
* plain `S3_BUCKET` — and `__<KEY>` for every named one, uppercased with
|
|
125
|
-
* non-alphanumerics collapsed to underscores: `media-cdn` → `S3_BUCKET__MEDIA_CDN`.
|
|
126
|
-
*
|
|
127
|
-
* The rule derives the variable name from the declared key rather than
|
|
128
|
-
* discovering keys by scanning the environment. Scanning would have to guess how
|
|
129
|
-
* `S3_BUCKET__MEDIA_CDN` splits into a key; deriving cannot be ambiguous, and a
|
|
130
|
-
* typo surfaces as a missing source at boot instead of a silently ignored
|
|
131
|
-
* variable.
|
|
132
|
-
*
|
|
133
|
-
* It lives in this package, with no dependencies, because four things must agree
|
|
134
|
-
* on it exactly: the CLI (validating a build), the runtime (reading its own
|
|
135
|
-
* environment), the control plane (writing a tenant's Secret), and the docs. A
|
|
136
|
-
* second implementation of a naming convention is a second chance to disagree.
|
|
137
|
-
*
|
|
138
|
-
* @group Models
|
|
139
|
-
*/
|
|
140
|
-
export function storageEnvSuffix(key: string, defaultKey: string = DEFAULT_STORAGE_SOURCE_KEY): string {
|
|
141
|
-
if (!key || key === defaultKey) return "";
|
|
142
|
-
const normalized = key
|
|
143
|
-
.replace(/[^A-Za-z0-9]+/g, "_")
|
|
144
|
-
.replace(/^_+|_+$/g, "")
|
|
145
|
-
.toUpperCase();
|
|
146
|
-
if (!normalized) {
|
|
147
|
-
throw new Error(
|
|
148
|
-
`Source key "${key}" cannot be turned into an environment variable name. ` +
|
|
149
|
-
"Use a key containing at least one letter or digit."
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
return `__${normalized}`;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Two distinct keys that collapse onto the same variable name, or `null`.
|
|
157
|
-
*
|
|
158
|
-
* `media-cdn` and `media_cdn` are different source keys but the same suffix, so
|
|
159
|
-
* without this one of them silently reads the other's configuration. Returns the
|
|
160
|
-
* offending pair rather than throwing, so each caller can raise it in its own
|
|
161
|
-
* idiom — a `BundleError` at boot, a build failure in the CLI, a rejected deploy
|
|
162
|
-
* in a control plane.
|
|
163
|
-
*
|
|
164
|
-
* @group Models
|
|
165
|
-
*/
|
|
166
|
-
export function findStorageSuffixCollision(
|
|
167
|
-
keys: string[],
|
|
168
|
-
defaultKey: string = DEFAULT_STORAGE_SOURCE_KEY
|
|
169
|
-
): { a: string; b: string; suffix: string } | null {
|
|
170
|
-
const seen = new Map<string, string>();
|
|
171
|
-
for (const key of keys) {
|
|
172
|
-
const suffix = storageEnvSuffix(key, defaultKey);
|
|
173
|
-
const existing = seen.get(suffix);
|
|
174
|
-
if (existing !== undefined && existing !== key) {
|
|
175
|
-
return { a: existing, b: key, suffix };
|
|
176
|
-
}
|
|
177
|
-
seen.set(suffix, key);
|
|
178
|
-
}
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/** The `storage` block of `rebase.json`, structurally. */
|
|
183
|
-
export type DeclaredStorageSources = Record<string, {
|
|
184
|
-
engine: string;
|
|
185
|
-
transport?: StorageSourceTransport;
|
|
186
|
-
label?: string;
|
|
187
|
-
}>;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Merge the two places a project may declare storage sources into one list.
|
|
191
|
-
*
|
|
192
|
-
* `rebase.json` is authoritative for every field it states. Config code may add
|
|
193
|
-
* sources it does not mention and fill in fields it left out, but may not
|
|
194
|
-
* contradict it: the manifest is what a host reads to decide which buckets need
|
|
195
|
-
* configuring, and a runtime that quietly disagreed with it would put the
|
|
196
|
-
* console back to describing a topology the tenant does not have — the exact
|
|
197
|
-
* failure this whole mechanism exists to end.
|
|
198
|
-
*
|
|
199
|
-
* Note what is *not* here: no default source is invented when both inputs are
|
|
200
|
-
* empty. That decision belongs to the resolver, which knows whether declaring
|
|
201
|
-
* nothing means "one plain bucket" (it does) or "no storage at all".
|
|
202
|
-
*
|
|
203
|
-
* @group Models
|
|
204
|
-
*/
|
|
205
|
-
export function normalizeStorageSources(
|
|
206
|
-
declared: DeclaredStorageSources | StorageSourceDefinition[] | undefined,
|
|
207
|
-
exported: StorageSourceDefinition[] | undefined
|
|
208
|
-
): StorageSourceDefinition[] {
|
|
209
|
-
const merged = new Map<string, StorageSourceDefinition>();
|
|
210
|
-
|
|
211
|
-
// Two shapes, one meaning. `rebase.json` states sources as a record keyed by
|
|
212
|
-
// source key, which is how JSON expresses a set of named things; the bundle
|
|
213
|
-
// manifest stores the already-resolved array. Accepting both is what lets the
|
|
214
|
-
// CLI and the runtime call this with what each of them happens to hold.
|
|
215
|
-
const declaredEntries: [string, { engine: string; transport?: StorageSourceTransport; label?: string }][] =
|
|
216
|
-
Array.isArray(declared)
|
|
217
|
-
? declared.filter(d => d?.key).map(d => [d.key, d])
|
|
218
|
-
: Object.entries(declared ?? {});
|
|
219
|
-
|
|
220
|
-
for (const [key, config] of declaredEntries) {
|
|
221
|
-
merged.set(key, {
|
|
222
|
-
key,
|
|
223
|
-
engine: config.engine,
|
|
224
|
-
transport: config.transport ?? "server",
|
|
225
|
-
...(config.label !== undefined ? { label: config.label } : {})
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
for (const definition of exported ?? []) {
|
|
230
|
-
if (!definition?.key) continue;
|
|
231
|
-
const existing = merged.get(definition.key);
|
|
232
|
-
if (!existing) {
|
|
233
|
-
merged.set(definition.key, {
|
|
234
|
-
key: definition.key,
|
|
235
|
-
engine: definition.engine,
|
|
236
|
-
transport: definition.transport ?? "server",
|
|
237
|
-
...(definition.label !== undefined ? { label: definition.label } : {})
|
|
238
|
-
});
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
// Fill gaps only. `rebase.json` stated these; code does not overrule it.
|
|
242
|
-
if (existing.label === undefined && definition.label !== undefined) {
|
|
243
|
-
existing.label = definition.label;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return Array.from(merged.values());
|
|
248
|
-
}
|
package/src/types/websockets.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
export interface WebSocketErrorPayload {
|
|
2
|
-
error?: string | { message: string; code?: string };
|
|
3
|
-
message?: string;
|
|
4
|
-
code?: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface WebSocketMessage {
|
|
8
|
-
type: string;
|
|
9
|
-
payload?: unknown;
|
|
10
|
-
subscriptionId?: string;
|
|
11
|
-
requestId?: string;
|
|
12
|
-
rows?: Record<string, unknown>[];
|
|
13
|
-
row?: Record<string, unknown> | null;
|
|
14
|
-
error?: string;
|
|
15
|
-
/**
|
|
16
|
-
* Channel name, on broadcast and presence frames.
|
|
17
|
-
*
|
|
18
|
-
* These are addressed by channel rather than by `requestId` or
|
|
19
|
-
* `subscriptionId`, so this is the only field that routes them.
|
|
20
|
-
*/
|
|
21
|
-
channel?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* The key columns a collection's rows are addressed by.
|
|
26
|
-
*
|
|
27
|
-
* A row is exactly its columns and carries no address, so a subscriber that has
|
|
28
|
-
* to recognise one — to patch it, or to keep its reference across a refetch —
|
|
29
|
-
* derives the address from these. The SDK is usable with no collections
|
|
30
|
-
* declared at all, so the server is the only side that knows them.
|
|
31
|
-
*
|
|
32
|
-
* Undefined when the server cannot resolve them: a table with no primary key
|
|
33
|
-
* and no `id` column has no address, and rows of it cannot be recognised by
|
|
34
|
-
* anyone.
|
|
35
|
-
*/
|
|
36
|
-
export type WirePrimaryKeys = { fieldName: string; type: "string" | "number"; isUUID?: boolean }[];
|
|
37
|
-
|
|
38
|
-
export interface CollectionUpdateMessage extends WebSocketMessage {
|
|
39
|
-
type: "collection_update";
|
|
40
|
-
subscriptionId: string;
|
|
41
|
-
rows: Record<string, unknown>[];
|
|
42
|
-
/**
|
|
43
|
-
* See {@link WirePrimaryKeys}. Sent with the rows themselves — and not only
|
|
44
|
-
* with a patch — because a CDC-originated change sends no patch at all: it
|
|
45
|
-
* invalidates and goes straight to a refetch, and the merge that preserves
|
|
46
|
-
* unchanged rows' references needs an address to match them by.
|
|
47
|
-
*/
|
|
48
|
-
pks?: WirePrimaryKeys;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface SingleUpdateMessage extends WebSocketMessage {
|
|
52
|
-
type: "single_update";
|
|
53
|
-
subscriptionId: string;
|
|
54
|
-
row: Record<string, unknown> | null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Lightweight patch message sent to collection subscribers when a single
|
|
59
|
-
* row is created, updated, or deleted. The client can merge this into
|
|
60
|
-
* its cached collection data for near-instant cross-tab updates without
|
|
61
|
-
* waiting for a full collection refetch.
|
|
62
|
-
*/
|
|
63
|
-
export interface CollectionPatchMessage extends WebSocketMessage {
|
|
64
|
-
type: "collection_patch";
|
|
65
|
-
subscriptionId: string;
|
|
66
|
-
/** The address of the row this patch refers to — derived, never read off it. */
|
|
67
|
-
id: string;
|
|
68
|
-
/** The updated row, or null if deleted */
|
|
69
|
-
row: Record<string, unknown> | null;
|
|
70
|
-
/** See {@link WirePrimaryKeys}: how the subscriber finds {@link id} in its cache. */
|
|
71
|
-
pks?: WirePrimaryKeys;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* One retained broadcast, as it travels on the wire.
|
|
76
|
-
*
|
|
77
|
-
* `seq` is per-channel, dense and monotonically increasing — it is the only
|
|
78
|
-
* thing a reconnecting client needs to say where it got to. See
|
|
79
|
-
* {@link ChannelHistoryMessage}.
|
|
80
|
-
*/
|
|
81
|
-
export interface ChannelHistoryEntry {
|
|
82
|
-
seq: number;
|
|
83
|
-
event: string;
|
|
84
|
-
payload: unknown;
|
|
85
|
-
/**
|
|
86
|
-
* The server-side client id of whoever sent it, for information only.
|
|
87
|
-
*
|
|
88
|
-
* Deliberately not used to filter a client's own messages out of a replay:
|
|
89
|
-
* a reconnect assigns a brand-new client id, so the very case replay exists
|
|
90
|
-
* for is the case where this would fail to match. Consumers that cannot
|
|
91
|
-
* tolerate re-applying their own operations must make them idempotent.
|
|
92
|
-
*/
|
|
93
|
-
senderId?: string;
|
|
94
|
-
/** When the server accepted it, ISO-8601. */
|
|
95
|
-
at: string;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Server → client: the retained messages a client missed.
|
|
100
|
-
*
|
|
101
|
-
* `retained: false` means the channel has no retention rule configured, so
|
|
102
|
-
* there is no history to replay and there never will be — an explicit answer
|
|
103
|
-
* rather than an empty one, so a client can tell "nothing missed" apart from
|
|
104
|
-
* "this channel does not keep history".
|
|
105
|
-
*/
|
|
106
|
-
export interface ChannelHistoryMessage extends WebSocketMessage {
|
|
107
|
-
type: "channel_history";
|
|
108
|
-
channel: string;
|
|
109
|
-
messages: ChannelHistoryEntry[];
|
|
110
|
-
retained: boolean;
|
|
111
|
-
/**
|
|
112
|
-
* The highest seq the server holds for this channel, whether or not it was
|
|
113
|
-
* returned. Lets a client that capped its request with `limit` see that it
|
|
114
|
-
* is still behind, and decide to resync wholesale instead of paging.
|
|
115
|
-
*/
|
|
116
|
-
latestSeq?: number;
|
|
117
|
-
}
|
package/src/users/index.ts
DELETED
package/src/users/user.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* The canonical representation of an authenticated user in the Rebase ecosystem.
|
|
4
|
-
*
|
|
5
|
-
* Used by {@link AuthController}, collections, callbacks, and both the
|
|
6
|
-
* `@rebasepro/client` and `@rebasepro/app` packages. It is the only user type
|
|
7
|
-
* those packages export — the `RebaseUser` / `UserInfo` aliases are gone.
|
|
8
|
-
*
|
|
9
|
-
* **Backend-managed fields** (`uid`, `email`, `roles`, `metadata`, `createdAt`)
|
|
10
|
-
* are populated by the server. **Client-visible fields** (`displayName`,
|
|
11
|
-
* `photoURL`, `providerId`, `isAnonymous`, `emailVerified`) may be set during
|
|
12
|
-
* authentication or profile updates.
|
|
13
|
-
*
|
|
14
|
-
* @see AdminUser — the admin-API DTO, which adds audit fields (`createdAt`,
|
|
15
|
-
* `updatedAt`) and required `roles`.
|
|
16
|
-
*
|
|
17
|
-
* @group Models
|
|
18
|
-
*/
|
|
19
|
-
export type User = {
|
|
20
|
-
/**
|
|
21
|
-
* The user's unique ID, scoped to the project.
|
|
22
|
-
*/
|
|
23
|
-
readonly uid: string;
|
|
24
|
-
/**
|
|
25
|
-
* The display name of the user.
|
|
26
|
-
*/
|
|
27
|
-
readonly displayName: string | null;
|
|
28
|
-
/**
|
|
29
|
-
* The email of the user.
|
|
30
|
-
*/
|
|
31
|
-
readonly email: string | null;
|
|
32
|
-
/**
|
|
33
|
-
* The profile photo URL of the user.
|
|
34
|
-
*/
|
|
35
|
-
readonly photoURL: string | null;
|
|
36
|
-
/**
|
|
37
|
-
* The provider used to authenticate the user (e.g. `"password"`,
|
|
38
|
-
* `"google"`, `"github"`).
|
|
39
|
-
*/
|
|
40
|
-
readonly providerId: string;
|
|
41
|
-
/**
|
|
42
|
-
* Whether the user is anonymous (created via anonymous sign-in).
|
|
43
|
-
*/
|
|
44
|
-
readonly isAnonymous: boolean;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Whether the user's email address has been verified.
|
|
48
|
-
*/
|
|
49
|
-
readonly emailVerified?: boolean;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Role IDs assigned to this user (e.g. `["admin", "editor"]`).
|
|
53
|
-
*/
|
|
54
|
-
roles?: string[];
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The date and time when the user was created.
|
|
58
|
-
*/
|
|
59
|
-
createdAt?: Date | string | null;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Additional metadata/custom claims associated with the user.
|
|
63
|
-
* Accessible by the frontend, but only writable by the backend.
|
|
64
|
-
*/
|
|
65
|
-
readonly metadata?: Record<string, any>;
|
|
66
|
-
|
|
67
|
-
getIdToken?: (forceRefresh?: boolean) => Promise<string>;
|
|
68
|
-
|
|
69
|
-
};
|