@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.
Files changed (69) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/LICENSE +202 -0
  3. package/MIGRATIONS.md +328 -0
  4. package/NOTICE +37 -0
  5. package/README.md +343 -0
  6. package/SEMANTICS.md +729 -0
  7. package/dist/authz.d.ts +524 -0
  8. package/dist/authz.d.ts.map +1 -0
  9. package/dist/authz.js +889 -0
  10. package/dist/authz.js.map +1 -0
  11. package/dist/db.d.ts +145 -0
  12. package/dist/db.d.ts.map +1 -0
  13. package/dist/db.js +217 -0
  14. package/dist/db.js.map +1 -0
  15. package/dist/delivery.d.ts +293 -0
  16. package/dist/delivery.d.ts.map +1 -0
  17. package/dist/delivery.js +519 -0
  18. package/dist/delivery.js.map +1 -0
  19. package/dist/errors.d.ts +16 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +21 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/filelayer.d.ts +542 -0
  24. package/dist/filelayer.d.ts.map +1 -0
  25. package/dist/filelayer.js +1360 -0
  26. package/dist/filelayer.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +8 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/simple.d.ts +297 -0
  32. package/dist/simple.d.ts.map +1 -0
  33. package/dist/simple.js +492 -0
  34. package/dist/simple.js.map +1 -0
  35. package/dist/storage.d.ts +269 -0
  36. package/dist/storage.d.ts.map +1 -0
  37. package/dist/storage.js +700 -0
  38. package/dist/storage.js.map +1 -0
  39. package/dist/store.d.ts +432 -0
  40. package/dist/store.d.ts.map +1 -0
  41. package/dist/store.js +862 -0
  42. package/dist/store.js.map +1 -0
  43. package/package.json +77 -0
  44. package/schema.sql +1190 -0
  45. package/src/authz.ts +1398 -0
  46. package/src/db.ts +271 -0
  47. package/src/delivery.ts +737 -0
  48. package/src/errors.ts +24 -0
  49. package/src/filelayer.ts +1836 -0
  50. package/src/index.ts +7 -0
  51. package/src/simple.ts +666 -0
  52. package/src/storage.ts +917 -0
  53. package/src/store.ts +1072 -0
  54. package/test/delivery.test.ts +0 -0
  55. package/test/group-subjects.test.ts +1072 -0
  56. package/test/helpers.ts +65 -0
  57. package/test/listing.test.ts +689 -0
  58. package/test/local-s3.d.mts +33 -0
  59. package/test/local-s3.mjs +400 -0
  60. package/test/persistence.test.ts +953 -0
  61. package/test/regression.test.ts +619 -0
  62. package/test/s3-live.test.ts +322 -0
  63. package/test/security.test.ts +1652 -0
  64. package/test/semantics.test.ts +888 -0
  65. package/test/storage.test.ts +437 -0
  66. package/test/tiers.test.ts +432 -0
  67. package/test/vault-example.test.ts +302 -0
  68. package/tsconfig.build.json +29 -0
  69. 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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"}