@noy-db/hub 0.4.0-pre.3 → 0.4.0-pre.4
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/cargo/index.js +2 -2
- package/dist/{chunk-GU5AYA2Q.js → chunk-4X6DJZHY.js} +2 -2
- package/dist/{chunk-N4A3DCBT.js → chunk-5KI3REO3.js} +2 -2
- package/dist/{chunk-OWLPX2GI.js → chunk-BLB7P7LS.js} +2 -2
- package/dist/{chunk-J6U4BOKP.js → chunk-JW3XCZA2.js} +9 -9
- package/dist/{chunk-UBF7HTOR.js → chunk-QUIG6BZT.js} +15 -15
- package/dist/{chunk-UBF7HTOR.js.map → chunk-QUIG6BZT.js.map} +1 -1
- package/dist/{chunk-SN75YVM5.js → chunk-U73LHVPF.js} +15 -15
- package/dist/{chunk-SN75YVM5.js.map → chunk-U73LHVPF.js.map} +1 -1
- package/dist/{chunk-LUH2MPEF.js → chunk-W7TCXZWU.js} +423 -467
- package/dist/chunk-W7TCXZWU.js.map +1 -0
- package/dist/{collection-facade-ENLTJZBT.js → collection-facade-CMZGQ6IS.js} +2 -2
- package/dist/index.js +7 -7
- package/dist/kernel/collection-config.d.ts +11 -69
- package/dist/kernel/collection.d.ts +10 -21
- package/dist/kernel/noydb.d.ts +11 -12
- package/dist/kernel/vault.d.ts +21 -68
- package/dist/{noydb-KUX2TJMX.js → noydb-N5IW6OFZ.js} +7 -7
- package/dist/port/with/archive-strategy.d.ts +31 -0
- package/dist/port/with/strategies.d.ts +134 -0
- package/dist/query/index.js +1 -1
- package/dist/team/index.js +1 -1
- package/dist/tiers/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-LUH2MPEF.js.map +0 -1
- /package/dist/{chunk-GU5AYA2Q.js.map → chunk-4X6DJZHY.js.map} +0 -0
- /package/dist/{chunk-N4A3DCBT.js.map → chunk-5KI3REO3.js.map} +0 -0
- /package/dist/{chunk-OWLPX2GI.js.map → chunk-BLB7P7LS.js.map} +0 -0
- /package/dist/{chunk-J6U4BOKP.js.map → chunk-JW3XCZA2.js.map} +0 -0
- /package/dist/{collection-facade-ENLTJZBT.js.map → collection-facade-CMZGQ6IS.js.map} +0 -0
- /package/dist/{noydb-KUX2TJMX.js.map → noydb-N5IW6OFZ.js.map} +0 -0
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
buildPersistedIndexCallbacks,
|
|
32
32
|
encodeVecId,
|
|
33
33
|
syncTierSearch
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-JW3XCZA2.js";
|
|
35
35
|
import {
|
|
36
36
|
derivePersistedSchema,
|
|
37
37
|
isZod4Schema
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
CustodyApi,
|
|
45
45
|
NO_CARGO,
|
|
46
46
|
NO_CUSTODY
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-U73LHVPF.js";
|
|
48
48
|
import {
|
|
49
49
|
resolveManagedSecret,
|
|
50
50
|
saveSealedPassphrase
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
NO_TIERS,
|
|
73
73
|
classifySealedShred,
|
|
74
74
|
syncDerivedOutputs
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-5KI3REO3.js";
|
|
76
76
|
import {
|
|
77
77
|
NO_PORTABILITY
|
|
78
78
|
} from "./chunk-GYB2QK5H.js";
|
|
@@ -115,7 +115,7 @@ import {
|
|
|
115
115
|
NO_AGGREGATE,
|
|
116
116
|
Query,
|
|
117
117
|
ScanBuilder
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-4X6DJZHY.js";
|
|
119
119
|
import {
|
|
120
120
|
EXPORT_AUDIT_COLLECTION,
|
|
121
121
|
createExportBlobsHandle,
|
|
@@ -163,7 +163,7 @@ import {
|
|
|
163
163
|
rotatePassphrase,
|
|
164
164
|
updateAuthenticator,
|
|
165
165
|
writeMagicLinkGrant
|
|
166
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-QUIG6BZT.js";
|
|
167
167
|
import {
|
|
168
168
|
assertKeyringOpenAllowed,
|
|
169
169
|
buildRecipientKeyringFile,
|
|
@@ -293,6 +293,284 @@ import {
|
|
|
293
293
|
ValidationError
|
|
294
294
|
} from "./chunk-IGM563N5.js";
|
|
295
295
|
|
|
296
|
+
// src/via/blob/binding.ts
|
|
297
|
+
async function eraseBlobs(ctx, cfg) {
|
|
298
|
+
if (cfg.purgeBlobsForRecord) return cfg.purgeBlobsForRecord(ctx.id);
|
|
299
|
+
return { shredded: 0, residue: [] };
|
|
300
|
+
}
|
|
301
|
+
function buildBlobDescribeFragment(fields) {
|
|
302
|
+
return {
|
|
303
|
+
blobFields: Object.fromEntries(
|
|
304
|
+
Object.entries(fields).map(([field, p]) => [field, {
|
|
305
|
+
...p.retainDays !== void 0 ? { retainDays: p.retainDays } : {},
|
|
306
|
+
...p.evictWhen !== void 0 ? { evictWhen: true } : {},
|
|
307
|
+
...p.legalHold !== void 0 ? { legalHold: true } : {},
|
|
308
|
+
...p.retainUntil !== void 0 ? { retainUntil: true } : {},
|
|
309
|
+
...p.external === true ? { external: true } : {},
|
|
310
|
+
...p.public === true ? { public: true } : {},
|
|
311
|
+
...p.backlink !== void 0 ? { backlink: p.backlink } : {}
|
|
312
|
+
}])
|
|
313
|
+
)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function blobBinding(cfg) {
|
|
317
|
+
return {
|
|
318
|
+
brand: "blob",
|
|
319
|
+
// encryptedAtRest: 'envelope' — blob chunks are AEAD-encrypted envelopes
|
|
320
|
+
// in `_blob_chunks` (service-side), not sealed record fields; queryable:
|
|
321
|
+
// 'none' — nothing indexes blob content; exportable — vault.exportBlobs()
|
|
322
|
+
// is a first-class door; forgettable — shredAllForRecord participates in
|
|
323
|
+
// vault.forget().
|
|
324
|
+
posture: { encryptedAtRest: "envelope", queryable: "none", exportable: true, forgettable: true },
|
|
325
|
+
covers: (field) => field in cfg.fields,
|
|
326
|
+
erase: (ctx) => eraseBlobs(ctx, cfg),
|
|
327
|
+
describeFragment: () => buildBlobDescribeFragment(cfg.fields)
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function linkBlobVia() {
|
|
331
|
+
installViaBinder("blob", (c) => blobBinding(c));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/port/with/blob-strategy.ts
|
|
335
|
+
linkBlobVia();
|
|
336
|
+
var NO_BLOBS = {
|
|
337
|
+
openSlot() {
|
|
338
|
+
throw new Error(
|
|
339
|
+
'Blob storage is not enabled on this Noydb instance. Import `{ withBlobs }` from "@noy-db/hub/blobs" and pass `withBlobs()` to `createNoydb({ blobStrategy: withBlobs() })`.'
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// src/with-audit/consent/strategy.ts
|
|
345
|
+
var NO_CONSENT = {
|
|
346
|
+
async write() {
|
|
347
|
+
},
|
|
348
|
+
async read() {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// src/with-commit/crdt/strategy.ts
|
|
354
|
+
var NOT_ENABLED = new Error(
|
|
355
|
+
'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from "@noy-db/hub/crdt" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.'
|
|
356
|
+
);
|
|
357
|
+
var NO_CRDT = {
|
|
358
|
+
buildLwwMapState() {
|
|
359
|
+
throw NOT_ENABLED;
|
|
360
|
+
},
|
|
361
|
+
buildRgaState() {
|
|
362
|
+
throw NOT_ENABLED;
|
|
363
|
+
},
|
|
364
|
+
mergeCrdtStates() {
|
|
365
|
+
throw NOT_ENABLED;
|
|
366
|
+
},
|
|
367
|
+
resolveCrdtSnapshot() {
|
|
368
|
+
throw NOT_ENABLED;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// src/with-commit/history/strategy.ts
|
|
373
|
+
function notEnabled(op) {
|
|
374
|
+
return new Error(
|
|
375
|
+
`${op} requires the history strategy. Import \`{ withHistory }\` from "@noy-db/hub/history" and pass it to \`createNoydb({ historyStrategy: withHistory() })\`.`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
var NO_HISTORY = {
|
|
379
|
+
async saveHistory() {
|
|
380
|
+
},
|
|
381
|
+
async getHistoryEntries() {
|
|
382
|
+
throw notEnabled("collection.history()");
|
|
383
|
+
},
|
|
384
|
+
async getVersionEnvelope() {
|
|
385
|
+
throw notEnabled("collection.getVersion()");
|
|
386
|
+
},
|
|
387
|
+
async pruneHistory() {
|
|
388
|
+
return 0;
|
|
389
|
+
},
|
|
390
|
+
async clearHistory() {
|
|
391
|
+
return 0;
|
|
392
|
+
},
|
|
393
|
+
async tombstoneHistory() {
|
|
394
|
+
return 0;
|
|
395
|
+
},
|
|
396
|
+
async rewrapHistory() {
|
|
397
|
+
},
|
|
398
|
+
async envelopePayloadHash() {
|
|
399
|
+
return "";
|
|
400
|
+
},
|
|
401
|
+
computePatch() {
|
|
402
|
+
return [];
|
|
403
|
+
},
|
|
404
|
+
diff() {
|
|
405
|
+
throw notEnabled("collection.diff()");
|
|
406
|
+
},
|
|
407
|
+
buildLedger() {
|
|
408
|
+
return null;
|
|
409
|
+
},
|
|
410
|
+
buildVaultInstant() {
|
|
411
|
+
throw notEnabled("vault.at() / vault.timeMachine()");
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// src/with-lookup/indexing/strategy.ts
|
|
416
|
+
var NO_INDEXING = {
|
|
417
|
+
createState() {
|
|
418
|
+
return DISABLED_STATE;
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
var DISABLED_STATE = {
|
|
422
|
+
isEnabled: false,
|
|
423
|
+
getEagerIndexes: () => null,
|
|
424
|
+
getPersistedIndexes: () => null
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// src/with-audit/periods/strategy.ts
|
|
428
|
+
var NOT_ENABLED2 = new Error(
|
|
429
|
+
'Accounting periods require the periods strategy. Import `{ withPeriods }` from "@noy-db/hub/periods" and pass it to `createNoydb({ periodsStrategy: withPeriods() })`.'
|
|
430
|
+
);
|
|
431
|
+
var NO_PERIODS = {
|
|
432
|
+
async loadPeriods() {
|
|
433
|
+
return [];
|
|
434
|
+
},
|
|
435
|
+
async chainAnchor() {
|
|
436
|
+
return { priorPeriodHash: "" };
|
|
437
|
+
},
|
|
438
|
+
assertTsWritable() {
|
|
439
|
+
},
|
|
440
|
+
validatePeriodName() {
|
|
441
|
+
throw NOT_ENABLED2;
|
|
442
|
+
},
|
|
443
|
+
async appendPeriodLedgerEntry() {
|
|
444
|
+
throw NOT_ENABLED2;
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// src/with-party/session/strategy.ts
|
|
449
|
+
function notEnabled2(op) {
|
|
450
|
+
return new Error(
|
|
451
|
+
`${op} requires the session strategy. Import \`{ withSession }\` from "@noy-db/hub/session" and pass it to \`createNoydb({ sessionStrategy: withSession() })\`.`
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
var NO_SESSION = {
|
|
455
|
+
validateSessionPolicy() {
|
|
456
|
+
throw notEnabled2("sessionPolicy");
|
|
457
|
+
},
|
|
458
|
+
createEnforcer() {
|
|
459
|
+
throw notEnabled2("session policy enforcement");
|
|
460
|
+
},
|
|
461
|
+
revokeAllSessions() {
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// src/with-fork/shadow/strategy.ts
|
|
466
|
+
var NOT_ENABLED3 = new Error(
|
|
467
|
+
'VaultFrame requires the shadow strategy. Import `{ withShadow }` from "@noy-db/hub/shadow" and pass it to `createNoydb({ shadowStrategy: withShadow() })`.'
|
|
468
|
+
);
|
|
469
|
+
var NO_SHADOW = {
|
|
470
|
+
buildFrame() {
|
|
471
|
+
throw NOT_ENABLED3;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
// src/with-fork/snapshots/strategy.ts
|
|
476
|
+
var NOT_ENABLED4 = new Error(
|
|
477
|
+
'Snapshots require the snapshot strategy. Import `{ withSnapshots }` from "@noy-db/hub/snapshots" and pass it to `createNoydb({ snapshotStrategy: withSnapshots({ store }) })`.'
|
|
478
|
+
);
|
|
479
|
+
var NO_SNAPSHOTS = {
|
|
480
|
+
async snapshot() {
|
|
481
|
+
throw NOT_ENABLED4;
|
|
482
|
+
},
|
|
483
|
+
async listSnapshots() {
|
|
484
|
+
throw NOT_ENABLED4;
|
|
485
|
+
},
|
|
486
|
+
async restoreSnapshot() {
|
|
487
|
+
throw NOT_ENABLED4;
|
|
488
|
+
},
|
|
489
|
+
async autoSnapshot() {
|
|
490
|
+
throw NOT_ENABLED4;
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
// src/with-party/team/sync-strategy.ts
|
|
495
|
+
function notEnabled3(op) {
|
|
496
|
+
return new Error(
|
|
497
|
+
`${op} requires the sync strategy. Import \`{ withSync }\` from "@noy-db/hub/sync" and pass it to \`createNoydb({ syncStrategy: withSync() })\`.`
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
var NO_SYNC = {
|
|
501
|
+
buildSyncEngine() {
|
|
502
|
+
throw notEnabled3("SyncEngine");
|
|
503
|
+
},
|
|
504
|
+
buildSyncTransaction() {
|
|
505
|
+
throw notEnabled3("SyncTransaction");
|
|
506
|
+
},
|
|
507
|
+
buildPresence() {
|
|
508
|
+
throw notEnabled3("collection.presence()");
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// src/with-commit/tx/strategy.ts
|
|
513
|
+
var NOT_ENABLED5 = new Error(
|
|
514
|
+
'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/tx" and pass it to `createNoydb({ txStrategy: withTransactions() })`.'
|
|
515
|
+
);
|
|
516
|
+
var NO_TX = {
|
|
517
|
+
async runTransaction(_db, _fn, _options, _txInvariants) {
|
|
518
|
+
throw NOT_ENABLED5;
|
|
519
|
+
},
|
|
520
|
+
async runDryRun() {
|
|
521
|
+
throw NOT_ENABLED5;
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
// src/port/with/archive-strategy.ts
|
|
526
|
+
var ARCHIVE_NOT_ENABLED = "vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb";
|
|
527
|
+
var NO_ARCHIVE = {
|
|
528
|
+
get store() {
|
|
529
|
+
throw new Error(ARCHIVE_NOT_ENABLED);
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// src/port/with/strategies.ts
|
|
534
|
+
var STRATEGY_DEFAULTS = {
|
|
535
|
+
aggregate: NO_AGGREGATE,
|
|
536
|
+
archive: NO_ARCHIVE,
|
|
537
|
+
attestation: NO_ATTESTATION,
|
|
538
|
+
blob: NO_BLOBS,
|
|
539
|
+
broker: NO_BROKER,
|
|
540
|
+
cargo: NO_CARGO,
|
|
541
|
+
classified: NO_CLASSIFIED,
|
|
542
|
+
consent: NO_CONSENT,
|
|
543
|
+
crdt: NO_CRDT,
|
|
544
|
+
custody: NO_CUSTODY,
|
|
545
|
+
forget: NO_FORGET,
|
|
546
|
+
history: NO_HISTORY,
|
|
547
|
+
i18n: NO_I18N,
|
|
548
|
+
index: NO_INDEXING,
|
|
549
|
+
lazy: IMPLICIT_LAZY,
|
|
550
|
+
periods: NO_PERIODS,
|
|
551
|
+
portability: NO_PORTABILITY,
|
|
552
|
+
sealedRecord: NO_SEALED_RECORD,
|
|
553
|
+
search: NO_SEARCH,
|
|
554
|
+
sequence: NO_SEQUENCE,
|
|
555
|
+
session: NO_SESSION,
|
|
556
|
+
shadow: NO_SHADOW,
|
|
557
|
+
snapshot: NO_SNAPSHOTS,
|
|
558
|
+
sync: NO_SYNC,
|
|
559
|
+
team: NO_TEAM,
|
|
560
|
+
tiers: NO_TIERS,
|
|
561
|
+
tx: NO_TX
|
|
562
|
+
};
|
|
563
|
+
var STRATEGY_KEYS = Object.keys(STRATEGY_DEFAULTS);
|
|
564
|
+
function resolveStrategies(options) {
|
|
565
|
+
const provided = options;
|
|
566
|
+
const resolved = { ...STRATEGY_DEFAULTS };
|
|
567
|
+
for (const key of STRATEGY_KEYS) {
|
|
568
|
+
const value = provided[`${key}Strategy`];
|
|
569
|
+
if (value !== void 0) resolved[key] = value;
|
|
570
|
+
}
|
|
571
|
+
return resolved;
|
|
572
|
+
}
|
|
573
|
+
|
|
296
574
|
// src/port/by/default-provider.ts
|
|
297
575
|
async function createDefaultCoordinationProvider(store) {
|
|
298
576
|
const { StoreCoordinationProvider } = await import("./store-coordination-provider-3AELCZ4Y.js");
|
|
@@ -964,61 +1242,6 @@ async function resolveTierSyncPrior(ctx, id, priorEnvelope) {
|
|
|
964
1242
|
return await ctx.codec.decryptRecord(priorEnvelope, { skipValidation: true, id });
|
|
965
1243
|
}
|
|
966
1244
|
|
|
967
|
-
// src/with-commit/history/strategy.ts
|
|
968
|
-
function notEnabled(op) {
|
|
969
|
-
return new Error(
|
|
970
|
-
`${op} requires the history strategy. Import \`{ withHistory }\` from "@noy-db/hub/history" and pass it to \`createNoydb({ historyStrategy: withHistory() })\`.`
|
|
971
|
-
);
|
|
972
|
-
}
|
|
973
|
-
var NO_HISTORY = {
|
|
974
|
-
async saveHistory() {
|
|
975
|
-
},
|
|
976
|
-
async getHistoryEntries() {
|
|
977
|
-
throw notEnabled("collection.history()");
|
|
978
|
-
},
|
|
979
|
-
async getVersionEnvelope() {
|
|
980
|
-
throw notEnabled("collection.getVersion()");
|
|
981
|
-
},
|
|
982
|
-
async pruneHistory() {
|
|
983
|
-
return 0;
|
|
984
|
-
},
|
|
985
|
-
async clearHistory() {
|
|
986
|
-
return 0;
|
|
987
|
-
},
|
|
988
|
-
async tombstoneHistory() {
|
|
989
|
-
return 0;
|
|
990
|
-
},
|
|
991
|
-
async rewrapHistory() {
|
|
992
|
-
},
|
|
993
|
-
async envelopePayloadHash() {
|
|
994
|
-
return "";
|
|
995
|
-
},
|
|
996
|
-
computePatch() {
|
|
997
|
-
return [];
|
|
998
|
-
},
|
|
999
|
-
diff() {
|
|
1000
|
-
throw notEnabled("collection.diff()");
|
|
1001
|
-
},
|
|
1002
|
-
buildLedger() {
|
|
1003
|
-
return null;
|
|
1004
|
-
},
|
|
1005
|
-
buildVaultInstant() {
|
|
1006
|
-
throw notEnabled("vault.at() / vault.timeMachine()");
|
|
1007
|
-
}
|
|
1008
|
-
};
|
|
1009
|
-
|
|
1010
|
-
// src/with-lookup/indexing/strategy.ts
|
|
1011
|
-
var NO_INDEXING = {
|
|
1012
|
-
createState() {
|
|
1013
|
-
return DISABLED_STATE;
|
|
1014
|
-
}
|
|
1015
|
-
};
|
|
1016
|
-
var DISABLED_STATE = {
|
|
1017
|
-
isEnabled: false,
|
|
1018
|
-
getEagerIndexes: () => null,
|
|
1019
|
-
getPersistedIndexes: () => null
|
|
1020
|
-
};
|
|
1021
|
-
|
|
1022
1245
|
// src/with-lookup/search/serialize.ts
|
|
1023
1246
|
function serializeIndex(idx) {
|
|
1024
1247
|
return JSON.stringify(idx.toSnapshot());
|
|
@@ -1621,54 +1844,6 @@ function buildDescription(input) {
|
|
|
1621
1844
|
};
|
|
1622
1845
|
}
|
|
1623
1846
|
|
|
1624
|
-
// src/via/blob/binding.ts
|
|
1625
|
-
async function eraseBlobs(ctx, cfg) {
|
|
1626
|
-
if (cfg.purgeBlobsForRecord) return cfg.purgeBlobsForRecord(ctx.id);
|
|
1627
|
-
return { shredded: 0, residue: [] };
|
|
1628
|
-
}
|
|
1629
|
-
function buildBlobDescribeFragment(fields) {
|
|
1630
|
-
return {
|
|
1631
|
-
blobFields: Object.fromEntries(
|
|
1632
|
-
Object.entries(fields).map(([field, p]) => [field, {
|
|
1633
|
-
...p.retainDays !== void 0 ? { retainDays: p.retainDays } : {},
|
|
1634
|
-
...p.evictWhen !== void 0 ? { evictWhen: true } : {},
|
|
1635
|
-
...p.legalHold !== void 0 ? { legalHold: true } : {},
|
|
1636
|
-
...p.retainUntil !== void 0 ? { retainUntil: true } : {},
|
|
1637
|
-
...p.external === true ? { external: true } : {},
|
|
1638
|
-
...p.public === true ? { public: true } : {},
|
|
1639
|
-
...p.backlink !== void 0 ? { backlink: p.backlink } : {}
|
|
1640
|
-
}])
|
|
1641
|
-
)
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
function blobBinding(cfg) {
|
|
1645
|
-
return {
|
|
1646
|
-
brand: "blob",
|
|
1647
|
-
// encryptedAtRest: 'envelope' — blob chunks are AEAD-encrypted envelopes
|
|
1648
|
-
// in `_blob_chunks` (service-side), not sealed record fields; queryable:
|
|
1649
|
-
// 'none' — nothing indexes blob content; exportable — vault.exportBlobs()
|
|
1650
|
-
// is a first-class door; forgettable — shredAllForRecord participates in
|
|
1651
|
-
// vault.forget().
|
|
1652
|
-
posture: { encryptedAtRest: "envelope", queryable: "none", exportable: true, forgettable: true },
|
|
1653
|
-
covers: (field) => field in cfg.fields,
|
|
1654
|
-
erase: (ctx) => eraseBlobs(ctx, cfg),
|
|
1655
|
-
describeFragment: () => buildBlobDescribeFragment(cfg.fields)
|
|
1656
|
-
};
|
|
1657
|
-
}
|
|
1658
|
-
function linkBlobVia() {
|
|
1659
|
-
installViaBinder("blob", (c) => blobBinding(c));
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
// src/port/with/blob-strategy.ts
|
|
1663
|
-
linkBlobVia();
|
|
1664
|
-
var NO_BLOBS = {
|
|
1665
|
-
openSlot() {
|
|
1666
|
-
throw new Error(
|
|
1667
|
-
'Blob storage is not enabled on this Noydb instance. Import `{ withBlobs }` from "@noy-db/hub/blobs" and pass `withBlobs()` to `createNoydb({ blobStrategy: withBlobs() })`.'
|
|
1668
|
-
);
|
|
1669
|
-
}
|
|
1670
|
-
};
|
|
1671
|
-
|
|
1672
1847
|
// src/with-formula/derivations/stale.ts
|
|
1673
1848
|
var _staleByRegistry = /* @__PURE__ */ new WeakMap();
|
|
1674
1849
|
var keyFor = (source, sourceId) => `${source}/${sourceId}`;
|
|
@@ -1742,43 +1917,6 @@ async function resolveStaleOnRead(accessor, outputCollection, id) {
|
|
|
1742
1917
|
}
|
|
1743
1918
|
}
|
|
1744
1919
|
|
|
1745
|
-
// src/with-commit/crdt/strategy.ts
|
|
1746
|
-
var NOT_ENABLED = new Error(
|
|
1747
|
-
'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from "@noy-db/hub/crdt" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.'
|
|
1748
|
-
);
|
|
1749
|
-
var NO_CRDT = {
|
|
1750
|
-
buildLwwMapState() {
|
|
1751
|
-
throw NOT_ENABLED;
|
|
1752
|
-
},
|
|
1753
|
-
buildRgaState() {
|
|
1754
|
-
throw NOT_ENABLED;
|
|
1755
|
-
},
|
|
1756
|
-
mergeCrdtStates() {
|
|
1757
|
-
throw NOT_ENABLED;
|
|
1758
|
-
},
|
|
1759
|
-
resolveCrdtSnapshot() {
|
|
1760
|
-
throw NOT_ENABLED;
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
|
-
// src/with-party/team/sync-strategy.ts
|
|
1765
|
-
function notEnabled2(op) {
|
|
1766
|
-
return new Error(
|
|
1767
|
-
`${op} requires the sync strategy. Import \`{ withSync }\` from "@noy-db/hub/sync" and pass it to \`createNoydb({ syncStrategy: withSync() })\`.`
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
var NO_SYNC = {
|
|
1771
|
-
buildSyncEngine() {
|
|
1772
|
-
throw notEnabled2("SyncEngine");
|
|
1773
|
-
},
|
|
1774
|
-
buildSyncTransaction() {
|
|
1775
|
-
throw notEnabled2("SyncTransaction");
|
|
1776
|
-
},
|
|
1777
|
-
buildPresence() {
|
|
1778
|
-
throw notEnabled2("collection.presence()");
|
|
1779
|
-
}
|
|
1780
|
-
};
|
|
1781
|
-
|
|
1782
1920
|
// src/kernel/via/compose.ts
|
|
1783
1921
|
function via(...descriptors) {
|
|
1784
1922
|
if (descriptors.length === 0) {
|
|
@@ -1942,7 +2080,7 @@ function compileViaBindings(opts, classifiedGuardCtx, eraseCfgOut) {
|
|
|
1942
2080
|
...i18nFields !== void 0 ? { i18nFields } : {},
|
|
1943
2081
|
...dictKeyFields !== void 0 ? { dictKeyFields } : {},
|
|
1944
2082
|
...i18nDensifyFields !== void 0 ? { i18nDensifyFields } : {},
|
|
1945
|
-
strategy: opts.
|
|
2083
|
+
strategy: opts.strategies.i18n,
|
|
1946
2084
|
...opts.defaultLocale !== void 0 ? { defaultLocale: opts.defaultLocale } : {},
|
|
1947
2085
|
...opts.autoTranslateHook !== void 0 ? { autoTranslateHook: opts.autoTranslateHook } : {},
|
|
1948
2086
|
...opts.dictLabelResolver !== void 0 ? { dictLabelResolver: opts.dictLabelResolver } : {},
|
|
@@ -2177,14 +2315,9 @@ function resolveCollectionConfig(opts) {
|
|
|
2177
2315
|
writeHooks: opts.writeHooks,
|
|
2178
2316
|
subsystemBus: opts.subsystemBus,
|
|
2179
2317
|
activeTxId: opts.activeTxId,
|
|
2180
|
-
|
|
2318
|
+
strategies: opts.strategies,
|
|
2181
2319
|
objectStore: opts.objectStore,
|
|
2182
2320
|
blobFields: opts.blobFields,
|
|
2183
|
-
aggregateStrategy: opts.aggregateStrategy ?? NO_AGGREGATE,
|
|
2184
|
-
crdtStrategy: opts.crdtStrategy ?? NO_CRDT,
|
|
2185
|
-
historyStrategy: opts.historyStrategy ?? NO_HISTORY,
|
|
2186
|
-
i18nStrategy: opts.i18nStrategy ?? NO_I18N,
|
|
2187
|
-
syncStrategy: opts.syncStrategy ?? NO_SYNC,
|
|
2188
2321
|
reconcileOnOpen: opts.reconcileOnOpen ?? "off",
|
|
2189
2322
|
getDEK: opts.getDEK,
|
|
2190
2323
|
onDirty: opts.onDirty,
|
|
@@ -2213,7 +2346,6 @@ function resolveCollectionConfig(opts) {
|
|
|
2213
2346
|
moneyFields: effectiveViaFields.moneyFields,
|
|
2214
2347
|
classified: resolvedClassified,
|
|
2215
2348
|
classifiedGuardCtx,
|
|
2216
|
-
classifiedStrategy: opts.classifiedStrategy ?? NO_CLASSIFIED,
|
|
2217
2349
|
computed: mergedComputed,
|
|
2218
2350
|
computedEdges,
|
|
2219
2351
|
viaDepsEdges,
|
|
@@ -2235,8 +2367,6 @@ function resolveCollectionConfig(opts) {
|
|
|
2235
2367
|
materializedViewSource: opts.materializedViewSource,
|
|
2236
2368
|
graphDispatch: opts.graphDispatch,
|
|
2237
2369
|
tiers: opts.tiers && opts.tiers.length > 0 ? new Set(opts.tiers) : null,
|
|
2238
|
-
tiersStrategy: opts.tiersStrategy ?? NO_TIERS,
|
|
2239
|
-
searchStrategy: opts.searchStrategy ?? NO_SEARCH,
|
|
2240
2370
|
tierMode: opts.tierMode ?? "invisibility",
|
|
2241
2371
|
blobTierPolicy: opts.blobTierPolicy ?? "isolate",
|
|
2242
2372
|
onCrossTierAccess: opts.onCrossTierAccess,
|
|
@@ -2298,25 +2428,20 @@ var Collection = class {
|
|
|
2298
2428
|
/** True when the caller explicitly provided a `historyConfig` option (vs. inheriting the vault default). */
|
|
2299
2429
|
historyConfigExplicit;
|
|
2300
2430
|
/**
|
|
2301
|
-
*
|
|
2302
|
-
*
|
|
2303
|
-
*
|
|
2304
|
-
*
|
|
2305
|
-
*
|
|
2306
|
-
*
|
|
2307
|
-
* reaches the bundle
|
|
2431
|
+
* Every opt-in service, resolved once by `createNoydb` (#838) and shared by
|
|
2432
|
+
* reference with the owning `Vault` and `Noydb`.
|
|
2433
|
+
*
|
|
2434
|
+
* Each entry is a tree-shake seam. An un-opted-in service resolves to its
|
|
2435
|
+
* `NO_*` stub — a tiny module that throws with an actionable message —
|
|
2436
|
+
* so, for example, none of the BlobSet / chunk / MIME-magic machinery
|
|
2437
|
+
* reaches the bundle unless the consumer imports `@noy-db/hub/blobs` and
|
|
2438
|
+
* passes `blobStrategy: blobs()` to `createNoydb`.
|
|
2308
2439
|
*/
|
|
2309
|
-
|
|
2440
|
+
strategies;
|
|
2310
2441
|
objectStore;
|
|
2311
2442
|
blobFields;
|
|
2312
2443
|
blobTierPolicy;
|
|
2313
2444
|
// #724 T2/T3
|
|
2314
|
-
aggregateStrategy;
|
|
2315
|
-
crdtStrategy;
|
|
2316
|
-
tiersStrategy;
|
|
2317
|
-
searchStrategy;
|
|
2318
|
-
historyStrategy;
|
|
2319
|
-
syncStrategy;
|
|
2320
2445
|
// In-memory cache of decrypted records (eager mode only). Lazy mode
|
|
2321
2446
|
// uses `lru` instead. Both fields exist so a single Collection instance
|
|
2322
2447
|
// doesn't need a runtime branch on every cache access.
|
|
@@ -2486,12 +2611,6 @@ var Collection = class {
|
|
|
2486
2611
|
/** C-A/R10 memoization: marker declared-set lookup (undefined=unresolved) + classified-handle persist-once flag. */
|
|
2487
2612
|
_markerDigestOnlyCache = void 0;
|
|
2488
2613
|
_markerPersisted = false;
|
|
2489
|
-
/**
|
|
2490
|
-
* Tree-shake seam for `reveal()` — defaults to `NO_CLASSIFIED`, which
|
|
2491
|
-
* throws `ClassifiedNotEnabledError`. Set via the `classifiedStrategy`
|
|
2492
|
-
* `createNoydb()` option (opt in with `withClassified()`).
|
|
2493
|
-
*/
|
|
2494
|
-
classifiedStrategy;
|
|
2495
2614
|
/** Async callback provided by the Vault to open a dynamic dictionary handle (for label-map pre-computation in the search index). Only used in `resolveDictLabelMaps()`; static dicts bypass this entirely. Mutable, assign-once — see {@link _reconcileReadState} (#671 item 1). */
|
|
2496
2615
|
getDictionary;
|
|
2497
2616
|
/**
|
|
@@ -2640,16 +2759,10 @@ var Collection = class {
|
|
|
2640
2759
|
this.writeHooks = cfg.writeHooks;
|
|
2641
2760
|
this.subsystemBus = cfg.subsystemBus;
|
|
2642
2761
|
this.activeTxId = cfg.activeTxId;
|
|
2643
|
-
this.
|
|
2762
|
+
this.strategies = cfg.strategies;
|
|
2644
2763
|
this.objectStore = cfg.objectStore;
|
|
2645
2764
|
this.blobFields = cfg.blobFields;
|
|
2646
2765
|
this.blobTierPolicy = cfg.blobTierPolicy ?? "isolate";
|
|
2647
|
-
this.aggregateStrategy = cfg.aggregateStrategy;
|
|
2648
|
-
this.crdtStrategy = cfg.crdtStrategy;
|
|
2649
|
-
this.tiersStrategy = cfg.tiersStrategy;
|
|
2650
|
-
this.searchStrategy = cfg.searchStrategy;
|
|
2651
|
-
this.historyStrategy = cfg.historyStrategy;
|
|
2652
|
-
this.syncStrategy = cfg.syncStrategy;
|
|
2653
2766
|
this.reconcileOnOpen = cfg.reconcileOnOpen;
|
|
2654
2767
|
this.getDEK = cfg.getDEK;
|
|
2655
2768
|
this.onDirty = cfg.onDirty;
|
|
@@ -2676,7 +2789,6 @@ var Collection = class {
|
|
|
2676
2789
|
this.classified = cfg.classified;
|
|
2677
2790
|
this.classifiedGuardCtx = cfg.classifiedGuardCtx;
|
|
2678
2791
|
this.vdigFields = cfg.vdigFields;
|
|
2679
|
-
this.classifiedStrategy = cfg.classifiedStrategy;
|
|
2680
2792
|
this.computed = cfg.computed;
|
|
2681
2793
|
this.getDictionary = cfg.getDictionary;
|
|
2682
2794
|
this.defaultLocale = cfg.defaultLocale;
|
|
@@ -2724,7 +2836,7 @@ var Collection = class {
|
|
|
2724
2836
|
deterministicFields: this.deterministicFields,
|
|
2725
2837
|
vdigFields: this.vdigFields,
|
|
2726
2838
|
crdtMode: this.crdtMode,
|
|
2727
|
-
crdtStrategy: this.
|
|
2839
|
+
crdtStrategy: this.strategies.crdt,
|
|
2728
2840
|
schema: this.schema,
|
|
2729
2841
|
getDEK: (collection) => this.getDEK(collection ?? this.name),
|
|
2730
2842
|
cekCache: this.cekCache,
|
|
@@ -2742,7 +2854,7 @@ var Collection = class {
|
|
|
2742
2854
|
const remoteJson = await this.codec.decryptJsonString(remote, id);
|
|
2743
2855
|
if (localJson === null) return local;
|
|
2744
2856
|
if (remoteJson === null) return remote;
|
|
2745
|
-
const merged = this.
|
|
2857
|
+
const merged = this.strategies.crdt.mergeCrdtStates(JSON.parse(localJson), JSON.parse(remoteJson));
|
|
2746
2858
|
const mergedVersion = Math.max(local._v, remote._v) + 1;
|
|
2747
2859
|
const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
2748
2860
|
return this.codec.encryptJsonString(JSON.stringify(merged), mergedVersion, cek);
|
|
@@ -2800,12 +2912,12 @@ var Collection = class {
|
|
|
2800
2912
|
}
|
|
2801
2913
|
this.lazy = opts.prefetch === false;
|
|
2802
2914
|
if (this.lazy) {
|
|
2803
|
-
this.lru =
|
|
2915
|
+
this.lru = opts.strategies.lazy.createCache(this.name, opts.cache);
|
|
2804
2916
|
this.hydrated = true;
|
|
2805
2917
|
} else {
|
|
2806
2918
|
this.lru = null;
|
|
2807
2919
|
}
|
|
2808
|
-
const strategy = opts.
|
|
2920
|
+
const strategy = opts.strategies.index;
|
|
2809
2921
|
this.indexState = strategy.createState({
|
|
2810
2922
|
defs: opts.indexes ?? [],
|
|
2811
2923
|
lazy: this.lazy
|
|
@@ -2960,7 +3072,7 @@ var Collection = class {
|
|
|
2960
3072
|
if (spec.storage === "digest-only") {
|
|
2961
3073
|
throw new ClassifiedRevealError(this.name, field, `storage:'digest-only' \u2014 verify-only; nothing recoverable to reveal`);
|
|
2962
3074
|
}
|
|
2963
|
-
return this.
|
|
3075
|
+
return this.strategies.classified.reveal({
|
|
2964
3076
|
collection: this.name,
|
|
2965
3077
|
spec,
|
|
2966
3078
|
encrypted: this.storeCiphertext,
|
|
@@ -2980,7 +3092,7 @@ var Collection = class {
|
|
|
2980
3092
|
throw new ClassifiedVerifyError(this.name, field, `storage:'never' \u2014 nothing is stored to verify against`);
|
|
2981
3093
|
}
|
|
2982
3094
|
const ctx = this._classifiedVerifyCtx(spec);
|
|
2983
|
-
return spec.storage === "digest-only" ? this.
|
|
3095
|
+
return spec.storage === "digest-only" ? this.strategies.classified.verify(ctx, id, field, candidate) : this.strategies.classified.verifyText(ctx, id, field, candidate);
|
|
2984
3096
|
}
|
|
2985
3097
|
/** k-of-n challenge over the collection's secretAnswer members. Requires withClassified(). */
|
|
2986
3098
|
async verifyGroup(id, answers, opts) {
|
|
@@ -2989,7 +3101,7 @@ var Collection = class {
|
|
|
2989
3101
|
throw new ClassifiedVerifyError(this.name, "*", "no groupable digest-only (secretAnswer) fields declared");
|
|
2990
3102
|
}
|
|
2991
3103
|
const ctx = { ...this._classifiedVerifyCtx(members[0].spec), groupMembers: members };
|
|
2992
|
-
return this.
|
|
3104
|
+
return this.strategies.classified.matchGroup(ctx, id, answers, opts);
|
|
2993
3105
|
}
|
|
2994
3106
|
_classifiedVerifyCtx(spec) {
|
|
2995
3107
|
return {
|
|
@@ -3044,7 +3156,7 @@ var Collection = class {
|
|
|
3044
3156
|
if (typeof candidate !== "string") {
|
|
3045
3157
|
throw new ClassifiedVerifyError(this.name, "*", "candidate must be a string");
|
|
3046
3158
|
}
|
|
3047
|
-
const target = await this.
|
|
3159
|
+
const target = await this.strategies.classified.computeTarget(this._classifiedVerifyCtx(spec), field, candidate);
|
|
3048
3160
|
const ids = await this.adapter.list(this.vault, this.name);
|
|
3049
3161
|
const hits = [];
|
|
3050
3162
|
const hitMap = /* @__PURE__ */ new Map();
|
|
@@ -3131,7 +3243,7 @@ var Collection = class {
|
|
|
3131
3243
|
id,
|
|
3132
3244
|
version: scrubbed._v,
|
|
3133
3245
|
actor: this.keyring.userId,
|
|
3134
|
-
payloadHash: await this.
|
|
3246
|
+
payloadHash: await this.strategies.history.envelopePayloadHash(scrubbed),
|
|
3135
3247
|
reason: "classified:scrub-equatable-tags"
|
|
3136
3248
|
});
|
|
3137
3249
|
}
|
|
@@ -3357,7 +3469,7 @@ var Collection = class {
|
|
|
3357
3469
|
if (this.syncAdapter !== void 0) presenceOpts.syncAdapter = this.syncAdapter;
|
|
3358
3470
|
if (opts?.staleMs !== void 0) presenceOpts.staleMs = opts.staleMs;
|
|
3359
3471
|
if (opts?.pollIntervalMs !== void 0) presenceOpts.pollIntervalMs = opts.pollIntervalMs;
|
|
3360
|
-
return this.
|
|
3472
|
+
return this.strategies.sync.buildPresence(presenceOpts);
|
|
3361
3473
|
}
|
|
3362
3474
|
/**
|
|
3363
3475
|
* Create or update a record. Runs inside the hub's write-queue tracker
|
|
@@ -3577,7 +3689,7 @@ var Collection = class {
|
|
|
3577
3689
|
}
|
|
3578
3690
|
}
|
|
3579
3691
|
}
|
|
3580
|
-
crdtState = this.
|
|
3692
|
+
crdtState = this.strategies.crdt.buildLwwMapState(record, existingState, now);
|
|
3581
3693
|
} else if (this.crdtMode === "rga") {
|
|
3582
3694
|
let existingState;
|
|
3583
3695
|
if (existingEnvelope) {
|
|
@@ -3589,7 +3701,7 @@ var Collection = class {
|
|
|
3589
3701
|
}
|
|
3590
3702
|
}
|
|
3591
3703
|
}
|
|
3592
|
-
crdtState = this.
|
|
3704
|
+
crdtState = this.strategies.crdt.buildRgaState(Array.isArray(record) ? record : [record], existingState, generateULID);
|
|
3593
3705
|
} else {
|
|
3594
3706
|
crdtState = { _crdt: "yjs", update: record };
|
|
3595
3707
|
}
|
|
@@ -3597,14 +3709,14 @@ var Collection = class {
|
|
|
3597
3709
|
const cek2 = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
3598
3710
|
const envelope2 = await this.codec.encryptJsonString(JSON.stringify(crdtState), version2, cek2, options?.source, options?.sourceTs);
|
|
3599
3711
|
await this.adapter.put(this.vault, this.name, id, envelope2);
|
|
3600
|
-
const resolvedRecord = this.
|
|
3712
|
+
const resolvedRecord = this.strategies.crdt.resolveCrdtSnapshot(crdtState);
|
|
3601
3713
|
const existingResolvedRecord = existingEnvelope ? await this.codec.decryptRecord(existingEnvelope, { skipValidation: true }) : null;
|
|
3602
3714
|
const existingResolved = existingResolvedRecord !== null ? { record: existingResolvedRecord, version: existingVersion } : void 0;
|
|
3603
3715
|
if (existingResolved && this.historyConfig.enabled !== false) {
|
|
3604
|
-
await this.
|
|
3716
|
+
await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existingResolved.record, existingResolved.version, cek2, void 0, void 0, this.vdigFields !== null ? { id, prev: existingEnvelope } : void 0, id));
|
|
3605
3717
|
this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: existingResolved.version });
|
|
3606
3718
|
if (this.historyConfig.maxVersions) {
|
|
3607
|
-
await this.
|
|
3719
|
+
await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
3608
3720
|
}
|
|
3609
3721
|
}
|
|
3610
3722
|
if (this.ledger) {
|
|
@@ -3614,9 +3726,9 @@ var Collection = class {
|
|
|
3614
3726
|
id,
|
|
3615
3727
|
version: version2,
|
|
3616
3728
|
actor: this.keyring.userId,
|
|
3617
|
-
payloadHash: await this.
|
|
3729
|
+
payloadHash: await this.strategies.history.envelopePayloadHash(envelope2)
|
|
3618
3730
|
};
|
|
3619
|
-
if (existingResolved) appendInput.delta = this.
|
|
3731
|
+
if (existingResolved) appendInput.delta = this.strategies.history.computePatch(resolvedRecord, existingResolved.record);
|
|
3620
3732
|
if (options?.reason !== void 0) appendInput.reason = options.reason;
|
|
3621
3733
|
await this.ledger.append(appendInput);
|
|
3622
3734
|
}
|
|
@@ -3663,21 +3775,21 @@ var Collection = class {
|
|
|
3663
3775
|
const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
3664
3776
|
const vdigCtx = this.vdigFields !== null ? { id, prev: await this.adapter.get(this.vault, this.name, id) } : void 0;
|
|
3665
3777
|
if (existing && this.historyConfig.enabled !== false) {
|
|
3666
|
-
await this.
|
|
3778
|
+
await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, vdigCtx, id));
|
|
3667
3779
|
this.emitter.emit("history:save", {
|
|
3668
3780
|
vault: this.vault,
|
|
3669
3781
|
collection: this.name,
|
|
3670
3782
|
id,
|
|
3671
3783
|
version: existing.version
|
|
3672
3784
|
});
|
|
3673
|
-
if (this.historyConfig.maxVersions) await this.
|
|
3785
|
+
if (this.historyConfig.maxVersions) await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
3674
3786
|
}
|
|
3675
3787
|
const envelope = await this.codec.encryptRecord(record, version, cek, options?.source, options?.sourceTs, vdigCtx, id);
|
|
3676
3788
|
await this.adapter.put(this.vault, this.name, id, envelope);
|
|
3677
3789
|
this.markerIds.delete(id);
|
|
3678
3790
|
await this._ensureClassifiedMarker();
|
|
3679
3791
|
if (this.embeddings) {
|
|
3680
|
-
await this.
|
|
3792
|
+
await this.strategies.search.embedOnWrite(this.searchContext(), id, record, version);
|
|
3681
3793
|
}
|
|
3682
3794
|
if (this.ledger) {
|
|
3683
3795
|
const appendInput = {
|
|
@@ -3686,10 +3798,10 @@ var Collection = class {
|
|
|
3686
3798
|
id,
|
|
3687
3799
|
version,
|
|
3688
3800
|
actor: this.keyring.userId,
|
|
3689
|
-
payloadHash: await this.
|
|
3801
|
+
payloadHash: await this.strategies.history.envelopePayloadHash(envelope)
|
|
3690
3802
|
};
|
|
3691
3803
|
if (existing) {
|
|
3692
|
-
appendInput.delta = this.
|
|
3804
|
+
appendInput.delta = this.strategies.history.computePatch(record, existing.record);
|
|
3693
3805
|
}
|
|
3694
3806
|
if (options?.reason !== void 0) appendInput.reason = options.reason;
|
|
3695
3807
|
await this.ledger.append(appendInput);
|
|
@@ -4208,10 +4320,10 @@ var Collection = class {
|
|
|
4208
4320
|
if (existing && this.historyConfig.enabled !== false) {
|
|
4209
4321
|
const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
4210
4322
|
const prevForVdig = this.vdigFields !== null ? await this.adapter.get(this.vault, this.name, id) : null;
|
|
4211
|
-
await this.
|
|
4323
|
+
await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, this.vdigFields !== null ? { id, prev: prevForVdig } : void 0, id));
|
|
4212
4324
|
}
|
|
4213
4325
|
const previousEnvelope = await this.adapter.get(this.vault, this.name, id);
|
|
4214
|
-
const previousPayloadHash = await this.
|
|
4326
|
+
const previousPayloadHash = await this.strategies.history.envelopePayloadHash(previousEnvelope);
|
|
4215
4327
|
let markerVersion;
|
|
4216
4328
|
if (this.onDirty) {
|
|
4217
4329
|
const live = previousEnvelope;
|
|
@@ -4422,28 +4534,28 @@ var Collection = class {
|
|
|
4422
4534
|
* see `src/search/tokenize.ts` for the Thai/CJK caveat.
|
|
4423
4535
|
*/
|
|
4424
4536
|
search(field, query, opts = {}) {
|
|
4425
|
-
return this.
|
|
4537
|
+
return this.strategies.search.search(this.searchContext(), field, query, opts);
|
|
4426
4538
|
}
|
|
4427
4539
|
/** Force-persist the lexical index now — gated behind `searchStrategy: withSearch()`. */
|
|
4428
4540
|
flushIndex() {
|
|
4429
|
-
return this.
|
|
4541
|
+
return this.strategies.search.flushIndex(this.searchContext());
|
|
4430
4542
|
}
|
|
4431
4543
|
/** Pre-build the lexical index — gated behind `searchStrategy: withSearch()`. */
|
|
4432
4544
|
warmIndex() {
|
|
4433
|
-
return this.
|
|
4545
|
+
return this.strategies.search.warmIndex(this.searchContext());
|
|
4434
4546
|
}
|
|
4435
4547
|
/** Retrieval (lexical | semantic | hybrid) — gated behind `searchStrategy: withSearch()`. */
|
|
4436
4548
|
retrieve(query, opts = {}) {
|
|
4437
|
-
return this.
|
|
4549
|
+
return this.strategies.search.retrieve(this.searchContext(), query, opts);
|
|
4438
4550
|
}
|
|
4439
4551
|
/** Raw-vector kNN — gated behind `searchStrategy: withSearch()`. */
|
|
4440
4552
|
similarTo(vector, opts = {}) {
|
|
4441
|
-
return this.
|
|
4553
|
+
return this.strategies.search.similarTo(this.searchContext(), vector, opts);
|
|
4442
4554
|
}
|
|
4443
4555
|
/** Opt-in bulk `_vec` re-derive (#788) — a plain collection has nothing to rebuild; gated behind `searchStrategy: withSearch()` otherwise. */
|
|
4444
4556
|
rebuildEmbeddings() {
|
|
4445
4557
|
if (!this.embeddings) return Promise.resolve({ rebuilt: 0, skipped: 0 });
|
|
4446
|
-
return this.
|
|
4558
|
+
return this.strategies.search.rebuildEmbeddings(this.searchContext());
|
|
4447
4559
|
}
|
|
4448
4560
|
/**
|
|
4449
4561
|
* Bind the {@link SearchContext} the search/retrieval surface needs. The
|
|
@@ -4653,7 +4765,7 @@ var Collection = class {
|
|
|
4653
4765
|
...this.defaultLocale !== void 0 ? { defaultLocale: this.defaultLocale } : {},
|
|
4654
4766
|
...resolver.resolveDictSource ? { resolveDictSource: (field) => resolver.resolveDictSource(leftCollection, field) } : {}
|
|
4655
4767
|
} : void 0;
|
|
4656
|
-
return new Query(source, void 0, joinContext, this.
|
|
4768
|
+
return new Query(source, void 0, joinContext, this.strategies.aggregate);
|
|
4657
4769
|
}
|
|
4658
4770
|
/**
|
|
4659
4771
|
* Subscribe to every put/delete on this collection. Returns an
|
|
@@ -4767,7 +4879,7 @@ var Collection = class {
|
|
|
4767
4879
|
// ─── History Methods ────────────────────────────────────────────
|
|
4768
4880
|
/** Get version history for a record, newest first. */
|
|
4769
4881
|
async history(id, options) {
|
|
4770
|
-
const envelopes = await this.
|
|
4882
|
+
const envelopes = await this.strategies.history.getHistoryEntries(
|
|
4771
4883
|
this.adapter,
|
|
4772
4884
|
this.vault,
|
|
4773
4885
|
this.name,
|
|
@@ -4799,7 +4911,7 @@ var Collection = class {
|
|
|
4799
4911
|
* and re-put the records through the normal `put()` path.
|
|
4800
4912
|
*/
|
|
4801
4913
|
async getVersion(id, version) {
|
|
4802
|
-
const envelope = await this.
|
|
4914
|
+
const envelope = await this.strategies.history.getVersionEnvelope(
|
|
4803
4915
|
this.adapter,
|
|
4804
4916
|
this.vault,
|
|
4805
4917
|
this.name,
|
|
@@ -4824,7 +4936,7 @@ var Collection = class {
|
|
|
4824
4936
|
*/
|
|
4825
4937
|
async diff(id, versionA, versionB) {
|
|
4826
4938
|
const recordA = versionA === 0 ? null : await this.resolveVersion(id, versionA);
|
|
4827
|
-
return this.
|
|
4939
|
+
return this.strategies.history.diff(recordA, versionB === void 0 || versionB === 0 ? versionB === 0 ? null : await this.resolveCurrentOrVersion(id) : await this.resolveVersion(id, versionB));
|
|
4828
4940
|
}
|
|
4829
4941
|
/** Resolve a version: try history first, then check if it's the current version. */
|
|
4830
4942
|
async resolveVersion(id, version) {
|
|
@@ -4841,7 +4953,7 @@ var Collection = class {
|
|
|
4841
4953
|
}
|
|
4842
4954
|
/** Prune history entries for a record (or all records if id is undefined). */
|
|
4843
4955
|
async pruneRecordHistory(id, options) {
|
|
4844
|
-
const pruned = await this.
|
|
4956
|
+
const pruned = await this.strategies.history.pruneHistory(
|
|
4845
4957
|
this.adapter,
|
|
4846
4958
|
this.vault,
|
|
4847
4959
|
this.name,
|
|
@@ -4860,7 +4972,7 @@ var Collection = class {
|
|
|
4860
4972
|
}
|
|
4861
4973
|
/** Clear all history for this collection (or a specific record). */
|
|
4862
4974
|
async clearHistory(id) {
|
|
4863
|
-
return this.
|
|
4975
|
+
return this.strategies.history.clearHistory(this.adapter, this.vault, this.name, id);
|
|
4864
4976
|
}
|
|
4865
4977
|
// ─── Core Methods ─────────────────────────────────────────────
|
|
4866
4978
|
/**
|
|
@@ -5282,7 +5394,7 @@ var Collection = class {
|
|
|
5282
5394
|
* vault-shared `_blob` DEK (enabling cross-collection deduplication).
|
|
5283
5395
|
*/
|
|
5284
5396
|
blob(id) {
|
|
5285
|
-
return this.
|
|
5397
|
+
return this.strategies.blob.openSlot({
|
|
5286
5398
|
store: this.adapter,
|
|
5287
5399
|
vault: this.vault,
|
|
5288
5400
|
collection: this.name,
|
|
@@ -5603,23 +5715,23 @@ var Collection = class {
|
|
|
5603
5715
|
// ─── Hierarchical Access ──────────────────────────
|
|
5604
5716
|
/** tier-aware put — gated behind `tiersStrategy: withTiers()`. `searchResidue: true` = stuck search compensation (#774, mirroring #764's elevate/demote posture); the write itself always completes. */
|
|
5605
5717
|
putAtTier(id, record, tier, opts) {
|
|
5606
|
-
return this.
|
|
5718
|
+
return this.strategies.tiers.putAtTier(this.tiersContext(), id, record, tier, opts);
|
|
5607
5719
|
}
|
|
5608
5720
|
/** tier-aware get — gated behind `tiersStrategy: withTiers()`. */
|
|
5609
5721
|
getAtTier(id) {
|
|
5610
|
-
return this.
|
|
5722
|
+
return this.strategies.tiers.getAtTier(this.tiersContext(), id);
|
|
5611
5723
|
}
|
|
5612
5724
|
/** list ids grouped by the caller's readability — gated behind `withTiers()`. */
|
|
5613
5725
|
listAtTier() {
|
|
5614
|
-
return this.
|
|
5726
|
+
return this.strategies.tiers.listAtTier(this.tiersContext());
|
|
5615
5727
|
}
|
|
5616
5728
|
/** elevate a record to a higher tier — gated behind `withTiers()`. `searchResidue: true` = stuck search compensation (#764); the move itself always completes. */
|
|
5617
5729
|
elevate(id, toTier) {
|
|
5618
|
-
return this.
|
|
5730
|
+
return this.strategies.tiers.elevate(this.tiersContext(), id, toTier);
|
|
5619
5731
|
}
|
|
5620
5732
|
/** demote a record to a lower tier — gated behind `withTiers()`. Same `searchResidue` posture as {@link elevate} (#764). */
|
|
5621
5733
|
demote(id, toTier) {
|
|
5622
|
-
return this.
|
|
5734
|
+
return this.strategies.tiers.demote(this.tiersContext(), id, toTier);
|
|
5623
5735
|
}
|
|
5624
5736
|
/**
|
|
5625
5737
|
* Emit a cross-tier access event. The subscriber sink stays collection-resident (it captures `onCrossTierAccess`); the tiers module reaches it via the {@link TiersContext.emitCrossTierEvent} callback.
|
|
@@ -5680,16 +5792,16 @@ var Collection = class {
|
|
|
5680
5792
|
},
|
|
5681
5793
|
syncIndexes: (id, rec, version, priorEnvelope) => syncTierIndexes(this.indexingContext(), id, rec, version, priorEnvelope),
|
|
5682
5794
|
syncSearch: (id, rec, version) => syncTierSearch(this.searchContext(), id, rec, version),
|
|
5683
|
-
syncHistory: async (id, fromDek, toDek) => this.
|
|
5795
|
+
syncHistory: async (id, fromDek, toDek) => this.strategies.history.rewrapHistory(this.adapter, this.vault, this.name, id, fromDek, toDek, await this.getDEK(this.name)),
|
|
5684
5796
|
saveHistorySnapshot: async (id, envelope) => {
|
|
5685
5797
|
if (this.historyConfig.enabled === false) return;
|
|
5686
|
-
await this.
|
|
5798
|
+
await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, envelope);
|
|
5687
5799
|
this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: envelope._v });
|
|
5688
|
-
if (this.historyConfig.maxVersions) await this.
|
|
5800
|
+
if (this.historyConfig.maxVersions) await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
5689
5801
|
},
|
|
5690
|
-
historyEnabled: this.historyConfig.enabled !== false && this.
|
|
5802
|
+
historyEnabled: this.historyConfig.enabled !== false && this.strategies.history !== NO_HISTORY,
|
|
5691
5803
|
// #728/#737: lets putAtTier skip decrypting `existing` when no real history strategy is wired
|
|
5692
|
-
syncBlobs: (id, fromTier, toTier) => this.
|
|
5804
|
+
syncBlobs: (id, fromTier, toTier) => this.strategies.blob !== NO_BLOBS ? this.blob(id).syncTierMove(fromTier, toTier, this.blobTierPolicy) : Promise.resolve(),
|
|
5693
5805
|
// #724 I1: gate on blob storage enabled (not on declared blobFields) so undeclared-field blobs still rehome; #746: syncTierMove mints/resumes the rehome journal marker; self-no-ops on an empty slot map
|
|
5694
5806
|
syncLedger: async (id) => {
|
|
5695
5807
|
await this.ledger?.purgeRecordDeltas(this.name, id);
|
|
@@ -6017,46 +6129,6 @@ var DeferredNumberingStore = class {
|
|
|
6017
6129
|
}
|
|
6018
6130
|
};
|
|
6019
6131
|
|
|
6020
|
-
// src/with-fork/shadow/strategy.ts
|
|
6021
|
-
var NOT_ENABLED2 = new Error(
|
|
6022
|
-
'VaultFrame requires the shadow strategy. Import `{ withShadow }` from "@noy-db/hub/shadow" and pass it to `createNoydb({ shadowStrategy: withShadow() })`.'
|
|
6023
|
-
);
|
|
6024
|
-
var NO_SHADOW = {
|
|
6025
|
-
buildFrame() {
|
|
6026
|
-
throw NOT_ENABLED2;
|
|
6027
|
-
}
|
|
6028
|
-
};
|
|
6029
|
-
|
|
6030
|
-
// src/with-audit/consent/strategy.ts
|
|
6031
|
-
var NO_CONSENT = {
|
|
6032
|
-
async write() {
|
|
6033
|
-
},
|
|
6034
|
-
async read() {
|
|
6035
|
-
return [];
|
|
6036
|
-
}
|
|
6037
|
-
};
|
|
6038
|
-
|
|
6039
|
-
// src/with-audit/periods/strategy.ts
|
|
6040
|
-
var NOT_ENABLED3 = new Error(
|
|
6041
|
-
'Accounting periods require the periods strategy. Import `{ withPeriods }` from "@noy-db/hub/periods" and pass it to `createNoydb({ periodsStrategy: withPeriods() })`.'
|
|
6042
|
-
);
|
|
6043
|
-
var NO_PERIODS = {
|
|
6044
|
-
async loadPeriods() {
|
|
6045
|
-
return [];
|
|
6046
|
-
},
|
|
6047
|
-
async chainAnchor() {
|
|
6048
|
-
return { priorPeriodHash: "" };
|
|
6049
|
-
},
|
|
6050
|
-
assertTsWritable() {
|
|
6051
|
-
},
|
|
6052
|
-
validatePeriodName() {
|
|
6053
|
-
throw NOT_ENABLED3;
|
|
6054
|
-
},
|
|
6055
|
-
async appendPeriodLedgerEntry() {
|
|
6056
|
-
throw NOT_ENABLED3;
|
|
6057
|
-
}
|
|
6058
|
-
};
|
|
6059
|
-
|
|
6060
6132
|
// src/with-audit/periods/vault-facade.ts
|
|
6061
6133
|
var VaultPeriods = class {
|
|
6062
6134
|
constructor(deps) {
|
|
@@ -8058,36 +8130,22 @@ var Vault = class {
|
|
|
8058
8130
|
syncAdapter;
|
|
8059
8131
|
getPurgeableTargets;
|
|
8060
8132
|
historyConfig;
|
|
8061
|
-
/**
|
|
8062
|
-
*
|
|
8063
|
-
|
|
8133
|
+
/**
|
|
8134
|
+
* Every opt-in service, resolved once by `createNoydb` (#838). Shared by
|
|
8135
|
+
* reference with the owning `Noydb` and with every `Collection` this vault
|
|
8136
|
+
* opens, so all three always agree about which services are enabled.
|
|
8137
|
+
*/
|
|
8138
|
+
strategies;
|
|
8064
8139
|
objectStore;
|
|
8065
|
-
/** Cold-storage archival strategy (the archive target store). */
|
|
8066
|
-
archiveStrategy;
|
|
8067
8140
|
/** Per-collection record archival policies. Indexed by collection name. */
|
|
8068
8141
|
archiveRegistry = /* @__PURE__ */ new Map();
|
|
8069
|
-
indexStrategy;
|
|
8070
|
-
lazyStrategy;
|
|
8071
|
-
aggregateStrategy;
|
|
8072
|
-
crdtStrategy;
|
|
8073
|
-
tiersStrategy;
|
|
8074
|
-
searchStrategy;
|
|
8075
|
-
/** Cargo (partition extraction) strategy — `NO_CARGO` (throwing) unless `withCargo()` was passed.
|
|
8076
|
-
* Public so the `extractPartition` free function (which takes a `Vault`) routes through it. */
|
|
8077
|
-
cargoStrategy;
|
|
8078
|
-
brokerStrategy;
|
|
8079
|
-
sealedRecordStrategy;
|
|
8080
|
-
portabilityStrategy;
|
|
8081
|
-
sequenceStrategy;
|
|
8082
|
-
consentStrategy;
|
|
8083
8142
|
periods;
|
|
8084
8143
|
linksEnforcer;
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
classifiedStrategy;
|
|
8144
|
+
/** Cargo (partition extraction) strategy — `NO_CARGO` (throwing) unless `withCargo()` was passed.
|
|
8145
|
+
* Public so the `extractPartition` free function (which takes a `Vault`) routes through it. */
|
|
8146
|
+
get cargoStrategy() {
|
|
8147
|
+
return this.strategies.cargo;
|
|
8148
|
+
}
|
|
8091
8149
|
/** Per-vault guard registry; `null` until `_initGuards()` runs (or for vaults that never register
|
|
8092
8150
|
* one) — the runtime class is dynamic-imported on demand to keep it out of the floor bundle. */
|
|
8093
8151
|
guardRegistry = null;
|
|
@@ -8269,23 +8327,10 @@ var Vault = class {
|
|
|
8269
8327
|
this.onRegisterConflictResolver = opts.onRegisterConflictResolver;
|
|
8270
8328
|
this.syncAdapter = opts.syncAdapter;
|
|
8271
8329
|
this.getPurgeableTargets = opts.getPurgeableTargets ?? (() => []);
|
|
8272
|
-
this.
|
|
8330
|
+
this.strategies = opts.strategies;
|
|
8273
8331
|
this.objectStore = opts.objectStore;
|
|
8274
|
-
this.archiveStrategy = opts.archiveStrategy;
|
|
8275
|
-
this.indexStrategy = opts.indexStrategy;
|
|
8276
|
-
this.lazyStrategy = opts.lazyStrategy;
|
|
8277
|
-
this.aggregateStrategy = opts.aggregateStrategy;
|
|
8278
|
-
this.crdtStrategy = opts.crdtStrategy;
|
|
8279
|
-
this.tiersStrategy = opts.tiersStrategy;
|
|
8280
|
-
this.searchStrategy = opts.searchStrategy;
|
|
8281
|
-
this.cargoStrategy = opts.cargoStrategy ?? NO_CARGO;
|
|
8282
|
-
this.brokerStrategy = opts.brokerStrategy ?? NO_BROKER;
|
|
8283
|
-
this.sealedRecordStrategy = opts.sealedRecordStrategy ?? NO_SEALED_RECORD;
|
|
8284
|
-
this.portabilityStrategy = opts.portabilityStrategy ?? NO_PORTABILITY;
|
|
8285
|
-
this.sequenceStrategy = opts.sequenceStrategy ?? NO_SEQUENCE;
|
|
8286
|
-
this.consentStrategy = opts.consentStrategy ?? NO_CONSENT;
|
|
8287
8332
|
this.periods = new VaultPeriods({
|
|
8288
|
-
strategy:
|
|
8333
|
+
strategy: this.strategies.periods,
|
|
8289
8334
|
adapter: this.adapter,
|
|
8290
8335
|
vault: this.name,
|
|
8291
8336
|
encrypted: this.encrypted,
|
|
@@ -8310,12 +8355,6 @@ var Vault = class {
|
|
|
8310
8355
|
getActiveTxContext: () => this.noydb._activeTxContextOrNull,
|
|
8311
8356
|
emitter: this.emitter
|
|
8312
8357
|
});
|
|
8313
|
-
this.shadowStrategy = opts.shadowStrategy ?? NO_SHADOW;
|
|
8314
|
-
this.historyStrategy = opts.historyStrategy ?? NO_HISTORY;
|
|
8315
|
-
this.forgetStrategy = opts.forgetStrategy ?? NO_FORGET;
|
|
8316
|
-
this.i18nStrategy = opts.i18nStrategy ?? NO_I18N;
|
|
8317
|
-
this.syncStrategy = opts.syncStrategy ?? NO_SYNC;
|
|
8318
|
-
this.classifiedStrategy = opts.classifiedStrategy ?? NO_CLASSIFIED;
|
|
8319
8358
|
this.graph = new ViaGraph();
|
|
8320
8359
|
void opts.guardStrategies;
|
|
8321
8360
|
this.historyConfig = opts.historyConfig ?? { enabled: true };
|
|
@@ -8330,19 +8369,19 @@ var Vault = class {
|
|
|
8330
8369
|
getDEK: (collection) => this.getDEK(collection),
|
|
8331
8370
|
role: () => this.keyring.role,
|
|
8332
8371
|
getRawRecord: async (collection, recId) => await this.collection(collection).get(recId, { locale: "raw" })
|
|
8333
|
-
},
|
|
8372
|
+
}, this.strategies.attestation);
|
|
8334
8373
|
this.user = this.noydb.userApiFactory({
|
|
8335
8374
|
adapter: this.adapter,
|
|
8336
8375
|
vaultName: this.name,
|
|
8337
8376
|
writerKeyringId: this.keyring.userId,
|
|
8338
8377
|
getDek: () => this.getDEK(USER_ENVELOPE_COLLECTION),
|
|
8339
8378
|
checkGate: (gate, presented) => this.noydb.checkGate(this.name, gate, presented),
|
|
8340
|
-
exportAccessible: (opts2) => this.
|
|
8341
|
-
unilateralWithdraw: (opts2) => this.
|
|
8342
|
-
requestWithdraw: (opts2) => this.
|
|
8343
|
-
listWithdrawals: (opts2) => this.
|
|
8344
|
-
approveWithdraw: (requestId, opts2) => this.
|
|
8345
|
-
rejectWithdraw: (requestId, opts2) => this.
|
|
8379
|
+
exportAccessible: (opts2) => this.strategies.portability.exportAccessibleData(this, opts2),
|
|
8380
|
+
unilateralWithdraw: (opts2) => this.strategies.portability.withdrawAccessibleData(this, opts2),
|
|
8381
|
+
requestWithdraw: (opts2) => this.strategies.portability.requestWithdrawal(this, opts2),
|
|
8382
|
+
listWithdrawals: (opts2) => this.strategies.portability.listWithdrawalRequests(this, opts2),
|
|
8383
|
+
approveWithdraw: (requestId, opts2) => this.strategies.portability.approveWithdrawal(this, requestId, opts2),
|
|
8384
|
+
rejectWithdraw: (requestId, opts2) => this.strategies.portability.rejectWithdrawal(this, requestId, opts2)
|
|
8346
8385
|
});
|
|
8347
8386
|
this.custody = new CustodyApi(
|
|
8348
8387
|
(options, factors) => this.noydb.grantCustodian(this.name, options, factors),
|
|
@@ -8400,7 +8439,7 @@ var Vault = class {
|
|
|
8400
8439
|
* dispatch reads/writes — from this vault's OWN privates, rather than passing `this` itself. */
|
|
8401
8440
|
_viaReconcileCtx() {
|
|
8402
8441
|
return {
|
|
8403
|
-
i18nStrategy: this.
|
|
8442
|
+
i18nStrategy: this.strategies.i18n,
|
|
8404
8443
|
locale: this.locale,
|
|
8405
8444
|
translateText: this.translateText,
|
|
8406
8445
|
i18nFieldRegistry: this.i18nFieldRegistry,
|
|
@@ -8441,7 +8480,7 @@ var Vault = class {
|
|
|
8441
8480
|
this.satelliteRegistry = declareSatellite({
|
|
8442
8481
|
adapter: this.adapter,
|
|
8443
8482
|
vaultName: this.name,
|
|
8444
|
-
forgetSubjects: this.
|
|
8483
|
+
forgetSubjects: this.strategies.forget.subjects,
|
|
8445
8484
|
getDEK: this.getDEK,
|
|
8446
8485
|
getBaseSchema: (base) => this.collectionCache.get(base)?.getSchema(),
|
|
8447
8486
|
getBaseCrdt: (base) => this.collectionCache.get(base)?.getConfig()?.crdt,
|
|
@@ -8561,22 +8600,9 @@ var Vault = class {
|
|
|
8561
8600
|
// #693: re-create gate fallback
|
|
8562
8601
|
historyConfig: effectiveHistoryConfig,
|
|
8563
8602
|
historyConfigExplicit: options?.historyConfig !== void 0,
|
|
8564
|
-
// thread the vault-wide blob strategy into every
|
|
8565
|
-
// collection. `undefined` is intentionally preserved so the
|
|
8566
|
-
// Collection constructor uses its NO_BLOBS default.
|
|
8567
|
-
...this.blobStrategy !== void 0 ? { blobStrategy: this.blobStrategy } : {},
|
|
8568
8603
|
...this.objectStore !== void 0 ? { objectStore: this.objectStore } : {},
|
|
8569
8604
|
...options?.blobFields !== void 0 ? { blobFields: options.blobFields } : {},
|
|
8570
|
-
|
|
8571
|
-
...this.lazyStrategy !== void 0 ? { lazyStrategy: this.lazyStrategy } : {},
|
|
8572
|
-
...this.aggregateStrategy !== void 0 ? { aggregateStrategy: this.aggregateStrategy } : {},
|
|
8573
|
-
...this.crdtStrategy !== void 0 ? { crdtStrategy: this.crdtStrategy } : {},
|
|
8574
|
-
...this.tiersStrategy !== void 0 ? { tiersStrategy: this.tiersStrategy } : {},
|
|
8575
|
-
...this.searchStrategy !== void 0 ? { searchStrategy: this.searchStrategy } : {},
|
|
8576
|
-
historyStrategy: this.historyStrategy,
|
|
8577
|
-
i18nStrategy: this.i18nStrategy,
|
|
8578
|
-
syncStrategy: this.syncStrategy,
|
|
8579
|
-
classifiedStrategy: this.classifiedStrategy,
|
|
8605
|
+
strategies: this.strategies,
|
|
8580
8606
|
// Per-collection ledger opt-out: when this collection sets
|
|
8581
8607
|
// `historyConfig.ledger: false`, withhold the ledger reference so all
|
|
8582
8608
|
// four `if (this.ledger)` append sites in Collection no-op. The chain
|
|
@@ -8634,7 +8660,7 @@ var Vault = class {
|
|
|
8634
8660
|
collOpts.sensitive = options.sensitive;
|
|
8635
8661
|
}
|
|
8636
8662
|
if (options?.perRecordKeys !== void 0) collOpts.perRecordKeys = options.perRecordKeys;
|
|
8637
|
-
const subjectKey = this.
|
|
8663
|
+
const subjectKey = this.strategies.forget.subjects[collectionName];
|
|
8638
8664
|
if (subjectKey !== void 0) {
|
|
8639
8665
|
if (options?.perRecordKeys === false) {
|
|
8640
8666
|
console.warn(
|
|
@@ -9015,7 +9041,7 @@ var Vault = class {
|
|
|
9015
9041
|
const values = getAtPath(obj, field);
|
|
9016
9042
|
for (const value of values) {
|
|
9017
9043
|
if (value === void 0 || value === null) continue;
|
|
9018
|
-
this.
|
|
9044
|
+
this.strategies.i18n.validateI18nTextValue(value, field, descriptor);
|
|
9019
9045
|
}
|
|
9020
9046
|
}
|
|
9021
9047
|
}
|
|
@@ -9056,7 +9082,7 @@ var Vault = class {
|
|
|
9056
9082
|
this.reservedLookupCollections.set(dictCollectionName(name), name);
|
|
9057
9083
|
let handle = this.dictionaryCache.get(name);
|
|
9058
9084
|
if (!handle) {
|
|
9059
|
-
handle = this.
|
|
9085
|
+
handle = this.strategies.i18n.buildDictionaryHandle({
|
|
9060
9086
|
adapter: this.adapter,
|
|
9061
9087
|
compartmentName: this.name,
|
|
9062
9088
|
dictionaryName: name,
|
|
@@ -9269,7 +9295,7 @@ var Vault = class {
|
|
|
9269
9295
|
};
|
|
9270
9296
|
}
|
|
9271
9297
|
if (!this.sequenceStore) {
|
|
9272
|
-
this.sequenceStore = this.
|
|
9298
|
+
this.sequenceStore = this.strategies.sequence.createStore({
|
|
9273
9299
|
adapter: this.adapter,
|
|
9274
9300
|
vault: this.name,
|
|
9275
9301
|
encrypted: this.encrypted,
|
|
@@ -9367,7 +9393,7 @@ var Vault = class {
|
|
|
9367
9393
|
return runListArchived(this._archiveContext(), collection);
|
|
9368
9394
|
}
|
|
9369
9395
|
_archiveContext() {
|
|
9370
|
-
const strategy = this.
|
|
9396
|
+
const strategy = this.strategies.archive;
|
|
9371
9397
|
if (!strategy) {
|
|
9372
9398
|
throw new Error(
|
|
9373
9399
|
"vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb"
|
|
@@ -9534,7 +9560,7 @@ var Vault = class {
|
|
|
9534
9560
|
*/
|
|
9535
9561
|
getLedgerOrNull() {
|
|
9536
9562
|
if (!this.ledgerStore) {
|
|
9537
|
-
this.ledgerStore = this.
|
|
9563
|
+
this.ledgerStore = this.strategies.history.buildLedger({
|
|
9538
9564
|
adapter: this.adapter,
|
|
9539
9565
|
vault: this.name,
|
|
9540
9566
|
encrypted: this.encrypted,
|
|
@@ -9559,7 +9585,7 @@ var Vault = class {
|
|
|
9559
9585
|
* number of distinct subjects re-indexed.
|
|
9560
9586
|
*/
|
|
9561
9587
|
async rebuildSubjectIndex() {
|
|
9562
|
-
if (Object.keys(this.
|
|
9588
|
+
if (Object.keys(this.strategies.forget.subjects).length === 0) {
|
|
9563
9589
|
throw new ForgetStrategyNotConfiguredError();
|
|
9564
9590
|
}
|
|
9565
9591
|
return rebuildSubjectIndex(
|
|
@@ -9567,7 +9593,7 @@ var Vault = class {
|
|
|
9567
9593
|
this.name,
|
|
9568
9594
|
this.getDEK,
|
|
9569
9595
|
this.encrypted,
|
|
9570
|
-
this.
|
|
9596
|
+
this.strategies.forget.subjects,
|
|
9571
9597
|
async (collectionName, id, env) => {
|
|
9572
9598
|
const coll = this.collection(collectionName);
|
|
9573
9599
|
return coll._decodeEnvelope(env, id);
|
|
@@ -9592,7 +9618,7 @@ var Vault = class {
|
|
|
9592
9618
|
* @throws ForgetStrategyNotConfiguredError when no `withForgetCascade` was set.
|
|
9593
9619
|
*/
|
|
9594
9620
|
async forget(subjectId) {
|
|
9595
|
-
if (Object.keys(this.
|
|
9621
|
+
if (Object.keys(this.strategies.forget.subjects).length === 0) {
|
|
9596
9622
|
throw new ForgetStrategyNotConfiguredError();
|
|
9597
9623
|
}
|
|
9598
9624
|
const ledger = this.getLedgerOrNull();
|
|
@@ -9614,17 +9640,17 @@ var Vault = class {
|
|
|
9614
9640
|
const sealedResidue = [];
|
|
9615
9641
|
const indexResidue = [];
|
|
9616
9642
|
const ledgerDeltaResidue = [];
|
|
9617
|
-
const blobsEnabled = this.
|
|
9643
|
+
const blobsEnabled = this.strategies.blob !== NO_BLOBS;
|
|
9618
9644
|
const actor = this.keyring.userId;
|
|
9619
9645
|
const fanoutStats = { recordsErased: 0, aggregatesRecomputed: 0, residueFrozen: [], lookupReferencesCascaded: 0, lookupReferencesNullified: 0, lookupReferencesResidue: [], derivedResidueUndecodable: [], derivedResidueDeclined: [] };
|
|
9620
9646
|
const { partitionSealedCekKeys, shouldSkipBlobScan, bumpResidueCount, residueNoticesFromMap } = await import("./purge-scope-FGNNLWHD.js");
|
|
9621
|
-
const scopedPurge = this.
|
|
9647
|
+
const scopedPurge = this.strategies.forget.scopedPurge === true;
|
|
9622
9648
|
const sealedCekScopedSkipped = /* @__PURE__ */ new Map();
|
|
9623
9649
|
const blobScopedSkipped = /* @__PURE__ */ new Map();
|
|
9624
9650
|
for (const ref2 of allRefs) {
|
|
9625
9651
|
const coll = this.collection(ref2.collection);
|
|
9626
9652
|
const satelliteOf = ref2.satelliteOf;
|
|
9627
|
-
const perRecordKeys = this.
|
|
9653
|
+
const perRecordKeys = this.strategies.forget.subjects[satelliteOf ?? ref2.collection] !== void 0;
|
|
9628
9654
|
const lookupCompareKeys = await this.linksEnforcer.checkLookupRefsRestrict(this.graph, ref2.collection, ref2.collection, ref2.id);
|
|
9629
9655
|
const live = await this.adapter.get(this.name, ref2.collection, ref2.id);
|
|
9630
9656
|
if (perRecordKeys && live && live._data && !hasPerRecordKey(live)) {
|
|
@@ -9684,7 +9710,7 @@ var Vault = class {
|
|
|
9684
9710
|
collections.add(ref2.collection);
|
|
9685
9711
|
await forgetDerivedFanout(this, { collection: ref2.collection, id: ref2.id }, live, fanoutStats, lookupCompareKeys);
|
|
9686
9712
|
}
|
|
9687
|
-
historyVersionsShredded += await this.
|
|
9713
|
+
historyVersionsShredded += await this.strategies.history.tombstoneHistory(
|
|
9688
9714
|
this.adapter,
|
|
9689
9715
|
this.name,
|
|
9690
9716
|
ref2.collection,
|
|
@@ -9814,7 +9840,7 @@ var Vault = class {
|
|
|
9814
9840
|
* `<collection>/<id>/<pid>` key the delivery envelope was written under.
|
|
9815
9841
|
*/
|
|
9816
9842
|
async sealRecordToHost(collection, id, hostSealer, opts) {
|
|
9817
|
-
return this.
|
|
9843
|
+
return this.strategies.sealedRecord.sealRecordToHost(this._sealingContext(), collection, id, hostSealer, opts);
|
|
9818
9844
|
}
|
|
9819
9845
|
/**
|
|
9820
9846
|
* Revoke a sealed-CEK grant. **Default is SOFT**: deletes the `pid` delivery
|
|
@@ -9824,7 +9850,7 @@ var Vault = class {
|
|
|
9824
9850
|
* longer open the record. See `revokeSealedRecord` in `record-keys/sealing.ts`.
|
|
9825
9851
|
*/
|
|
9826
9852
|
async revokeSealedRecord(collection, id, pid, opts) {
|
|
9827
|
-
return this.
|
|
9853
|
+
return this.strategies.sealedRecord.revokeSealedRecord(this._sealingContext(), collection, id, pid, opts);
|
|
9828
9854
|
}
|
|
9829
9855
|
/**
|
|
9830
9856
|
* HARD-rotate a record's CEK: decrypt the live body under the old CEK,
|
|
@@ -9844,7 +9870,7 @@ var Vault = class {
|
|
|
9844
9870
|
* @throws {@link RecordCekNotFoundError} if the record is missing or has no `_cek`.
|
|
9845
9871
|
*/
|
|
9846
9872
|
async rotateRecordCek(collection, id) {
|
|
9847
|
-
return this.
|
|
9873
|
+
return this.strategies.sealedRecord.rotateRecordCek(this._sealingContext(), collection, id);
|
|
9848
9874
|
}
|
|
9849
9875
|
/**
|
|
9850
9876
|
* Build the {@link SealingContext} the record-keys grantor functions need:
|
|
@@ -10151,7 +10177,7 @@ var Vault = class {
|
|
|
10151
10177
|
*/
|
|
10152
10178
|
at(timestamp) {
|
|
10153
10179
|
const iso = timestamp instanceof Date ? timestamp.toISOString() : timestamp;
|
|
10154
|
-
return this.
|
|
10180
|
+
return this.strategies.history.buildVaultInstant(
|
|
10155
10181
|
{
|
|
10156
10182
|
adapter: this.adapter,
|
|
10157
10183
|
name: this.name,
|
|
@@ -10183,11 +10209,11 @@ var Vault = class {
|
|
|
10183
10209
|
*.
|
|
10184
10210
|
*/
|
|
10185
10211
|
frame() {
|
|
10186
|
-
return this.
|
|
10212
|
+
return this.strategies.shadow.buildFrame(this);
|
|
10187
10213
|
}
|
|
10188
10214
|
/** Credential-broker handle (#479); `NO_BROKER` throws unless `brokerStrategy: withBroker(config)` was passed to createNoydb(). */
|
|
10189
10215
|
broker() {
|
|
10190
|
-
return buildCredentialBrokerHandle(this.
|
|
10216
|
+
return buildCredentialBrokerHandle(this.strategies.broker, this.adapter, this.name, () => this.keyring);
|
|
10191
10217
|
}
|
|
10192
10218
|
/**
|
|
10193
10219
|
* Run `fn` under a consent scope. Every `get` / `put` / `delete`
|
|
@@ -10229,7 +10255,7 @@ var Vault = class {
|
|
|
10229
10255
|
*.
|
|
10230
10256
|
*/
|
|
10231
10257
|
async consentAudit(filter = {}) {
|
|
10232
|
-
return this.
|
|
10258
|
+
return this.strategies.consent.read(this.adapter, this.name, this.encrypted, this.getDEK, filter);
|
|
10233
10259
|
}
|
|
10234
10260
|
/**
|
|
10235
10261
|
* Called by Collection after every access when a consent scope is
|
|
@@ -10240,7 +10266,7 @@ var Vault = class {
|
|
|
10240
10266
|
async _logConsent(op, collection, recordId) {
|
|
10241
10267
|
const ctx = this.consentContext;
|
|
10242
10268
|
if (!ctx) return;
|
|
10243
|
-
await this.
|
|
10269
|
+
await this.strategies.consent.write(
|
|
10244
10270
|
this.adapter,
|
|
10245
10271
|
this.name,
|
|
10246
10272
|
this.encrypted,
|
|
@@ -10719,7 +10745,7 @@ var Vault = class {
|
|
|
10719
10745
|
vault: this.name,
|
|
10720
10746
|
userId: () => this.keyring.userId,
|
|
10721
10747
|
getLedgerOrNull: () => this.getLedgerOrNull(),
|
|
10722
|
-
envelopePayloadHash: (envelope) => this.
|
|
10748
|
+
envelopePayloadHash: (envelope) => this.strategies.history.envelopePayloadHash(envelope),
|
|
10723
10749
|
reloadKeyringAndRebuildDEK: async () => {
|
|
10724
10750
|
if (this.reloadKeyring) {
|
|
10725
10751
|
this.keyring = await this.reloadKeyring();
|
|
@@ -11404,25 +11430,6 @@ var QuickUnlockStore = class {
|
|
|
11404
11430
|
}
|
|
11405
11431
|
};
|
|
11406
11432
|
|
|
11407
|
-
// src/with-fork/snapshots/strategy.ts
|
|
11408
|
-
var NOT_ENABLED4 = new Error(
|
|
11409
|
-
'Snapshots require the snapshot strategy. Import `{ withSnapshots }` from "@noy-db/hub/snapshots" and pass it to `createNoydb({ snapshotStrategy: withSnapshots({ store }) })`.'
|
|
11410
|
-
);
|
|
11411
|
-
var NO_SNAPSHOTS = {
|
|
11412
|
-
async snapshot() {
|
|
11413
|
-
throw NOT_ENABLED4;
|
|
11414
|
-
},
|
|
11415
|
-
async listSnapshots() {
|
|
11416
|
-
throw NOT_ENABLED4;
|
|
11417
|
-
},
|
|
11418
|
-
async restoreSnapshot() {
|
|
11419
|
-
throw NOT_ENABLED4;
|
|
11420
|
-
},
|
|
11421
|
-
async autoSnapshot() {
|
|
11422
|
-
throw NOT_ENABLED4;
|
|
11423
|
-
}
|
|
11424
|
-
};
|
|
11425
|
-
|
|
11426
11433
|
// src/with-fork/snapshots/scheduler.ts
|
|
11427
11434
|
var SnapshotScheduler = class {
|
|
11428
11435
|
policy;
|
|
@@ -11623,19 +11630,6 @@ var NoydbSnapshots = class {
|
|
|
11623
11630
|
}
|
|
11624
11631
|
};
|
|
11625
11632
|
|
|
11626
|
-
// src/with-commit/tx/strategy.ts
|
|
11627
|
-
var NOT_ENABLED5 = new Error(
|
|
11628
|
-
'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/tx" and pass it to `createNoydb({ txStrategy: withTransactions() })`.'
|
|
11629
|
-
);
|
|
11630
|
-
var NO_TX = {
|
|
11631
|
-
async runTransaction(_db, _fn, _options, _txInvariants) {
|
|
11632
|
-
throw NOT_ENABLED5;
|
|
11633
|
-
},
|
|
11634
|
-
async runDryRun() {
|
|
11635
|
-
throw NOT_ENABLED5;
|
|
11636
|
-
}
|
|
11637
|
-
};
|
|
11638
|
-
|
|
11639
11633
|
// src/kernel/memory-store.ts
|
|
11640
11634
|
function memoryStore() {
|
|
11641
11635
|
const store = /* @__PURE__ */ new Map();
|
|
@@ -11719,23 +11713,6 @@ function memoryStore() {
|
|
|
11719
11713
|
};
|
|
11720
11714
|
}
|
|
11721
11715
|
|
|
11722
|
-
// src/with-party/session/strategy.ts
|
|
11723
|
-
function notEnabled3(op) {
|
|
11724
|
-
return new Error(
|
|
11725
|
-
`${op} requires the session strategy. Import \`{ withSession }\` from "@noy-db/hub/session" and pass it to \`createNoydb({ sessionStrategy: withSession() })\`.`
|
|
11726
|
-
);
|
|
11727
|
-
}
|
|
11728
|
-
var NO_SESSION = {
|
|
11729
|
-
validateSessionPolicy() {
|
|
11730
|
-
throw notEnabled3("sessionPolicy");
|
|
11731
|
-
},
|
|
11732
|
-
createEnforcer() {
|
|
11733
|
-
throw notEnabled3("session policy enforcement");
|
|
11734
|
-
},
|
|
11735
|
-
revokeAllSessions() {
|
|
11736
|
-
}
|
|
11737
|
-
};
|
|
11738
|
-
|
|
11739
11716
|
// src/with-party/auth-introspection/index.ts
|
|
11740
11717
|
async function describeAuthConfig(store, vault) {
|
|
11741
11718
|
const policy = await loadVaultPolicy(store, vault) ?? defaultPolicySnapshot();
|
|
@@ -12689,21 +12666,22 @@ var Noydb = class {
|
|
|
12689
12666
|
writeRelay;
|
|
12690
12667
|
/** Per-vault policy enforcers. */
|
|
12691
12668
|
policyEnforcers = /* @__PURE__ */ new Map();
|
|
12692
|
-
txStrategy;
|
|
12693
|
-
forgetStrategy;
|
|
12694
12669
|
/**
|
|
12695
|
-
*
|
|
12696
|
-
* `
|
|
12697
|
-
*
|
|
12670
|
+
* Every opt-in service, resolved once (#838). Shared by reference with each
|
|
12671
|
+
* `Vault` this instance opens and, through them, every `Collection` — so
|
|
12672
|
+
* there is exactly one resolution and no construction path can disagree
|
|
12673
|
+
* about which services are enabled (the #834 bug class).
|
|
12698
12674
|
*/
|
|
12699
|
-
|
|
12675
|
+
strategies;
|
|
12700
12676
|
/**
|
|
12701
|
-
* Opt-in
|
|
12702
|
-
* `
|
|
12703
|
-
*
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12677
|
+
* Opt-in sovereign-custody (FR-6) strategy — `NO_CUSTODY` (throwing) unless
|
|
12678
|
+
* `withCustody()` was passed. Kept as a public accessor because `Vault`
|
|
12679
|
+
* routes `vault.custody.liberate` through `this.noydb.custodyStrategy`.
|
|
12680
|
+
* @internal
|
|
12681
|
+
*/
|
|
12682
|
+
get custodyStrategy() {
|
|
12683
|
+
return this.strategies.custody;
|
|
12684
|
+
}
|
|
12707
12685
|
snapshots;
|
|
12708
12686
|
policyManager;
|
|
12709
12687
|
/** Pre-resolved policy-gate engine function (mirrors `coordinationProvider`/`userApiFactory` above). */
|
|
@@ -12747,14 +12725,9 @@ var Noydb = class {
|
|
|
12747
12725
|
this.userApiFactory = options.userApiFactory;
|
|
12748
12726
|
if (!options.policyFactory || !options.policyCheckGateFn) throw new ValidationError("Noydb must be constructed via createNoydb(), which resolves the default policy service.");
|
|
12749
12727
|
this.policyCheckGate = options.policyCheckGateFn;
|
|
12750
|
-
this.
|
|
12751
|
-
this.forgetStrategy = options.forgetStrategy ?? NO_FORGET;
|
|
12752
|
-
this.custodyStrategy = options.custodyStrategy ?? NO_CUSTODY;
|
|
12753
|
-
this.teamStrategy = options.teamStrategy ?? NO_TEAM;
|
|
12754
|
-
this.sessionStrategy = options.sessionStrategy ?? NO_SESSION;
|
|
12755
|
-
this.syncStrategy = options.syncStrategy ?? NO_SYNC;
|
|
12728
|
+
this.strategies = resolveStrategies(options);
|
|
12756
12729
|
this.snapshots = new NoydbSnapshots({
|
|
12757
|
-
strategy:
|
|
12730
|
+
strategy: this.strategies.snapshot,
|
|
12758
12731
|
user: options.user,
|
|
12759
12732
|
isClosed: () => this.closed,
|
|
12760
12733
|
getVault: (name) => this.vaultCache.get(name),
|
|
@@ -12791,7 +12764,7 @@ var Noydb = class {
|
|
|
12791
12764
|
}
|
|
12792
12765
|
});
|
|
12793
12766
|
if (options.sessionPolicy) {
|
|
12794
|
-
this.
|
|
12767
|
+
this.strategies.session.validateSessionPolicy(options.sessionPolicy);
|
|
12795
12768
|
}
|
|
12796
12769
|
this.#registerGuardGate();
|
|
12797
12770
|
this.#registerPeriodGate();
|
|
@@ -12800,7 +12773,7 @@ var Noydb = class {
|
|
|
12800
12773
|
}
|
|
12801
12774
|
/** @internal — resolved forget strategy (NO_FORGET when not configured). */
|
|
12802
12775
|
get _forgetStrategy() {
|
|
12803
|
-
return this.
|
|
12776
|
+
return this.strategies.forget;
|
|
12804
12777
|
}
|
|
12805
12778
|
// GDPR subject-index maintenance. When `withForgetCascade` declares
|
|
12806
12779
|
// any subject fields, keep the encrypted `_subject_index` in lock-step with
|
|
@@ -12813,7 +12786,7 @@ var Noydb = class {
|
|
|
12813
12786
|
// does NOT) — drop the ref so a deleted record never lingers in the
|
|
12814
12787
|
// index (RISK #2). Without it, forget() would try to shred a ghost.
|
|
12815
12788
|
#registerForgetHooks() {
|
|
12816
|
-
const subjects = this.
|
|
12789
|
+
const subjects = this.strategies.forget.subjects;
|
|
12817
12790
|
if (Object.keys(subjects).length === 0) return;
|
|
12818
12791
|
const subjectFieldFor = (collection) => subjects[collection];
|
|
12819
12792
|
this.writeHooks.onAfterWrite(async (event) => {
|
|
@@ -13002,7 +12975,7 @@ var Noydb = class {
|
|
|
13002
12975
|
if (targets.length > 0) {
|
|
13003
12976
|
const primary = targets.find((t) => t.role === "sync-peer") ?? targets[0];
|
|
13004
12977
|
const effectivePolicy = this.options.syncPolicy ?? primary.policy ?? INDEXED_STORE_POLICY;
|
|
13005
|
-
syncEngine = this.
|
|
12978
|
+
syncEngine = this.strategies.sync.buildSyncEngine({
|
|
13006
12979
|
local: this.options.store,
|
|
13007
12980
|
remote: primary.store,
|
|
13008
12981
|
vault: name,
|
|
@@ -13016,7 +12989,7 @@ var Noydb = class {
|
|
|
13016
12989
|
for (const target of targets) {
|
|
13017
12990
|
if (target === primary) continue;
|
|
13018
12991
|
const targetPolicy = target.policy ?? this.options.syncPolicy ?? INDEXED_STORE_POLICY;
|
|
13019
|
-
const engine = this.
|
|
12992
|
+
const engine = this.strategies.sync.buildSyncEngine({
|
|
13020
12993
|
local: this.options.store,
|
|
13021
12994
|
remote: target.store,
|
|
13022
12995
|
vault: name,
|
|
@@ -13049,31 +13022,14 @@ var Noydb = class {
|
|
|
13049
13022
|
syncAdapter: targets.length > 0 ? targets[0].store : void 0,
|
|
13050
13023
|
getPurgeableTargets: () => targets.filter((t) => t.role === "backup" || t.role === "archive").map((t) => ({ store: t.store, role: t.role, ...t.label !== void 0 ? { label: t.label } : {} })),
|
|
13051
13024
|
historyConfig: this.options.history,
|
|
13052
|
-
|
|
13025
|
+
// #838 — the 21 conditional strategy spreads that used to live here are
|
|
13026
|
+
// one shared reference. This block is where #834's drift happened: a
|
|
13027
|
+
// copy of it silently omitted six strategies, and there was nothing to
|
|
13028
|
+
// catch that. There is no longer a per-service line to omit.
|
|
13029
|
+
strategies: this.strategies,
|
|
13053
13030
|
...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
|
|
13054
|
-
...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
|
|
13055
|
-
...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
|
|
13056
|
-
...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
|
|
13057
|
-
...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
|
|
13058
|
-
...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
|
|
13059
|
-
...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
|
|
13060
|
-
...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
|
|
13061
|
-
...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
|
|
13062
|
-
...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
|
|
13063
|
-
...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
|
|
13064
|
-
...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
|
|
13065
|
-
...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
|
|
13066
|
-
...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
|
|
13067
|
-
...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
|
|
13068
|
-
...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
|
|
13069
13031
|
...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
|
|
13070
13032
|
...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
|
|
13071
|
-
forgetStrategy: this.forgetStrategy,
|
|
13072
|
-
...this.options.attestationStrategy !== void 0 ? { attestationStrategy: this.options.attestationStrategy } : {},
|
|
13073
|
-
...this.options.classifiedStrategy !== void 0 ? { classifiedStrategy: this.options.classifiedStrategy } : {},
|
|
13074
|
-
...this.options.sealedRecordStrategy !== void 0 ? { sealedRecordStrategy: this.options.sealedRecordStrategy } : {},
|
|
13075
|
-
...this.options.portabilityStrategy !== void 0 ? { portabilityStrategy: this.options.portabilityStrategy } : {},
|
|
13076
|
-
...this.options.sequenceStrategy !== void 0 ? { sequenceStrategy: this.options.sequenceStrategy } : {},
|
|
13077
13033
|
locale: opts?.locale,
|
|
13078
13034
|
...opts?.meta !== void 0 ? { meta: opts.meta } : {},
|
|
13079
13035
|
// Thread the translator hook so Collection.put() can invoke it
|
|
@@ -13142,7 +13098,7 @@ var Noydb = class {
|
|
|
13142
13098
|
* Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
|
|
13143
13099
|
*/
|
|
13144
13100
|
async grant(vault, options, factors) {
|
|
13145
|
-
return this.
|
|
13101
|
+
return this.strategies.team.grant(this.team, vault, options, factors);
|
|
13146
13102
|
}
|
|
13147
13103
|
/**
|
|
13148
13104
|
* Revoke a user's access to a vault.
|
|
@@ -13155,7 +13111,7 @@ var Noydb = class {
|
|
|
13155
13111
|
* Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
|
|
13156
13112
|
*/
|
|
13157
13113
|
async revoke(vault, options, factors) {
|
|
13158
|
-
return this.
|
|
13114
|
+
return this.strategies.team.revoke(this.team, vault, options, factors);
|
|
13159
13115
|
}
|
|
13160
13116
|
/**
|
|
13161
13117
|
* Grant the FR-6 `custodian` role to a user (owner-only custody API).
|
|
@@ -13168,7 +13124,7 @@ var Noydb = class {
|
|
|
13168
13124
|
* owner-only invariant even if a host mis-configures the gate.
|
|
13169
13125
|
*/
|
|
13170
13126
|
async grantCustodian(vault, options, factors) {
|
|
13171
|
-
return this.
|
|
13127
|
+
return this.strategies.custody.grantCustodian(this, vault, options, factors);
|
|
13172
13128
|
}
|
|
13173
13129
|
/** @internal — grant-custodian engine, reached only via withCustody(); the
|
|
13174
13130
|
* keyring engine arrives as an argument so the floor never carries it (#267). */
|
|
@@ -13187,7 +13143,7 @@ var Noydb = class {
|
|
|
13187
13143
|
* 'owner'` check, so an admin cannot unwind a custodianship.
|
|
13188
13144
|
*/
|
|
13189
13145
|
async revokeCustodian(vault, options, factors) {
|
|
13190
|
-
return this.
|
|
13146
|
+
return this.strategies.custody.revokeCustodian(this, vault, options, factors);
|
|
13191
13147
|
}
|
|
13192
13148
|
/** @internal — revoke-custodian engine, reached only via withCustody().
|
|
13193
13149
|
* Mirrors `_grantCustodianImpl` (#267: engine passed in). */
|
|
@@ -13266,7 +13222,7 @@ var Noydb = class {
|
|
|
13266
13222
|
* Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
|
|
13267
13223
|
*/
|
|
13268
13224
|
async rotate(vault, collections) {
|
|
13269
|
-
return this.
|
|
13225
|
+
return this.strategies.team.rotate(this.team, vault, collections);
|
|
13270
13226
|
}
|
|
13271
13227
|
/** List all users with access to a vault. */
|
|
13272
13228
|
async listUsers(vault) {
|
|
@@ -13556,7 +13512,7 @@ var Noydb = class {
|
|
|
13556
13512
|
}
|
|
13557
13513
|
transaction(arg, maybeFn) {
|
|
13558
13514
|
if (typeof arg === "function") {
|
|
13559
|
-
return this.
|
|
13515
|
+
return this.strategies.tx.runTransaction(this, arg);
|
|
13560
13516
|
}
|
|
13561
13517
|
if (typeof arg === "object" && arg !== null && arg.dryRun === true) {
|
|
13562
13518
|
if (typeof maybeFn !== "function") {
|
|
@@ -13564,7 +13520,7 @@ var Noydb = class {
|
|
|
13564
13520
|
"db.transaction({ dryRun: true }, fn) requires the callback as the second argument."
|
|
13565
13521
|
);
|
|
13566
13522
|
}
|
|
13567
|
-
return this.
|
|
13523
|
+
return this.strategies.tx.runDryRun(this, maybeFn);
|
|
13568
13524
|
}
|
|
13569
13525
|
if (typeof arg === "object" && arg !== null && arg.amendment === true) {
|
|
13570
13526
|
if (typeof maybeFn !== "function") {
|
|
@@ -13572,7 +13528,7 @@ var Noydb = class {
|
|
|
13572
13528
|
"db.transaction({ amendment: true }, fn) requires the callback as the second argument."
|
|
13573
13529
|
);
|
|
13574
13530
|
}
|
|
13575
|
-
return this.
|
|
13531
|
+
return this.strategies.tx.runTransaction(this, maybeFn, arg);
|
|
13576
13532
|
}
|
|
13577
13533
|
const vault = arg;
|
|
13578
13534
|
const comp = this.vaultCache.get(vault);
|
|
@@ -13582,7 +13538,7 @@ var Noydb = class {
|
|
|
13582
13538
|
);
|
|
13583
13539
|
}
|
|
13584
13540
|
const engine = this.getSyncEngine(vault);
|
|
13585
|
-
return this.
|
|
13541
|
+
return this.strategies.sync.buildSyncTransaction(comp, engine);
|
|
13586
13542
|
}
|
|
13587
13543
|
/**
|
|
13588
13544
|
* Internal accessor for the primary store — used by the tx
|
|
@@ -13863,7 +13819,7 @@ var Noydb = class {
|
|
|
13863
13819
|
enforcer.destroy();
|
|
13864
13820
|
}
|
|
13865
13821
|
this.policyEnforcers.clear();
|
|
13866
|
-
this.
|
|
13822
|
+
this.strategies.session.revokeAllSessions();
|
|
13867
13823
|
for (const engine of this.syncEngines.values()) {
|
|
13868
13824
|
engine.stopAutoSync();
|
|
13869
13825
|
}
|
|
@@ -14364,4 +14320,4 @@ export {
|
|
|
14364
14320
|
Noydb,
|
|
14365
14321
|
createNoydb
|
|
14366
14322
|
};
|
|
14367
|
-
//# sourceMappingURL=chunk-
|
|
14323
|
+
//# sourceMappingURL=chunk-W7TCXZWU.js.map
|