@tearleads/client-sdk 0.1.42 → 0.1.44
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/client/containerDocumentDiscovery.js +71 -29
- package/client/containerDocumentDiscovery.js.map +1 -1
- package/client/deviceFirst.js +4 -5
- package/client/deviceFirst.js.map +1 -1
- package/data/blobs/transferPool.js +35 -8
- package/data/blobs/transferPool.js.map +1 -1
- package/data/containers/shared/projection.js +12 -0
- package/data/containers/shared/projection.js.map +1 -1
- package/data/documents/blob/shared/types.d.ts +2 -3
- package/data/documents/blob/shared/types.js.map +1 -1
- package/data/documents/shared/events.js +0 -1
- package/data/documents/shared/events.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistence.js +6 -22
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +5 -15
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerPendingUpdatePersistence.js +6 -15
- package/data/persistence/container-contents/containerPendingUpdatePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRecoveryPersistence.js +3 -4
- package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js +3 -5
- package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
- package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
- package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
- package/data/persistence/containers/containerSyncWatermarkPersistence.d.ts +11 -3
- package/data/persistence/containers/containerSyncWatermarkPersistence.js +46 -58
- package/data/persistence/containers/containerSyncWatermarkPersistence.js.map +1 -1
- package/data/persistence/documents/documentsPersistence.js +4 -9
- package/data/persistence/documents/documentsPersistence.js.map +1 -1
- package/data/persistence/documents/internal/discardDocument.js +1 -2
- package/data/persistence/documents/internal/discardDocument.js.map +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js +1 -2
- package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js +17 -25
- package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js +2 -14
- package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
- package/data/persistence/documents/internal/syncQueuePersistence.js +3 -3
- package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
- package/data/sqlite/documentHistoryPersistence.d.ts +9 -3
- package/data/sqlite/documentHistoryPersistence.js +31 -8
- package/data/sqlite/documentHistoryPersistence.js.map +1 -1
- package/data/sqlite/documentPendingUpdatePersistence.d.ts +58 -11
- package/data/sqlite/documentPendingUpdatePersistence.js +137 -63
- package/data/sqlite/documentPendingUpdatePersistence.js.map +1 -1
- package/data/sqlite/documentPersistence.d.ts +1 -1
- package/data/sqlite/documentPersistence.js +1 -1
- package/data/sqlite/documentPersistence.js.map +1 -1
- package/data/sqlite/documentPersistenceTypes.d.ts +2 -2
- package/data/sqlite/documentPersistenceTypes.js.map +1 -1
- package/data/sqlite/documentRecordPersistence.js +5 -4
- package/data/sqlite/documentRecordPersistence.js.map +1 -1
- package/data/sqlite/schema.d.ts +167 -517
- package/data/sqlite/schema.js +68 -82
- package/data/sqlite/schema.js.map +1 -1
- package/internal/api-client/ApiClient.d.ts +18 -41
- package/internal/api-client/ApiClient.js +9 -14
- package/internal/api-client/ApiClient.js.map +1 -1
- package/internal/api-client/apiRequestRuntime.d.ts +2 -0
- package/internal/api-client/apiRequestRuntime.js +4 -0
- package/internal/api-client/apiRequestRuntime.js.map +1 -1
- package/internal/api-client/binaryRequestOperationTransport.d.ts +18 -0
- package/internal/api-client/index.d.ts +1 -0
- package/internal/api-client/index.js +1 -0
- package/internal/api-client/index.js.map +1 -1
- package/internal/api-client/operationTransportFactory.d.ts +6 -0
- package/internal/api-client/requestInternals.js +7 -7
- package/internal/api-client/requestInternals.js.map +1 -1
- package/internal/api-client/routes/blobs/get.d.ts +7 -0
- package/internal/api-client/routes/blobs/get.js.map +1 -1
- package/internal/api-client/routes/blobs/multipart.js +1 -11
- package/internal/api-client/routes/blobs/multipart.js.map +1 -1
- package/internal/api-client/routes/blobs/multipartUpload.d.ts +14 -0
- package/internal/api-client/routes/blobs/multipartUpload.js +94 -43
- package/internal/api-client/routes/blobs/multipartUpload.js.map +1 -1
- package/internal/api-client/routes/containers/reads.d.ts +13 -7
- package/internal/api-client/routes/containers/reads.js +36 -15
- package/internal/api-client/routes/containers/reads.js.map +1 -1
- package/internal/api-client/types.d.ts +1 -5
- package/internal/api-client/types.js.map +1 -1
- package/internal/validators/containerReadRefinements.js +15 -5
- package/internal/validators/containerReadRefinements.js.map +1 -1
- package/internal/validators/containerReadSchemas.d.ts +36 -0
- package/internal/validators/containerReadSchemas.js +64 -1
- package/internal/validators/containerReadSchemas.js.map +1 -1
- package/internal/validators/operation/attachments.d.ts +80 -160
- package/internal/validators/operation/auth.d.ts +760 -1664
- package/internal/validators/operation/blobDownloads.js +1 -1
- package/internal/validators/operation/blobDownloads.js.map +1 -1
- package/internal/validators/operation/containerMutations.d.ts +416 -856
- package/internal/validators/operation/containerReads.d.ts +118 -182
- package/internal/validators/operation/containerReads.js +20 -54
- package/internal/validators/operation/containerReads.js.map +1 -1
- package/internal/validators/operation/documentMutations.d.ts +120 -264
- package/internal/validators/operation/documentSync.d.ts +40 -80
- package/internal/validators/operation/index.d.ts +2 -2
- package/internal/validators/operation/index.js +2 -2
- package/internal/validators/operation/index.js.map +1 -1
- package/internal/validators/operation/multipartBlobs.d.ts +70 -190
- package/internal/validators/operation/multipartBlobs.js +2 -24
- package/internal/validators/operation/multipartBlobs.js.map +1 -1
- package/internal/validators/operation/multipartPartUploads.d.ts +5 -5
- package/internal/validators/operation/multipartPartUploads.js +6 -20
- package/internal/validators/operation/multipartPartUploads.js.map +1 -1
- package/internal/validators/operation/organizations.d.ts +882 -1906
- package/internal/validators/operation/principals.d.ts +120 -240
- package/internal/validators/operation/registry.d.ts +3 -4
- package/internal/validators/operation/registry.js +3 -4
- package/internal/validators/operation/registry.js.map +1 -1
- package/internal/validators/request/blob.d.ts +100 -201
- package/internal/validators/request/blob.js +6 -13
- package/internal/validators/request/blob.js.map +1 -1
- package/internal/validators/request/container.d.ts +136 -272
- package/internal/validators/request/container.js +16 -10
- package/internal/validators/request/container.js.map +1 -1
- package/internal/validators/request/containerDocumentLanes.d.ts +23 -0
- package/internal/validators/request/containerDocumentLanes.js +23 -0
- package/internal/validators/request/containerDocumentLanes.js.map +1 -0
- package/internal/validators/request/containerManifestRef.d.ts +54 -0
- package/internal/validators/request/containerManifestRef.js +28 -0
- package/internal/validators/request/containerManifestRef.js.map +1 -0
- package/internal/validators/request/containerMetadata.d.ts +160 -368
- package/internal/validators/request/containerParentLanes.js +5 -35
- package/internal/validators/request/containerParentLanes.js.map +1 -1
- package/internal/validators/request/document.d.ts +100 -245
- package/internal/validators/request/document.js +1 -2
- package/internal/validators/request/document.js.map +1 -1
- package/internal/validators/request/documentSyncSchema.d.ts +42 -109
- package/internal/validators/request/documentSyncSchema.js +8 -25
- package/internal/validators/request/documentSyncSchema.js.map +1 -1
- package/internal/validators/request/index.d.ts +2 -1
- package/internal/validators/request/index.js +2 -1
- package/internal/validators/request/index.js.map +1 -1
- package/internal/validators/request/organization.d.ts +160 -320
- package/internal/validators/request/organizationProvisioning.d.ts +2424 -5312
- package/internal/validators/request/principal.d.ts +160 -320
- package/internal/validators/request/registration.d.ts +760 -1664
- package/internal/validators/response/blob.d.ts +48 -27
- package/internal/validators/response/blob.js +3 -10
- package/internal/validators/response/blob.js.map +1 -1
- package/internal/validators/response/containerDocumentLanes.d.ts +82 -0
- package/internal/validators/response/containerDocumentLanes.js +35 -0
- package/internal/validators/response/containerDocumentLanes.js.map +1 -0
- package/internal/validators/response/containerParentLanes.js +3 -15
- package/internal/validators/response/containerParentLanes.js.map +1 -1
- package/internal/validators/response/index.d.ts +3 -2
- package/internal/validators/response/index.js +2 -2
- package/internal/validators/response/index.js.map +1 -1
- package/internal/validators/util/blob.d.ts +7 -0
- package/internal/validators/util/blob.js +7 -0
- package/internal/validators/util/blob.js.map +1 -1
- package/internal/validators/util/blobTransferSchemas.d.ts +41 -0
- package/internal/validators/util/blobTransferSchemas.js +39 -0
- package/internal/validators/util/blobTransferSchemas.js.map +1 -0
- package/internal/validators/util/containerLimits.d.ts +7 -0
- package/internal/validators/util/containerLimits.js +7 -0
- package/internal/validators/util/containerLimits.js.map +1 -1
- package/internal/validators/util/index.d.ts +2 -1
- package/internal/validators/util/index.js +2 -1
- package/internal/validators/util/index.js.map +1 -1
- package/package.json +1 -1
- package/sync/reconciliation/knownContainerSweep.js +57 -54
- package/sync/reconciliation/knownContainerSweep.js.map +1 -1
- package/sync/reconciliation/reconcileContainer.js +49 -17
- package/sync/reconciliation/reconcileContainer.js.map +1 -1
- package/sync/reconciliation/service.js +44 -16
- package/sync/reconciliation/service.js.map +1 -1
- package/sync/reconciliation/serviceTypes.d.ts +23 -2
- package/sync/reconciliation/serviceTypes.js.map +1 -1
- package/workflows/blobs/multipartFirstParts.js +82 -0
- package/workflows/blobs/multipartFirstParts.js.map +1 -0
- package/workflows/blobs/multipartStageResolution.js +83 -0
- package/workflows/blobs/multipartStageResolution.js.map +1 -0
- package/workflows/blobs/multipartUpload.js +45 -89
- package/workflows/blobs/multipartUpload.js.map +1 -1
- package/workflows/container-contents/containerDocumentListing.js +92 -38
- package/workflows/container-contents/containerDocumentListing.js.map +1 -1
- package/workflows/container-contents/containerPersistence.d.ts +8 -2
- package/workflows/container-contents/containerPersistence.js +6 -7
- package/workflows/container-contents/containerPersistence.js.map +1 -1
- package/workflows/container-contents/documentDiscovery.d.ts +3 -3
- package/workflows/container-contents/documentDiscovery.js +24 -96
- package/workflows/container-contents/documentDiscovery.js.map +1 -1
- package/workflows/container-contents/documentDiscoveryApply.js +65 -0
- package/workflows/container-contents/documentDiscoveryApply.js.map +1 -0
- package/workflows/container-contents/documentDiscoveryLanes.js +53 -0
- package/workflows/container-contents/documentDiscoveryLanes.js.map +1 -0
- package/workflows/container-contents/documentDiscoveryTypes.d.ts +25 -19
- package/workflows/container-contents/documentDiscoveryTypes.js.map +1 -1
- package/workflows/container-contents/documentPriming.js +2 -1
- package/workflows/container-contents/documentPriming.js.map +1 -1
- package/workflows/container-contents/documentQueries/sql.js +4 -4
- package/workflows/container-contents/documentQueries/sql.js.map +1 -1
- package/workflows/container-contents/pendingWrites/deferredTails.js +6 -3
- package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
- package/workflows/container-contents/pendingWrites/sources.js +2 -1
- package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
- package/workflows/container-contents/pendingWrites.js +2 -1
- package/workflows/container-contents/pendingWrites.js.map +1 -1
- package/workflows/container-contents/remoteHydration/laneFetchMarkers.js +11 -17
- package/workflows/container-contents/remoteHydration/laneFetchMarkers.js.map +1 -1
- package/workflows/containers/child/create.js +3 -3
- package/workflows/containers/child/create.js.map +1 -1
- package/workflows/containers/child/move.js +2 -2
- package/workflows/containers/child/move.js.map +1 -1
- package/workflows/containers/child/mutationRequestCore.js +5 -4
- package/workflows/containers/child/mutationRequestCore.js.map +1 -1
- package/workflows/containers/child/recitePlan.js +3 -2
- package/workflows/containers/child/recitePlan.js.map +1 -1
- package/workflows/containers/child/sharePlanCore.js +2 -2
- package/workflows/containers/child/sharePlanCore.js.map +1 -1
- package/workflows/containers/root/create.js +2 -2
- package/workflows/containers/root/create.js.map +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.d.ts +20 -46
- package/workflows/sync/remoteReset.js +9 -9
- package/workflows/sync/remoteReset.js.map +1 -1
- package/workflows/sync/remoteResetCursorScope.js +10 -18
- package/workflows/sync/remoteResetCursorScope.js.map +1 -1
- package/workflows/sync/remoteResetPlans.js +6 -3
- package/workflows/sync/remoteResetPlans.js.map +1 -1
- package/workflows/sync/remoteResetScope.js +4 -11
- package/workflows/sync/remoteResetScope.js.map +1 -1
- package/internal/validators/operation/blobTransferSchemas.js +0 -11
- package/internal/validators/operation/blobTransferSchemas.js.map +0 -1
|
@@ -1,48 +1,90 @@
|
|
|
1
1
|
import { sqlContainerContentsPersistence } from "../data/persistence/container-contents/containerContentsPersistence.js";
|
|
2
2
|
import { holdContainerDocumentTombstones, listKnownContainerDocumentPlacements, listRetryableHeldContainerDocumentTombstones, loadLocalDocumentAccessEpoch, refuteContainerDocumentTombstoneHolds, } from "../data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js";
|
|
3
3
|
import { createDocumentDiscoveryEvidenceStore } from "../data/persistence/documents/documentDiscoveryEvidencePersistence.js";
|
|
4
|
-
import {
|
|
4
|
+
import { listContainerDocumentLanesFromApi } from "../workflows/container-contents/containerDocumentListing.js";
|
|
5
5
|
import { createDiscoveredDocumentVerifier } from "../workflows/container-contents/documentDiscoveryEvidence.js";
|
|
6
|
+
import { discoverContainerDocumentLanes, } from "../workflows/container-contents/documentDiscoveryLanes.js";
|
|
6
7
|
import { createContainerDocumentQueriesFromRuntime } from "../workflows/container-contents/documentQueries.js";
|
|
7
8
|
import { createContainerDocumentTombstoneVerifier, createDocumentHeadLinkSetLoader, } from "../workflows/container-contents/documentTombstoneEvidence.js";
|
|
8
|
-
import { createContainerContentsWorkflowRuntime } from "../workflows/container-contents/runtime.js";
|
|
9
|
+
import { createContainerContentsWorkflowRuntime, } from "../workflows/container-contents/runtime.js";
|
|
9
10
|
import { createRuntimePrincipalPolicyWarmer } from "../workflows/principals/runtimePolicyWarmer.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const input = runtimeService.workflowInput();
|
|
13
|
-
if (input.infra.dbStatus !== "ready") {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
const runtime = createContainerContentsWorkflowRuntime(input);
|
|
17
|
-
const evidenceStore = createDocumentDiscoveryEvidenceStore(input.infra.execSql);
|
|
18
|
-
// Capture the reset fence before reading scope, so a reset between this read
|
|
19
|
-
// and listing cannot publish old-organization evidence into its replacement.
|
|
20
|
-
const generation = await evidenceStore.begin();
|
|
21
|
-
const stored = await sqlContainerContentsPersistence.loadContainerMetadataState(input.infra.execSql, containerId);
|
|
22
|
-
if (!stored)
|
|
23
|
-
return null;
|
|
24
|
-
const containerOrganizationId = stored.container.organizationId;
|
|
11
|
+
function createDiscoveryLane(input) {
|
|
12
|
+
const { containerOrganizationId, execSql, request, runtime } = input;
|
|
25
13
|
const warmReferencedPrincipalPolicies = createRuntimePrincipalPolicyWarmer(runtime);
|
|
26
14
|
const loadHead = createDocumentHeadLinkSetLoader(runtime);
|
|
27
|
-
const loadEpoch = (documentId) => loadLocalDocumentAccessEpoch(
|
|
28
|
-
return
|
|
29
|
-
...
|
|
30
|
-
apiClient: runtime.apiClient,
|
|
31
|
-
beginDocumentDiscovery: async () => generation,
|
|
15
|
+
const loadEpoch = (documentId) => loadLocalDocumentAccessEpoch(execSql, documentId);
|
|
16
|
+
return {
|
|
17
|
+
...input.queries,
|
|
32
18
|
cacheReferencedPrincipalPolicies: (references) => containerOrganizationId
|
|
33
19
|
? warmReferencedPrincipalPolicies({
|
|
34
20
|
organizationId: containerOrganizationId,
|
|
35
21
|
references,
|
|
36
22
|
})
|
|
37
23
|
: Promise.resolve(),
|
|
38
|
-
containerId,
|
|
39
|
-
holdContainerDocumentTombstones: (tombstones) => holdContainerDocumentTombstones(
|
|
40
|
-
listHeldContainerDocumentTombstones: (containerIds) => listRetryableHeldContainerDocumentTombstones(
|
|
41
|
-
listKnownContainerDocumentPlacements: (placements) => listKnownContainerDocumentPlacements(
|
|
42
|
-
onFullListing,
|
|
43
|
-
refuteContainerDocumentTombstoneHolds: (placements) => refuteContainerDocumentTombstoneHolds(
|
|
24
|
+
containerId: request.containerId,
|
|
25
|
+
holdContainerDocumentTombstones: (tombstones) => holdContainerDocumentTombstones(execSql, tombstones),
|
|
26
|
+
listHeldContainerDocumentTombstones: (containerIds) => listRetryableHeldContainerDocumentTombstones(execSql, containerIds),
|
|
27
|
+
listKnownContainerDocumentPlacements: (placements) => listKnownContainerDocumentPlacements(execSql, placements),
|
|
28
|
+
onFullListing: request.onFullListing,
|
|
29
|
+
refuteContainerDocumentTombstoneHolds: (placements) => refuteContainerDocumentTombstoneHolds(execSql, placements),
|
|
44
30
|
verifyContainerDocumentTombstones: createContainerDocumentTombstoneVerifier(containerOrganizationId, loadHead, loadEpoch),
|
|
45
|
-
verifyDiscoveredDocuments: createDiscoveredDocumentVerifier(containerOrganizationId, loadHead, loadEpoch, evidenceStore, onPendingDiscovery),
|
|
31
|
+
verifyDiscoveredDocuments: createDiscoveredDocumentVerifier(containerOrganizationId, loadHead, loadEpoch, input.evidenceStore, request.onPendingDiscovery),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Internal adapter shared by explicit discovery and background reconciliation:
|
|
36
|
+
* one batched listing for every requested container, then per-container
|
|
37
|
+
* verification scoped to each container's durable organization.
|
|
38
|
+
*/
|
|
39
|
+
export async function discoverContainerDocumentLanesForRuntime({ onOutcome, requests, runtimeService, }) {
|
|
40
|
+
const unlisted = (containerId) => ({
|
|
41
|
+
containerId,
|
|
42
|
+
status: "fulfilled",
|
|
43
|
+
value: null,
|
|
44
|
+
});
|
|
45
|
+
const input = runtimeService.workflowInput();
|
|
46
|
+
if (input.infra.dbStatus !== "ready") {
|
|
47
|
+
return requests.map(({ containerId }) => unlisted(containerId));
|
|
48
|
+
}
|
|
49
|
+
const runtime = createContainerContentsWorkflowRuntime(input);
|
|
50
|
+
const execSql = input.infra.execSql;
|
|
51
|
+
const evidenceStore = createDocumentDiscoveryEvidenceStore(execSql);
|
|
52
|
+
const queries = createContainerDocumentQueriesFromRuntime(runtime);
|
|
53
|
+
// Capture the reset fence before reading any lane's scope, so a reset
|
|
54
|
+
// between these reads and the listing cannot publish old-organization
|
|
55
|
+
// evidence into its replacement.
|
|
56
|
+
const generation = await evidenceStore.begin();
|
|
57
|
+
const lanes = [];
|
|
58
|
+
for (const request of requests) {
|
|
59
|
+
const stored = await sqlContainerContentsPersistence.loadContainerMetadataState(execSql, request.containerId);
|
|
60
|
+
if (stored)
|
|
61
|
+
lanes.push(createDiscoveryLane({
|
|
62
|
+
containerOrganizationId: stored.container.organizationId,
|
|
63
|
+
evidenceStore,
|
|
64
|
+
execSql,
|
|
65
|
+
queries,
|
|
66
|
+
request,
|
|
67
|
+
runtime,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
const outcomes = await discoverContainerDocumentLanes({
|
|
71
|
+
generation,
|
|
72
|
+
lanes,
|
|
73
|
+
listContainerDocumentLanes: (listed) => listContainerDocumentLanesFromApi(runtime.apiClient, listed),
|
|
74
|
+
loadContainerDocumentWatermark: queries.loadContainerDocumentWatermark,
|
|
75
|
+
onOutcome,
|
|
76
|
+
});
|
|
77
|
+
const outcomeByContainerId = new Map(outcomes.map((outcome) => [outcome.containerId, outcome]));
|
|
78
|
+
return requests.map(({ containerId }) => outcomeByContainerId.get(containerId) ?? unlisted(containerId));
|
|
79
|
+
}
|
|
80
|
+
/** Discovers one container; a rejected lane rethrows its failure. */
|
|
81
|
+
export async function discoverContainerDocumentsForRuntime({ runtimeService, ...request }) {
|
|
82
|
+
const [outcome] = await discoverContainerDocumentLanesForRuntime({
|
|
83
|
+
requests: [request],
|
|
84
|
+
runtimeService,
|
|
46
85
|
});
|
|
86
|
+
if (outcome?.status === "rejected")
|
|
87
|
+
throw outcome.reason;
|
|
88
|
+
return outcome?.value ?? null;
|
|
47
89
|
}
|
|
48
90
|
//# sourceMappingURL=containerDocumentDiscovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerDocumentDiscovery.js","sourceRoot":"","sources":["containerDocumentDiscovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,qEAAqE,CAAC;AACtH,OAAO,EACL,+BAA+B,EAC/B,oCAAoC,EACpC,4CAA4C,EAC5C,4BAA4B,EAC5B,qCAAqC,GACtC,MAAM,0EAA0E,CAAC;AAClF,OAAO,EAAE,oCAAoC,EAAE,MAAM,oEAAoE,CAAC;AAC1H,OAAO,EAAE,iCAAiC,EAAE,MAAM,mDAAmD,CAAC;AACtG,OAAO,EAAE,gCAAgC,EAAE,MAAM,2DAA2D,CAAC;AAC7G,OAAO,EAAE,yCAAyC,EAAE,MAAM,iDAAiD,CAAC;AAC5G,OAAO,EACL,wCAAwC,EACxC,+BAA+B,GAChC,MAAM,2DAA2D,CAAC;AACnE,OAAO,EAAE,sCAAsC,EAAE,MAAM,yCAAyC,CAAC;AACjG,OAAO,EAAE,kCAAkC,EAAE,MAAM,6CAA6C,CAAC;AAGjG,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oCAAoC,CAAC,EACzD,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,cAAc,GAMf;IACC,MAAM,KAAK,GAAG,cAAc,CAAC,aAAa,EAAE,CAAC;IAC7C,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,sCAAsC,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,oCAAoC,CACxD,KAAK,CAAC,KAAK,CAAC,OAAO,CACpB,CAAC;IACF,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC;IAC/C,MAAM,MAAM,GACV,MAAM,+BAA+B,CAAC,0BAA0B,CAC9D,KAAK,CAAC,KAAK,CAAC,OAAO,EACnB,WAAW,CACZ,CAAC;IACJ,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,uBAAuB,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC;IAChE,MAAM,+BAA+B,GACnC,kCAAkC,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,+BAA+B,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,CAAC,UAAkB,EAAE,EAAE,CACvC,4BAA4B,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAChE,OAAO,iCAAiC,CAAC;QACvC,GAAG,yCAAyC,CAAC,OAAO,CAAC;QACrD,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU;QAC9C,gCAAgC,EAAE,CAAC,UAAU,EAAE,EAAE,CAC/C,uBAAuB;YACrB,CAAC,CAAC,+BAA+B,CAAC;gBAC9B,cAAc,EAAE,uBAAuB;gBACvC,UAAU;aACX,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE;QACvB,WAAW;QACX,+BAA+B,EAAE,CAAC,UAAU,EAAE,EAAE,CAC9C,+BAA+B,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC;QAClE,mCAAmC,EAAE,CAAC,YAAY,EAAE,EAAE,CACpD,4CAA4C,CAC1C,KAAK,CAAC,KAAK,CAAC,OAAO,EACnB,YAAY,CACb;QACH,oCAAoC,EAAE,CAAC,UAAU,EAAE,EAAE,CACnD,oCAAoC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC;QACvE,aAAa;QACb,qCAAqC,EAAE,CAAC,UAAU,EAAE,EAAE,CACpD,qCAAqC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC;QACxE,iCAAiC,EAAE,wCAAwC,CACzE,uBAAuB,EACvB,QAAQ,EACR,SAAS,CACV;QACD,yBAAyB,EAAE,gCAAgC,CACzD,uBAAuB,EACvB,QAAQ,EACR,SAAS,EACT,aAAa,EACb,kBAAkB,CACnB;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { DocumentSummary } from \"../data/documents/documentSummary\";\nimport { sqlContainerContentsPersistence } from \"../data/persistence/container-contents/containerContentsPersistence\";\nimport {\n holdContainerDocumentTombstones,\n listKnownContainerDocumentPlacements,\n listRetryableHeldContainerDocumentTombstones,\n loadLocalDocumentAccessEpoch,\n refuteContainerDocumentTombstoneHolds,\n} from \"../data/persistence/documents/containerDocumentTombstoneHoldsPersistence\";\nimport { createDocumentDiscoveryEvidenceStore } from \"../data/persistence/documents/documentDiscoveryEvidencePersistence\";\nimport { discoverContainerDocumentsFromApi } from \"../workflows/container-contents/documentDiscovery\";\nimport { createDiscoveredDocumentVerifier } from \"../workflows/container-contents/documentDiscoveryEvidence\";\nimport { createContainerDocumentQueriesFromRuntime } from \"../workflows/container-contents/documentQueries\";\nimport {\n createContainerDocumentTombstoneVerifier,\n createDocumentHeadLinkSetLoader,\n} from \"../workflows/container-contents/documentTombstoneEvidence\";\nimport { createContainerContentsWorkflowRuntime } from \"../workflows/container-contents/runtime\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../workflows/principals/runtimePolicyWarmer\";\nimport type { InternalRuntime } from \"./workflowRuntime\";\n\n/** Internal adapter shared by explicit discovery and background reconciliation. */\nexport async function discoverContainerDocumentsForRuntime({\n containerId,\n onFullListing,\n onPendingDiscovery,\n runtimeService,\n}: {\n containerId: string;\n onFullListing?: ((documentIds: ReadonlyArray<string>) => void) | undefined;\n onPendingDiscovery?: ((delayMs: number) => void) | undefined;\n runtimeService: InternalRuntime;\n}): Promise<ReadonlyArray<DocumentSummary> | null> {\n const input = runtimeService.workflowInput();\n if (input.infra.dbStatus !== \"ready\") {\n return null;\n }\n const runtime = createContainerContentsWorkflowRuntime(input);\n const evidenceStore = createDocumentDiscoveryEvidenceStore(\n input.infra.execSql,\n );\n // Capture the reset fence before reading scope, so a reset between this read\n // and listing cannot publish old-organization evidence into its replacement.\n const generation = await evidenceStore.begin();\n const stored =\n await sqlContainerContentsPersistence.loadContainerMetadataState(\n input.infra.execSql,\n containerId,\n );\n if (!stored) return null;\n const containerOrganizationId = stored.container.organizationId;\n const warmReferencedPrincipalPolicies =\n createRuntimePrincipalPolicyWarmer(runtime);\n const loadHead = createDocumentHeadLinkSetLoader(runtime);\n const loadEpoch = (documentId: string) =>\n loadLocalDocumentAccessEpoch(input.infra.execSql, documentId);\n return discoverContainerDocumentsFromApi({\n ...createContainerDocumentQueriesFromRuntime(runtime),\n apiClient: runtime.apiClient,\n beginDocumentDiscovery: async () => generation,\n cacheReferencedPrincipalPolicies: (references) =>\n containerOrganizationId\n ? warmReferencedPrincipalPolicies({\n organizationId: containerOrganizationId,\n references,\n })\n : Promise.resolve(),\n containerId,\n holdContainerDocumentTombstones: (tombstones) =>\n holdContainerDocumentTombstones(input.infra.execSql, tombstones),\n listHeldContainerDocumentTombstones: (containerIds) =>\n listRetryableHeldContainerDocumentTombstones(\n input.infra.execSql,\n containerIds,\n ),\n listKnownContainerDocumentPlacements: (placements) =>\n listKnownContainerDocumentPlacements(input.infra.execSql, placements),\n onFullListing,\n refuteContainerDocumentTombstoneHolds: (placements) =>\n refuteContainerDocumentTombstoneHolds(input.infra.execSql, placements),\n verifyContainerDocumentTombstones: createContainerDocumentTombstoneVerifier(\n containerOrganizationId,\n loadHead,\n loadEpoch,\n ),\n verifyDiscoveredDocuments: createDiscoveredDocumentVerifier(\n containerOrganizationId,\n loadHead,\n loadEpoch,\n evidenceStore,\n onPendingDiscovery,\n ),\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerDocumentDiscovery.js","sourceRoot":"","sources":["containerDocumentDiscovery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentSummary } from \"../data/documents/documentSummary\";\nimport { sqlContainerContentsPersistence } from \"../data/persistence/container-contents/containerContentsPersistence\";\nimport {\n holdContainerDocumentTombstones,\n listKnownContainerDocumentPlacements,\n listRetryableHeldContainerDocumentTombstones,\n loadLocalDocumentAccessEpoch,\n refuteContainerDocumentTombstoneHolds,\n} from \"../data/persistence/documents/containerDocumentTombstoneHoldsPersistence\";\nimport { createDocumentDiscoveryEvidenceStore } from \"../data/persistence/documents/documentDiscoveryEvidencePersistence\";\nimport { listContainerDocumentLanesFromApi } from \"../workflows/container-contents/containerDocumentListing\";\nimport { createDiscoveredDocumentVerifier } from \"../workflows/container-contents/documentDiscoveryEvidence\";\nimport {\n type ContainerDocumentDiscoveryLane,\n type ContainerDocumentDiscoveryOutcome,\n type ContainerDocumentDiscoveryOutcomeHandler,\n discoverContainerDocumentLanes,\n} from \"../workflows/container-contents/documentDiscoveryLanes\";\nimport { createContainerDocumentQueriesFromRuntime } from \"../workflows/container-contents/documentQueries\";\nimport {\n createContainerDocumentTombstoneVerifier,\n createDocumentHeadLinkSetLoader,\n} from \"../workflows/container-contents/documentTombstoneEvidence\";\nimport {\n type ContainerContentsWorkflowRuntime,\n createContainerContentsWorkflowRuntime,\n} from \"../workflows/container-contents/runtime\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../workflows/principals/runtimePolicyWarmer\";\nimport type { InternalRuntime } from \"./workflowRuntime\";\n\nexport type { ContainerDocumentDiscoveryOutcome } from \"../workflows/container-contents/documentDiscoveryLanes\";\n\n/** One container to discover, with the reconciler's per-lane callbacks. */\nexport interface ContainerDocumentDiscoveryRequest {\n readonly containerId: string;\n readonly onFullListing?:\n | ((documentIds: ReadonlyArray<string>) => void)\n | undefined;\n readonly onPendingDiscovery?: ((delayMs: number) => void) | undefined;\n}\n\ntype ExecSql = ReturnType<InternalRuntime[\"workflowInput\"]>[\"infra\"][\"execSql\"];\n\nfunction createDiscoveryLane(input: {\n readonly containerOrganizationId: string | undefined;\n readonly evidenceStore: ReturnType<\n typeof createDocumentDiscoveryEvidenceStore\n >;\n readonly execSql: ExecSql;\n readonly queries: ReturnType<\n typeof createContainerDocumentQueriesFromRuntime\n >;\n readonly request: ContainerDocumentDiscoveryRequest;\n readonly runtime: ContainerContentsWorkflowRuntime;\n}): ContainerDocumentDiscoveryLane {\n const { containerOrganizationId, execSql, request, runtime } = input;\n const warmReferencedPrincipalPolicies =\n createRuntimePrincipalPolicyWarmer(runtime);\n const loadHead = createDocumentHeadLinkSetLoader(runtime);\n const loadEpoch = (documentId: string) =>\n loadLocalDocumentAccessEpoch(execSql, documentId);\n return {\n ...input.queries,\n cacheReferencedPrincipalPolicies: (references) =>\n containerOrganizationId\n ? warmReferencedPrincipalPolicies({\n organizationId: containerOrganizationId,\n references,\n })\n : Promise.resolve(),\n containerId: request.containerId,\n holdContainerDocumentTombstones: (tombstones) =>\n holdContainerDocumentTombstones(execSql, tombstones),\n listHeldContainerDocumentTombstones: (containerIds) =>\n listRetryableHeldContainerDocumentTombstones(execSql, containerIds),\n listKnownContainerDocumentPlacements: (placements) =>\n listKnownContainerDocumentPlacements(execSql, placements),\n onFullListing: request.onFullListing,\n refuteContainerDocumentTombstoneHolds: (placements) =>\n refuteContainerDocumentTombstoneHolds(execSql, placements),\n verifyContainerDocumentTombstones: createContainerDocumentTombstoneVerifier(\n containerOrganizationId,\n loadHead,\n loadEpoch,\n ),\n verifyDiscoveredDocuments: createDiscoveredDocumentVerifier(\n containerOrganizationId,\n loadHead,\n loadEpoch,\n input.evidenceStore,\n request.onPendingDiscovery,\n ),\n };\n}\n\n/**\n * Internal adapter shared by explicit discovery and background reconciliation:\n * one batched listing for every requested container, then per-container\n * verification scoped to each container's durable organization.\n */\nexport async function discoverContainerDocumentLanesForRuntime({\n onOutcome,\n requests,\n runtimeService,\n}: {\n readonly onOutcome?: ContainerDocumentDiscoveryOutcomeHandler | undefined;\n readonly requests: ReadonlyArray<ContainerDocumentDiscoveryRequest>;\n readonly runtimeService: InternalRuntime;\n}): Promise<ReadonlyArray<ContainerDocumentDiscoveryOutcome>> {\n const unlisted = (\n containerId: string,\n ): ContainerDocumentDiscoveryOutcome => ({\n containerId,\n status: \"fulfilled\",\n value: null,\n });\n const input = runtimeService.workflowInput();\n if (input.infra.dbStatus !== \"ready\") {\n return requests.map(({ containerId }) => unlisted(containerId));\n }\n const runtime = createContainerContentsWorkflowRuntime(input);\n const execSql = input.infra.execSql;\n const evidenceStore = createDocumentDiscoveryEvidenceStore(execSql);\n const queries = createContainerDocumentQueriesFromRuntime(runtime);\n // Capture the reset fence before reading any lane's scope, so a reset\n // between these reads and the listing cannot publish old-organization\n // evidence into its replacement.\n const generation = await evidenceStore.begin();\n const lanes: ContainerDocumentDiscoveryLane[] = [];\n for (const request of requests) {\n const stored =\n await sqlContainerContentsPersistence.loadContainerMetadataState(\n execSql,\n request.containerId,\n );\n if (stored)\n lanes.push(\n createDiscoveryLane({\n containerOrganizationId: stored.container.organizationId,\n evidenceStore,\n execSql,\n queries,\n request,\n runtime,\n }),\n );\n }\n const outcomes = await discoverContainerDocumentLanes({\n generation,\n lanes,\n listContainerDocumentLanes: (listed) =>\n listContainerDocumentLanesFromApi(runtime.apiClient, listed),\n loadContainerDocumentWatermark: queries.loadContainerDocumentWatermark,\n onOutcome,\n });\n const outcomeByContainerId = new Map(\n outcomes.map((outcome) => [outcome.containerId, outcome]),\n );\n return requests.map(\n ({ containerId }) =>\n outcomeByContainerId.get(containerId) ?? unlisted(containerId),\n );\n}\n\n/** Discovers one container; a rejected lane rethrows its failure. */\nexport async function discoverContainerDocumentsForRuntime({\n runtimeService,\n ...request\n}: ContainerDocumentDiscoveryRequest & {\n readonly runtimeService: InternalRuntime;\n}): Promise<ReadonlyArray<DocumentSummary> | null> {\n const [outcome] = await discoverContainerDocumentLanesForRuntime({\n requests: [request],\n runtimeService,\n });\n if (outcome?.status === \"rejected\") throw outcome.reason;\n return outcome?.value ?? null;\n}\n"]}
|
package/client/deviceFirst.js
CHANGED
|
@@ -8,7 +8,7 @@ import { createReconciledDocumentContentPuller } from "../sync/reconciliation/do
|
|
|
8
8
|
import { listAllContainerDocumentIdsFromApi } from "../workflows/container-contents/containerDocumentListing.js";
|
|
9
9
|
import { probeUndiscoveredRemoteDocumentBatch } from "../workflows/container-contents/documentHydrationProbe.js";
|
|
10
10
|
import { createContainerContentsDocumentsRuntime, createContainerContentsStoreWorkflowRuntime, } from "../workflows/container-contents/runtime.js";
|
|
11
|
-
import {
|
|
11
|
+
import { discoverContainerDocumentLanesForRuntime } from "./containerDocumentDiscovery.js";
|
|
12
12
|
export function createDeviceFirst(runtimeService, containerContents) {
|
|
13
13
|
return new DeviceFirstService(runtimeService, containerContents);
|
|
14
14
|
}
|
|
@@ -169,10 +169,9 @@ class DeviceFirstService {
|
|
|
169
169
|
// retain every regular container. Exclude only this identity's own system
|
|
170
170
|
// children; cold/auth backfill and explicit full Refresh cover those.
|
|
171
171
|
listAutomaticRootCatchupContainerIds,
|
|
172
|
-
discoverContainerDocuments: (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
onPendingDiscovery,
|
|
172
|
+
discoverContainerDocuments: (requests, onOutcome) => discoverContainerDocumentLanesForRuntime({
|
|
173
|
+
onOutcome,
|
|
174
|
+
requests,
|
|
176
175
|
runtimeService,
|
|
177
176
|
}),
|
|
178
177
|
loadContainerDelta: (containerId) => store.loadContainerDelta(containerId),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deviceFirst.js","sourceRoot":"","sources":["deviceFirst.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DomainScope } from \"../data/domainScope\";\nimport {\n disposeDomainSyncCoordinator,\n isDatabaseUnavailableError,\n} from \"../data/sync/syncCoordinator\";\nimport {\n type ContainerContentsStore,\n type ContainerContentsStoreOptions,\n isAutomaticRootCatchupContainerNode,\n isReconcilableContainerNode,\n isRemoteBackedContainerNode,\n} from \"../stores/container-contents\";\nimport { openDocumentStore } from \"../stores/documents\";\nimport {\n requestRegisteredDocumentRemoteSync,\n subscribeToPersistedDocumentDeletions,\n subscribeToPersistedDocuments,\n} from \"../stores/documents/registry\";\nimport {\n getOrCreateLocalProjectionStore,\n type LocalProjectionStore,\n type LocalProjectionView,\n} from \"../stores/local-projection\";\nimport {\n connectReconciliationTriggers,\n createReconciliationService,\n type ReconciliationHost,\n type ReconciliationService,\n} from \"../sync/reconciliation\";\nimport { createReconciledDocumentContentPuller } from \"../sync/reconciliation/documentContentPull\";\nimport { listAllContainerDocumentIdsFromApi } from \"../workflows/container-contents/containerDocumentListing\";\nimport { probeUndiscoveredRemoteDocumentBatch } from \"../workflows/container-contents/documentHydrationProbe\";\nimport {\n type ContainerContentsStoreWorkflowRuntime,\n createContainerContentsDocumentsRuntime,\n createContainerContentsStoreWorkflowRuntime,\n} from \"../workflows/container-contents/runtime\";\nimport type { ContainerContents } from \"./containerContents\";\nimport { discoverContainerDocumentsForRuntime } from \"./containerDocumentDiscovery\";\nimport type { InternalRuntime } from \"./workflowRuntime\";\n\nexport type { LocalProjectionView } from \"../stores/local-projection\";\n\n/** One domain scope's local read, local-write, and reconciliation handles. */\nexport interface DeviceFirstContainerContents {\n /**\n * Locally durable container tree and mutation store. Ordinary tree writes\n * update this store after local persistence and queue remote convergence in\n * the background; security-sensitive remote operations keep their explicit\n * online requirements.\n */\n readonly containerStore: ContainerContentsStore;\n /** Background remote reconciliation; never awaited for first paint. */\n readonly reconciler: ReconciliationService;\n /** Synchronously readable container/document projection. */\n readonly view: LocalProjectionView;\n}\n\n/**\n * Device-first facade. Opens a shared scope that pairs immediate local reads\n * and locally durable writes with background remote convergence.\n */\nexport interface DeviceFirst {\n /** Open all device-first handles for the current domain scope. */\n open(\n options?: ContainerContentsStoreOptions | undefined,\n ): DeviceFirstContainerContents;\n /** Stop the current scope's reconciler (if one was created) on teardown. */\n dispose(): void;\n}\n\nexport function createDeviceFirst(\n runtimeService: InternalRuntime,\n containerContents: ContainerContents,\n): DeviceFirst {\n return new DeviceFirstService(runtimeService, containerContents);\n}\n\ninterface DeviceFirstScopeEntry {\n contents: DeviceFirstContainerContents;\n disconnectReconciliationTriggers: () => void;\n unsubscribePersistedDocumentDeletions: () => void;\n unsubscribePersistedDocuments: () => void;\n}\n\nfunction createInitialDocumentProbeHost(\n runtimeService: InternalRuntime,\n domainScope: ReconciliationHost[\"domainScope\"],\n): Pick<\n ReconciliationHost,\n | \"listContainerDocumentIds\"\n | \"probeUndiscoveredDocumentsBatch\"\n | \"reportInitialDocumentProbeComplete\"\n> {\n return {\n listContainerDocumentIds: (containerId) => {\n const runtime = createDeviceFirstWorkflowRuntime(runtimeService);\n return listAllContainerDocumentIdsFromApi({\n apiClient: runtime.apiClient,\n containerId,\n reportErrors: false,\n });\n },\n probeUndiscoveredDocumentsBatch: async (input) => {\n const runtime = createDeviceFirstWorkflowRuntime(runtimeService);\n return probeUndiscoveredRemoteDocumentBatch({\n ...input,\n host: {\n documentWorkflowRuntime: (containerId) =>\n createContainerContentsDocumentsRuntime(runtime, containerId),\n openDocumentStore: (target) =>\n openDocumentStore(\n domainScope,\n target.localId,\n target.runtime,\n target.documentId,\n ),\n },\n runtime,\n });\n },\n reportInitialDocumentProbeComplete: (requestedCount) => {\n runtimeService\n .workflowInput()\n .util.log(\n `Initial document hydration probe requested ${requestedCount} syncs`,\n );\n },\n };\n}\n\nclass DeviceFirstService implements DeviceFirst {\n // A real Map (not WeakMap) so dispose() can iterate every scope seen this\n // session. A running reconciler holds event subscriptions that keep an idle,\n // stale-scope service (and its scope) reachable anyway, so WeakMap bought no\n // GC here; the entries are released explicitly on dispose().\n private readonly entriesByScope = new Map<\n DomainScope,\n DeviceFirstScopeEntry\n >();\n\n constructor(\n private readonly runtimeService: InternalRuntime,\n private readonly containerContents: ContainerContents,\n ) {}\n\n open(\n options?: ContainerContentsStoreOptions | undefined,\n ): DeviceFirstContainerContents {\n return this.getOrCreateEntry(options).contents;\n }\n\n dispose(): void {\n // Stop every reconciler created this session — not just the current\n // scope's. A scope change (e.g. anonymous -> authenticated) leaves the old\n // scope's reconciler subscribed and its coordinator pump live; tear them\n // all down. Force-stop each scope's coordinator (which runs the reconciler\n // lane) alongside stopping the service.\n for (const [domainScope, entry] of this.entriesByScope) {\n entry.contents.reconciler.stop();\n entry.disconnectReconciliationTriggers();\n entry.unsubscribePersistedDocumentDeletions();\n entry.unsubscribePersistedDocuments();\n disposeDomainSyncCoordinator(domainScope);\n }\n this.entriesByScope.clear();\n }\n\n private workflowRuntime(): ContainerContentsStoreWorkflowRuntime {\n return createDeviceFirstWorkflowRuntime(this.runtimeService);\n }\n\n private getOrCreateEntry(\n options?: ContainerContentsStoreOptions | undefined,\n ): DeviceFirstScopeEntry {\n const runtime = this.workflowRuntime();\n const domainScope = runtime.state.domainScope;\n const existing = this.entriesByScope.get(domainScope);\n if (existing) {\n // Do not call updateRuntime here: facade selectors run during React\n // render, and updateRuntime emits synchronously. Hosts drive runtime\n // updates through view.updateRuntime() from an effect instead.\n return existing;\n }\n\n const store = getOrCreateLocalProjectionStore({\n domainScope,\n runtime,\n options,\n });\n const service = createReconciliationService(\n this.createReconciliationHost(store, domainScope),\n );\n const disconnectReconciliationTriggers = connectReconciliationTriggers({\n service,\n store,\n });\n const unsubscribePersistedDocumentDeletions =\n subscribeToPersistedDocumentDeletions(domainScope, (localId) => {\n store.removePersistedDocument(localId);\n });\n const unsubscribePersistedDocuments = subscribeToPersistedDocuments(\n domainScope,\n (document, change) =>\n store.refreshPersistedDocument(document, change.placementChanged),\n );\n service.start();\n\n const view: LocalProjectionView = {\n getSnapshot: () => store.getSnapshot(),\n subscribe: (listener) => store.subscribe(listener),\n setActiveContainer: (containerId) =>\n store.setActiveContainer(containerId),\n updateRuntime: (nextRuntime) => store.updateRuntime(nextRuntime),\n };\n\n const entry: DeviceFirstScopeEntry = {\n contents: {\n containerStore: store.getContainerStore(),\n reconciler: service,\n view,\n },\n disconnectReconciliationTriggers,\n unsubscribePersistedDocumentDeletions,\n unsubscribePersistedDocuments,\n };\n this.entriesByScope.set(domainScope, entry);\n return entry;\n }\n\n private createReconciliationHost(\n store: LocalProjectionStore,\n domainScope: ReconciliationHost[\"domainScope\"],\n ): ReconciliationHost {\n const runtimeService = this.runtimeService;\n const containerContents = this.containerContents;\n const requestDocumentContentPull = createReconciledDocumentContentPuller({\n getContainer: (containerId) =>\n store\n .getSnapshot()\n .containers.find((container) => container.id === containerId) ?? null,\n pullDocumentContent: (input) =>\n containerContents.pullDocumentContent(input),\n requestRegisteredDocumentRemoteSync: (localId, documentId) =>\n requestRegisteredDocumentRemoteSync(domainScope, localId, documentId),\n });\n const canDiscoverContainerDocuments = (containerId: string) => {\n const container = store\n .getSnapshot()\n .containers.find((node) => node.id === containerId);\n return container ? isRemoteBackedContainerNode(container) : false;\n };\n const listKnownContainerIds = () => {\n // A local-first id is not listable yet and may still be racing its create\n // request. Once remote-backed, it participates normally; system contents\n // are especially important during rematerialization because this device\n // may not have authored them.\n const homeOrganizationId =\n runtimeService.workflowInput().auth.organizationId;\n return store\n .getSnapshot()\n .containers.flatMap((node) =>\n isReconcilableContainerNode(node, homeOrganizationId)\n ? [node.id]\n : [],\n );\n };\n const listAutomaticRootCatchupContainerIds = () => {\n const homeOrganizationId =\n runtimeService.workflowInput().auth.organizationId;\n return store\n .getSnapshot()\n .containers.flatMap((node) =>\n isAutomaticRootCatchupContainerNode(node, homeOrganizationId)\n ? [node.id]\n : [],\n );\n };\n return {\n domainScope,\n canDiscoverContainerDocuments,\n getRuntimeStatus: () => {\n const input = runtimeService.workflowInput();\n return {\n dbStatus: input.infra.dbStatus,\n isAuthenticated: input.auth.isAuthenticated,\n online: input.state.online,\n };\n },\n listKnownContainerIds,\n // Root discovery can surface directly granted non-root containers, so\n // retain every regular container. Exclude only this identity's own system\n // children; cold/auth backfill and explicit full Refresh cover those.\n listAutomaticRootCatchupContainerIds,\n discoverContainerDocuments: (\n containerId,\n onFullListing,\n onPendingDiscovery,\n ) =>\n discoverContainerDocumentsForRuntime({\n containerId,\n onFullListing,\n onPendingDiscovery,\n runtimeService,\n }),\n loadContainerDelta: (containerId) =>\n store.loadContainerDelta(containerId),\n applyReconciled: (delta) => store.applyReconciled(delta),\n requestDocumentContentPull,\n ...createInitialDocumentProbeHost(runtimeService, domainScope),\n refreshTree: async () => {\n await store.getContainerStore().refresh();\n },\n refreshRootTree: async () => {\n await store.getContainerStore().refreshRootLane();\n },\n isIgnorableError: isDatabaseUnavailableError,\n // Resolve the runtime per call: it is rebuilt as the active identity\n // changes, and a reference captured here would report into a dead host.\n logError: (message, error) =>\n logReconciliationFailure(this.workflowRuntime(), message, error),\n };\n }\n}\n\n// Returns the host's result: both callbacks are declared `=> void` but may be\n// async, and the lane reporter only catches a rejection it is handed.\nfunction logReconciliationFailure(\n runtime: ContainerContentsStoreWorkflowRuntime,\n message: string,\n error: unknown,\n): unknown {\n const { log, logError } = runtime.util;\n return logError ? logError(message, error) : log(message);\n}\n\nexport function createDeviceFirstWorkflowRuntime(\n runtimeService: InternalRuntime,\n): ContainerContentsStoreWorkflowRuntime {\n return createContainerContentsStoreWorkflowRuntime(\n runtimeService.workflowInput(),\n runtimeService.adoptRootContainer,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"deviceFirst.js","sourceRoot":"","sources":["deviceFirst.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DomainScope } from \"../data/domainScope\";\nimport {\n disposeDomainSyncCoordinator,\n isDatabaseUnavailableError,\n} from \"../data/sync/syncCoordinator\";\nimport {\n type ContainerContentsStore,\n type ContainerContentsStoreOptions,\n isAutomaticRootCatchupContainerNode,\n isReconcilableContainerNode,\n isRemoteBackedContainerNode,\n} from \"../stores/container-contents\";\nimport { openDocumentStore } from \"../stores/documents\";\nimport {\n requestRegisteredDocumentRemoteSync,\n subscribeToPersistedDocumentDeletions,\n subscribeToPersistedDocuments,\n} from \"../stores/documents/registry\";\nimport {\n getOrCreateLocalProjectionStore,\n type LocalProjectionStore,\n type LocalProjectionView,\n} from \"../stores/local-projection\";\nimport {\n connectReconciliationTriggers,\n createReconciliationService,\n type ReconciliationHost,\n type ReconciliationService,\n} from \"../sync/reconciliation\";\nimport { createReconciledDocumentContentPuller } from \"../sync/reconciliation/documentContentPull\";\nimport { listAllContainerDocumentIdsFromApi } from \"../workflows/container-contents/containerDocumentListing\";\nimport { probeUndiscoveredRemoteDocumentBatch } from \"../workflows/container-contents/documentHydrationProbe\";\nimport {\n type ContainerContentsStoreWorkflowRuntime,\n createContainerContentsDocumentsRuntime,\n createContainerContentsStoreWorkflowRuntime,\n} from \"../workflows/container-contents/runtime\";\nimport type { ContainerContents } from \"./containerContents\";\nimport { discoverContainerDocumentLanesForRuntime } from \"./containerDocumentDiscovery\";\nimport type { InternalRuntime } from \"./workflowRuntime\";\n\nexport type { LocalProjectionView } from \"../stores/local-projection\";\n\n/** One domain scope's local read, local-write, and reconciliation handles. */\nexport interface DeviceFirstContainerContents {\n /**\n * Locally durable container tree and mutation store. Ordinary tree writes\n * update this store after local persistence and queue remote convergence in\n * the background; security-sensitive remote operations keep their explicit\n * online requirements.\n */\n readonly containerStore: ContainerContentsStore;\n /** Background remote reconciliation; never awaited for first paint. */\n readonly reconciler: ReconciliationService;\n /** Synchronously readable container/document projection. */\n readonly view: LocalProjectionView;\n}\n\n/**\n * Device-first facade. Opens a shared scope that pairs immediate local reads\n * and locally durable writes with background remote convergence.\n */\nexport interface DeviceFirst {\n /** Open all device-first handles for the current domain scope. */\n open(\n options?: ContainerContentsStoreOptions | undefined,\n ): DeviceFirstContainerContents;\n /** Stop the current scope's reconciler (if one was created) on teardown. */\n dispose(): void;\n}\n\nexport function createDeviceFirst(\n runtimeService: InternalRuntime,\n containerContents: ContainerContents,\n): DeviceFirst {\n return new DeviceFirstService(runtimeService, containerContents);\n}\n\ninterface DeviceFirstScopeEntry {\n contents: DeviceFirstContainerContents;\n disconnectReconciliationTriggers: () => void;\n unsubscribePersistedDocumentDeletions: () => void;\n unsubscribePersistedDocuments: () => void;\n}\n\nfunction createInitialDocumentProbeHost(\n runtimeService: InternalRuntime,\n domainScope: ReconciliationHost[\"domainScope\"],\n): Pick<\n ReconciliationHost,\n | \"listContainerDocumentIds\"\n | \"probeUndiscoveredDocumentsBatch\"\n | \"reportInitialDocumentProbeComplete\"\n> {\n return {\n listContainerDocumentIds: (containerId) => {\n const runtime = createDeviceFirstWorkflowRuntime(runtimeService);\n return listAllContainerDocumentIdsFromApi({\n apiClient: runtime.apiClient,\n containerId,\n reportErrors: false,\n });\n },\n probeUndiscoveredDocumentsBatch: async (input) => {\n const runtime = createDeviceFirstWorkflowRuntime(runtimeService);\n return probeUndiscoveredRemoteDocumentBatch({\n ...input,\n host: {\n documentWorkflowRuntime: (containerId) =>\n createContainerContentsDocumentsRuntime(runtime, containerId),\n openDocumentStore: (target) =>\n openDocumentStore(\n domainScope,\n target.localId,\n target.runtime,\n target.documentId,\n ),\n },\n runtime,\n });\n },\n reportInitialDocumentProbeComplete: (requestedCount) => {\n runtimeService\n .workflowInput()\n .util.log(\n `Initial document hydration probe requested ${requestedCount} syncs`,\n );\n },\n };\n}\n\nclass DeviceFirstService implements DeviceFirst {\n // A real Map (not WeakMap) so dispose() can iterate every scope seen this\n // session. A running reconciler holds event subscriptions that keep an idle,\n // stale-scope service (and its scope) reachable anyway, so WeakMap bought no\n // GC here; the entries are released explicitly on dispose().\n private readonly entriesByScope = new Map<\n DomainScope,\n DeviceFirstScopeEntry\n >();\n\n constructor(\n private readonly runtimeService: InternalRuntime,\n private readonly containerContents: ContainerContents,\n ) {}\n\n open(\n options?: ContainerContentsStoreOptions | undefined,\n ): DeviceFirstContainerContents {\n return this.getOrCreateEntry(options).contents;\n }\n\n dispose(): void {\n // Stop every reconciler created this session — not just the current\n // scope's. A scope change (e.g. anonymous -> authenticated) leaves the old\n // scope's reconciler subscribed and its coordinator pump live; tear them\n // all down. Force-stop each scope's coordinator (which runs the reconciler\n // lane) alongside stopping the service.\n for (const [domainScope, entry] of this.entriesByScope) {\n entry.contents.reconciler.stop();\n entry.disconnectReconciliationTriggers();\n entry.unsubscribePersistedDocumentDeletions();\n entry.unsubscribePersistedDocuments();\n disposeDomainSyncCoordinator(domainScope);\n }\n this.entriesByScope.clear();\n }\n\n private workflowRuntime(): ContainerContentsStoreWorkflowRuntime {\n return createDeviceFirstWorkflowRuntime(this.runtimeService);\n }\n\n private getOrCreateEntry(\n options?: ContainerContentsStoreOptions | undefined,\n ): DeviceFirstScopeEntry {\n const runtime = this.workflowRuntime();\n const domainScope = runtime.state.domainScope;\n const existing = this.entriesByScope.get(domainScope);\n if (existing) {\n // Do not call updateRuntime here: facade selectors run during React\n // render, and updateRuntime emits synchronously. Hosts drive runtime\n // updates through view.updateRuntime() from an effect instead.\n return existing;\n }\n\n const store = getOrCreateLocalProjectionStore({\n domainScope,\n runtime,\n options,\n });\n const service = createReconciliationService(\n this.createReconciliationHost(store, domainScope),\n );\n const disconnectReconciliationTriggers = connectReconciliationTriggers({\n service,\n store,\n });\n const unsubscribePersistedDocumentDeletions =\n subscribeToPersistedDocumentDeletions(domainScope, (localId) => {\n store.removePersistedDocument(localId);\n });\n const unsubscribePersistedDocuments = subscribeToPersistedDocuments(\n domainScope,\n (document, change) =>\n store.refreshPersistedDocument(document, change.placementChanged),\n );\n service.start();\n\n const view: LocalProjectionView = {\n getSnapshot: () => store.getSnapshot(),\n subscribe: (listener) => store.subscribe(listener),\n setActiveContainer: (containerId) =>\n store.setActiveContainer(containerId),\n updateRuntime: (nextRuntime) => store.updateRuntime(nextRuntime),\n };\n\n const entry: DeviceFirstScopeEntry = {\n contents: {\n containerStore: store.getContainerStore(),\n reconciler: service,\n view,\n },\n disconnectReconciliationTriggers,\n unsubscribePersistedDocumentDeletions,\n unsubscribePersistedDocuments,\n };\n this.entriesByScope.set(domainScope, entry);\n return entry;\n }\n\n private createReconciliationHost(\n store: LocalProjectionStore,\n domainScope: ReconciliationHost[\"domainScope\"],\n ): ReconciliationHost {\n const runtimeService = this.runtimeService;\n const containerContents = this.containerContents;\n const requestDocumentContentPull = createReconciledDocumentContentPuller({\n getContainer: (containerId) =>\n store\n .getSnapshot()\n .containers.find((container) => container.id === containerId) ?? null,\n pullDocumentContent: (input) =>\n containerContents.pullDocumentContent(input),\n requestRegisteredDocumentRemoteSync: (localId, documentId) =>\n requestRegisteredDocumentRemoteSync(domainScope, localId, documentId),\n });\n const canDiscoverContainerDocuments = (containerId: string) => {\n const container = store\n .getSnapshot()\n .containers.find((node) => node.id === containerId);\n return container ? isRemoteBackedContainerNode(container) : false;\n };\n const listKnownContainerIds = () => {\n // A local-first id is not listable yet and may still be racing its create\n // request. Once remote-backed, it participates normally; system contents\n // are especially important during rematerialization because this device\n // may not have authored them.\n const homeOrganizationId =\n runtimeService.workflowInput().auth.organizationId;\n return store\n .getSnapshot()\n .containers.flatMap((node) =>\n isReconcilableContainerNode(node, homeOrganizationId)\n ? [node.id]\n : [],\n );\n };\n const listAutomaticRootCatchupContainerIds = () => {\n const homeOrganizationId =\n runtimeService.workflowInput().auth.organizationId;\n return store\n .getSnapshot()\n .containers.flatMap((node) =>\n isAutomaticRootCatchupContainerNode(node, homeOrganizationId)\n ? [node.id]\n : [],\n );\n };\n return {\n domainScope,\n canDiscoverContainerDocuments,\n getRuntimeStatus: () => {\n const input = runtimeService.workflowInput();\n return {\n dbStatus: input.infra.dbStatus,\n isAuthenticated: input.auth.isAuthenticated,\n online: input.state.online,\n };\n },\n listKnownContainerIds,\n // Root discovery can surface directly granted non-root containers, so\n // retain every regular container. Exclude only this identity's own system\n // children; cold/auth backfill and explicit full Refresh cover those.\n listAutomaticRootCatchupContainerIds,\n discoverContainerDocuments: (requests, onOutcome) =>\n discoverContainerDocumentLanesForRuntime({\n onOutcome,\n requests,\n runtimeService,\n }),\n loadContainerDelta: (containerId) =>\n store.loadContainerDelta(containerId),\n applyReconciled: (delta) => store.applyReconciled(delta),\n requestDocumentContentPull,\n ...createInitialDocumentProbeHost(runtimeService, domainScope),\n refreshTree: async () => {\n await store.getContainerStore().refresh();\n },\n refreshRootTree: async () => {\n await store.getContainerStore().refreshRootLane();\n },\n isIgnorableError: isDatabaseUnavailableError,\n // Resolve the runtime per call: it is rebuilt as the active identity\n // changes, and a reference captured here would report into a dead host.\n logError: (message, error) =>\n logReconciliationFailure(this.workflowRuntime(), message, error),\n };\n }\n}\n\n// Returns the host's result: both callbacks are declared `=> void` but may be\n// async, and the lane reporter only catches a rejection it is handed.\nfunction logReconciliationFailure(\n runtime: ContainerContentsStoreWorkflowRuntime,\n message: string,\n error: unknown,\n): unknown {\n const { log, logError } = runtime.util;\n return logError ? logError(message, error) : log(message);\n}\n\nexport function createDeviceFirstWorkflowRuntime(\n runtimeService: InternalRuntime,\n): ContainerContentsStoreWorkflowRuntime {\n return createContainerContentsStoreWorkflowRuntime(\n runtimeService.workflowInput(),\n runtimeService.adoptRootContainer,\n );\n}\n"]}
|
|
@@ -2,20 +2,51 @@
|
|
|
2
2
|
export const BLOB_TRANSFER_CONCURRENCY = 4;
|
|
3
3
|
const TRANSFER_IDLE_TIMEOUT_MS = 120_000;
|
|
4
4
|
const pools = new WeakMap();
|
|
5
|
-
|
|
6
|
-
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
7
|
-
throw new RangeError("Blob transfer timeout must be positive and finite");
|
|
5
|
+
function poolFor(client) {
|
|
8
6
|
let pool = pools.get(client);
|
|
9
7
|
if (!pool) {
|
|
10
8
|
pool = { active: 0, waiting: [] };
|
|
11
9
|
pools.set(client, pool);
|
|
12
10
|
}
|
|
11
|
+
return pool;
|
|
12
|
+
}
|
|
13
|
+
function permitFrom(pool) {
|
|
14
|
+
let held = true;
|
|
15
|
+
return {
|
|
16
|
+
release() {
|
|
17
|
+
if (!held)
|
|
18
|
+
return;
|
|
19
|
+
held = false;
|
|
20
|
+
const next = pool.waiting.shift();
|
|
21
|
+
if (next)
|
|
22
|
+
next();
|
|
23
|
+
else
|
|
24
|
+
pool.active -= 1;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export async function acquireBlobTransferPermit(client) {
|
|
29
|
+
const pool = poolFor(client);
|
|
13
30
|
if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {
|
|
14
31
|
await new Promise((resolve) => pool.waiting.push(resolve));
|
|
15
32
|
}
|
|
16
33
|
else {
|
|
17
34
|
pool.active += 1;
|
|
18
35
|
}
|
|
36
|
+
return permitFrom(pool);
|
|
37
|
+
}
|
|
38
|
+
/** A permit only if one is free now; never queues behind other transfers. */
|
|
39
|
+
export function tryAcquireBlobTransferPermit(client) {
|
|
40
|
+
const pool = poolFor(client);
|
|
41
|
+
if (pool.active >= BLOB_TRANSFER_CONCURRENCY)
|
|
42
|
+
return null;
|
|
43
|
+
pool.active += 1;
|
|
44
|
+
return permitFrom(pool);
|
|
45
|
+
}
|
|
46
|
+
export async function runBlobTransfer(client, transfer, timeoutMs = TRANSFER_IDLE_TIMEOUT_MS, heldPermit) {
|
|
47
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
48
|
+
throw new RangeError("Blob transfer timeout must be positive and finite");
|
|
49
|
+
const permit = heldPermit ?? (await acquireBlobTransferPermit(client));
|
|
19
50
|
const controller = new AbortController();
|
|
20
51
|
let timer;
|
|
21
52
|
const progress = () => {
|
|
@@ -43,11 +74,7 @@ export async function runBlobTransfer(client, transfer, timeoutMs = TRANSFER_IDL
|
|
|
43
74
|
}
|
|
44
75
|
finally {
|
|
45
76
|
clearTimeout(timer);
|
|
46
|
-
|
|
47
|
-
if (next)
|
|
48
|
-
next();
|
|
49
|
-
else
|
|
50
|
-
pool.active -= 1;
|
|
77
|
+
permit.release();
|
|
51
78
|
}
|
|
52
79
|
}
|
|
53
80
|
//# sourceMappingURL=transferPool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transferPool.js","sourceRoot":"","sources":["transferPool.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAKzC,MAAM,KAAK,GAAG,IAAI,OAAO,EAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"transferPool.js","sourceRoot":"","sources":["transferPool.ts"],"names":[],"mappings":"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","sourcesContent":["/** Bound byte I/O across documents sharing a client, including multipart parts. */\nexport const BLOB_TRANSFER_CONCURRENCY = 4;\nconst TRANSFER_IDLE_TIMEOUT_MS = 120_000;\ninterface TransferPool {\n active: number;\n waiting: Array<() => void>;\n}\nconst pools = new WeakMap<object, TransferPool>();\n\n/**\n * One slot of a client's transfer pool, held ahead of its transfer by bytes\n * that must exist before the transfer can start (a multipart stage's first\n * parts are encrypted to describe them). Releasing is idempotent.\n */\nexport interface BlobTransferPermit {\n release(): void;\n}\n\nfunction poolFor(client: object): TransferPool {\n let pool = pools.get(client);\n if (!pool) {\n pool = { active: 0, waiting: [] };\n pools.set(client, pool);\n }\n return pool;\n}\n\nfunction permitFrom(pool: TransferPool): BlobTransferPermit {\n let held = true;\n return {\n release() {\n if (!held) return;\n held = false;\n const next = pool.waiting.shift();\n if (next) next();\n else pool.active -= 1;\n },\n };\n}\n\nexport async function acquireBlobTransferPermit(\n client: object,\n): Promise<BlobTransferPermit> {\n const pool = poolFor(client);\n if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {\n await new Promise<void>((resolve) => pool.waiting.push(resolve));\n } else {\n pool.active += 1;\n }\n return permitFrom(pool);\n}\n\n/** A permit only if one is free now; never queues behind other transfers. */\nexport function tryAcquireBlobTransferPermit(\n client: object,\n): BlobTransferPermit | null {\n const pool = poolFor(client);\n if (pool.active >= BLOB_TRANSFER_CONCURRENCY) return null;\n pool.active += 1;\n return permitFrom(pool);\n}\n\nexport async function runBlobTransfer<T>(\n client: object,\n transfer: (signal: AbortSignal, progress: () => void) => Promise<T>,\n timeoutMs = TRANSFER_IDLE_TIMEOUT_MS,\n heldPermit?: BlobTransferPermit,\n): Promise<T> {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)\n throw new RangeError(\"Blob transfer timeout must be positive and finite\");\n const permit = heldPermit ?? (await acquireBlobTransferPermit(client));\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const progress = () => {\n controller.signal.throwIfAborted();\n clearTimeout(timer);\n timer = setTimeout(\n () => controller.abort(new Error(\"Blob transfer timed out\")),\n timeoutMs,\n );\n };\n progress();\n try {\n // A native bridge or custom transport may ignore abort. Bound its logical\n // ownership anyway; callers must check the signal before accepting results.\n return await new Promise<T>((resolve, reject) => {\n const aborted = () => reject(controller.signal.reason);\n controller.signal.addEventListener(\"abort\", aborted, { once: true });\n void Promise.resolve()\n .then(() => transfer(controller.signal, progress))\n .then(\n (value) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n resolve(value);\n },\n (error: unknown) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n reject(error);\n },\n );\n });\n } finally {\n clearTimeout(timer);\n permit.release();\n }\n}\n"]}
|
|
@@ -37,6 +37,18 @@ export function getParentCreateContext(parentProjection) {
|
|
|
37
37
|
export function asContainerManifestBundle(bundle) {
|
|
38
38
|
return readCanonicalManifestBundle(bundle, "Container manifest bundle");
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Cite a manifest the server already stores. Mutation requests carry these
|
|
42
|
+
* references instead of echoing the bundles a writer projection served; the
|
|
43
|
+
* server resolves each from its own verified store.
|
|
44
|
+
*/
|
|
45
|
+
export function containerManifestRef(bundle) {
|
|
46
|
+
const containerId = Reflect.get(bundle.state, "containerId");
|
|
47
|
+
if (typeof containerId !== "string" || containerId.length === 0) {
|
|
48
|
+
throw new Error("Container manifest is missing a container id");
|
|
49
|
+
}
|
|
50
|
+
return { containerId, manifestHash: bundle.manifestHash };
|
|
51
|
+
}
|
|
40
52
|
export function readContainerState(bundle) {
|
|
41
53
|
return readContainerAccessManifestState(bundle.state, "Container manifest state");
|
|
42
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projection.js","sourceRoot":"","sources":["projection.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,kCAAkC,EAClC,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EACL,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,WAAW,CAAC;AAGnB,MAAM,UAAU,0BAA0B,CACxC,IAAkE;IAElE,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACxE,CAAC;AAUD,SAAS,uBAAuB,CAC9B,UAA6C,EAC7C,MAAkC;IAElC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,uBAAuB,CAAC,QAAQ,CAAC,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,GAAG,CAAC,kBAAkB,KAAK,QAAQ,CAAC,YAAY,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,gBAAmD;IAEnD,OAAO,uBAAuB,CAAC,gBAAgB,EAAE;QAC/C,eAAe,EAAE,sCAAsC;QACvD,eAAe,EAAE,6CAA6C;QAC9D,gBAAgB,EACd,4DAA4D;QAC9D,kBAAkB,EAAE,oDAAoD;QACxE,QAAQ,EAAE,+BAA+B;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAyD;IAEzD,OAAO,2BAA2B,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAyD;IAEzD,OAAO,gCAAgC,CACrC,MAAM,CAAC,KAAK,EACZ,0BAA0B,CAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,UAA6C;IAE7C,OAAO,uBAAuB,CAAC,UAAU,EAAE;QACzC,eAAe,EAAE,+BAA+B;QAChD,eAAe,EAAE,sCAAsC;QACvD,gBAAgB,EAAE,qDAAqD;QACvE,kBAAkB,EAAE,6CAA6C;QACjE,QAAQ,EAAE,+BAA+B;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,UAA6C;IAE7C,MAAM,WAAW,GAAG,kBAAkB,CACpC,yBAAyB,CAAC,UAAU,CAAC,CAAC,QAAQ,CAC/C,CAAC;IACF,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,WAAW,KAAK,WAAW,CAAC,iBAAiB,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAM9C;IACC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE;QAC/D,aAAa,CAAC,KAAK,CAAC,eAAe,CAAC;KACrC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAEtE,OAAO;QACL,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,aAAa,EAAE,WAAW;QAC1B,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW;QACxC,mBAAmB,EAAE,KAAK,CAAC,SAAS,CAAC,mBAAmB;QACxD,uBAAuB,EAAE,KAAK,CAAC,SAAS,CAAC,YAAY;QACrD,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC;QACnD,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC;QAC7C,gBAAgB,EAAE,KAAK,CAAC,YAAY;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAMhD;IAKC,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE;QACjE,KAAK,CAAC,+BAA+B;KACtC,CAAC,CAAC;IACH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,gBAAgB,GAA8B;QAClD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,mBAAmB,EAAE,QAAQ,KAAK,CAAC,MAAM,kBAAkB,SAAS,CAAC,cAAc,EAAE;QACrF,uBAAuB,EAAE,SAAS,CAAC,cAAc;KAClD,CAAC;IACF,MAAM,eAAe,GAAgC;QACnD,aAAa,EAAE,MAAM;QACrB,WAAW,EAAE,KAAK,CAAC,MAAM;QACzB,mBAAmB,EAAE,gBAAgB,CAAC,mBAAmB;QACzD,uBAAuB,EAAE,gBAAgB,CAAC,uBAAuB;KAClE,CAAC;IAEF,OAAO;QACL,eAAe;QACf,gBAAgB;QAChB,IAAI,EAAE;YACJ,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;YAC9C,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,mBAAmB,EAAE,gBAAgB,CAAC,mBAAmB;YACzD,uBAAuB,EAAE,gBAAgB,CAAC,uBAAuB;YACjE,aAAa,EAAE,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC;YACrD,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC;YAC/C,gBAAgB,EAAE,KAAK,CAAC,YAAY;SACrC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kCAAkC,CAAC,KAMxD;IAIC,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE;QACjE,aAAa,CAAC,KAAK,CAAC,+BAA+B,CAAC;KACrD,CAAC,CAAC;IACH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,eAAe,GAAgC;QACnD,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,aAAa;QAChD,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW;QAC5C,mBAAmB,EAAE,kCAAkC,CACrD,KAAK,CAAC,aAAa,CACpB;QACD,uBAAuB,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc;KAC5D,CAAC;IAEF,OAAO;QACL,eAAe;QACf,IAAI,EAAE;YACJ,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;YAC9C,aAAa,EAAE,eAAe,CAAC,aAAa;YAC5C,WAAW,EAAE,eAAe,CAAC,WAAW;YACxC,mBAAmB,EAAE,eAAe,CAAC,mBAAmB;YACxD,uBAAuB,EAAE,eAAe,CAAC,uBAAuB;YAChE,aAAa,EAAE,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC;YACrD,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC;YAC/C,gBAAgB,EAAE,KAAK,CAAC,YAAY;SACrC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAA6C;IAE7C,MAAM,WAAW,GAAG,kBAAkB,CACpC,yBAAyB,CAAC,UAAU,CAAC,CAAC,QAAQ,CAC/C,CAAC;IACF,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,WAAW,CAAC,WAAW,KAAK,WAAW,CAAC,iBAAiB,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,SAAS,GAAG,WAAW,CAAC,qBAAqB,CAAC;IACpD,IAAI,CAAC,SAAS;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import {\n type ContainerGrantPrincipalHead,\n type ContainerKekRecipientTarget,\n type ContainerKeyWrap,\n type ContainerUserRecipientKey,\n derivePrincipalRecipientKeyEpochId,\n wrapDekForRecipients,\n} from \"@tearleads/crypto\";\nimport { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readManifestContainerId } from \"../../documents/shared/readers\";\nimport {\n readCanonicalManifestBundle,\n readContainerAccessManifestState,\n} from \"./readers\";\nimport type { ParentContainerCreateContext } from \"./types\";\n\nexport function uniqueSortedManifestHashes(\n path: readonly ContainerWriterProjectionResponse[\"path\"][number][],\n): string[] {\n return [...new Set(path.map((bundle) => bundle.manifestHash))].sort();\n}\n\ninterface LeafContainerContextErrors {\n readonly emptyProjection: string;\n readonly inconsistentKek: string;\n readonly inconsistentPath: string;\n readonly inconsistentTarget: string;\n readonly staleKek: string;\n}\n\nfunction getLeafContainerContext(\n projection: ContainerWriterProjectionResponse,\n errors: LeafContainerContextErrors,\n): ParentContainerCreateContext {\n if (projection.path.length !== projection.containerKeks.length) {\n throw new Error(errors.inconsistentPath);\n }\n\n const manifest = projection.path.at(-1);\n const kek = projection.containerKeks.at(-1);\n if (!manifest || !kek) {\n throw new Error(errors.emptyProjection);\n }\n if (readManifestContainerId(manifest) !== projection.containerId) {\n throw new Error(errors.inconsistentTarget);\n }\n if (kek.containerId !== projection.containerId) {\n throw new Error(errors.inconsistentKek);\n }\n if (kek.accessManifestHash !== manifest.manifestHash) {\n throw new Error(errors.staleKek);\n }\n\n return { manifest, kek };\n}\n\nexport function getParentCreateContext(\n parentProjection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(parentProjection, {\n emptyProjection: \"Container parent projection is empty\",\n inconsistentKek: \"Container parent KEK target is inconsistent\",\n inconsistentPath:\n \"Container parent projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container parent projection target is inconsistent\",\n staleKek: \"Container parent KEK is stale\",\n });\n}\n\nexport function asContainerManifestBundle(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): AccessManifestBundleWire {\n return readCanonicalManifestBundle(bundle, \"Container manifest bundle\");\n}\n\nexport function readContainerState(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): ReturnType<typeof readContainerAccessManifestState> {\n return readContainerAccessManifestState(\n bundle.state,\n \"Container manifest state\",\n );\n}\n\nexport function getTargetContainerContext(\n projection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(projection, {\n emptyProjection: \"Container projection is empty\",\n inconsistentKek: \"Container target KEK is inconsistent\",\n inconsistentPath: \"Container projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container projection target is inconsistent\",\n staleKek: \"Container target KEK is stale\",\n });\n}\n\nexport function getParentKekForTarget(\n projection: ContainerWriterProjectionResponse,\n): ContainerKekResponse | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parentKek = projection.containerKeks.at(-2);\n if (!parentKek || parentKek.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent KEK is unavailable\");\n }\n\n return parentKek;\n}\n\nexport async function wrapContainerKeyToParent(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n parentKek: ContainerKekResponse;\n parentPublicKey: string;\n}): Promise<ContainerKeyWrap> {\n const [wrapped] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.parentPublicKey),\n ]);\n if (!wrapped) throw new Error(\"Container parent wrap is unavailable\");\n\n return {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"container\",\n recipientId: input.parentKek.containerId,\n recipientKeyEpochId: input.parentKek.containerKeyEpochId,\n recipientKeyFingerprint: input.parentKek.keyEpochHash,\n kemCipherText: bytesToBase64(wrapped.kemCipherText),\n wrappedKey: bytesToBase64(wrapped.wrappedKey),\n wrapManifestHash: input.manifestHash,\n };\n}\n\nexport async function wrapContainerKeyToRootUser(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n recipientEncapsulationPublicKey: Uint8Array;\n userId: string;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n userRecipientKey: ContainerUserRecipientKey;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n input.recipientEncapsulationPublicKey,\n ]);\n if (!recipient) {\n throw new Error(\"Container root recipient wrap is unavailable\");\n }\n\n const userRecipientKey: ContainerUserRecipientKey = {\n userId: input.userId,\n recipientKeyEpochId: `user:${input.userId}:encapsulation:${recipient.keyFingerprint}`,\n recipientKeyFingerprint: recipient.keyFingerprint,\n };\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n };\n\n return {\n recipientTarget,\n userRecipientKey,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport async function wrapContainerKeyToManagedPrincipal(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n principalEncapsulationPublicKey: string;\n principalHead: ContainerGrantPrincipalHead;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.principalEncapsulationPublicKey),\n ]);\n if (!recipient) {\n throw new Error(\n \"Container managed principal recipient wrap is unavailable\",\n );\n }\n\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: input.principalHead.principalType,\n recipientId: input.principalHead.principalId,\n recipientKeyEpochId: derivePrincipalRecipientKeyEpochId(\n input.principalHead,\n ),\n recipientKeyFingerprint: input.principalHead.keyFingerprint,\n };\n\n return {\n recipientTarget,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: recipientTarget.recipientKind,\n recipientId: recipientTarget.recipientId,\n recipientKeyEpochId: recipientTarget.recipientKeyEpochId,\n recipientKeyFingerprint: recipientTarget.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport function getParentWrappingPublicKey(\n projection: ContainerWriterProjectionResponse,\n): string | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parent = projection.path.at(-2);\n if (!parent) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const parentState = readContainerState(parent);\n if (parentState.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const publicKey = parentState.containerKeyPublicKey;\n if (!publicKey)\n throw new Error(\"Container parent wrapping public key is missing\");\n return publicKey;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["projection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerGrantPrincipalHead,\n type ContainerKekRecipientTarget,\n type ContainerKeyWrap,\n type ContainerUserRecipientKey,\n derivePrincipalRecipientKeyEpochId,\n wrapDekForRecipients,\n} from \"@tearleads/crypto\";\nimport { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport type {\n AccessManifestBundleWire,\n ContainerManifestRef,\n} from \"@tearleads/validators/request\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readManifestContainerId } from \"../../documents/shared/readers\";\nimport {\n readCanonicalManifestBundle,\n readContainerAccessManifestState,\n} from \"./readers\";\nimport type { ParentContainerCreateContext } from \"./types\";\n\nexport function uniqueSortedManifestHashes(\n path: readonly ContainerWriterProjectionResponse[\"path\"][number][],\n): string[] {\n return [...new Set(path.map((bundle) => bundle.manifestHash))].sort();\n}\n\ninterface LeafContainerContextErrors {\n readonly emptyProjection: string;\n readonly inconsistentKek: string;\n readonly inconsistentPath: string;\n readonly inconsistentTarget: string;\n readonly staleKek: string;\n}\n\nfunction getLeafContainerContext(\n projection: ContainerWriterProjectionResponse,\n errors: LeafContainerContextErrors,\n): ParentContainerCreateContext {\n if (projection.path.length !== projection.containerKeks.length) {\n throw new Error(errors.inconsistentPath);\n }\n\n const manifest = projection.path.at(-1);\n const kek = projection.containerKeks.at(-1);\n if (!manifest || !kek) {\n throw new Error(errors.emptyProjection);\n }\n if (readManifestContainerId(manifest) !== projection.containerId) {\n throw new Error(errors.inconsistentTarget);\n }\n if (kek.containerId !== projection.containerId) {\n throw new Error(errors.inconsistentKek);\n }\n if (kek.accessManifestHash !== manifest.manifestHash) {\n throw new Error(errors.staleKek);\n }\n\n return { manifest, kek };\n}\n\nexport function getParentCreateContext(\n parentProjection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(parentProjection, {\n emptyProjection: \"Container parent projection is empty\",\n inconsistentKek: \"Container parent KEK target is inconsistent\",\n inconsistentPath:\n \"Container parent projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container parent projection target is inconsistent\",\n staleKek: \"Container parent KEK is stale\",\n });\n}\n\nexport function asContainerManifestBundle(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): AccessManifestBundleWire {\n return readCanonicalManifestBundle(bundle, \"Container manifest bundle\");\n}\n\n/**\n * Cite a manifest the server already stores. Mutation requests carry these\n * references instead of echoing the bundles a writer projection served; the\n * server resolves each from its own verified store.\n */\nexport function containerManifestRef(bundle: {\n readonly manifestHash: string;\n readonly state: Record<string, unknown>;\n}): ContainerManifestRef {\n const containerId = Reflect.get(bundle.state, \"containerId\");\n if (typeof containerId !== \"string\" || containerId.length === 0) {\n throw new Error(\"Container manifest is missing a container id\");\n }\n return { containerId, manifestHash: bundle.manifestHash };\n}\n\nexport function readContainerState(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): ReturnType<typeof readContainerAccessManifestState> {\n return readContainerAccessManifestState(\n bundle.state,\n \"Container manifest state\",\n );\n}\n\nexport function getTargetContainerContext(\n projection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(projection, {\n emptyProjection: \"Container projection is empty\",\n inconsistentKek: \"Container target KEK is inconsistent\",\n inconsistentPath: \"Container projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container projection target is inconsistent\",\n staleKek: \"Container target KEK is stale\",\n });\n}\n\nexport function getParentKekForTarget(\n projection: ContainerWriterProjectionResponse,\n): ContainerKekResponse | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parentKek = projection.containerKeks.at(-2);\n if (!parentKek || parentKek.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent KEK is unavailable\");\n }\n\n return parentKek;\n}\n\nexport async function wrapContainerKeyToParent(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n parentKek: ContainerKekResponse;\n parentPublicKey: string;\n}): Promise<ContainerKeyWrap> {\n const [wrapped] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.parentPublicKey),\n ]);\n if (!wrapped) throw new Error(\"Container parent wrap is unavailable\");\n\n return {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"container\",\n recipientId: input.parentKek.containerId,\n recipientKeyEpochId: input.parentKek.containerKeyEpochId,\n recipientKeyFingerprint: input.parentKek.keyEpochHash,\n kemCipherText: bytesToBase64(wrapped.kemCipherText),\n wrappedKey: bytesToBase64(wrapped.wrappedKey),\n wrapManifestHash: input.manifestHash,\n };\n}\n\nexport async function wrapContainerKeyToRootUser(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n recipientEncapsulationPublicKey: Uint8Array;\n userId: string;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n userRecipientKey: ContainerUserRecipientKey;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n input.recipientEncapsulationPublicKey,\n ]);\n if (!recipient) {\n throw new Error(\"Container root recipient wrap is unavailable\");\n }\n\n const userRecipientKey: ContainerUserRecipientKey = {\n userId: input.userId,\n recipientKeyEpochId: `user:${input.userId}:encapsulation:${recipient.keyFingerprint}`,\n recipientKeyFingerprint: recipient.keyFingerprint,\n };\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n };\n\n return {\n recipientTarget,\n userRecipientKey,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport async function wrapContainerKeyToManagedPrincipal(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n principalEncapsulationPublicKey: string;\n principalHead: ContainerGrantPrincipalHead;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.principalEncapsulationPublicKey),\n ]);\n if (!recipient) {\n throw new Error(\n \"Container managed principal recipient wrap is unavailable\",\n );\n }\n\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: input.principalHead.principalType,\n recipientId: input.principalHead.principalId,\n recipientKeyEpochId: derivePrincipalRecipientKeyEpochId(\n input.principalHead,\n ),\n recipientKeyFingerprint: input.principalHead.keyFingerprint,\n };\n\n return {\n recipientTarget,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: recipientTarget.recipientKind,\n recipientId: recipientTarget.recipientId,\n recipientKeyEpochId: recipientTarget.recipientKeyEpochId,\n recipientKeyFingerprint: recipientTarget.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport function getParentWrappingPublicKey(\n projection: ContainerWriterProjectionResponse,\n): string | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parent = projection.path.at(-2);\n if (!parent) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const parentState = readContainerState(parent);\n if (parentState.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const publicKey = parentState.containerKeyPublicKey;\n if (!publicKey)\n throw new Error(\"Container parent wrapping public key is missing\");\n return publicKey;\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RequestFailureKind, RequestResultOptions, UploadMultipartBlobPartBytesRequest } from "../../../../internal/api-client/index.js";
|
|
2
2
|
import type { BlobContentKeyTarget, BlobEnvelopeHeaderRecord, BlobEnvelopeRecord, WriteHeader } from "../../../../internal/crypto/index.js";
|
|
3
|
-
import type { BlobAttachmentBindRequest, BlobAttachmentDetachRequest, BlobContentKeyBundleRequest,
|
|
4
|
-
import type { BlobAttachmentBindResponse, BlobAttachmentDetachResponse, BlobAttachmentSummary,
|
|
3
|
+
import type { BlobAttachmentBindRequest, BlobAttachmentDetachRequest, BlobContentKeyBundleRequest, InitiateMultipartBlobStageRequest } from "../../../../internal/validators/request/index.js";
|
|
4
|
+
import type { BlobAttachmentBindResponse, BlobAttachmentDetachResponse, BlobAttachmentSummary, DocumentWriterProjectionResponse, InitiateMultipartBlobStageResponse, MultipartBlobStageStatusResponse, UploadMultipartBlobPartResponse } from "../../../../internal/validators/response/index.js";
|
|
5
5
|
import type { BlobByteSourceInput, BlobBytes } from "../../../blobContracts.js";
|
|
6
6
|
import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../../keyingProjectionVerification.js";
|
|
7
7
|
import type { ExecSql } from "../../../sqlite/sqlSchema.js";
|
|
@@ -27,7 +27,6 @@ export interface BlobAttachmentApi {
|
|
|
27
27
|
readonly message: string;
|
|
28
28
|
readonly status: number | null;
|
|
29
29
|
} | null;
|
|
30
|
-
completeMultipartBlobStage(stageId: string, input: CompleteMultipartBlobStageRequest): Promise<CompleteMultipartBlobStageResponse | null>;
|
|
31
30
|
getDocumentWriterProjection(documentId: string): Promise<DocumentWriterProjectionResponse | null>;
|
|
32
31
|
getMultipartBlobStage(stageId: string): Promise<MultipartBlobStageStatusResponse | null>;
|
|
33
32
|
initiateMultipartBlobStage(input: InitiateMultipartBlobStageRequest): Promise<InitiateMultipartBlobStageResponse | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAkCA,MAAM,CAAC,MAAM,mCAAmC,GAC9C,wCAAwC,CAAC;AAC3C,MAAM,CAAC,MAAM,8BAA8B,GACzC,mCAAmC,CAAC;AACtC,MAAM,CAAC,MAAM,gCAAgC,GAC3C,qCAAqC,CAAC;AACxC,MAAM,CAAC,MAAM,6BAA6B,GACxC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,yCAAyC,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC","sourcesContent":["import type {\n RequestFailureKind,\n RequestResultOptions,\n UploadMultipartBlobPartBytesRequest,\n} from \"@tearleads/api-client\";\nimport type {\n BlobContentKeyTarget,\n BlobEnvelopeHeaderRecord,\n BlobEnvelopeRecord,\n WriteHeader,\n} from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentBindRequest,\n BlobAttachmentDetachRequest,\n BlobContentKeyBundleRequest,\n InitiateMultipartBlobStageRequest,\n} from \"@tearleads/validators/request\";\nimport type {\n BlobAttachmentBindResponse,\n BlobAttachmentDetachResponse,\n BlobAttachmentSummary,\n DocumentWriterProjectionResponse,\n InitiateMultipartBlobStageResponse,\n MultipartBlobStageStatusResponse,\n UploadMultipartBlobPartResponse,\n} from \"@tearleads/validators/response\";\nimport type { BlobByteSourceInput, BlobBytes } from \"../../../blobContracts\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentCreateAuthor } from \"../../shared/types\";\n\nexport const BLOB_CONTENT_RECORD_KEY_INFO_DOMAIN =\n \"tearleads.blob.content-record-key-info\";\nexport const BLOB_CONTENT_RECORD_AAD_DOMAIN =\n \"tearleads.blob.content-record-aad\";\nexport const BLOB_CONTENT_RECORD_NONCE_DOMAIN =\n \"tearleads.blob.content-record-nonce\";\nexport const BLOB_CONTENT_RECORD_HKDF_SALT: Uint8Array<ArrayBuffer> =\n new TextEncoder().encode(\"tearleads.blob.content-record-hkdf-salt\");\nexport const TEXT_ENCODER = new TextEncoder();\n\nexport interface BlobAttachmentRequestOptions {\n readonly expectedPaymentRequiredOrganizationId?: string | undefined;\n}\n\nexport interface BlobAttachmentApi {\n bindBlobAttachment(\n blobId: string,\n input: BlobAttachmentBindRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentBindResponse | null>;\n clearWriterProjectionCaches?(): void;\n evictDocumentWriterProjection?(documentId: string): void;\n getRequestFailure?(input: {\n method: \"DELETE\" | \"GET\" | \"POST\" | \"PUT\";\n path: string;\n }): {\n readonly code?: string | undefined;\n readonly kind: RequestFailureKind;\n readonly message: string;\n readonly status: number | null;\n } | null;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n getMultipartBlobStage(\n stageId: string,\n ): Promise<MultipartBlobStageStatusResponse | null>;\n initiateMultipartBlobStage(\n input: InitiateMultipartBlobStageRequest,\n ): Promise<InitiateMultipartBlobStageResponse | null>;\n uploadMultipartBlobPartBytes(\n stageId: string,\n partNumber: number,\n input: UploadMultipartBlobPartBytesRequest,\n options?: RequestResultOptions,\n ): Promise<UploadMultipartBlobPartResponse | null>;\n}\n\nexport interface BlobAttachmentDetachApi {\n detachBlobAttachment(\n blobId: string,\n bindingId: string,\n input: BlobAttachmentDetachRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentDetachResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n}\n\nexport type { BlobContentKeyTarget };\n\n/**\n * Aliases of the crypto parser's own types. The parser is shared with the API,\n * so restating these shapes here would let the two drift apart silently.\n */\nexport type BlobEncryptedBytesRecord = BlobEnvelopeRecord;\n\n/**\n * The envelope as the header establishes it. Streaming readers hold this\n * before any ciphertext is read, so it has no `chunks`: an empty array there\n * would read as an empty object rather than an unread one.\n */\nexport type BlobEncryptedBytesHeader = BlobEnvelopeHeaderRecord;\n\nexport type BlobEncryptedChunk = BlobEnvelopeRecord[\"chunks\"][number];\n\nexport interface BlobSourceSnapshot {\n readonly byteLength: number;\n readonly chunkSha256: readonly string[];\n readonly chunkSize: number;\n readonly sha256: string;\n}\n\nexport interface BlobEncryptionPlan {\n readonly byteLength: number;\n readonly chunkSize: number;\n readonly metadataHash: string;\n readonly partCount: number;\n readonly plaintextByteLength: number;\n readonly plaintextSha256: string;\n readonly sha256: string;\n encryptPart(index: number): Promise<BlobBytes>;\n getPartByteLength(index: number): number;\n}\n\nexport interface DocumentManifestIdentity {\n documentId: string;\n manifestHash: string;\n organizationId: string;\n}\n\nexport interface BlobAttachmentMaterial {\n blobAccessManifestHash: string;\n contentKeyBundle: BlobContentKeyBundleRequest;\n encrypted: BlobEncryptionPlan;\n manifestIdentity: DocumentManifestIdentity;\n targetHash: string;\n targets: BlobContentKeyTarget[];\n writerProjection: DocumentWriterProjectionResponse;\n}\n\n/**\n * Progress for an in-flight multipart blob upload.\n */\nexport interface MultipartUploadProgress {\n readonly bytesTotal: number;\n readonly bytesUploaded: number;\n readonly partsCompleted: number;\n readonly partsTotal: number;\n}\n\nexport type MultipartUploadProgressListener = (\n progress: MultipartUploadProgress,\n) => void;\n\n/**\n * Fires once a multipart stage has been opened (or resumed), with its id and\n * plaintext chunk size. Callers persist both so a later attempt can reproduce\n * the same encrypted parts and resume instead of orphaning the partial upload.\n */\nexport type MultipartStageResolvedListener = (input: {\n readonly partSize: number;\n readonly stageId: string;\n}) => void | Promise<void>;\n\nexport interface UploadDocumentAttachmentInput {\n apiClient: BlobAttachmentApi;\n author: DocumentCreateAuthor;\n blobId?: string | undefined;\n bindingId?: string | undefined;\n bytes: BlobByteSourceInput;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedBindingId: string | null;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n // A persisted nonce seed. The plaintext digest derives the envelope IV from\n // it, then each chunk derives a unique IV. Same-source retries reproduce the\n // encrypted parts; changed bytes cannot reuse their AES-GCM nonces.\n nonceSeed?: Uint8Array | undefined;\n multipart?: MultipartBlobUploadOptions | undefined;\n onMultipartProgress?: MultipartUploadProgressListener | undefined;\n onStageResolved?: MultipartStageResolvedListener | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface MultipartBlobUploadOptions {\n /** Exactly 5 MiB per plaintext encryption chunk; transport parts include envelope overhead. */\n readonly partSize: number;\n // The id of a previously opened stage to resume. When set, the upload refetches\n // that stage and skips parts the server already has instead of opening a new\n // one; if the stage is gone (expired), it falls back to a fresh stage.\n readonly resumeStageId?: string | undefined;\n readonly uploadConcurrency?: number | undefined;\n}\n\nexport interface UploadDocumentAttachmentResult {\n blobId: string;\n bindingId: string;\n request: BlobAttachmentBindRequest;\n response: BlobAttachmentBindResponse;\n sha256: string;\n byteLength: number;\n writeHeader: WriteHeader;\n writeHeaderHash: string;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DetachDocumentAttachmentInput {\n apiClient: BlobAttachmentDetachApi;\n author: DocumentCreateAuthor;\n bindingId: string;\n blobId: string;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface DetachDocumentAttachmentResult {\n request: BlobAttachmentDetachRequest;\n response: BlobAttachmentDetachResponse;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DecryptDocumentAttachmentBlobInput {\n binding: BlobAttachmentSummary;\n encryptedBytes: BlobBytes;\n expectedDocumentId: string;\n expectedSlotId: string;\n execSql: ExecSql;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n targetSecretKey: Uint8Array;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}\n"]}
|
|
@@ -62,7 +62,6 @@ export async function buildDocumentCreatePlan({ author, containerProjection, con
|
|
|
62
62
|
body: readCanonicalRecord(body, "Document create body"),
|
|
63
63
|
expectedManifestHash: manifestHash,
|
|
64
64
|
manifest: readCanonicalRecord(manifest, "Document create manifest"),
|
|
65
|
-
previousManifest: null,
|
|
66
65
|
targetContainerPathRefs: containerPathRefs(containerProjection.path),
|
|
67
66
|
contentKeyBundle: {
|
|
68
67
|
contentKeyEpoch,
|