@powerhousedao/reactor-attachments 6.1.0-staging.0 → 6.2.0-dev.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/dist/client.d.ts +23 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +61 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +24 -429
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +212 -485
- package/dist/index.js.map +1 -1
- package/dist/null-attachment-transport-BBhQIk5A.d.ts +617 -0
- package/dist/null-attachment-transport-BBhQIk5A.d.ts.map +1 -0
- package/dist/null-attachment-transport-Drx03s02.js +686 -0
- package/dist/null-attachment-transport-Drx03s02.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
import { AttachmentHash, AttachmentRef, JwtHandler } from "@powerhousedao/reactor";
|
|
2
|
+
|
|
3
|
+
//#region src/errors.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when an attachment ref or hash is not known to the store.
|
|
6
|
+
*/
|
|
7
|
+
declare class AttachmentNotFound extends Error {
|
|
8
|
+
constructor(identifier: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Thrown when a reservation ID is not found in the reservation store.
|
|
12
|
+
*/
|
|
13
|
+
declare class ReservationNotFound extends Error {
|
|
14
|
+
constructor(reservationId: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Thrown when an attachment ref string does not match the expected format.
|
|
18
|
+
*/
|
|
19
|
+
declare class InvalidAttachmentRef extends Error {
|
|
20
|
+
constructor(ref: string);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Thrown when an upload exceeds the configured maximum byte cap.
|
|
24
|
+
* Route handlers should map this to HTTP 413 Payload Too Large.
|
|
25
|
+
*/
|
|
26
|
+
declare class UploadTooLarge extends Error {
|
|
27
|
+
readonly maxBytes: number;
|
|
28
|
+
constructor(maxBytes: number);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Thrown by reserve() when the claimed hash is already available in the store.
|
|
32
|
+
* The caller should use err.ref directly and upload nothing -- this is the
|
|
33
|
+
* dedup fast path: duplicate content never leaves the client.
|
|
34
|
+
*/
|
|
35
|
+
declare class AttachmentAlreadyExists extends Error {
|
|
36
|
+
readonly hash: AttachmentHash;
|
|
37
|
+
readonly ref: AttachmentRef;
|
|
38
|
+
constructor(hash: AttachmentHash, ref: AttachmentRef);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Thrown by send() when the server-computed hash of the uploaded bytes
|
|
42
|
+
* does not match the hash claimed at reservation time. Nothing is committed;
|
|
43
|
+
* the reservation is retained so the client can retry with correct bytes.
|
|
44
|
+
*/
|
|
45
|
+
declare class HashMismatch extends Error {
|
|
46
|
+
readonly claimed: AttachmentHash;
|
|
47
|
+
readonly actual: AttachmentHash;
|
|
48
|
+
constructor(claimed: AttachmentHash, actual: AttachmentHash);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Thrown by send() when the uploaded byte count does not equal the
|
|
52
|
+
* sizeBytes declared at reservation time. The handle may reject
|
|
53
|
+
* mid-stream as soon as the count exceeds the declaration.
|
|
54
|
+
* Nothing is committed; the reservation is retained for retry.
|
|
55
|
+
*
|
|
56
|
+
* "actual" is the byte count received from the stream before aborting --
|
|
57
|
+
* it includes the chunk that crossed the declaration and can exceed bytes
|
|
58
|
+
* persisted. On mid-stream aborts the true total is unknown; at least
|
|
59
|
+
* "actual" bytes were sent.
|
|
60
|
+
*/
|
|
61
|
+
declare class SizeMismatch extends Error {
|
|
62
|
+
readonly declared: number;
|
|
63
|
+
readonly actual: number;
|
|
64
|
+
constructor(declared: number, actual: number);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Thrown by get() when the hash is reserved by an in-flight upload and
|
|
68
|
+
* bytes are not yet available anywhere. Deliberately NOT a subclass of
|
|
69
|
+
* AttachmentNotFound -- callers must distinguish "retry later" from "unknown".
|
|
70
|
+
* After expiresAtUtc has passed the hash reads as not found.
|
|
71
|
+
*
|
|
72
|
+
* metadata is populated when the reservation is local and its fields are
|
|
73
|
+
* known (mimeType, fileName, sizeBytes). It is undefined when the pending
|
|
74
|
+
* state is learned from a remote transport that did not supply the full
|
|
75
|
+
* Attachment-Pending header (transport-pending / degraded wire case).
|
|
76
|
+
*/
|
|
77
|
+
declare class AttachmentPending extends Error {
|
|
78
|
+
readonly hash: AttachmentHash;
|
|
79
|
+
readonly expiresAtUtc: string;
|
|
80
|
+
readonly metadata: {
|
|
81
|
+
readonly mimeType: string;
|
|
82
|
+
readonly fileName: string;
|
|
83
|
+
readonly sizeBytes: number;
|
|
84
|
+
} | undefined;
|
|
85
|
+
constructor(hash: AttachmentHash, expiresAtUtc: string, meta?: {
|
|
86
|
+
mimeType: string;
|
|
87
|
+
fileName: string;
|
|
88
|
+
sizeBytes: number;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/types.d.ts
|
|
93
|
+
/**
|
|
94
|
+
* Status of attachment data in the local store.
|
|
95
|
+
* 'pending' is a virtual status synthesized at query time from live,
|
|
96
|
+
* hash-bearing reservations -- it never appears in the attachment table.
|
|
97
|
+
*/
|
|
98
|
+
type AttachmentStatus = "available" | "evicted" | "pending";
|
|
99
|
+
/**
|
|
100
|
+
* Metadata about an attachment. For committed attachments (available/evicted),
|
|
101
|
+
* expiresAtUtc is null. For pending attachments synthesized from a live
|
|
102
|
+
* reservation, expiresAtUtc carries the reservation expiry so callers can
|
|
103
|
+
* emit Retry-After or bound polling loops.
|
|
104
|
+
*/
|
|
105
|
+
type AttachmentHeader = {
|
|
106
|
+
hash: AttachmentHash;
|
|
107
|
+
mimeType: string;
|
|
108
|
+
fileName: string;
|
|
109
|
+
sizeBytes: number;
|
|
110
|
+
extension: string | null;
|
|
111
|
+
status: AttachmentStatus;
|
|
112
|
+
source: "local" | "sync";
|
|
113
|
+
createdAtUtc: string;
|
|
114
|
+
lastAccessedAtUtc: string;
|
|
115
|
+
expiresAtUtc: string | null;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Metadata provided alongside attachment data during sync, and returned
|
|
119
|
+
* via the switchboard's `Attachment-Metadata` header on GET/HEAD.
|
|
120
|
+
* `createdAtUtc` is the original upload time, propagated from the source
|
|
121
|
+
* so that the receiving store preserves it instead of synthesizing the
|
|
122
|
+
* fetch time. `lastAccessedAtUtc` is the source reactor's most recent
|
|
123
|
+
* access time; it is optional because not every producer (e.g. a fresh
|
|
124
|
+
* `put` from a transport) tracks access yet. Receiving stores that
|
|
125
|
+
* persist locally (LRU concerns) reset it on every read regardless.
|
|
126
|
+
*
|
|
127
|
+
* Reliability note: `lastAccessedAtUtc` arriving over the wire is
|
|
128
|
+
* best-effort. When the producer omits it, the consumer (see
|
|
129
|
+
* `RemoteAttachmentStore` / `SwitchboardAttachmentTransport`) coalesces
|
|
130
|
+
* with `createdAtUtc`, so the field can silently equal `createdAtUtc`
|
|
131
|
+
* even on a server that has never been read. Do NOT use the wire value
|
|
132
|
+
* for LRU eviction or staleness decisions on remote data; always read
|
|
133
|
+
* the field from the local store after persistence, where the receiving
|
|
134
|
+
* store is the authority.
|
|
135
|
+
*/
|
|
136
|
+
type AttachmentMetadata = {
|
|
137
|
+
mimeType: string;
|
|
138
|
+
fileName: string;
|
|
139
|
+
sizeBytes: number;
|
|
140
|
+
extension: string | null;
|
|
141
|
+
createdAtUtc: string;
|
|
142
|
+
lastAccessedAtUtc?: string;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Upload-first reservation. clientHash and sizeBytes are absent;
|
|
146
|
+
* the ref is only known after send() completes.
|
|
147
|
+
*/
|
|
148
|
+
type UploadFirstReserveAttachmentOptions = {
|
|
149
|
+
mimeType: string;
|
|
150
|
+
fileName: string;
|
|
151
|
+
extension?: string | null;
|
|
152
|
+
clientHash?: undefined;
|
|
153
|
+
sizeBytes?: undefined;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Hash-first reservation. clientHash is present and sizeBytes is required.
|
|
157
|
+
* The ref is known at reservation time; send() verifies the uploaded bytes
|
|
158
|
+
* against the claimed hash and declared size. The explicit "?: undefined"
|
|
159
|
+
* on UploadFirstReserveAttachmentOptions makes clientHash a narrowing discriminant:
|
|
160
|
+
* checking options.clientHash !== undefined narrows sizeBytes to number.
|
|
161
|
+
*/
|
|
162
|
+
type HashFirstReserveAttachmentOptions = {
|
|
163
|
+
mimeType: string;
|
|
164
|
+
fileName: string;
|
|
165
|
+
extension?: string | null;
|
|
166
|
+
/**
|
|
167
|
+
* Content hash claimed by the client (lowercase SHA-256 hex).
|
|
168
|
+
*/
|
|
169
|
+
clientHash: AttachmentHash;
|
|
170
|
+
/**
|
|
171
|
+
* Declared size in bytes. Required when clientHash is present.
|
|
172
|
+
* Reported by stat() during the pending window and enforced on
|
|
173
|
+
* ingest: an upload whose actual byte count differs is rejected.
|
|
174
|
+
*/
|
|
175
|
+
sizeBytes: number;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Options provided when reserving an attachment slot.
|
|
179
|
+
*
|
|
180
|
+
* Use HashFirstReserveAttachmentOptions when clientHash is known up front;
|
|
181
|
+
* the service then operates in hash-first mode: reserve() rejects if the
|
|
182
|
+
* content is already available, and send() verifies the uploaded bytes.
|
|
183
|
+
*
|
|
184
|
+
* Use UploadFirstReserveAttachmentOptions (or omit clientHash) for the
|
|
185
|
+
* upload-first flow where the ref is only known after send() completes.
|
|
186
|
+
*/
|
|
187
|
+
type ReserveAttachmentOptions = UploadFirstReserveAttachmentOptions | HashFirstReserveAttachmentOptions;
|
|
188
|
+
/**
|
|
189
|
+
* Result of uploading attachment data through a handle.
|
|
190
|
+
*/
|
|
191
|
+
type AttachmentUploadResult = {
|
|
192
|
+
hash: AttachmentHash;
|
|
193
|
+
ref: AttachmentRef;
|
|
194
|
+
header: AttachmentHeader;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Response when retrieving attachment data from the local store.
|
|
198
|
+
*/
|
|
199
|
+
type AttachmentResponse = {
|
|
200
|
+
header: AttachmentHeader;
|
|
201
|
+
body: ReadableStream<Uint8Array>;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Response when fetching attachment data from a remote transport.
|
|
205
|
+
* Lighter than AttachmentResponse -- a remote peer cannot meaningfully
|
|
206
|
+
* populate status or source, which are local reactor concerns.
|
|
207
|
+
* The store assigns those fields when it calls put() on receipt.
|
|
208
|
+
*/
|
|
209
|
+
type TransportResponse = {
|
|
210
|
+
hash: AttachmentHash;
|
|
211
|
+
metadata: AttachmentMetadata;
|
|
212
|
+
body: ReadableStream<Uint8Array>;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Three-way result from IAttachmentTransport.fetch(). Replaces
|
|
216
|
+
* TransportResponse | null to make the pending state explicit, so
|
|
217
|
+
* peers receiving a synced operation whose attachment is in-flight can
|
|
218
|
+
* distinguish "retry later" from "permanently unknown".
|
|
219
|
+
*/
|
|
220
|
+
type TransportFetchResult = {
|
|
221
|
+
kind: "data";
|
|
222
|
+
response: TransportResponse;
|
|
223
|
+
} | {
|
|
224
|
+
kind: "pending";
|
|
225
|
+
hash: AttachmentHash;
|
|
226
|
+
expiresAtUtc: string;
|
|
227
|
+
retryAfterMs: number;
|
|
228
|
+
} | {
|
|
229
|
+
kind: "not-found";
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Configuration for creating an attachment transport instance.
|
|
233
|
+
*/
|
|
234
|
+
type AttachmentTransportConfig = {
|
|
235
|
+
type: string;
|
|
236
|
+
parameters: Record<string, unknown>;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* A reservation for an in-progress attachment upload.
|
|
240
|
+
* Created by reserve(), deleted when upload.send() completes or
|
|
241
|
+
* once expiresAtUtc has passed and a sweep runs.
|
|
242
|
+
* clientHash and sizeBytes are set in hash-first mode and null in
|
|
243
|
+
* upload-first mode.
|
|
244
|
+
*/
|
|
245
|
+
type Reservation = {
|
|
246
|
+
reservationId: string;
|
|
247
|
+
mimeType: string;
|
|
248
|
+
fileName: string;
|
|
249
|
+
extension: string | null;
|
|
250
|
+
createdAtUtc: string;
|
|
251
|
+
expiresAtUtc: string;
|
|
252
|
+
clientHash: string | null;
|
|
253
|
+
sizeBytes: number | null;
|
|
254
|
+
};
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/interfaces.d.ts
|
|
257
|
+
/**
|
|
258
|
+
* Client-facing interface for uploading, querying, and retrieving attachments.
|
|
259
|
+
* This is what applications (editors, Connect, CLI tools) interact with.
|
|
260
|
+
*/
|
|
261
|
+
interface IAttachmentService {
|
|
262
|
+
/**
|
|
263
|
+
* Reserve a new attachment slot and return an upload handle.
|
|
264
|
+
*
|
|
265
|
+
* When options.clientHash is provided (hash-first mode):
|
|
266
|
+
* - @throws AttachmentAlreadyExists if data for that hash is currently
|
|
267
|
+
* available. The error carries the canonical ref; the caller uses it
|
|
268
|
+
* directly and uploads nothing (dedup fast path).
|
|
269
|
+
* - If the hash is evicted, the reservation is created: the client holds
|
|
270
|
+
* the bytes and the upload restores them.
|
|
271
|
+
* - If the hash is pending (another in-flight reservation), the
|
|
272
|
+
* reservation is created: concurrent reservations are deliberately
|
|
273
|
+
* permitted (see design doc -- no uniqueness race).
|
|
274
|
+
* - The returned handle's ref field is set immediately to the computed ref.
|
|
275
|
+
*
|
|
276
|
+
* When options.clientHash is absent (upload-first mode):
|
|
277
|
+
* - No pre-check against the store.
|
|
278
|
+
* - The returned handle's ref field is null until send() completes.
|
|
279
|
+
*/
|
|
280
|
+
reserve(options: ReserveAttachmentOptions): Promise<IAttachmentUpload>;
|
|
281
|
+
/**
|
|
282
|
+
* Get attachment metadata by ref.
|
|
283
|
+
*
|
|
284
|
+
* @throws AttachmentNotFound if the ref is unknown.
|
|
285
|
+
* Returns an AttachmentHeader with status='pending' and expiresAtUtc set if
|
|
286
|
+
* the hash has an active reservation but no committed bytes. Callers must
|
|
287
|
+
* check header.status to distinguish pending from available.
|
|
288
|
+
*/
|
|
289
|
+
stat(ref: AttachmentRef): Promise<AttachmentHeader>;
|
|
290
|
+
/**
|
|
291
|
+
* Retrieve attachment data.
|
|
292
|
+
*
|
|
293
|
+
* Always succeeds for any known, available ref. The underlying store
|
|
294
|
+
* handles re-fetching evicted data from the transport transparently.
|
|
295
|
+
*
|
|
296
|
+
* @throws AttachmentPending if the hash is reserved but bytes not yet
|
|
297
|
+
* available. There is no store-level wait; polling across the
|
|
298
|
+
* pending window is the caller's loop, bounded by the error's
|
|
299
|
+
* expiresAtUtc. A wait inside get() would hold request handlers
|
|
300
|
+
* open across multi-second windows and hide retry policy where
|
|
301
|
+
* callers cannot tune it.
|
|
302
|
+
*/
|
|
303
|
+
get(ref: AttachmentRef, signal?: AbortSignal): Promise<AttachmentResponse>;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Upload handle returned by reserve(). Encapsulates all transport-specific
|
|
307
|
+
* concerns (URLs, credentials, streaming protocols) behind a single send() method.
|
|
308
|
+
*/
|
|
309
|
+
interface IAttachmentUpload {
|
|
310
|
+
/**
|
|
311
|
+
* Unique identifier for this reservation.
|
|
312
|
+
*/
|
|
313
|
+
reservationId: string;
|
|
314
|
+
/**
|
|
315
|
+
* The ref this upload will produce. Set immediately when the
|
|
316
|
+
* reservation carries a client hash (hash-first mode); null in the
|
|
317
|
+
* upload-first flow, where the ref is only known after send() completes.
|
|
318
|
+
*/
|
|
319
|
+
ref: AttachmentRef | null;
|
|
320
|
+
/**
|
|
321
|
+
* Reservation TTL contract, from the server in remote mode.
|
|
322
|
+
* ISO 8601 UTC string indicating when the reservation expires.
|
|
323
|
+
* Clients use this to bound retry windows and populate the pending-upload queue.
|
|
324
|
+
*/
|
|
325
|
+
readonly expiresAtUtc: string;
|
|
326
|
+
/**
|
|
327
|
+
* Stream attachment data through this handle.
|
|
328
|
+
*
|
|
329
|
+
* The handle manages the full upload lifecycle internally:
|
|
330
|
+
* writing bytes to the backing store, computing or verifying
|
|
331
|
+
* the content hash, creating the attachment record, and
|
|
332
|
+
* cleaning up the reservation.
|
|
333
|
+
*
|
|
334
|
+
* Dedup: if an attachment with the same content hash already
|
|
335
|
+
* exists, send() returns the existing ref. Content-addressed
|
|
336
|
+
* storage means identical uploads converge on the same hash.
|
|
337
|
+
*
|
|
338
|
+
* When the reservation carries a client hash, the handle verifies
|
|
339
|
+
* the received bytes against the claims:
|
|
340
|
+
* - @throws SizeMismatch if the byte count differs from the declared
|
|
341
|
+
* sizeBytes. The handle may reject mid-stream as soon as the count
|
|
342
|
+
* exceeds the declaration, without consuming the rest.
|
|
343
|
+
* - @throws HashMismatch if the server-computed hash differs from the
|
|
344
|
+
* claimed hash. Nothing is committed; the reservation is retained
|
|
345
|
+
* so the client can retry with the correct bytes.
|
|
346
|
+
*
|
|
347
|
+
* @returns The content hash, ref, and header for the uploaded attachment.
|
|
348
|
+
*/
|
|
349
|
+
send(data: ReadableStream<Uint8Array>): Promise<AttachmentUploadResult>;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Read-only subset of IAttachmentStore.
|
|
353
|
+
*
|
|
354
|
+
* Adapters that cannot safely support the local-only write/GC surface
|
|
355
|
+
* (remote stores, forwarding caches) implement this narrow interface
|
|
356
|
+
* instead of stub-rejecting unsupported methods. Consumers that only
|
|
357
|
+
* need to query metadata or stream attachment bytes can take this type
|
|
358
|
+
* to make their dependency requirements explicit.
|
|
359
|
+
*/
|
|
360
|
+
interface IAttachmentReader {
|
|
361
|
+
/**
|
|
362
|
+
* Get attachment metadata without streaming body data.
|
|
363
|
+
* Does NOT update lastAccessedAtUtc -- this is a metadata check,
|
|
364
|
+
* not a data access.
|
|
365
|
+
*
|
|
366
|
+
* @throws AttachmentNotFound if the hash is unknown.
|
|
367
|
+
* Returns an AttachmentHeader with status='pending' and expiresAtUtc set if
|
|
368
|
+
* the hash has an active reservation but no committed bytes. Callers must
|
|
369
|
+
* check header.status to distinguish pending from available.
|
|
370
|
+
*/
|
|
371
|
+
stat(hash: AttachmentHash): Promise<AttachmentHeader>;
|
|
372
|
+
/**
|
|
373
|
+
* Retrieve attachment header and data stream by hash.
|
|
374
|
+
* Updates lastAccessedAtUtc on access.
|
|
375
|
+
*
|
|
376
|
+
* If the data has been evicted, re-fetches it from the transport,
|
|
377
|
+
* restores it locally via put(), and returns the data. This makes
|
|
378
|
+
* eviction transparent to callers -- get() always succeeds for
|
|
379
|
+
* any known, available hash.
|
|
380
|
+
*
|
|
381
|
+
* @throws AttachmentNotFound if the hash is unknown (no metadata
|
|
382
|
+
* record exists and no pending reservation).
|
|
383
|
+
* @throws AttachmentPending if the hash is reserved by an in-flight
|
|
384
|
+
* upload; bytes are not yet available. There is no store-level
|
|
385
|
+
* wait -- polling is the caller's responsibility.
|
|
386
|
+
*/
|
|
387
|
+
get(hash: AttachmentHash, signal?: AbortSignal): Promise<AttachmentResponse>;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Reactor-facing interface for managing local attachment data.
|
|
391
|
+
* The IAttachmentTransport calls put when it receives data from a remote.
|
|
392
|
+
* The store notifies its configured transport when new data arrives,
|
|
393
|
+
* forming a bidirectional store-transport pair.
|
|
394
|
+
*/
|
|
395
|
+
interface IAttachmentStore extends IAttachmentReader {
|
|
396
|
+
/**
|
|
397
|
+
* Check whether attachment data is available locally.
|
|
398
|
+
* Returns true if the bytes can be served from this reactor's store
|
|
399
|
+
* without a transport round-trip. Does not trigger a remote fetch.
|
|
400
|
+
* Returns false for pending and evicted hashes.
|
|
401
|
+
*/
|
|
402
|
+
has(hash: AttachmentHash): Promise<boolean>;
|
|
403
|
+
/**
|
|
404
|
+
* Store attachment data received from a remote (during sync or re-fetch).
|
|
405
|
+
* Called by IAttachmentTransport implementations during sync, and
|
|
406
|
+
* internally by get() when restoring evicted data.
|
|
407
|
+
*
|
|
408
|
+
* Behavior depends on existing state:
|
|
409
|
+
* - No existing row: INSERT with source='sync', status='available'.
|
|
410
|
+
* - Existing row with status='evicted': restore data, set status
|
|
411
|
+
* to 'available'.
|
|
412
|
+
* - Existing row with status='available': no-op (dedup).
|
|
413
|
+
*/
|
|
414
|
+
put(hash: AttachmentHash, metadata: AttachmentMetadata, data: ReadableStream<Uint8Array>): Promise<void>;
|
|
415
|
+
/**
|
|
416
|
+
* Evict attachment data to reclaim storage.
|
|
417
|
+
*
|
|
418
|
+
* Removes the local bytes and sets status to 'evicted'. The
|
|
419
|
+
* metadata record is retained so the hash is still known. If the
|
|
420
|
+
* data is needed again, the service fetches it via the transport.
|
|
421
|
+
*
|
|
422
|
+
* Eviction must not destroy data while a get() stream is in
|
|
423
|
+
* flight. Implementations must skip hashes with active readers
|
|
424
|
+
* (e.g. via a refcount or lease) and revisit them on the next
|
|
425
|
+
* GC pass.
|
|
426
|
+
*
|
|
427
|
+
* On immutable backends, this unpins/stops serving rather
|
|
428
|
+
* than deleting.
|
|
429
|
+
*/
|
|
430
|
+
evict(hash: AttachmentHash): Promise<void>;
|
|
431
|
+
/**
|
|
432
|
+
* Get the total storage used by locally available attachment data.
|
|
433
|
+
* Used by the GC policy to decide when to evict.
|
|
434
|
+
*/
|
|
435
|
+
storageUsed(): Promise<number>;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Transport for moving attachment data between reactors.
|
|
439
|
+
*
|
|
440
|
+
* Forms a bidirectional pair with IAttachmentStore. The store calls
|
|
441
|
+
* announce/push when new data arrives locally. The transport calls
|
|
442
|
+
* store.put() when data arrives from a remote.
|
|
443
|
+
*/
|
|
444
|
+
interface IAttachmentTransport {
|
|
445
|
+
/**
|
|
446
|
+
* Fetch attachment data by hash from a remote source.
|
|
447
|
+
*
|
|
448
|
+
* Returns a three-way discriminated union so callers can distinguish
|
|
449
|
+
* "data available", "upload in flight -- retry after expiry", and
|
|
450
|
+
* "not found -- possibly permanently". Conflating the last two would
|
|
451
|
+
* cause callers to apply long backoff to transient pending state,
|
|
452
|
+
* or to retry indefinitely on a permanently missing hash.
|
|
453
|
+
*
|
|
454
|
+
* @param hash - Content hash of the attachment
|
|
455
|
+
* @param signal - Abort signal for cancellation
|
|
456
|
+
*/
|
|
457
|
+
fetch(hash: AttachmentHash, signal?: AbortSignal): Promise<TransportFetchResult>;
|
|
458
|
+
/**
|
|
459
|
+
* Announce that this reactor has attachment data available.
|
|
460
|
+
*
|
|
461
|
+
* For server-centric transports, this may be a no-op (the server
|
|
462
|
+
* already has the data after upload).
|
|
463
|
+
*/
|
|
464
|
+
announce(hash: AttachmentHash): Promise<void>;
|
|
465
|
+
/**
|
|
466
|
+
* Push attachment data to a specific remote.
|
|
467
|
+
*
|
|
468
|
+
* Used for eager replication strategies where the source reactor
|
|
469
|
+
* pushes data to known peers rather than waiting for pull requests.
|
|
470
|
+
*
|
|
471
|
+
* @param hash - Content hash of the attachment
|
|
472
|
+
* @param remote - Target remote identifier
|
|
473
|
+
* @param data - The attachment data stream
|
|
474
|
+
*/
|
|
475
|
+
push(hash: AttachmentHash, remote: string, data: ReadableStream<Uint8Array>): Promise<void>;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Factory for creating attachment transport instances.
|
|
479
|
+
* Mirrors IChannelFactory for operation sync.
|
|
480
|
+
*/
|
|
481
|
+
interface IAttachmentTransportFactory {
|
|
482
|
+
instance(config: AttachmentTransportConfig): IAttachmentTransport;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Store for managing attachment reservations.
|
|
486
|
+
* Reservations are transient records tracking in-progress uploads.
|
|
487
|
+
*/
|
|
488
|
+
interface IReservationStore {
|
|
489
|
+
create(options: ReserveAttachmentOptions): Promise<Reservation>;
|
|
490
|
+
get(reservationId: string): Promise<Reservation>;
|
|
491
|
+
delete(reservationId: string): Promise<void>;
|
|
492
|
+
/**
|
|
493
|
+
* Delete reservations whose expires_at_utc is at or before `now`.
|
|
494
|
+
* Returns the number of rows deleted.
|
|
495
|
+
*
|
|
496
|
+
* Reservations are not auto-swept; consumers should call this on a
|
|
497
|
+
* cron / interval to clean up rows left behind by aborted uploads.
|
|
498
|
+
*/
|
|
499
|
+
deleteExpired(now?: Date): Promise<number>;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Factory for creating transport-specific upload handles.
|
|
503
|
+
* The service calls this during reserve() to create a handle
|
|
504
|
+
* that knows how to stream bytes to the appropriate backend.
|
|
505
|
+
*/
|
|
506
|
+
interface IAttachmentUploadFactory {
|
|
507
|
+
createUpload(reservation: Reservation): IAttachmentUpload;
|
|
508
|
+
}
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region src/attachment-service.d.ts
|
|
511
|
+
declare class AttachmentService implements IAttachmentService {
|
|
512
|
+
private readonly store;
|
|
513
|
+
private readonly reservations;
|
|
514
|
+
private readonly uploadFactory;
|
|
515
|
+
constructor(store: IAttachmentReader, reservations: IReservationStore, uploadFactory: IAttachmentUploadFactory);
|
|
516
|
+
reserve(options: ReserveAttachmentOptions): Promise<IAttachmentUpload>;
|
|
517
|
+
stat(ref: AttachmentRef): Promise<AttachmentHeader>;
|
|
518
|
+
get(ref: AttachmentRef, signal?: AbortSignal): Promise<AttachmentResponse>;
|
|
519
|
+
private reserveHashFirst;
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region src/ref.d.ts
|
|
523
|
+
type ParsedRef = {
|
|
524
|
+
version: number;
|
|
525
|
+
hash: AttachmentHash;
|
|
526
|
+
};
|
|
527
|
+
declare function parseRef(ref: AttachmentRef): ParsedRef;
|
|
528
|
+
declare function createRef(hash: AttachmentHash, version?: number): AttachmentRef;
|
|
529
|
+
//#endregion
|
|
530
|
+
//#region src/switchboard/switchboard-attachment-transport.d.ts
|
|
531
|
+
type SwitchboardTransportConfig = {
|
|
532
|
+
remoteUrl: string;
|
|
533
|
+
jwtHandler?: JwtHandler;
|
|
534
|
+
fetchFn?: typeof fetch;
|
|
535
|
+
};
|
|
536
|
+
declare class SwitchboardAttachmentTransport implements IAttachmentTransport {
|
|
537
|
+
private readonly remoteUrl;
|
|
538
|
+
private readonly jwtHandler?;
|
|
539
|
+
private readonly fetchFn;
|
|
540
|
+
constructor(config: SwitchboardTransportConfig);
|
|
541
|
+
fetch(hash: AttachmentHash, signal?: AbortSignal): Promise<TransportFetchResult>;
|
|
542
|
+
announce(_hash: AttachmentHash): Promise<void>;
|
|
543
|
+
push(hash: AttachmentHash, remote: string, data: ReadableStream<Uint8Array>): Promise<void>;
|
|
544
|
+
private parsePendingExpiry;
|
|
545
|
+
private parseMetadataHeaders;
|
|
546
|
+
}
|
|
547
|
+
//#endregion
|
|
548
|
+
//#region src/switchboard/remote-reservation-store.d.ts
|
|
549
|
+
type SwitchboardClientConfig = {
|
|
550
|
+
remoteUrl: string;
|
|
551
|
+
jwtHandler?: JwtHandler;
|
|
552
|
+
fetchFn?: typeof fetch;
|
|
553
|
+
};
|
|
554
|
+
declare class RemoteReservationStore implements IReservationStore {
|
|
555
|
+
private readonly remoteUrl;
|
|
556
|
+
private readonly jwtHandler?;
|
|
557
|
+
private readonly fetchFn;
|
|
558
|
+
constructor(config: SwitchboardClientConfig);
|
|
559
|
+
create(options: ReserveAttachmentOptions): Promise<Reservation>;
|
|
560
|
+
get(reservationId: string): Promise<Reservation>;
|
|
561
|
+
delete(reservationId: string): Promise<void>;
|
|
562
|
+
deleteExpired(): Promise<number>;
|
|
563
|
+
}
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/switchboard/remote-attachment-upload.d.ts
|
|
566
|
+
declare class RemoteAttachmentUpload implements IAttachmentUpload {
|
|
567
|
+
readonly reservationId: string;
|
|
568
|
+
readonly ref: AttachmentRef | null;
|
|
569
|
+
readonly expiresAtUtc: string;
|
|
570
|
+
private readonly remoteUrl;
|
|
571
|
+
private readonly jwtHandler?;
|
|
572
|
+
private readonly fetchFn;
|
|
573
|
+
constructor(reservation: Reservation, config: SwitchboardClientConfig);
|
|
574
|
+
send(data: ReadableStream<Uint8Array>): Promise<AttachmentUploadResult>;
|
|
575
|
+
}
|
|
576
|
+
//#endregion
|
|
577
|
+
//#region src/switchboard/remote-attachment-upload-factory.d.ts
|
|
578
|
+
declare class RemoteAttachmentUploadFactory implements IAttachmentUploadFactory {
|
|
579
|
+
private readonly config;
|
|
580
|
+
constructor(config: SwitchboardClientConfig);
|
|
581
|
+
createUpload(reservation: Reservation): IAttachmentUpload;
|
|
582
|
+
}
|
|
583
|
+
//#endregion
|
|
584
|
+
//#region src/switchboard/remote-attachment-store.d.ts
|
|
585
|
+
declare class RemoteAttachmentStore implements IAttachmentReader {
|
|
586
|
+
private readonly remoteUrl;
|
|
587
|
+
private readonly jwtHandler?;
|
|
588
|
+
private readonly fetchFn;
|
|
589
|
+
constructor(config: SwitchboardClientConfig);
|
|
590
|
+
/**
|
|
591
|
+
* Get attachment metadata. Normally returns a pending AttachmentHeader
|
|
592
|
+
* (status: 'pending') when the server responds 202 with a full
|
|
593
|
+
* Attachment-Pending header. When only expiresAtUtc is present in the
|
|
594
|
+
* header (degraded wire), throws AttachmentPending instead -- the
|
|
595
|
+
* AttachmentPending throw is the degraded-wire case.
|
|
596
|
+
*/
|
|
597
|
+
stat(hash: AttachmentHash): Promise<AttachmentHeader>;
|
|
598
|
+
get(hash: AttachmentHash, signal?: AbortSignal): Promise<AttachmentResponse>;
|
|
599
|
+
private fetchAttachment;
|
|
600
|
+
}
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region src/switchboard/create-remote-attachment-service.d.ts
|
|
603
|
+
declare function createRemoteAttachmentService(config: SwitchboardClientConfig): IAttachmentService;
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/null-attachment-transport.d.ts
|
|
606
|
+
/**
|
|
607
|
+
* No-op transport for deployments without remote sync.
|
|
608
|
+
* fetch() always returns not-found, announce() and push() are no-ops.
|
|
609
|
+
*/
|
|
610
|
+
declare class NullAttachmentTransport implements IAttachmentTransport {
|
|
611
|
+
fetch(): Promise<TransportFetchResult>;
|
|
612
|
+
announce(): Promise<void>;
|
|
613
|
+
push(): Promise<void>;
|
|
614
|
+
}
|
|
615
|
+
//#endregion
|
|
616
|
+
export { ReserveAttachmentOptions as A, SizeMismatch as B, AttachmentMetadata as C, AttachmentUploadResult as D, AttachmentTransportConfig as E, AttachmentNotFound as F, AttachmentPending as I, HashMismatch as L, TransportResponse as M, UploadFirstReserveAttachmentOptions as N, HashFirstReserveAttachmentOptions as O, AttachmentAlreadyExists as P, InvalidAttachmentRef as R, AttachmentHeader as S, AttachmentStatus as T, UploadTooLarge as V, IAttachmentTransport as _, RemoteAttachmentUpload as a, IAttachmentUploadFactory as b, SwitchboardAttachmentTransport as c, createRef as d, parseRef as f, IAttachmentStore as g, IAttachmentService as h, RemoteAttachmentUploadFactory as i, TransportFetchResult as j, Reservation as k, SwitchboardTransportConfig as l, IAttachmentReader as m, createRemoteAttachmentService as n, RemoteReservationStore as o, AttachmentService as p, RemoteAttachmentStore as r, SwitchboardClientConfig as s, NullAttachmentTransport as t, ParsedRef as u, IAttachmentTransportFactory as v, AttachmentResponse as w, IReservationStore as x, IAttachmentUpload as y, ReservationNotFound as z };
|
|
617
|
+
//# sourceMappingURL=null-attachment-transport-BBhQIk5A.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-attachment-transport-BBhQIk5A.d.ts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/interfaces.ts","../src/attachment-service.ts","../src/ref.ts","../src/switchboard/switchboard-attachment-transport.ts","../src/switchboard/remote-reservation-store.ts","../src/switchboard/remote-attachment-upload.ts","../src/switchboard/remote-attachment-upload-factory.ts","../src/switchboard/remote-attachment-store.ts","../src/switchboard/create-remote-attachment-service.ts","../src/null-attachment-transport.ts"],"mappings":"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"}
|