@rebasepro/types 0.24.0 → 0.24.1-canary.gcb918fc
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 +8 -4
- package/dist/controllers/client.d.ts +68 -10
- package/dist/controllers/data.d.ts +412 -76
- package/dist/controllers/data_driver.d.ts +85 -1
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/storage-references.d.ts +114 -0
- package/dist/controllers/storage.d.ts +20 -79
- package/dist/index.es.js +140 -12
- package/dist/index.es.js.map +1 -1
- package/dist/types/auth_adapter.d.ts +32 -1
- package/dist/types/backend.d.ts +168 -4
- package/dist/types/backup.d.ts +19 -0
- package/dist/types/cron.d.ts +22 -7
- package/dist/types/database_adapter.d.ts +32 -6
- package/dist/types/entities.d.ts +11 -0
- package/dist/types/history.d.ts +15 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/project_manifest.d.ts +8 -0
- package/dist/types/properties.d.ts +28 -2
- package/dist/types/register.d.ts +43 -0
- package/dist/types/relations.d.ts +37 -1
- package/dist/types/resource_kinds.d.ts +7 -1
- package/dist/types/storage_authorize.d.ts +5 -0
- package/dist/types/websockets.d.ts +32 -1
- package/package.json +1 -1
|
@@ -21,10 +21,25 @@ export interface FetchOneProps<M extends Record<string, unknown> = Record<string
|
|
|
21
21
|
*/
|
|
22
22
|
withDeleted?: boolean | "only";
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* What a row listener subscribes to: the row, and the relations each frame
|
|
26
|
+
* loads into it.
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export type ListenOneTarget<M extends Record<string, unknown> = Record<string, unknown>> = FetchOneProps<M> & {
|
|
31
|
+
/**
|
|
32
|
+
* Relations to load into every frame, as {@link FetchCollectionProps.include}
|
|
33
|
+
* loads them into each row of a list. Without it a to-many relation
|
|
34
|
+
* is absent from each frame, and the admin's record form, opened by
|
|
35
|
+
* URL, showed it empty — so a save from it unlinked every related row.
|
|
36
|
+
*/
|
|
37
|
+
include?: IncludeSpec;
|
|
38
|
+
};
|
|
24
39
|
/**
|
|
25
40
|
* @internal
|
|
26
41
|
*/
|
|
27
|
-
export type ListenOneProps<M extends Record<string, unknown> = Record<string, unknown>> =
|
|
42
|
+
export type ListenOneProps<M extends Record<string, unknown> = Record<string, unknown>> = ListenOneTarget<M> & {
|
|
28
43
|
onUpdate: (row: Record<string, unknown> | null) => void;
|
|
29
44
|
onError?: (error: Error) => void;
|
|
30
45
|
};
|
|
@@ -172,6 +187,13 @@ export type ListenCollectionProps<M extends Record<string, unknown> = Record<str
|
|
|
172
187
|
* the two spellings then disagreed about what a page was.
|
|
173
188
|
*/
|
|
174
189
|
page?: number;
|
|
190
|
+
/**
|
|
191
|
+
* Subscribe to the count alone: the server reads no rows, and each
|
|
192
|
+
* frame carries `rows: []` and `meta.total`. A server that predates it
|
|
193
|
+
* ignores the key and answers with the rows asked for (so ask for
|
|
194
|
+
* `limit: 1`) and the same `meta`. See `listenCount`.
|
|
195
|
+
*/
|
|
196
|
+
countOnly?: boolean;
|
|
175
197
|
onUpdate: (rows: Record<string, unknown>[], meta?: CollectionUpdateMeta) => void;
|
|
176
198
|
onError?: (error: Error) => void;
|
|
177
199
|
};
|
|
@@ -211,6 +233,39 @@ export interface SaveProps<M extends Record<string, unknown> = Record<string, un
|
|
|
211
233
|
* targets rather than a 500 naming a constraint the caller never wrote.
|
|
212
234
|
*/
|
|
213
235
|
onConflict?: readonly string[];
|
|
236
|
+
/**
|
|
237
|
+
* A check on the stored row an update addresses, run by the driver inside
|
|
238
|
+
* the write's own transaction, before any hook runs and before anything is
|
|
239
|
+
* written. See {@link RowPrecondition}. Honoured only by a driver that
|
|
240
|
+
* declares {@link DataDriver.checksRowPreconditions}; ignored on a create.
|
|
241
|
+
*/
|
|
242
|
+
precondition?: RowPrecondition;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* A check a caller makes on the row a write addresses, inside that write.
|
|
246
|
+
*
|
|
247
|
+
* The REST routes used to read the row in a transaction of their own before
|
|
248
|
+
* writing it, to answer a missing row with their 404 and to compare
|
|
249
|
+
* `If-Match`. Two transactions: the read loaded every declared relation of the
|
|
250
|
+
* row, and two writes carrying the same tag could both pass the comparison,
|
|
251
|
+
* because neither saw the other's write before making its own.
|
|
252
|
+
*
|
|
253
|
+
* @internal
|
|
254
|
+
*/
|
|
255
|
+
export interface RowPrecondition {
|
|
256
|
+
/**
|
|
257
|
+
* Lock the row before it is read, so no other write to it can land between
|
|
258
|
+
* this check and this write. A conditional write (`If-Match`) sets it; a
|
|
259
|
+
* plain existence check does not need it and does not pay for it.
|
|
260
|
+
*/
|
|
261
|
+
lock?: boolean;
|
|
262
|
+
/**
|
|
263
|
+
* Judge the row as this caller reads it at the address written (their
|
|
264
|
+
* policies, their `beforeQuery`, the trash hidden unless the write is a
|
|
265
|
+
* restore or a purge) — `undefined` when there is none. Throw to refuse the
|
|
266
|
+
* write; nothing has been written when this runs.
|
|
267
|
+
*/
|
|
268
|
+
check(stored: Record<string, unknown> | undefined): void | Promise<void>;
|
|
214
269
|
}
|
|
215
270
|
/**
|
|
216
271
|
* @internal
|
|
@@ -277,6 +332,12 @@ export interface DeleteProps<M extends Record<string, unknown> = Record<string,
|
|
|
277
332
|
* already this one.
|
|
278
333
|
*/
|
|
279
334
|
hard?: boolean;
|
|
335
|
+
/**
|
|
336
|
+
* A check on the stored row, inside the delete's own transaction, before
|
|
337
|
+
* any hook runs. See {@link RowPrecondition}. Honoured only by a driver
|
|
338
|
+
* that declares {@link DataDriver.checksRowPreconditions}.
|
|
339
|
+
*/
|
|
340
|
+
precondition?: RowPrecondition;
|
|
280
341
|
}
|
|
281
342
|
/**
|
|
282
343
|
* @internal
|
|
@@ -517,6 +578,21 @@ export interface DataDriver {
|
|
|
517
578
|
* Count the number of entities in a collection
|
|
518
579
|
*/
|
|
519
580
|
count?<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;
|
|
581
|
+
/**
|
|
582
|
+
* Run several reads as one: `work` is handed a driver whose reads all go
|
|
583
|
+
* through a single read-only transaction that reads one snapshot, under
|
|
584
|
+
* this driver's identity and row-level security, and its result is
|
|
585
|
+
* returned.
|
|
586
|
+
*
|
|
587
|
+
* A list page is a read and a count, and each was a transaction of its
|
|
588
|
+
* own — the second checkout, `BEGIN`, identity setup and `COMMIT` cost as
|
|
589
|
+
* many round trips as the count itself. On one snapshot the two also
|
|
590
|
+
* agree: `meta.total` describes the rows the page was taken from, and an
|
|
591
|
+
* `ETag` the row the body was rendered from.
|
|
592
|
+
*
|
|
593
|
+
* Optional: a driver without it is called directly, read by read.
|
|
594
|
+
*/
|
|
595
|
+
readTogether?<T>(work: (driver: DataDriver) => Promise<T>): Promise<T>;
|
|
520
596
|
/**
|
|
521
597
|
* Check if the given filter combination is valid
|
|
522
598
|
* @param props
|
|
@@ -548,6 +624,14 @@ export interface DataDriver {
|
|
|
548
624
|
* `fetchCollection` pipeline, enabling include-aware eager-loading.
|
|
549
625
|
*/
|
|
550
626
|
restFetchService?: RestFetchService;
|
|
627
|
+
/**
|
|
628
|
+
* This driver reads the row an update or a delete addresses inside that
|
|
629
|
+
* write's own transaction, and runs {@link SaveProps.precondition} /
|
|
630
|
+
* {@link DeleteProps.precondition} on it there. A caller may then leave its
|
|
631
|
+
* own read of the row out. A driver without it ignores the precondition,
|
|
632
|
+
* so a caller must read the row itself.
|
|
633
|
+
*/
|
|
634
|
+
readonly checksRowPreconditions?: boolean;
|
|
551
635
|
/**
|
|
552
636
|
* Return the admin capabilities of this driver.
|
|
553
637
|
* @see SQLAdmin
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { StorageSource } from "./storage.js";
|
|
2
|
+
/**
|
|
3
|
+
* The scheme of a **storage reference**: a stored object named inside text.
|
|
4
|
+
*
|
|
5
|
+
* Text that embeds a file — a markdown body above all — cannot hold a private
|
|
6
|
+
* object's URL: that URL carries a download token which expires in minutes,
|
|
7
|
+
* after which every reader of the text gets a 401 for an image that is still in
|
|
8
|
+
* the bucket. It holds a reference instead,
|
|
9
|
+
* `rebase-storage:posts/cover.png` (`?storageId=media` for a named source),
|
|
10
|
+
* and whoever renders the text exchanges each reference for a fresh URL with
|
|
11
|
+
* {@link resolveStorageReferences} — `resolveStorageReferences(text, client)`
|
|
12
|
+
* from `@rebasepro/client` on a site.
|
|
13
|
+
*
|
|
14
|
+
* @group Models
|
|
15
|
+
*/
|
|
16
|
+
export declare const STORAGE_REFERENCE_SCHEME = "rebase-storage:";
|
|
17
|
+
/**
|
|
18
|
+
* The object a storage reference names.
|
|
19
|
+
*
|
|
20
|
+
* @group Models
|
|
21
|
+
*/
|
|
22
|
+
export interface StorageReferenceTarget {
|
|
23
|
+
/** The object's key in its storage source. */
|
|
24
|
+
key: string;
|
|
25
|
+
/** The named storage source holding it. Absent for the default source. */
|
|
26
|
+
storageId?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The reference for an object — what text stores in place of its URL.
|
|
30
|
+
*
|
|
31
|
+
* Every part is percent-encoded, so the reference contains no space,
|
|
32
|
+
* parenthesis or quote and survives as one markdown link destination whatever
|
|
33
|
+
* the file was called.
|
|
34
|
+
*
|
|
35
|
+
* @group Models
|
|
36
|
+
*/
|
|
37
|
+
export declare function storageReference(key: string, storageId?: string | null): string;
|
|
38
|
+
/**
|
|
39
|
+
* Whether a string — an image's `src`, a link's `href` — is a storage reference.
|
|
40
|
+
*
|
|
41
|
+
* @group Models
|
|
42
|
+
*/
|
|
43
|
+
export declare function isStorageReference(value: string | null | undefined): value is string;
|
|
44
|
+
/**
|
|
45
|
+
* The object a storage reference names, or `null` for anything else — a URL, a
|
|
46
|
+
* bare key, or a reference whose key would climb out of its prefix.
|
|
47
|
+
*
|
|
48
|
+
* @group Models
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseStorageReference(value: string | null | undefined): StorageReferenceTarget | null;
|
|
51
|
+
/**
|
|
52
|
+
* The object a private file's download URL was minted for, or `null` for any
|
|
53
|
+
* other URL.
|
|
54
|
+
*
|
|
55
|
+
* Text written before storage references stored such URLs —
|
|
56
|
+
* `…/storage/file/posts/cover.png?token=…` — and their tokens expired minutes
|
|
57
|
+
* later. The token still names the object it was minted for, so the URL can be
|
|
58
|
+
* traded for a fresh one, or for a reference. Read without verifying the
|
|
59
|
+
* token: it grants nothing here, it only says which object is meant, and the
|
|
60
|
+
* key in the URL must agree with it. Host-agnostic, since a URL written
|
|
61
|
+
* through one origin may be read through another.
|
|
62
|
+
*
|
|
63
|
+
* @group Models
|
|
64
|
+
*/
|
|
65
|
+
export declare function storageTargetOfDownloadUrl(url: string): StorageReferenceTarget | null;
|
|
66
|
+
/**
|
|
67
|
+
* Every object `text` names: its storage references, and the private files'
|
|
68
|
+
* download URLs saved in it before references existed. An object named more
|
|
69
|
+
* than once may be listed more than once.
|
|
70
|
+
*
|
|
71
|
+
* @group Models
|
|
72
|
+
*/
|
|
73
|
+
export declare function storageTargetsInText(text: string): StorageReferenceTarget[];
|
|
74
|
+
/**
|
|
75
|
+
* `text` with every private file's download URL replaced by the storage
|
|
76
|
+
* reference for its object — for rewriting text saved before references, so
|
|
77
|
+
* it stores what new text stores. Any other URL is left as it is.
|
|
78
|
+
*
|
|
79
|
+
* @group Models
|
|
80
|
+
*/
|
|
81
|
+
export declare function storageReferencesForDownloadUrls(text: string): string;
|
|
82
|
+
/**
|
|
83
|
+
* Where {@link resolveStorageReferences} gets URLs from: a function that
|
|
84
|
+
* answers one, or anything shaped like a Rebase client — its `storage` for the
|
|
85
|
+
* default source and `createStorageSource(id)` for a named one.
|
|
86
|
+
*
|
|
87
|
+
* @group Models
|
|
88
|
+
*/
|
|
89
|
+
export type StorageReferenceResolver = ((target: StorageReferenceTarget) => Promise<string | null | undefined>) | {
|
|
90
|
+
storage?: StorageSource;
|
|
91
|
+
createStorageSource?(storageId: string): StorageSource;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Exchange every storage reference in `text` for a URL, at the moment the text
|
|
95
|
+
* is rendered.
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* const html = markdown.render(await resolveStorageReferences(post.body, client));
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* Each distinct object is asked for once — `getSignedUrl(key)` on its source —
|
|
102
|
+
* so a private object gets a freshly minted download URL every time the text is
|
|
103
|
+
* rendered. A reference that cannot be resolved (no such object, an unknown
|
|
104
|
+
* source) is left as it was, so a missing object reads as a missing image
|
|
105
|
+
* rather than as a failed render.
|
|
106
|
+
*
|
|
107
|
+
* A private file's download URL saved in the text before references existed
|
|
108
|
+
* is renewed the same way: its expired token still names the object (see
|
|
109
|
+
* {@link storageTargetOfDownloadUrl}). One that cannot be resolved is left as
|
|
110
|
+
* it was.
|
|
111
|
+
*
|
|
112
|
+
* @group Models
|
|
113
|
+
*/
|
|
114
|
+
export declare function resolveStorageReferences(text: string, from: StorageReferenceResolver): Promise<string>;
|
|
@@ -54,89 +54,12 @@ export declare function isPublicStoragePath(path: string | null | undefined): bo
|
|
|
54
54
|
* so the key `default/photo.png` sent as it is names the root `photo.png`:
|
|
55
55
|
* {@link defaultBucketPath} is the spelling that names the key itself.
|
|
56
56
|
*
|
|
57
|
-
* Shared by every storage source that talks to those routes
|
|
58
|
-
*
|
|
57
|
+
* Shared by every storage source that talks to those routes, so they address
|
|
58
|
+
* an object alike.
|
|
59
59
|
*
|
|
60
60
|
* @group Models
|
|
61
61
|
*/
|
|
62
62
|
export declare function storageObjectPath(keyOrUrl: string, bucket?: string): string;
|
|
63
|
-
/**
|
|
64
|
-
* The scheme of a **storage reference**: a stored object named inside text.
|
|
65
|
-
*
|
|
66
|
-
* Text that embeds a file — a markdown body above all — cannot hold a private
|
|
67
|
-
* object's URL: that URL carries a download token which expires in minutes,
|
|
68
|
-
* after which every reader of the text gets a 401 for an image that is still in
|
|
69
|
-
* the bucket. It holds a reference instead,
|
|
70
|
-
* `rebase-storage:posts/cover.png` (`?storageId=media` for a named source),
|
|
71
|
-
* and whoever renders the text exchanges each reference for a fresh URL with
|
|
72
|
-
* {@link resolveStorageReferences} — `resolveStorageReferences(text, client)`
|
|
73
|
-
* from `@rebasepro/client` on a site.
|
|
74
|
-
*
|
|
75
|
-
* @group Models
|
|
76
|
-
*/
|
|
77
|
-
export declare const STORAGE_REFERENCE_SCHEME = "rebase-storage:";
|
|
78
|
-
/**
|
|
79
|
-
* The object a storage reference names.
|
|
80
|
-
*
|
|
81
|
-
* @group Models
|
|
82
|
-
*/
|
|
83
|
-
export interface StorageReferenceTarget {
|
|
84
|
-
/** The object's key in its storage source. */
|
|
85
|
-
key: string;
|
|
86
|
-
/** The named storage source holding it. Absent for the default source. */
|
|
87
|
-
storageId?: string;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* The reference for an object — what text stores in place of its URL.
|
|
91
|
-
*
|
|
92
|
-
* Every part is percent-encoded, so the reference contains no space,
|
|
93
|
-
* parenthesis or quote and survives as one markdown link destination whatever
|
|
94
|
-
* the file was called.
|
|
95
|
-
*
|
|
96
|
-
* @group Models
|
|
97
|
-
*/
|
|
98
|
-
export declare function storageReference(key: string, storageId?: string | null): string;
|
|
99
|
-
/**
|
|
100
|
-
* Whether a string — an image's `src`, a link's `href` — is a storage reference.
|
|
101
|
-
*
|
|
102
|
-
* @group Models
|
|
103
|
-
*/
|
|
104
|
-
export declare function isStorageReference(value: string | null | undefined): value is string;
|
|
105
|
-
/**
|
|
106
|
-
* The object a storage reference names, or `null` for anything else — a URL, a
|
|
107
|
-
* bare key, or a reference whose key would climb out of its prefix.
|
|
108
|
-
*
|
|
109
|
-
* @group Models
|
|
110
|
-
*/
|
|
111
|
-
export declare function parseStorageReference(value: string | null | undefined): StorageReferenceTarget | null;
|
|
112
|
-
/**
|
|
113
|
-
* Where {@link resolveStorageReferences} gets URLs from: a function that
|
|
114
|
-
* answers one, or anything shaped like a Rebase client — its `storage` for the
|
|
115
|
-
* default source and `createStorageSource(id)` for a named one.
|
|
116
|
-
*
|
|
117
|
-
* @group Models
|
|
118
|
-
*/
|
|
119
|
-
export type StorageReferenceResolver = ((target: StorageReferenceTarget) => Promise<string | null | undefined>) | {
|
|
120
|
-
storage?: StorageSource;
|
|
121
|
-
createStorageSource?(storageId: string): StorageSource;
|
|
122
|
-
};
|
|
123
|
-
/**
|
|
124
|
-
* Exchange every storage reference in `text` for a URL, at the moment the text
|
|
125
|
-
* is rendered.
|
|
126
|
-
*
|
|
127
|
-
* ```ts
|
|
128
|
-
* const html = markdown.render(await resolveStorageReferences(post.body, client));
|
|
129
|
-
* ```
|
|
130
|
-
*
|
|
131
|
-
* Each distinct object is asked for once — `getSignedUrl(key)` on its source —
|
|
132
|
-
* so a private object gets a freshly minted download URL every time the text is
|
|
133
|
-
* rendered. A reference that cannot be resolved (no such object, an unknown
|
|
134
|
-
* source) is left as it was, so a missing object reads as a missing image
|
|
135
|
-
* rather than as a failed render.
|
|
136
|
-
*
|
|
137
|
-
* @group Models
|
|
138
|
-
*/
|
|
139
|
-
export declare function resolveStorageReferences(text: string, from: StorageReferenceResolver): Promise<string>;
|
|
140
63
|
/**
|
|
141
64
|
* @group Models
|
|
142
65
|
*/
|
|
@@ -356,4 +279,22 @@ export declare interface StorageReference {
|
|
|
356
279
|
* this reference is the root.
|
|
357
280
|
*/
|
|
358
281
|
parent: StorageReference | null;
|
|
282
|
+
/**
|
|
283
|
+
* The object's size in bytes, as the listing read it. Set on the objects
|
|
284
|
+
* of a listing from the built-in local, S3 and GCS sources; absent on
|
|
285
|
+
* folders and from a source that cannot list it without a request per
|
|
286
|
+
* object. Since 0.24.
|
|
287
|
+
*/
|
|
288
|
+
size?: number;
|
|
289
|
+
/**
|
|
290
|
+
* When the object was last written, as an ISO 8601 timestamp — set where
|
|
291
|
+
* {@link size} is.
|
|
292
|
+
*/
|
|
293
|
+
updated?: string;
|
|
294
|
+
/**
|
|
295
|
+
* The object's stored content type, as the listing read it: set by local
|
|
296
|
+
* storage and GCS. An S3 listing does not carry it, so on S3 it is absent
|
|
297
|
+
* and `getSignedUrl()` (or the metadata route) still says.
|
|
298
|
+
*/
|
|
299
|
+
contentType?: string;
|
|
359
300
|
}
|
package/dist/index.es.js
CHANGED
|
@@ -855,6 +855,23 @@ var RELEVANCE_SORT_FIELD = "_score";
|
|
|
855
855
|
* @group Models
|
|
856
856
|
*/
|
|
857
857
|
var JUNCTION_PIVOT_KEY = "_pivot";
|
|
858
|
+
/**
|
|
859
|
+
* The key a row carries the totals of its counted relations under.
|
|
860
|
+
*
|
|
861
|
+
* An include that asks for a count — `include: { tags: { limit: 4, count: true } }`
|
|
862
|
+
* — serves, beside the (capped) `tags`, how many related rows there are in all:
|
|
863
|
+
* `{ id: 1, tags: [ …4 rows ], _count: { tags: 37 } }`. One object per row,
|
|
864
|
+
* keyed by relation name, so counting a second relation adds a key rather than
|
|
865
|
+
* a second top-level name.
|
|
866
|
+
*
|
|
867
|
+
* Leading underscore, like {@link JUNCTION_PIVOT_KEY} and `_matches`: it
|
|
868
|
+
* describes the read, not the record, and no column or form writes it. A
|
|
869
|
+
* collection with a property of this name cannot ask for a count — the read
|
|
870
|
+
* answers 400 rather than writing over the column.
|
|
871
|
+
*
|
|
872
|
+
* @group Models
|
|
873
|
+
*/
|
|
874
|
+
var INCLUDE_COUNT_KEY = "_count";
|
|
858
875
|
/** @group Models */
|
|
859
876
|
function hasForeignKeyOnTarget(relation) {
|
|
860
877
|
return relation.kind === "hasOne" || relation.kind === "hasMany";
|
|
@@ -1865,6 +1882,7 @@ registerResourceKind({
|
|
|
1865
1882
|
amendResourceKind("database", { envBases: [
|
|
1866
1883
|
"DATABASE_URL",
|
|
1867
1884
|
"DATABASE_READ_URL",
|
|
1885
|
+
"DATABASE_DIRECT_URL",
|
|
1868
1886
|
"ADMIN_CONNECTION_STRING",
|
|
1869
1887
|
"REBASE_DRIVER",
|
|
1870
1888
|
"DB_POOL_MAX",
|
|
@@ -3221,10 +3239,13 @@ var BATCH_REF_KEY = "$ref";
|
|
|
3221
3239
|
* one, which is the case worth catching.
|
|
3222
3240
|
*
|
|
3223
3241
|
* Any `$`-prefixed key counts, because `{ $increment: 1 }` written to a number
|
|
3224
|
-
* column as a JSON document is the failure this exists to prevent.
|
|
3225
|
-
*
|
|
3226
|
-
* `map`
|
|
3227
|
-
*
|
|
3242
|
+
* column as a JSON document is the failure this exists to prevent.
|
|
3243
|
+
*
|
|
3244
|
+
* Except on a `map` (pass `propertyType`): a map's value is a JSON document,
|
|
3245
|
+
* and one may legitimately carry `$` keys — a JSON Schema's `$schema`, a
|
|
3246
|
+
* MongoDB-style export. There, only a single-key object whose key is one of
|
|
3247
|
+
* {@link FIELD_OPERATORS} is an operation, and anything else is data. A caller
|
|
3248
|
+
* that does not know the property type gets the strict reading.
|
|
3228
3249
|
*
|
|
3229
3250
|
* The one exception is `{ $ref: … }`, the batch's backward reference. It stands
|
|
3230
3251
|
* where a *value* goes and is resolved to one before the row is written, so it
|
|
@@ -3233,15 +3254,16 @@ var BATCH_REF_KEY = "$ref";
|
|
|
3233
3254
|
*
|
|
3234
3255
|
* @group Data
|
|
3235
3256
|
*/
|
|
3236
|
-
function isFieldOperation(value) {
|
|
3257
|
+
function isFieldOperation(value, propertyType) {
|
|
3237
3258
|
if (typeof value !== "object" || value === null || Array.isArray(value) || value instanceof Date) return false;
|
|
3238
3259
|
const keys = Object.keys(value);
|
|
3239
3260
|
if (keys.length === 1 && keys[0] === "$ref") return false;
|
|
3261
|
+
if (propertyType === "map") return keys.length === 1 && FIELD_OPERATORS.includes(keys[0]);
|
|
3240
3262
|
return keys.some((key) => key.startsWith("$"));
|
|
3241
3263
|
}
|
|
3242
3264
|
/** True when any value in a write payload is (or is attempting to be) one. @group Data */
|
|
3243
3265
|
function hasFieldOperation(values) {
|
|
3244
|
-
return !!values && Object.values(values).some(isFieldOperation);
|
|
3266
|
+
return !!values && Object.values(values).some((value) => isFieldOperation(value));
|
|
3245
3267
|
}
|
|
3246
3268
|
//#endregion
|
|
3247
3269
|
//#region src/controllers/data_driver.ts
|
|
@@ -3366,8 +3388,8 @@ function isPublicStoragePath(path) {
|
|
|
3366
3388
|
* so the key `default/photo.png` sent as it is names the root `photo.png`:
|
|
3367
3389
|
* {@link defaultBucketPath} is the spelling that names the key itself.
|
|
3368
3390
|
*
|
|
3369
|
-
* Shared by every storage source that talks to those routes
|
|
3370
|
-
*
|
|
3391
|
+
* Shared by every storage source that talks to those routes, so they address
|
|
3392
|
+
* an object alike.
|
|
3371
3393
|
*
|
|
3372
3394
|
* @group Models
|
|
3373
3395
|
*/
|
|
@@ -3399,6 +3421,8 @@ function defaultBucketPath(key) {
|
|
|
3399
3421
|
const segments = key.split("/");
|
|
3400
3422
|
return segments.length > 1 && segments[0].toLowerCase() === "default" ? `default/${key}` : key;
|
|
3401
3423
|
}
|
|
3424
|
+
//#endregion
|
|
3425
|
+
//#region src/controllers/storage-references.ts
|
|
3402
3426
|
/**
|
|
3403
3427
|
* The scheme of a **storage reference**: a stored object named inside text.
|
|
3404
3428
|
*
|
|
@@ -3474,6 +3498,99 @@ function parseStorageReference(value) {
|
|
|
3474
3498
|
storageId
|
|
3475
3499
|
} : { key };
|
|
3476
3500
|
}
|
|
3501
|
+
/** The JSON in a JWT's payload segment, or `undefined` for anything else. */
|
|
3502
|
+
function jwtPayload(token) {
|
|
3503
|
+
const segments = token.split(".");
|
|
3504
|
+
if (segments.length !== 3) return void 0;
|
|
3505
|
+
try {
|
|
3506
|
+
const base64 = segments[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
3507
|
+
const binary = atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="));
|
|
3508
|
+
const json = new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)));
|
|
3509
|
+
const payload = JSON.parse(json);
|
|
3510
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : void 0;
|
|
3511
|
+
} catch {
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
/**
|
|
3516
|
+
* The object a private file's download URL was minted for, or `null` for any
|
|
3517
|
+
* other URL.
|
|
3518
|
+
*
|
|
3519
|
+
* Text written before storage references stored such URLs —
|
|
3520
|
+
* `…/storage/file/posts/cover.png?token=…` — and their tokens expired minutes
|
|
3521
|
+
* later. The token still names the object it was minted for, so the URL can be
|
|
3522
|
+
* traded for a fresh one, or for a reference. Read without verifying the
|
|
3523
|
+
* token: it grants nothing here, it only says which object is meant, and the
|
|
3524
|
+
* key in the URL must agree with it. Host-agnostic, since a URL written
|
|
3525
|
+
* through one origin may be read through another.
|
|
3526
|
+
*
|
|
3527
|
+
* @group Models
|
|
3528
|
+
*/
|
|
3529
|
+
function storageTargetOfDownloadUrl(url) {
|
|
3530
|
+
let parsed;
|
|
3531
|
+
try {
|
|
3532
|
+
parsed = new URL(url, "http://relative.invalid");
|
|
3533
|
+
} catch {
|
|
3534
|
+
return null;
|
|
3535
|
+
}
|
|
3536
|
+
const at = parsed.pathname.indexOf("/storage/file/");
|
|
3537
|
+
const token = parsed.searchParams.get("token");
|
|
3538
|
+
if (at === -1 || !token) return null;
|
|
3539
|
+
let key;
|
|
3540
|
+
try {
|
|
3541
|
+
key = parsed.pathname.slice(at + 14).split("/").map(decodeURIComponent).join("/");
|
|
3542
|
+
} catch {
|
|
3543
|
+
return null;
|
|
3544
|
+
}
|
|
3545
|
+
if (!key || key.split("/").some((segment) => segment === "..")) return null;
|
|
3546
|
+
const payload = jwtPayload(token);
|
|
3547
|
+
if (payload?.purpose !== "file-read" || typeof payload.path !== "string") return null;
|
|
3548
|
+
const slash = payload.path.indexOf("/");
|
|
3549
|
+
if (payload.path !== key && payload.path.slice(slash + 1) !== key) return null;
|
|
3550
|
+
const named = parsed.searchParams.get("storageId") ?? (typeof payload.storageId === "string" ? payload.storageId : void 0);
|
|
3551
|
+
return named && named !== "(default)" ? {
|
|
3552
|
+
key,
|
|
3553
|
+
storageId: named
|
|
3554
|
+
} : { key };
|
|
3555
|
+
}
|
|
3556
|
+
/**
|
|
3557
|
+
* A private file's download URL as it may appear in text. Parentheses are
|
|
3558
|
+
* allowed in the path, where an unencoded file name puts them; the query, a
|
|
3559
|
+
* token, has none, so the match ends where a markdown destination does.
|
|
3560
|
+
*/
|
|
3561
|
+
var DOWNLOAD_URL_PATTERN = /(?:https?:\/\/[^\s()<>"'\]]+)?\/storage\/file\/[^\s<>"'?#\]]+\?[^\s()<>"'#\]]*/g;
|
|
3562
|
+
/** Each download URL in `text` that names an object, with its reference. */
|
|
3563
|
+
function downloadUrlsIn(text) {
|
|
3564
|
+
const found = /* @__PURE__ */ new Map();
|
|
3565
|
+
if (!text.includes("/storage/file/")) return found;
|
|
3566
|
+
for (const url of text.match(DOWNLOAD_URL_PATTERN) ?? []) {
|
|
3567
|
+
const target = storageTargetOfDownloadUrl(url);
|
|
3568
|
+
if (target) found.set(url, storageReference(target.key, target.storageId));
|
|
3569
|
+
}
|
|
3570
|
+
return found;
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* Every object `text` names: its storage references, and the private files'
|
|
3574
|
+
* download URLs saved in it before references existed. An object named more
|
|
3575
|
+
* than once may be listed more than once.
|
|
3576
|
+
*
|
|
3577
|
+
* @group Models
|
|
3578
|
+
*/
|
|
3579
|
+
function storageTargetsInText(text) {
|
|
3580
|
+
return [...text.includes("rebase-storage:") ? text.match(STORAGE_REFERENCE_PATTERN) ?? [] : [], ...downloadUrlsIn(text).values()].map((reference) => parseStorageReference(reference)).filter((target) => target !== null);
|
|
3581
|
+
}
|
|
3582
|
+
/**
|
|
3583
|
+
* `text` with every private file's download URL replaced by the storage
|
|
3584
|
+
* reference for its object — for rewriting text saved before references, so
|
|
3585
|
+
* it stores what new text stores. Any other URL is left as it is.
|
|
3586
|
+
*
|
|
3587
|
+
* @group Models
|
|
3588
|
+
*/
|
|
3589
|
+
function storageReferencesForDownloadUrls(text) {
|
|
3590
|
+
const urls = downloadUrlsIn(text);
|
|
3591
|
+
if (urls.size === 0) return text;
|
|
3592
|
+
return text.replace(DOWNLOAD_URL_PATTERN, (url) => urls.get(url) ?? url);
|
|
3593
|
+
}
|
|
3477
3594
|
/**
|
|
3478
3595
|
* Exchange every storage reference in `text` for a URL, at the moment the text
|
|
3479
3596
|
* is rendered.
|
|
@@ -3488,12 +3605,19 @@ function parseStorageReference(value) {
|
|
|
3488
3605
|
* source) is left as it was, so a missing object reads as a missing image
|
|
3489
3606
|
* rather than as a failed render.
|
|
3490
3607
|
*
|
|
3608
|
+
* A private file's download URL saved in the text before references existed
|
|
3609
|
+
* is renewed the same way: its expired token still names the object (see
|
|
3610
|
+
* {@link storageTargetOfDownloadUrl}). One that cannot be resolved is left as
|
|
3611
|
+
* it was.
|
|
3612
|
+
*
|
|
3491
3613
|
* @group Models
|
|
3492
3614
|
*/
|
|
3493
3615
|
async function resolveStorageReferences(text, from) {
|
|
3494
|
-
if (!text
|
|
3616
|
+
if (!text) return text;
|
|
3617
|
+
const downloadUrls = downloadUrlsIn(text);
|
|
3618
|
+
if (!text.includes("rebase-storage:") && downloadUrls.size === 0) return text;
|
|
3495
3619
|
const resolve = typeof from === "function" ? from : resolverFromSources(from);
|
|
3496
|
-
const references = new Set(text.match(STORAGE_REFERENCE_PATTERN) ?? []);
|
|
3620
|
+
const references = /* @__PURE__ */ new Set([...text.match(STORAGE_REFERENCE_PATTERN) ?? [], ...downloadUrls.values()]);
|
|
3497
3621
|
const urls = /* @__PURE__ */ new Map();
|
|
3498
3622
|
await Promise.all([...references].map(async (reference) => {
|
|
3499
3623
|
const target = parseStorageReference(reference);
|
|
@@ -3504,7 +3628,11 @@ async function resolveStorageReferences(text, from) {
|
|
|
3504
3628
|
} catch {}
|
|
3505
3629
|
}));
|
|
3506
3630
|
if (urls.size === 0) return text;
|
|
3507
|
-
return text.replace(
|
|
3631
|
+
return (downloadUrls.size === 0 ? text : text.replace(DOWNLOAD_URL_PATTERN, (saved) => {
|
|
3632
|
+
const reference = downloadUrls.get(saved);
|
|
3633
|
+
const url = reference === void 0 ? void 0 : urls.get(reference);
|
|
3634
|
+
return url === void 0 ? saved : asLinkDestination(url);
|
|
3635
|
+
})).replace(STORAGE_REFERENCE_PATTERN, (reference) => {
|
|
3508
3636
|
const url = urls.get(reference);
|
|
3509
3637
|
return url === void 0 ? reference : asLinkDestination(url);
|
|
3510
3638
|
});
|
|
@@ -3531,6 +3659,6 @@ function resolverFromSources(client) {
|
|
|
3531
3659
|
};
|
|
3532
3660
|
}
|
|
3533
3661
|
//#endregion
|
|
3534
|
-
export { ADMIN_COLLECTION_KEYS, ADMIN_PROPERTY_KEYS, ADMIN_ROLE, ADMIN_SCOPES, ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, ANONYMOUS_USER_IDS, BATCH_REF_KEY, BUILT_IN_SCOPES, BUILT_IN_SCOPE_DESCRIPTIONS, BUNDLE_FORMAT_VERSION, CANONICAL_TO_REST, DATA_PLANE_SCOPES, DEFAULT_CAPABILITIES, DEFAULT_COMMIT_PATHS, DEFAULT_DATA_SOURCE_KEY, DEFAULT_FILTERABLE_RELATION_KINDS, DEFAULT_FUZZY_THRESHOLD, DEFAULT_LIST_LIMIT, DEFAULT_RESOURCE_KEY, DEFAULT_SEARCH_COLUMN, DEFAULT_SEARCH_LANGUAGE, DEFAULT_SEARCH_MODE, DEFAULT_SEARCH_WEIGHT, DEFAULT_STORAGE_SOURCE_KEY, DEFAULT_TENANT_BYPASS_ROLES, DEFAULT_VECTOR_LIST_LIMIT, EMPTY_ACCESS_MODEL, EntityReference, EntityRelation, FIELD_OPERATORS, FIREBASE_CAPABILITIES, GeoPoint, IMPERSONATE_HEADER, JUNCTION_PIVOT_KEY, KEY_MANAGEMENT_SCOPES, LEGACY_RLS_JWT_SQL, LEGACY_RLS_ROLES_SQL, LEGACY_RLS_SCHEMA, LEGACY_RLS_UID_SQL, LIST_OPS, ListLimitError, MAX_INCLUDE_DEPTH, MAX_LIST_LIMIT, MONGODB_CAPABILITIES, NULL_OPS, POSTGRES_CAPABILITIES, PUBLIC_STORAGE_PREFIX, REBASE_SCHEMA, RELEVANCE_SORT_FIELD, RESERVED_BACKEND_PREFIXES, RESOURCE_GRAPH_VERSION, REST_TO_CANONICAL, RLS_IS_ANONYMOUS_SQL, RLS_JWT_SQL, RLS_ROLES_SQL, RLS_UID_SQL, RUNTIME_CONTRACT_VERSION, RUNTIME_ONLY_COLLECTION_KEYS, RebaseApiError, RebaseClientError, SCHEMA_VERSION_HEADER, SCOPE_TARGETS, STORAGE_REFERENCE_SCHEME, Vector, amendResourceKind, applyCollectionPatch, bucket, buildResourceGraph, canonicalSchemaPayload, collectionPatchProblems, computeSchemaVersion, database, declareCron, declareFunction, declareResource, declaredDataSources, declaredDatabaseExtensions, declaredQueueConsumers, declaredResources, declaredStorageSources, declaredSubscriptions, describeScope, deserializeCollections, diffCollections, diffJsonValues, encodeRelationAggregateSort, envBasesForResource, findEnvSuffixCollision, findStorageSuffixCollision, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, hasAdminRole, hasFieldOperation, hasForeignKeyOnTarget, intersectScopes, isAdminScope, isAnonymousUid, isBranchAdmin, isBuiltInScope, isChannelBusInstance, isCollectionPatch, isDataPlaneScope, isDocumentAdmin, isFieldOperation, isFirebaseCollectionConfig, isLazyComponentRef, isManyToMany, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStorageKey, isPublicStoragePath, isRelationAggregateSort, isRelationalCollectionConfig, isResourceHandle, isSQLAdmin, isSchemaAdmin, isSchemaEditingAdmin, isSerializedCollectionRef, isStorageReference, isTenantClaimSource, isTenantMembershipSource, isToMany, isUnsupported, isValidAppHost, isValidEngine, knownScopes, nestAdminCollectionKeys, nestAdminKeysOf, nestAdminPropertyKeys, nestCollectionPatchPaths, parseAppAddress, parseEnvBoolean, parseRelationAggregateSort, parseScope, parseStorageReference, policy, queue, registerDataSourceCapabilities, registerResourceKind, reservedPrefixFor, resetDeclaredQueueConsumers, resetDeclaredResources, resetDeclaredSubscriptions, resolveClientListLimit, resolveResourceRefs, resolveStorageReferences, resourceEnvSuffix, resourceId, resourceKeyOf, resourceKind, resourceKinds, resourceToDataSource, resourceToStorageSource, rewriteLegacyRlsFunctions, runtimeOnlyKeyIn, scopeAcceptsTarget, scopeGrants, scopeGrantsAny, scopeTargets, scopesBeyond, scopesForRoles, serializeCollections, setQueueRuntime, setTopicRuntime, sortKeyToString, storageEnvSuffix, storageObjectPath, storageReference, summarizeRoles, summarizeScopes, toCanonicalOp, toCollectionJson, topic, unsupportedMethod, usesLegacyRlsFunctions, validateScopes };
|
|
3662
|
+
export { ADMIN_COLLECTION_KEYS, ADMIN_PROPERTY_KEYS, ADMIN_ROLE, ADMIN_SCOPES, ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, ANONYMOUS_USER_IDS, BATCH_REF_KEY, BUILT_IN_SCOPES, BUILT_IN_SCOPE_DESCRIPTIONS, BUNDLE_FORMAT_VERSION, CANONICAL_TO_REST, DATA_PLANE_SCOPES, DEFAULT_CAPABILITIES, DEFAULT_COMMIT_PATHS, DEFAULT_DATA_SOURCE_KEY, DEFAULT_FILTERABLE_RELATION_KINDS, DEFAULT_FUZZY_THRESHOLD, DEFAULT_LIST_LIMIT, DEFAULT_RESOURCE_KEY, DEFAULT_SEARCH_COLUMN, DEFAULT_SEARCH_LANGUAGE, DEFAULT_SEARCH_MODE, DEFAULT_SEARCH_WEIGHT, DEFAULT_STORAGE_SOURCE_KEY, DEFAULT_TENANT_BYPASS_ROLES, DEFAULT_VECTOR_LIST_LIMIT, EMPTY_ACCESS_MODEL, EntityReference, EntityRelation, FIELD_OPERATORS, FIREBASE_CAPABILITIES, GeoPoint, IMPERSONATE_HEADER, INCLUDE_COUNT_KEY, JUNCTION_PIVOT_KEY, KEY_MANAGEMENT_SCOPES, LEGACY_RLS_JWT_SQL, LEGACY_RLS_ROLES_SQL, LEGACY_RLS_SCHEMA, LEGACY_RLS_UID_SQL, LIST_OPS, ListLimitError, MAX_INCLUDE_DEPTH, MAX_LIST_LIMIT, MONGODB_CAPABILITIES, NULL_OPS, POSTGRES_CAPABILITIES, PUBLIC_STORAGE_PREFIX, REBASE_SCHEMA, RELEVANCE_SORT_FIELD, RESERVED_BACKEND_PREFIXES, RESOURCE_GRAPH_VERSION, REST_TO_CANONICAL, RLS_IS_ANONYMOUS_SQL, RLS_JWT_SQL, RLS_ROLES_SQL, RLS_UID_SQL, RUNTIME_CONTRACT_VERSION, RUNTIME_ONLY_COLLECTION_KEYS, RebaseApiError, RebaseClientError, SCHEMA_VERSION_HEADER, SCOPE_TARGETS, STORAGE_REFERENCE_SCHEME, Vector, amendResourceKind, applyCollectionPatch, bucket, buildResourceGraph, canonicalSchemaPayload, collectionPatchProblems, computeSchemaVersion, database, declareCron, declareFunction, declareResource, declaredDataSources, declaredDatabaseExtensions, declaredQueueConsumers, declaredResources, declaredStorageSources, declaredSubscriptions, describeScope, deserializeCollections, diffCollections, diffJsonValues, encodeRelationAggregateSort, envBasesForResource, findEnvSuffixCollision, findStorageSuffixCollision, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, hasAdminRole, hasFieldOperation, hasForeignKeyOnTarget, intersectScopes, isAdminScope, isAnonymousUid, isBranchAdmin, isBuiltInScope, isChannelBusInstance, isCollectionPatch, isDataPlaneScope, isDocumentAdmin, isFieldOperation, isFirebaseCollectionConfig, isLazyComponentRef, isManyToMany, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStorageKey, isPublicStoragePath, isRelationAggregateSort, isRelationalCollectionConfig, isResourceHandle, isSQLAdmin, isSchemaAdmin, isSchemaEditingAdmin, isSerializedCollectionRef, isStorageReference, isTenantClaimSource, isTenantMembershipSource, isToMany, isUnsupported, isValidAppHost, isValidEngine, knownScopes, nestAdminCollectionKeys, nestAdminKeysOf, nestAdminPropertyKeys, nestCollectionPatchPaths, parseAppAddress, parseEnvBoolean, parseRelationAggregateSort, parseScope, parseStorageReference, policy, queue, registerDataSourceCapabilities, registerResourceKind, reservedPrefixFor, resetDeclaredQueueConsumers, resetDeclaredResources, resetDeclaredSubscriptions, resolveClientListLimit, resolveResourceRefs, resolveStorageReferences, resourceEnvSuffix, resourceId, resourceKeyOf, resourceKind, resourceKinds, resourceToDataSource, resourceToStorageSource, rewriteLegacyRlsFunctions, runtimeOnlyKeyIn, scopeAcceptsTarget, scopeGrants, scopeGrantsAny, scopeTargets, scopesBeyond, scopesForRoles, serializeCollections, setQueueRuntime, setTopicRuntime, sortKeyToString, storageEnvSuffix, storageObjectPath, storageReference, storageReferencesForDownloadUrls, storageTargetOfDownloadUrl, storageTargetsInText, summarizeRoles, summarizeScopes, toCanonicalOp, toCollectionJson, topic, unsupportedMethod, usesLegacyRlsFunctions, validateScopes };
|
|
3535
3663
|
|
|
3536
3664
|
//# sourceMappingURL=index.es.js.map
|