@powerhousedao/reactor-attachments 6.2.3-dev.8 → 6.2.3-staging.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 +51 -36
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +20 -4
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +53 -85
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -156
- package/dist/index.js.map +1 -1
- package/dist/{null-attachment-transport-CMrO_ZKA.d.ts → null-attachment-transport-BkM6rq4R.d.ts} +30 -18
- package/dist/null-attachment-transport-BkM6rq4R.d.ts.map +1 -0
- package/dist/{null-attachment-transport-CrsUafCi.js → null-attachment-transport-D53Rz9lE.js} +20 -13
- package/dist/null-attachment-transport-D53Rz9lE.js.map +1 -0
- package/package.json +6 -6
- package/dist/null-attachment-transport-CMrO_ZKA.d.ts.map +0 -1
- package/dist/null-attachment-transport-CrsUafCi.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as UploadTooLarge, S as SizeMismatch, _ as AttachmentPending, a as RemoteAttachmentUpload, b as InvalidAttachmentRef, c as createFetchUploadTransport, d as createRef, f as parseRef, g as AttachmentNotFound, h as AttachmentAlreadyExists, i as RemoteAttachmentUploadFactory, l as SwitchboardAttachmentTransport, m as parseAttachmentUploadTarget, n as createRemoteAttachmentService, o as RemoteReservationStore, p as parseAttachmentDownloadTarget, r as RemoteAttachmentStore, s as createXhrUploadTransport, t as NullAttachmentTransport, u as AttachmentService, v as AttachmentTransferError, x as ReservationNotFound, y as HashMismatch } from "./null-attachment-transport-
|
|
1
|
+
import { C as UploadTooLarge, S as SizeMismatch, _ as AttachmentPending, a as RemoteAttachmentUpload, b as InvalidAttachmentRef, c as createFetchUploadTransport, d as createRef, f as parseRef, g as AttachmentNotFound, h as AttachmentAlreadyExists, i as RemoteAttachmentUploadFactory, l as SwitchboardAttachmentTransport, m as parseAttachmentUploadTarget, n as createRemoteAttachmentService, o as RemoteReservationStore, p as parseAttachmentDownloadTarget, r as RemoteAttachmentStore, s as createXhrUploadTransport, t as NullAttachmentTransport, u as AttachmentService, v as AttachmentTransferError, x as ReservationNotFound, y as HashMismatch } from "./null-attachment-transport-D53Rz9lE.js";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { Migrator, sql } from "kysely";
|
|
4
4
|
import { mkdir, rename, rm } from "node:fs/promises";
|
|
@@ -9,7 +9,7 @@ import { finished } from "node:stream/promises";
|
|
|
9
9
|
import { generatorTypeDefs } from "@powerhousedao/document-engineering/graphql";
|
|
10
10
|
import { constantCase, pascalCase } from "change-case";
|
|
11
11
|
import { Kind, buildASTSchema, getNamedType, isInputObjectType, isListType, isNonNullType, parse, print } from "graphql";
|
|
12
|
-
import { BaseReadModel } from "@powerhousedao/reactor";
|
|
12
|
+
import { BaseReadModel, defaultReadModelIndexingConfig } from "@powerhousedao/reactor";
|
|
13
13
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
14
14
|
import { GetObjectCommand, HeadObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
15
15
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
@@ -262,6 +262,9 @@ function wrapStreamWithCleanup(source, cleanup) {
|
|
|
262
262
|
});
|
|
263
263
|
}
|
|
264
264
|
var KyselyAttachmentStore = class {
|
|
265
|
+
db;
|
|
266
|
+
transport;
|
|
267
|
+
basePath;
|
|
265
268
|
activeReaders = /* @__PURE__ */ new Map();
|
|
266
269
|
constructor(db, transport, basePath) {
|
|
267
270
|
this.db = db;
|
|
@@ -290,18 +293,10 @@ var KyselyAttachmentStore = class {
|
|
|
290
293
|
async has(hash) {
|
|
291
294
|
return (await this.db.selectFrom("attachment").select("status").where("hash", "=", hash).executeTakeFirst())?.status === "available";
|
|
292
295
|
}
|
|
293
|
-
async get(hash, signal) {
|
|
296
|
+
async get(hash, signal, documentId) {
|
|
294
297
|
const row = await this.db.selectFrom("attachment").selectAll().where("hash", "=", hash).executeTakeFirst();
|
|
295
298
|
if (row) {
|
|
296
|
-
if (row.status === "evicted")
|
|
297
|
-
const remote = await this.transport.fetch(hash, signal);
|
|
298
|
-
if (remote.kind === "data") {
|
|
299
|
-
await this.put(hash, remote.response.metadata, remote.response.body);
|
|
300
|
-
return this.get(hash, signal);
|
|
301
|
-
}
|
|
302
|
-
if (remote.kind === "pending") throw new AttachmentPending(hash, remote.expiresAtUtc);
|
|
303
|
-
throw new AttachmentNotFound(hash);
|
|
304
|
-
}
|
|
299
|
+
if (row.status === "evicted") return this.fetchRemote(hash, signal, documentId);
|
|
305
300
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
306
301
|
await this.db.updateTable("attachment").set({ last_accessed_at_utc: now }).where("hash", "=", hash).execute();
|
|
307
302
|
const header = rowToHeader$1(row);
|
|
@@ -319,13 +314,7 @@ var KyselyAttachmentStore = class {
|
|
|
319
314
|
fileName: pending.file_name,
|
|
320
315
|
sizeBytes: pending.size_bytes
|
|
321
316
|
});
|
|
322
|
-
|
|
323
|
-
if (remote.kind === "data") {
|
|
324
|
-
await this.put(hash, remote.response.metadata, remote.response.body);
|
|
325
|
-
return this.get(hash, signal);
|
|
326
|
-
}
|
|
327
|
-
if (remote.kind === "pending") throw new AttachmentPending(hash, remote.expiresAtUtc);
|
|
328
|
-
throw new AttachmentNotFound(hash);
|
|
317
|
+
return this.fetchRemote(hash, signal, documentId);
|
|
329
318
|
}
|
|
330
319
|
async put(hash, metadata, data) {
|
|
331
320
|
const existing = await this.db.selectFrom("attachment").select(["hash", "status"]).where("hash", "=", hash).executeTakeFirst();
|
|
@@ -365,6 +354,16 @@ var KyselyAttachmentStore = class {
|
|
|
365
354
|
const result = await this.db.selectFrom("attachment").select(sql`COALESCE(SUM(size_bytes), 0)`.as("total")).where("status", "=", "available").executeTakeFirst();
|
|
366
355
|
return Number(result?.total ?? 0);
|
|
367
356
|
}
|
|
357
|
+
async fetchRemote(hash, signal, documentId) {
|
|
358
|
+
if (documentId === void 0) throw new AttachmentNotFound(hash);
|
|
359
|
+
const remote = await this.transport.fetch(hash, documentId, signal);
|
|
360
|
+
if (remote.kind === "data") {
|
|
361
|
+
await this.put(hash, remote.response.metadata, remote.response.body);
|
|
362
|
+
return this.get(hash, signal);
|
|
363
|
+
}
|
|
364
|
+
if (remote.kind === "pending") throw new AttachmentPending(hash, remote.expiresAtUtc);
|
|
365
|
+
throw new AttachmentNotFound(hash);
|
|
366
|
+
}
|
|
368
367
|
async findPendingReservation(hash, now) {
|
|
369
368
|
const row = await this.db.selectFrom("attachment_reservation as r").leftJoin("attachment as a", "a.hash", "r.client_hash").select([
|
|
370
369
|
"r.mime_type",
|
|
@@ -398,7 +397,7 @@ var KyselyAttachmentStore = class {
|
|
|
398
397
|
};
|
|
399
398
|
//#endregion
|
|
400
399
|
//#region src/storage/kysely/reservation-store.ts
|
|
401
|
-
const DEFAULT_RESERVATION_TTL_MS =
|
|
400
|
+
const DEFAULT_RESERVATION_TTL_MS = 864e5;
|
|
402
401
|
function rowToReservation(row) {
|
|
403
402
|
return {
|
|
404
403
|
reservationId: row.reservation_id,
|
|
@@ -412,6 +411,7 @@ function rowToReservation(row) {
|
|
|
412
411
|
};
|
|
413
412
|
}
|
|
414
413
|
var KyselyReservationStore = class {
|
|
414
|
+
db;
|
|
415
415
|
ttlMs;
|
|
416
416
|
constructor(db, ttlMs = DEFAULT_RESERVATION_TTL_MS) {
|
|
417
417
|
this.db = db;
|
|
@@ -601,6 +601,11 @@ function rowToHeader(row) {
|
|
|
601
601
|
};
|
|
602
602
|
}
|
|
603
603
|
var DirectAttachmentUpload = class {
|
|
604
|
+
reservation;
|
|
605
|
+
db;
|
|
606
|
+
basePath;
|
|
607
|
+
reservations;
|
|
608
|
+
maxBytes;
|
|
604
609
|
reservationId;
|
|
605
610
|
ref;
|
|
606
611
|
expiresAtUtc;
|
|
@@ -670,6 +675,10 @@ var DirectAttachmentUpload = class {
|
|
|
670
675
|
//#endregion
|
|
671
676
|
//#region src/direct/direct-attachment-upload-factory.ts
|
|
672
677
|
var DirectAttachmentUploadFactory = class {
|
|
678
|
+
db;
|
|
679
|
+
basePath;
|
|
680
|
+
reservations;
|
|
681
|
+
maxBytes;
|
|
673
682
|
constructor(db, basePath, reservations, maxBytes) {
|
|
674
683
|
this.db = db;
|
|
675
684
|
this.basePath = basePath;
|
|
@@ -688,6 +697,8 @@ var DirectAttachmentUploadFactory = class {
|
|
|
688
697
|
* can never accidentally return a direct-provider target.
|
|
689
698
|
*/
|
|
690
699
|
var FilesystemAttachmentBackend = class {
|
|
700
|
+
store;
|
|
701
|
+
config;
|
|
691
702
|
kind = "filesystem";
|
|
692
703
|
constructor(store, config) {
|
|
693
704
|
this.store = store;
|
|
@@ -739,6 +750,8 @@ var S3AttachmentUploadFactory = class {
|
|
|
739
750
|
//#endregion
|
|
740
751
|
//#region src/attachment-builder.ts
|
|
741
752
|
var AttachmentBuilder = class {
|
|
753
|
+
db;
|
|
754
|
+
storagePath;
|
|
742
755
|
transport = new NullAttachmentTransport();
|
|
743
756
|
customUploadFactory;
|
|
744
757
|
maxUploadBytes;
|
|
@@ -811,7 +824,7 @@ var AttachmentBuilder = class {
|
|
|
811
824
|
//#endregion
|
|
812
825
|
//#region src/reference-index/attachment-schema-compiler.ts
|
|
813
826
|
const ATTACHMENT_REF_TYPE = "AttachmentRef";
|
|
814
|
-
const CODEGEN_SCALAR_NAMES = new Set([
|
|
827
|
+
const CODEGEN_SCALAR_NAMES = /* @__PURE__ */ new Set([
|
|
815
828
|
"Unknown",
|
|
816
829
|
"DateTime",
|
|
817
830
|
"Address",
|
|
@@ -859,11 +872,12 @@ function buildEffectiveSchema(specification, context) {
|
|
|
859
872
|
const stateSchemas = Object.values(specification.state).map((state) => state.schema);
|
|
860
873
|
const operationSchemas = specification.modules.flatMap((moduleSpecification) => moduleSpecification.operations.flatMap((operation) => operation.schema === null ? [] : [operation.schema]));
|
|
861
874
|
try {
|
|
862
|
-
|
|
875
|
+
const document = parse([
|
|
863
876
|
...scalarSchemas,
|
|
864
877
|
...stateSchemas,
|
|
865
878
|
...operationSchemas
|
|
866
|
-
].filter(Boolean).join("\n\n"))
|
|
879
|
+
].filter(Boolean).join("\n\n"));
|
|
880
|
+
return buildASTSchema(dedupeTypeDefinitions(document));
|
|
867
881
|
} catch {
|
|
868
882
|
throw compilationError(context, "the effective GraphQL schema is invalid");
|
|
869
883
|
}
|
|
@@ -1001,6 +1015,8 @@ function extractValue(plan, value, path, context, refs, seenRefs, activeObjects)
|
|
|
1001
1015
|
}
|
|
1002
1016
|
}
|
|
1003
1017
|
var SchemaCompiledAttachmentExtractor = class {
|
|
1018
|
+
context;
|
|
1019
|
+
rootPlan;
|
|
1004
1020
|
constructor(context, rootPlan) {
|
|
1005
1021
|
this.context = context;
|
|
1006
1022
|
this.rootPlan = rootPlan;
|
|
@@ -1063,12 +1079,16 @@ var AttachmentSchemaCompiler = class {
|
|
|
1063
1079
|
//#endregion
|
|
1064
1080
|
//#region src/read-models/attachment-reference/kysely-attachment-reference-store.ts
|
|
1065
1081
|
var KyselyAttachmentReferenceStore = class {
|
|
1082
|
+
db;
|
|
1066
1083
|
constructor(db) {
|
|
1067
1084
|
this.db = db;
|
|
1068
1085
|
}
|
|
1069
1086
|
async hasReference(documentId, ref) {
|
|
1070
1087
|
return await this.db.selectFrom("attachment_reference").select("document_id").where("document_id", "=", documentId).where("attachment_ref", "=", ref).executeTakeFirst() !== void 0;
|
|
1071
1088
|
}
|
|
1089
|
+
async referencingScopes(documentId, ref) {
|
|
1090
|
+
return (await this.db.selectFrom("attachment_reference").select("scope").distinct().where("document_id", "=", documentId).where("attachment_ref", "=", ref).execute()).map((row) => row.scope);
|
|
1091
|
+
}
|
|
1072
1092
|
async addReferences(references) {
|
|
1073
1093
|
if (references.length === 0) return;
|
|
1074
1094
|
await this.db.insertInto("attachment_reference").values(references.map((reference) => ({
|
|
@@ -1160,6 +1180,7 @@ async function getAttachmentReferenceMigrationStatus(db, schema = ATTACHMENT_REF
|
|
|
1160
1180
|
//#endregion
|
|
1161
1181
|
//#region src/read-models/attachment-reference/index-builder.ts
|
|
1162
1182
|
var AttachmentReferenceIndexBuilder = class {
|
|
1183
|
+
db;
|
|
1163
1184
|
constructor(db) {
|
|
1164
1185
|
this.db = db;
|
|
1165
1186
|
}
|
|
@@ -1172,49 +1193,28 @@ var AttachmentReferenceIndexBuilder = class {
|
|
|
1172
1193
|
//#endregion
|
|
1173
1194
|
//#region src/read-models/attachment-reference/attachment-reference-read-model.ts
|
|
1174
1195
|
const ATTACHMENT_REFERENCE_READ_MODEL_ID = "attachment-reference-read-model";
|
|
1196
|
+
/**
|
|
1197
|
+
* Indexes attachment references in chunks.
|
|
1198
|
+
*
|
|
1199
|
+
* Each reference row stands on its own and is written insert-or-do-nothing, so
|
|
1200
|
+
* a batch that commits in pieces exposes no partial structure, and re-indexing
|
|
1201
|
+
* the same range writes nothing new: the catch-up sweep needs no stream suffix.
|
|
1202
|
+
*/
|
|
1175
1203
|
var AttachmentReferenceReadModel = class extends BaseReadModel {
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
* How far a replay may skip ahead of the cursor: the highest ordinal already
|
|
1180
|
-
* pulled from the index while the cursor was parked.
|
|
1181
|
-
*
|
|
1182
|
-
* NOT a claim that every ordinal below it committed -- the parked ordinal is
|
|
1183
|
-
* precisely the one that did not -- so it is a hint, and {@link replayFrom}
|
|
1184
|
-
* re-probes the gap before honouring it.
|
|
1185
|
-
*/
|
|
1186
|
-
replayedThrough;
|
|
1187
|
-
warnedCheckpoint;
|
|
1204
|
+
documentModelRegistry;
|
|
1205
|
+
schemaCompiler;
|
|
1206
|
+
referenceWriter;
|
|
1188
1207
|
constructor(db, operationIndex, writeCache, consistencyTracker, documentModelRegistry, schemaCompiler, referenceWriter) {
|
|
1189
1208
|
super(db, operationIndex, writeCache, consistencyTracker, {
|
|
1190
1209
|
readModelId: ATTACHMENT_REFERENCE_READ_MODEL_ID,
|
|
1191
|
-
rebuildStateOnInit: false
|
|
1210
|
+
rebuildStateOnInit: false,
|
|
1211
|
+
indexing: defaultReadModelIndexingConfig,
|
|
1212
|
+
replayStreamSuffix: false
|
|
1192
1213
|
});
|
|
1193
1214
|
this.documentModelRegistry = documentModelRegistry;
|
|
1194
1215
|
this.schemaCompiler = schemaCompiler;
|
|
1195
1216
|
this.referenceWriter = referenceWriter;
|
|
1196
1217
|
}
|
|
1197
|
-
indexOperations(items) {
|
|
1198
|
-
return this.enqueue(() => this.indexOperationsInOrdinalOrder(items));
|
|
1199
|
-
}
|
|
1200
|
-
init() {
|
|
1201
|
-
return this.enqueue(async () => {
|
|
1202
|
-
const viewState = await this.loadState();
|
|
1203
|
-
if (viewState !== void 0) this.lastOrdinal = viewState;
|
|
1204
|
-
else await this.initializeState();
|
|
1205
|
-
let page = await this.operationIndex.getSinceOrdinal(this.lastOrdinal);
|
|
1206
|
-
while (page.results.length > 0) {
|
|
1207
|
-
await this.indexOperationsInOrdinalOrder(page.results);
|
|
1208
|
-
if (!page.next) break;
|
|
1209
|
-
page = await page.next();
|
|
1210
|
-
}
|
|
1211
|
-
});
|
|
1212
|
-
}
|
|
1213
|
-
enqueue(work) {
|
|
1214
|
-
const result = this.indexingQueue.then(work);
|
|
1215
|
-
this.indexingQueue = result.catch(() => void 0);
|
|
1216
|
-
return result;
|
|
1217
|
-
}
|
|
1218
1218
|
async commitOperations(items) {
|
|
1219
1219
|
const references = [];
|
|
1220
1220
|
for (const { operation, context } of items) {
|
|
@@ -1232,102 +1232,6 @@ var AttachmentReferenceReadModel = class extends BaseReadModel {
|
|
|
1232
1232
|
}
|
|
1233
1233
|
if (references.length > 0) await this.referenceWriter.addReferences(references);
|
|
1234
1234
|
}
|
|
1235
|
-
async indexOperationsInOrdinalOrder(incoming) {
|
|
1236
|
-
let candidates = this.sortAndDedupe(incoming);
|
|
1237
|
-
if (candidates.length === 0) return;
|
|
1238
|
-
const incomingMax = candidates[candidates.length - 1].context.ordinal;
|
|
1239
|
-
if (this.contiguousEnd(candidates) < incomingMax) {
|
|
1240
|
-
const replayed = await this.loadThroughOrdinal(incomingMax);
|
|
1241
|
-
candidates = this.sortAndDedupe([...replayed, ...candidates]);
|
|
1242
|
-
}
|
|
1243
|
-
const checkpoint = this.contiguousEnd(candidates);
|
|
1244
|
-
if (checkpoint < incomingMax && checkpoint !== this.warnedCheckpoint) {
|
|
1245
|
-
this.warnedCheckpoint = checkpoint;
|
|
1246
|
-
console.warn(`[${this.config.readModelId}] indexed through ordinal ${incomingMax} but parked the cursor at ${checkpoint}: ordinal ${checkpoint + 1} is missing`);
|
|
1247
|
-
}
|
|
1248
|
-
const previousOrdinal = this.lastOrdinal;
|
|
1249
|
-
this.checkpointTarget = checkpoint;
|
|
1250
|
-
try {
|
|
1251
|
-
await super.indexOperations(candidates);
|
|
1252
|
-
} catch (error) {
|
|
1253
|
-
this.lastOrdinal = previousOrdinal;
|
|
1254
|
-
this.replayedThrough = void 0;
|
|
1255
|
-
throw error;
|
|
1256
|
-
} finally {
|
|
1257
|
-
this.checkpointTarget = void 0;
|
|
1258
|
-
}
|
|
1259
|
-
if (checkpoint > previousOrdinal) this.replayedThrough = void 0;
|
|
1260
|
-
else if (checkpoint < incomingMax) this.replayedThrough = Math.max(this.replayedThrough ?? checkpoint, incomingMax);
|
|
1261
|
-
}
|
|
1262
|
-
/**
|
|
1263
|
-
* Writes the cursor parked by indexOperationsInOrdinalOrder instead of the
|
|
1264
|
-
* batch maximum, so indexing an operation above a gap never advances past it.
|
|
1265
|
-
*/
|
|
1266
|
-
async saveState(trx, items) {
|
|
1267
|
-
const target = this.checkpointTarget;
|
|
1268
|
-
if (target === void 0) {
|
|
1269
|
-
await super.saveState(trx, items);
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
this.lastOrdinal = target;
|
|
1273
|
-
await trx.updateTable("ViewState").set({
|
|
1274
|
-
lastOrdinal: target,
|
|
1275
|
-
lastOperationTimestamp: /* @__PURE__ */ new Date()
|
|
1276
|
-
}).where("readModelId", "=", this.config.readModelId).execute();
|
|
1277
|
-
}
|
|
1278
|
-
/** Last ordinal of the contiguous run starting at lastOrdinal + 1. */
|
|
1279
|
-
contiguousEnd(items) {
|
|
1280
|
-
let expectedOrdinal = this.lastOrdinal + 1;
|
|
1281
|
-
for (const item of items) {
|
|
1282
|
-
const ordinal = item.context.ordinal;
|
|
1283
|
-
if (ordinal < expectedOrdinal) continue;
|
|
1284
|
-
if (ordinal > expectedOrdinal) break;
|
|
1285
|
-
expectedOrdinal++;
|
|
1286
|
-
}
|
|
1287
|
-
return expectedOrdinal - 1;
|
|
1288
|
-
}
|
|
1289
|
-
/**
|
|
1290
|
-
* Opens a replay at the lowest ordinal still worth reading.
|
|
1291
|
-
*
|
|
1292
|
-
* {@link replayedThrough} is what keeps a permanently held hole -- a
|
|
1293
|
-
* rolled-back insert, which never fills -- from re-reading the whole tail on
|
|
1294
|
-
* every batch. It cannot be trusted on its own: a hole that fills without
|
|
1295
|
-
* being delivered here is visible only in the index, and a mark that is
|
|
1296
|
-
* never questioned would hide that operation for the life of the process.
|
|
1297
|
-
* That happens whenever another writer commits the gap (a second reactor on
|
|
1298
|
-
* the same database), and it leaves the cursor parked below an operation
|
|
1299
|
-
* whose references were never written -- `hasReference` then answers false
|
|
1300
|
-
* for an attachment that is genuinely referenced.
|
|
1301
|
-
*
|
|
1302
|
-
* So a parked batch spends one page probing the gap: the first row above the
|
|
1303
|
-
* cursor is the missing ordinal itself once it commits. Finding it drops the
|
|
1304
|
-
* mark and replays from the cursor; not finding it leaves the mark standing,
|
|
1305
|
-
* which is the cheap path and the common one.
|
|
1306
|
-
*/
|
|
1307
|
-
async replayFrom() {
|
|
1308
|
-
const fromCursor = await this.operationIndex.getSinceOrdinal(this.lastOrdinal);
|
|
1309
|
-
if (this.replayedThrough === void 0) return fromCursor;
|
|
1310
|
-
if (fromCursor.results[0]?.context.ordinal === this.lastOrdinal + 1) {
|
|
1311
|
-
this.replayedThrough = void 0;
|
|
1312
|
-
return fromCursor;
|
|
1313
|
-
}
|
|
1314
|
-
return this.operationIndex.getSinceOrdinal(this.replayedThrough);
|
|
1315
|
-
}
|
|
1316
|
-
async loadThroughOrdinal(maxOrdinal) {
|
|
1317
|
-
const operations = [];
|
|
1318
|
-
let page = await this.replayFrom();
|
|
1319
|
-
for (;;) {
|
|
1320
|
-
for (const item of page.results) if (item.context.ordinal <= maxOrdinal) operations.push(item);
|
|
1321
|
-
if (page.results.some(({ context }) => context.ordinal >= maxOrdinal) || !page.next) break;
|
|
1322
|
-
page = await page.next();
|
|
1323
|
-
}
|
|
1324
|
-
return operations;
|
|
1325
|
-
}
|
|
1326
|
-
sortAndDedupe(items) {
|
|
1327
|
-
const byOrdinal = /* @__PURE__ */ new Map();
|
|
1328
|
-
for (const item of items) byOrdinal.set(item.context.ordinal, item);
|
|
1329
|
-
return [...byOrdinal.values()].sort((left, right) => left.context.ordinal - right.context.ordinal);
|
|
1330
|
-
}
|
|
1331
1235
|
};
|
|
1332
1236
|
//#endregion
|
|
1333
1237
|
//#region src/storage/s3/config.ts
|
|
@@ -1341,7 +1245,7 @@ function required(env, name) {
|
|
|
1341
1245
|
if (value.trim() !== value) throw new Error(`${name} must not have leading or trailing whitespace`);
|
|
1342
1246
|
return value;
|
|
1343
1247
|
}
|
|
1344
|
-
const LOOPBACK_HOSTNAMES = new Set([
|
|
1248
|
+
const LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
1345
1249
|
"127.0.0.1",
|
|
1346
1250
|
"localhost",
|
|
1347
1251
|
"[::1]"
|
|
@@ -1423,9 +1327,10 @@ function sha256HexToBase64(hash) {
|
|
|
1423
1327
|
//#region src/storage/s3/primitives.ts
|
|
1424
1328
|
const defaultPresigner = (client, command, expiresInSeconds) => getSignedUrl(client, command, {
|
|
1425
1329
|
expiresIn: expiresInSeconds,
|
|
1426
|
-
unhoistableHeaders: new Set(["x-amz-checksum-sha256"])
|
|
1330
|
+
unhoistableHeaders: /* @__PURE__ */ new Set(["x-amz-checksum-sha256"])
|
|
1427
1331
|
});
|
|
1428
1332
|
var S3AttachmentPrimitives = class {
|
|
1333
|
+
config;
|
|
1429
1334
|
client;
|
|
1430
1335
|
presign;
|
|
1431
1336
|
now;
|
|
@@ -1496,7 +1401,7 @@ function createS3AttachmentPrimitives(config, dependencies = {}) {
|
|
|
1496
1401
|
//#endregion
|
|
1497
1402
|
//#region src/storage/s3/backend.ts
|
|
1498
1403
|
const READINESS_PROBE_HASH = "0".repeat(64);
|
|
1499
|
-
const OBJECT_NOT_FOUND_NAMES = new Set([
|
|
1404
|
+
const OBJECT_NOT_FOUND_NAMES = /* @__PURE__ */ new Set([
|
|
1500
1405
|
"NotFound",
|
|
1501
1406
|
"NoSuchKey",
|
|
1502
1407
|
"NoSuchObject"
|
|
@@ -1514,6 +1419,8 @@ function requireHashFirstReservation(reservation) {
|
|
|
1514
1419
|
}
|
|
1515
1420
|
/** Server-only S3 capability. Callers complete authorization before download. */
|
|
1516
1421
|
var S3AttachmentBackend = class {
|
|
1422
|
+
db;
|
|
1423
|
+
config;
|
|
1517
1424
|
kind = "s3";
|
|
1518
1425
|
primitives;
|
|
1519
1426
|
now;
|