@filelayer/core 0.3.0
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/CHANGELOG.md +338 -0
- package/LICENSE +202 -0
- package/MIGRATIONS.md +328 -0
- package/NOTICE +37 -0
- package/README.md +343 -0
- package/SEMANTICS.md +729 -0
- package/dist/authz.d.ts +524 -0
- package/dist/authz.d.ts.map +1 -0
- package/dist/authz.js +889 -0
- package/dist/authz.js.map +1 -0
- package/dist/db.d.ts +145 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +217 -0
- package/dist/db.js.map +1 -0
- package/dist/delivery.d.ts +293 -0
- package/dist/delivery.d.ts.map +1 -0
- package/dist/delivery.js +519 -0
- package/dist/delivery.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/filelayer.d.ts +542 -0
- package/dist/filelayer.d.ts.map +1 -0
- package/dist/filelayer.js +1360 -0
- package/dist/filelayer.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/simple.d.ts +297 -0
- package/dist/simple.d.ts.map +1 -0
- package/dist/simple.js +492 -0
- package/dist/simple.js.map +1 -0
- package/dist/storage.d.ts +269 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +700 -0
- package/dist/storage.js.map +1 -0
- package/dist/store.d.ts +432 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +862 -0
- package/dist/store.js.map +1 -0
- package/package.json +77 -0
- package/schema.sql +1190 -0
- package/src/authz.ts +1398 -0
- package/src/db.ts +271 -0
- package/src/delivery.ts +737 -0
- package/src/errors.ts +24 -0
- package/src/filelayer.ts +1836 -0
- package/src/index.ts +7 -0
- package/src/simple.ts +666 -0
- package/src/storage.ts +917 -0
- package/src/store.ts +1072 -0
- package/test/delivery.test.ts +0 -0
- package/test/group-subjects.test.ts +1072 -0
- package/test/helpers.ts +65 -0
- package/test/listing.test.ts +689 -0
- package/test/local-s3.d.mts +33 -0
- package/test/local-s3.mjs +400 -0
- package/test/persistence.test.ts +953 -0
- package/test/regression.test.ts +619 -0
- package/test/s3-live.test.ts +322 -0
- package/test/security.test.ts +1652 -0
- package/test/semantics.test.ts +888 -0
- package/test/storage.test.ts +437 -0
- package/test/tiers.test.ts +432 -0
- package/test/vault-example.test.ts +302 -0
- package/tsconfig.build.json +29 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* STORAGE ADAPTERS
|
|
3
|
+
*
|
|
4
|
+
* P2 (no ambient authority) is why this interface is deliberately dumb: it
|
|
5
|
+
* takes an opaque key and moves bytes. It has no idea what an org is, cannot
|
|
6
|
+
* be asked "who may read this", and is never consulted during an authorization
|
|
7
|
+
* decision. If the adapter could answer access questions there would be two
|
|
8
|
+
* authorization paths, and the second one is always the one that leaks.
|
|
9
|
+
*
|
|
10
|
+
* Corollary: object keys are NOT secrets and are not treated as such anywhere.
|
|
11
|
+
*
|
|
12
|
+
* -----------------------------------------------------------------------------
|
|
13
|
+
* WHAT CHANGED, AND WHY
|
|
14
|
+
* -----------------------------------------------------------------------------
|
|
15
|
+
*
|
|
16
|
+
* 1. `provider` is now part of the interface.
|
|
17
|
+
*
|
|
18
|
+
* `file.storage_provider` was written as the literal `'memory'` in
|
|
19
|
+
* `Filelayer.upload()`, regardless of which adapter was configured. Against
|
|
20
|
+
* `CREATE UNIQUE INDEX file_storage_key_idx ON file (storage_provider,
|
|
21
|
+
* storage_key)` that means a production database records every object as
|
|
22
|
+
* living in an in-memory store, and the one column that says WHERE the bytes
|
|
23
|
+
* are is wrong for every row. An adapter must therefore be able to name
|
|
24
|
+
* itself, and the name must come from the adapter rather than from the call
|
|
25
|
+
* site.
|
|
26
|
+
*
|
|
27
|
+
* 2. Everything is streaming-capable.
|
|
28
|
+
*
|
|
29
|
+
* `put()` took a `Uint8Array` and delivery returned one. That is a permanent
|
|
30
|
+
* tax on the heap: a 2 GB upload was 2 GB of resident memory in the API
|
|
31
|
+
* process, twice (once in the adapter, once in the response). `put()` now
|
|
32
|
+
* accepts a `ReadableStream` and uses S3 multipart above a part threshold;
|
|
33
|
+
* `stream()` returns a byte stream plus the metadata a correct HTTP response
|
|
34
|
+
* needs, and supports ranged reads.
|
|
35
|
+
*
|
|
36
|
+
* 3. `head()` exists.
|
|
37
|
+
*
|
|
38
|
+
* A `stat()` that has to download the object to learn its size is not a
|
|
39
|
+
* stat.
|
|
40
|
+
*
|
|
41
|
+
* 4. `presignGet()` is OPTIONAL, and its optionality is the point.
|
|
42
|
+
*
|
|
43
|
+
* It is the only capability the redirect delivery mode needs, and an adapter
|
|
44
|
+
* that cannot mint a presigned URL simply does not offer redirect delivery
|
|
45
|
+
* (`MemoryStorage` does not). Nothing else in the system may call it:
|
|
46
|
+
* a presigned URL is authority that outlives the decision that produced it,
|
|
47
|
+
* which is exactly the property P4 exists to deny, so it is reachable only
|
|
48
|
+
* through the explicitly-acknowledged redirect mode in `delivery.ts`.
|
|
49
|
+
*
|
|
50
|
+
* 5. `list()` is OPTIONAL and exists for exactly one caller: orphan collection.
|
|
51
|
+
*
|
|
52
|
+
* The storage write is not transactional (see `db.ts`). Bytes are written
|
|
53
|
+
* before the metadata transaction commits, so a crash in between leaves an
|
|
54
|
+
* object with no `file` row. That is a garbage-collection problem, not a
|
|
55
|
+
* correctness one -- an orphan is unreachable, because every read path starts
|
|
56
|
+
* from a `file` row -- but it is still our problem. `list()` is what makes it
|
|
57
|
+
* collectable.
|
|
58
|
+
*/
|
|
59
|
+
/** Bytes, or a stream of bytes. Large uploads must use the second form. */
|
|
60
|
+
export type PutBody = Uint8Array | ReadableStream<Uint8Array>;
|
|
61
|
+
export interface StoragePutOptions {
|
|
62
|
+
/** Total length when known. Lets a small streaming put skip multipart. */
|
|
63
|
+
contentLength?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface StoragePutResult {
|
|
66
|
+
/** Bytes actually written. Authoritative for `file.size_bytes`. */
|
|
67
|
+
bytes: number;
|
|
68
|
+
etag: string | null;
|
|
69
|
+
}
|
|
70
|
+
export interface ByteRange {
|
|
71
|
+
start: number;
|
|
72
|
+
/** Inclusive, per HTTP. Omit for "to the end". */
|
|
73
|
+
end?: number;
|
|
74
|
+
}
|
|
75
|
+
export interface ObjectHead {
|
|
76
|
+
size: number;
|
|
77
|
+
contentType: string | null;
|
|
78
|
+
etag: string | null;
|
|
79
|
+
lastModified: Date | null;
|
|
80
|
+
}
|
|
81
|
+
export interface ObjectStream {
|
|
82
|
+
body: ReadableStream<Uint8Array>;
|
|
83
|
+
/** Bytes in THIS response (the range length for a ranged read). */
|
|
84
|
+
size: number | null;
|
|
85
|
+
contentType: string | null;
|
|
86
|
+
etag: string | null;
|
|
87
|
+
/** Present only when the store honoured a range request. */
|
|
88
|
+
range?: {
|
|
89
|
+
start: number;
|
|
90
|
+
end: number;
|
|
91
|
+
total: number;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export interface ListEntry {
|
|
95
|
+
key: string;
|
|
96
|
+
size: number;
|
|
97
|
+
lastModified: Date | null;
|
|
98
|
+
}
|
|
99
|
+
export interface PresignOptions {
|
|
100
|
+
/** Seconds. The adapter clamps; the DELIVERY layer clamps harder. */
|
|
101
|
+
expiresInSeconds: number;
|
|
102
|
+
/** Forced onto the response by the object store, so the store cannot be
|
|
103
|
+
* tricked into serving our bytes with an attacker-chosen content type. */
|
|
104
|
+
responseContentType?: string;
|
|
105
|
+
responseContentDisposition?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface StorageAdapter {
|
|
108
|
+
/**
|
|
109
|
+
* The value written to `file.storage_provider`. It participates in a UNIQUE
|
|
110
|
+
* index with the key, so it is part of an object's identity: change it for an
|
|
111
|
+
* existing deployment and every existing row points at the wrong store.
|
|
112
|
+
*
|
|
113
|
+
* Conventional values: 'memory', 's3', 'r2', 'gcs'.
|
|
114
|
+
*/
|
|
115
|
+
readonly provider: string;
|
|
116
|
+
put(key: string, body: PutBody, contentType: string, opts?: StoragePutOptions): Promise<StoragePutResult>;
|
|
117
|
+
/** Buffered read. Only for callers that genuinely want the whole object. */
|
|
118
|
+
get(key: string): Promise<Uint8Array | null>;
|
|
119
|
+
stream(key: string, opts?: {
|
|
120
|
+
range?: ByteRange;
|
|
121
|
+
}): Promise<ObjectStream | null>;
|
|
122
|
+
head(key: string): Promise<ObjectHead | null>;
|
|
123
|
+
delete(key: string): Promise<void>;
|
|
124
|
+
/** Optional. Present => this adapter can support redirect delivery. */
|
|
125
|
+
presignGet?(key: string, opts: PresignOptions): Promise<string>;
|
|
126
|
+
/** Optional. Present => orphan collection can run against this adapter. */
|
|
127
|
+
list?(prefix: string, opts?: {
|
|
128
|
+
limit?: number;
|
|
129
|
+
cursor?: string | null;
|
|
130
|
+
}): Promise<{
|
|
131
|
+
entries: ListEntry[];
|
|
132
|
+
cursor: string | null;
|
|
133
|
+
}>;
|
|
134
|
+
}
|
|
135
|
+
/** Narrowing helpers, so callers do not hand-roll `typeof x.presignGet`. */
|
|
136
|
+
export declare function canPresign(s: StorageAdapter): s is StorageAdapter & Required<Pick<StorageAdapter, 'presignGet'>>;
|
|
137
|
+
export declare function canList(s: StorageAdapter): s is StorageAdapter & Required<Pick<StorageAdapter, 'list'>>;
|
|
138
|
+
/** Collect a byte stream, refusing to exceed `limit`. */
|
|
139
|
+
export declare function collectStream(stream: ReadableStream<Uint8Array>, limit?: number): Promise<Uint8Array>;
|
|
140
|
+
export declare function bytesToStream(body: Uint8Array): ReadableStream<Uint8Array>;
|
|
141
|
+
export declare class MemoryStorage implements StorageAdapter {
|
|
142
|
+
readonly provider = "memory";
|
|
143
|
+
private readonly objects;
|
|
144
|
+
put(key: string, body: PutBody, contentType: string): Promise<StoragePutResult>;
|
|
145
|
+
get(key: string): Promise<Uint8Array | null>;
|
|
146
|
+
head(key: string): Promise<ObjectHead | null>;
|
|
147
|
+
delete(key: string): Promise<void>;
|
|
148
|
+
stream(key: string, opts?: {
|
|
149
|
+
range?: ByteRange;
|
|
150
|
+
}): Promise<ObjectStream | null>;
|
|
151
|
+
list(prefix: string, opts?: {
|
|
152
|
+
limit?: number;
|
|
153
|
+
cursor?: string | null;
|
|
154
|
+
}): Promise<{
|
|
155
|
+
entries: ListEntry[];
|
|
156
|
+
cursor: string | null;
|
|
157
|
+
}>;
|
|
158
|
+
/**
|
|
159
|
+
* DELIBERATELY ABSENT: `presignGet`.
|
|
160
|
+
*
|
|
161
|
+
* There is no URL that reaches an in-process Map, so redirect delivery is
|
|
162
|
+
* structurally unavailable here rather than fake. A test that wants to
|
|
163
|
+
* exercise redirect delivery must run against something that can actually
|
|
164
|
+
* mint one -- which is the point.
|
|
165
|
+
*/
|
|
166
|
+
/** Test-only: lets a test assert that delete really removed the bytes. */
|
|
167
|
+
keys(): string[];
|
|
168
|
+
}
|
|
169
|
+
export interface S3Config {
|
|
170
|
+
/** e.g. https://<account>.r2.cloudflarestorage.com, or a test server URL. */
|
|
171
|
+
endpoint: string;
|
|
172
|
+
bucket: string;
|
|
173
|
+
region: string;
|
|
174
|
+
accessKeyId: string;
|
|
175
|
+
secretAccessKey: string;
|
|
176
|
+
/** For STS / temporary credentials. Sent as `x-amz-security-token`. */
|
|
177
|
+
sessionToken?: string;
|
|
178
|
+
/**
|
|
179
|
+
* What lands in `file.storage_provider`. Defaults to 'r2' for an R2 endpoint
|
|
180
|
+
* and 's3' otherwise. It is part of an object's identity (see the UNIQUE
|
|
181
|
+
* index), so pin it explicitly for anything long-lived.
|
|
182
|
+
*/
|
|
183
|
+
provider?: string;
|
|
184
|
+
/**
|
|
185
|
+
* `https://host/<bucket>/<key>` (default, and what R2 uses) vs
|
|
186
|
+
* `https://<bucket>.host/<key>`.
|
|
187
|
+
*/
|
|
188
|
+
pathStyle?: boolean;
|
|
189
|
+
/** Multipart part size. S3 requires >= 5 MiB for all but the last part. */
|
|
190
|
+
partSizeBytes?: number;
|
|
191
|
+
/** Hard ceiling on a presigned URL's lifetime, in seconds. */
|
|
192
|
+
maxPresignSeconds?: number;
|
|
193
|
+
}
|
|
194
|
+
export declare class S3Storage implements StorageAdapter {
|
|
195
|
+
readonly provider: string;
|
|
196
|
+
private readonly cfg;
|
|
197
|
+
constructor(cfg: S3Config);
|
|
198
|
+
put(key: string, body: PutBody, contentType: string, opts?: StoragePutOptions): Promise<StoragePutResult>;
|
|
199
|
+
private putBuffer;
|
|
200
|
+
/**
|
|
201
|
+
* Streaming upload.
|
|
202
|
+
*
|
|
203
|
+
* The first `partSizeBytes` are buffered because we cannot know until we have
|
|
204
|
+
* them whether this is a one-shot PUT or a multipart upload, and a one-shot
|
|
205
|
+
* PUT needs `content-length` (and a payload hash) up front. Everything beyond
|
|
206
|
+
* that is uploaded part by part and never all resident at once, so peak
|
|
207
|
+
* memory is bounded by ONE part regardless of object size. That bound is the
|
|
208
|
+
* entire point of this method.
|
|
209
|
+
*/
|
|
210
|
+
private putStream;
|
|
211
|
+
private createMultipartUpload;
|
|
212
|
+
private uploadPart;
|
|
213
|
+
private completeMultipartUpload;
|
|
214
|
+
private abortMultipartUpload;
|
|
215
|
+
get(key: string): Promise<Uint8Array | null>;
|
|
216
|
+
head(key: string): Promise<ObjectHead | null>;
|
|
217
|
+
stream(key: string, opts?: {
|
|
218
|
+
range?: ByteRange;
|
|
219
|
+
}): Promise<ObjectStream | null>;
|
|
220
|
+
delete(key: string): Promise<void>;
|
|
221
|
+
list(prefix: string, opts?: {
|
|
222
|
+
limit?: number;
|
|
223
|
+
cursor?: string | null;
|
|
224
|
+
}): Promise<{
|
|
225
|
+
entries: ListEntry[];
|
|
226
|
+
cursor: string | null;
|
|
227
|
+
}>;
|
|
228
|
+
/**
|
|
229
|
+
* A query-string-signed GET URL.
|
|
230
|
+
*
|
|
231
|
+
* READ THE WARNING IN `delivery.ts` BEFORE CALLING THIS. The URL is bearer
|
|
232
|
+
* authority that the object store will honour until it expires, and the
|
|
233
|
+
* object store has never heard of a grant, a revocation or an org. That is
|
|
234
|
+
* why it is not reachable from any ordinary delivery path.
|
|
235
|
+
*
|
|
236
|
+
* `response-content-type` and `response-content-disposition` are signed into
|
|
237
|
+
* the URL, so the object store -- not the client -- decides what the bytes are
|
|
238
|
+
* served as. Without them a redirect would drop the `nosniff`/`attachment`
|
|
239
|
+
* protections that `deliveryHeaders()` exists to guarantee.
|
|
240
|
+
*/
|
|
241
|
+
presignGet(key: string, opts: PresignOptions): Promise<string>;
|
|
242
|
+
/**
|
|
243
|
+
* Path-style: `https://host/<bucket>/<key>`. Virtual-hosted:
|
|
244
|
+
* `https://<bucket>.host/<key>`.
|
|
245
|
+
*
|
|
246
|
+
* The canonical URI is built by RFC-3986-encoding each SEGMENT and is carried
|
|
247
|
+
* separately from `URL.pathname`, because `new URL()` normalises `.`/`..`
|
|
248
|
+
* segments and re-encodes some characters. Signing one string and sending
|
|
249
|
+
* another is the classic SigV4 bug and produces a 403 that looks like a
|
|
250
|
+
* credentials problem.
|
|
251
|
+
*/
|
|
252
|
+
private objectUrl;
|
|
253
|
+
private sign;
|
|
254
|
+
private signedFetch;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* RFC 3986 unreserved-set encoding.
|
|
258
|
+
*
|
|
259
|
+
* `encodeURIComponent` leaves `!'()*` alone and `encodeURI` additionally leaves
|
|
260
|
+
* `#?&=+,:;@$` alone. The previous implementation used `encodeURI` on the whole
|
|
261
|
+
* key, which meant a key containing `#` truncated the URL at the fragment, a key
|
|
262
|
+
* containing `?` started a query string, and a key containing `+` signed one
|
|
263
|
+
* byte sequence and sent another. Keys are constructed by us today, but "the
|
|
264
|
+
* caller never puts a `#` in a key" is not a property the type system carries.
|
|
265
|
+
*/
|
|
266
|
+
export declare function rfc3986(s: string): string;
|
|
267
|
+
/** Sorted by encoded key, then encoded value. Empty values keep their `=`. */
|
|
268
|
+
export declare function canonicalQueryString(query: Record<string, string>): string;
|
|
269
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|