@tearleads/client-sdk 0.1.79 → 0.1.81
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/deviceFirst/index.d.ts +1 -1
- package/client/deviceFirst/index.js +1 -1
- package/client/deviceFirst/index.js.map +1 -1
- package/client/runtime/principalMutationApi.js +1 -1
- package/client/runtime/principalMutationApi.js.map +1 -1
- package/client/runtime/principalMutationDispatch.js +1 -1
- package/client/runtime/principalMutationDispatch.js.map +1 -1
- package/client/runtime/rootContainerAdoption.js.map +1 -1
- package/client/runtime/workflowRuntime.d.ts +1 -1
- package/client/runtime/workflowRuntime.js.map +1 -1
- package/client/session/sessionPurgeRecovery.js +1 -1
- package/client/session/sessionPurgeRecovery.js.map +1 -1
- package/data/blobs/attachments/projection.js +2 -3
- package/data/blobs/attachments/projection.js.map +1 -1
- package/data/documents/documentConstants.d.ts +1 -0
- package/data/documents/documentConstants.js +1 -0
- package/data/documents/documentConstants.js.map +1 -1
- package/data/documents/shared/containerKek/containerKekEntryVerification.d.ts +3 -0
- package/data/documents/shared/containerKek/index.d.ts +5 -0
- package/data/documents/shared/containerKek/index.js +9 -0
- package/data/documents/shared/containerKek/index.js.map +1 -0
- package/data/documents/shared/projection/index.d.ts +1 -1
- package/data/documents/shared/projection/index.js +1 -1
- package/data/documents/shared/projection/index.js.map +1 -1
- package/data/documents/shared/sync/syncResponseAuthorization.js +1 -1
- package/data/documents/shared/sync/syncResponseAuthorization.js.map +1 -1
- package/data/keyingProjectionVerification/container/containerCreateManifest.d.ts +12 -0
- package/data/keyingProjectionVerification/container/containerDestinationVerification.d.ts +16 -0
- package/data/keyingProjectionVerification/index.d.ts +5 -0
- package/data/keyingProjectionVerification/index.js +6 -1
- package/data/keyingProjectionVerification/index.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence.d.ts +3 -0
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyCache.js +1 -1
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyCache.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyCheckpointSelection.d.ts +6 -0
- package/data/{persistence → keyingProjectionVerification}/principalPolicy/principalPolicyCheckpointSelection.js +1 -1
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyCheckpointSelection.js.map +1 -0
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyVerification.d.ts +24 -0
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyVerification.js +1 -1
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyVerification.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicy/resolvedPrincipalPolicy.js +1 -1
- package/data/keyingProjectionVerification/principalPolicy/resolvedPrincipalPolicy.js.map +1 -1
- package/data/persistence/container-contents/documentPlacement.js +1 -1
- package/data/persistence/container-contents/documentPlacement.js.map +1 -1
- package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js +1 -1
- package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js.map +1 -1
- package/data/persistence/documents/documentsPersistence.d.ts +1 -1
- package/data/persistence/documents/documentsPersistence.js +2 -3
- package/data/persistence/documents/documentsPersistence.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
- package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js +1 -1
- package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js.map +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentProjectionRows.js +1 -2
- package/data/persistence/documents/internal/documentProjectionRows.js.map +1 -1
- package/data/persistence/documents/internal/documentPullContinuationPersistence.js +1 -1
- package/data/persistence/documents/internal/documentPullContinuationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentRows.js +1 -2
- package/data/persistence/documents/internal/documentRows.js.map +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
- package/data/persistence/documents/internal/pendingCreateAdoption.js +1 -1
- package/data/persistence/documents/internal/pendingCreateAdoption.js.map +1 -1
- package/data/persistence/documents/internal/rowQueryPersistence.js +1 -1
- package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
- package/data/persistence/keyingCheckpoints/keyingCheckpointAdvancePersistence.js +11 -51
- package/data/persistence/keyingCheckpoints/keyingCheckpointAdvancePersistence.js.map +1 -1
- package/data/persistence/keyingCheckpoints/locallyAcknowledgedCheckpointPersistence.d.ts +1 -30
- package/data/persistence/keyingCheckpoints/locallyAcknowledgedCheckpointPersistence.js +4 -85
- package/data/persistence/keyingCheckpoints/locallyAcknowledgedCheckpointPersistence.js.map +1 -1
- package/data/persistence/principalPolicy/locallyAcknowledgedPrincipalPolicyPersistence.js +88 -0
- package/data/persistence/principalPolicy/locallyAcknowledgedPrincipalPolicyPersistence.js.map +1 -0
- package/data/persistence/principalPolicy/verifiedPrincipalPolicyBundlePersistence.js +53 -0
- package/data/persistence/principalPolicy/verifiedPrincipalPolicyBundlePersistence.js.map +1 -0
- package/package.json +1 -1
- package/stores/local-projection/localProjectionStore.d.ts +1 -1
- package/stores/local-projection/localProjectionStore.js +1 -1
- package/stores/local-projection/localProjectionStore.js.map +1 -1
- package/stores/local-projection/registry.d.ts +1 -1
- package/stores/local-projection/registry.js.map +1 -1
- package/stores/local-projection/types.d.ts +1 -1
- package/stores/local-projection/types.js.map +1 -1
- package/workflows/blobs/hydration/decrypt.js +1 -2
- package/workflows/blobs/hydration/decrypt.js.map +1 -1
- package/workflows/blobs/hydration/hydrate.d.ts +1 -1
- package/workflows/blobs/hydration/hydrate.js.map +1 -1
- package/workflows/container-contents/container-state/create/createAdoption.js +1 -2
- package/workflows/container-contents/container-state/create/createAdoption.js.map +1 -1
- package/workflows/container-contents/container-state/purge/purgeTreeScope.js +1 -1
- package/workflows/container-contents/container-state/purge/purgeTreeScope.js.map +1 -1
- package/workflows/container-contents/info/documentInfo.js +1 -1
- package/workflows/container-contents/info/documentInfo.js.map +1 -1
- package/workflows/container-contents/metadata/index.js +1 -2
- package/workflows/container-contents/metadata/index.js.map +1 -1
- package/workflows/container-contents/metadata/metadataMutationPreparation.js +1 -1
- package/workflows/container-contents/metadata/metadataMutationPreparation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataPullContinuationInvalidation.js +1 -1
- package/workflows/container-contents/metadata/metadataPullContinuationInvalidation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataSyncErrors.js +1 -1
- package/workflows/container-contents/metadata/metadataSyncErrors.js.map +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.d.ts +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js.map +1 -1
- package/workflows/container-contents/metadata/metadataTypes.d.ts +1 -1
- package/workflows/container-contents/metadata/metadataTypes.js.map +1 -1
- package/workflows/container-contents/pendingWrites/index.js +1 -1
- package/workflows/container-contents/pendingWrites/index.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js +1 -3
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js.map +1 -1
- package/workflows/containers/child/create/index.js +1 -1
- package/workflows/containers/child/create/index.js.map +1 -1
- package/workflows/containers/child/move/moveRotation.js +1 -1
- package/workflows/containers/child/move/moveRotation.js.map +1 -1
- package/workflows/containers/child/move/moveWraps.js +1 -1
- package/workflows/containers/child/move/moveWraps.js.map +1 -1
- package/workflows/containers/child/rekey/rekeyProjection.js +1 -1
- package/workflows/containers/child/rekey/rekeyProjection.js.map +1 -1
- package/workflows/containers/child/rotation/rotationContext.js +1 -2
- package/workflows/containers/child/rotation/rotationContext.js.map +1 -1
- package/workflows/containers/child/share/shareAncestorRepair.js +1 -2
- package/workflows/containers/child/share/shareAncestorRepair.js.map +1 -1
- package/workflows/containers/index.d.ts +2 -3
- package/workflows/containers/index.js +1 -2
- package/workflows/containers/index.js.map +1 -1
- package/workflows/containers/writeRefusal.js +1 -1
- package/workflows/containers/writeRefusal.js.map +1 -1
- package/workflows/documents/linkSet/linkSetProjectionSeed.js +1 -1
- package/workflows/documents/linkSet/linkSetProjectionSeed.js.map +1 -1
- package/workflows/documents/syncRekeys/syncAutomaticContainerRekeys.js +1 -1
- package/workflows/documents/syncRekeys/syncAutomaticContainerRekeys.js.map +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js.map +1 -1
- package/workflows/organizations/groupPolicy/groupPolicyMutationContext.js +2 -2
- package/workflows/organizations/groupPolicy/groupPolicyMutationContext.js.map +1 -1
- package/workflows/organizations/groups/deleteOrganizationGroup.js +1 -1
- package/workflows/organizations/groups/deleteOrganizationGroup.js.map +1 -1
- package/workflows/organizations/groups/organizationGroupDirectory.js +1 -1
- package/workflows/organizations/groups/organizationGroupDirectory.js.map +1 -1
- package/workflows/organizations/provisioning/createOrganization.d.ts +1 -1
- package/workflows/organizations/provisioning/createOrganization.js +1 -1
- package/workflows/organizations/provisioning/createOrganization.js.map +1 -1
- package/workflows/organizations/provisioning/organizationProvisioningAttempt.d.ts +1 -1
- package/workflows/organizations/provisioning/organizationProvisioningAttempt.js.map +1 -1
- package/workflows/organizations/readModel/listLocalOrganizations.js +1 -1
- package/workflows/organizations/readModel/listLocalOrganizations.js.map +1 -1
- package/workflows/principals/externalAdminPolicy.js +1 -1
- package/workflows/principals/externalAdminPolicy.js.map +1 -1
- package/workflows/principals/policyCache/principalPolicyCacheAdvance.js +1 -1
- package/workflows/principals/policyCache/principalPolicyCacheAdvance.js.map +1 -1
- package/workflows/principals/policyCache/principalPolicyOrganizationScope.js +1 -1
- package/workflows/principals/policyCache/principalPolicyOrganizationScope.js.map +1 -1
- package/workflows/registration/index.d.ts +2 -1
- package/workflows/registration/index.js +2 -1
- package/workflows/registration/index.js.map +1 -1
- package/workflows/registration/organizationProvisioning.d.ts +39 -0
- package/workflows/registration/organizationProvisioning.js +211 -0
- package/workflows/registration/organizationProvisioning.js.map +1 -0
- package/workflows/registration/organizationProvisioningArtifacts.d.ts +2 -3
- package/workflows/registration/organizationProvisioningArtifacts.js.map +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.d.ts +3 -3
- package/workflows/registration/provisioningBootstrapBuilders.js +3 -4
- package/workflows/registration/provisioningBootstrapBuilders.js.map +1 -1
- package/workflows/registration/registerIdentity.d.ts +2 -39
- package/workflows/registration/registerIdentity.js +2 -207
- package/workflows/registration/registerIdentity.js.map +1 -1
- package/workflows/registration/registrationPrincipalPolicyPersistence.js +1 -1
- package/workflows/registration/registrationPrincipalPolicyPersistence.js.map +1 -1
- package/workflows/sync/remoteResetPlans.js +2 -2
- package/workflows/sync/remoteResetPlans.js.map +1 -1
- package/data/persistence/documents/internal/constants.d.ts +0 -1
- package/data/persistence/documents/internal/constants.js +0 -2
- package/data/persistence/documents/internal/constants.js.map +0 -1
- package/data/persistence/principalKeys/principalGrantRetirementPersistence.d.ts +0 -9
- package/data/persistence/principalPolicy/principalPolicyCheckpointSelection.js.map +0 -1
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { accessManifestCheckpointFromManifest, KeyingVerificationError, verifyAccessManifestLocalCheckpoint,
|
|
2
|
-
import { keyingCheckpointTables
|
|
1
|
+
import { accessManifestCheckpointFromManifest, KeyingVerificationError, verifyAccessManifestLocalCheckpoint, } from "../../../internal/crypto/index.js";
|
|
2
|
+
import { keyingCheckpointTables } from "../../sqlite/schema/index.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
4
|
import { ensureSqlTables } from "../../sqlite/sqlSchema.js";
|
|
5
|
-
import { assertContainerNotRetired
|
|
6
|
-
import {
|
|
7
|
-
import { assertBundleMatchesVerifiedPolicy } from "../principalPolicy/verifiedPrincipalPolicyBundle.js";
|
|
8
|
-
import { accessManifestObjectKey, loadStoredAccessManifestCheckpoint, loadStoredPrincipalPolicyCheckpoint, principalPolicyKey, upsertAccessManifestCheckpointInTransaction, upsertPrincipalPolicyCheckpointInTransaction, } from "./keyingCheckpointPersistence.js";
|
|
5
|
+
import { assertContainerNotRetired } from "../principalKeys/principalGrantRetirementPersistence.js";
|
|
6
|
+
import { accessManifestObjectKey, loadStoredAccessManifestCheckpoint, loadStoredPrincipalPolicyCheckpoint, upsertAccessManifestCheckpointInTransaction, } from "./keyingCheckpointPersistence.js";
|
|
9
7
|
export function locallyAuthoredAccessManifestHead(plan) {
|
|
10
8
|
return {
|
|
11
9
|
checkpoint: accessManifestCheckpointFromManifest({
|
|
@@ -85,83 +83,4 @@ export async function advanceLocallyAcknowledgedAccessManifestHeadsAtomically(in
|
|
|
85
83
|
await runtime.transaction(acknowledge, { behavior: "immediate" });
|
|
86
84
|
return true;
|
|
87
85
|
}
|
|
88
|
-
function validateAcknowledgedPolicy(policy, checkpoint) {
|
|
89
|
-
verifyPrincipalPolicyCheckpoint({
|
|
90
|
-
chain: policy.history ?? [],
|
|
91
|
-
currentState: policy.state,
|
|
92
|
-
localCheckpoint: checkpoint,
|
|
93
|
-
});
|
|
94
|
-
if (!checkpoint && policy.version !== 1) {
|
|
95
|
-
throw new KeyingVerificationError("stale_predecessor", "locally acknowledged principal policy does not begin at version 1");
|
|
96
|
-
}
|
|
97
|
-
if (checkpoint && policy.version > checkpoint.version + 1) {
|
|
98
|
-
throw new KeyingVerificationError("stale_predecessor", "locally acknowledged principal policy does not directly extend the durable checkpoint");
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function assertUniqueAcknowledgedPolicies(entries) {
|
|
102
|
-
const seen = new Set();
|
|
103
|
-
for (const { policy } of entries) {
|
|
104
|
-
const key = principalPolicyKey(policy);
|
|
105
|
-
if (seen.has(key)) {
|
|
106
|
-
throw new KeyingVerificationError("duplicate_entry", `locally acknowledged policy batch repeats ${key}`);
|
|
107
|
-
}
|
|
108
|
-
seen.add(key);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
async function storeAcknowledgedPrincipalPolicyBundles(input) {
|
|
112
|
-
assertUniqueAcknowledgedPolicies(input.entries);
|
|
113
|
-
await Promise.all(input.entries.map((entry) => assertBundleMatchesVerifiedPolicy(entry)));
|
|
114
|
-
await ensureSqlTables(input.execSql, [
|
|
115
|
-
...principalPolicyTables,
|
|
116
|
-
...keyingCheckpointTables,
|
|
117
|
-
]);
|
|
118
|
-
const runtime = getClientSQLitePersistenceRuntime(input.execSql);
|
|
119
|
-
const store = async (tx) => {
|
|
120
|
-
for (const { policy } of input.entries) {
|
|
121
|
-
validateAcknowledgedPolicy(policy, await loadStoredPrincipalPolicyCheckpoint(tx, policy));
|
|
122
|
-
}
|
|
123
|
-
if (input.retiredContainers)
|
|
124
|
-
await storePrincipalGrantRetirements(tx, input.retiredContainers, input.entries.map(({ policy }) => policy), input.organizationId);
|
|
125
|
-
for (const entry of input.entries) {
|
|
126
|
-
if (input.placement === "current") {
|
|
127
|
-
await writePrincipalPolicyBundleInTransaction(tx, entry.bundle, input.updatedAt, input.organizationId);
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
await retainPrincipalPolicyBundleInTransaction(tx, entry.bundle, input.updatedAt, input.organizationId);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
for (const { policy } of input.entries) {
|
|
134
|
-
await upsertPrincipalPolicyCheckpointInTransaction(tx, policy.checkpoint, input.updatedAt, input.organizationId);
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
if (input.stillCurrent) {
|
|
138
|
-
await runtime.guardedTransaction(store, input.stillCurrent, {
|
|
139
|
-
behavior: "immediate",
|
|
140
|
-
});
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
await runtime.transaction(store, { behavior: "immediate" });
|
|
144
|
-
}
|
|
145
|
-
/** Atomically pins and caches exact full policy bundles acknowledged by the API. */
|
|
146
|
-
export function persistLocallyAcknowledgedPrincipalPolicyBundles(input) {
|
|
147
|
-
return storeAcknowledgedPrincipalPolicyBundles({
|
|
148
|
-
...input,
|
|
149
|
-
placement: "current",
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
export function persistLocallyAcknowledgedPrincipalPolicyBundle(input) {
|
|
153
|
-
return persistLocallyAcknowledgedPrincipalPolicyBundles({
|
|
154
|
-
entries: [input],
|
|
155
|
-
execSql: input.execSql,
|
|
156
|
-
organizationId: input.organizationId,
|
|
157
|
-
stillCurrent: input.stillCurrent,
|
|
158
|
-
updatedAt: input.updatedAt,
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
export function retainLocallyAcknowledgedPrincipalPolicyBundles(input) {
|
|
162
|
-
return storeAcknowledgedPrincipalPolicyBundles({
|
|
163
|
-
...input,
|
|
164
|
-
placement: "history",
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
86
|
//# sourceMappingURL=locallyAcknowledgedCheckpointPersistence.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locallyAcknowledgedCheckpointPersistence.js","sourceRoot":"","sources":["locallyAcknowledgedCheckpointPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AccessManifest,\n type AccessManifestCheckpoint,\n accessManifestCheckpointFromManifest,\n KeyingVerificationError,\n type PrincipalPolicyCheckpoint,\n type VerifiedPrincipalPolicy,\n verifyAccessManifestLocalCheckpoint,\n verifyPrincipalPolicyCheckpoint,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport {\n keyingCheckpointTables,\n principalPolicyTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../../sqlite/sqlSchema\";\nimport {\n type AcknowledgedPrincipalGrantRetirements,\n assertContainerNotRetired,\n storePrincipalGrantRetirements,\n} from \"../principalKeys/principalGrantRetirementPersistence\";\nimport {\n retainPrincipalPolicyBundleInTransaction,\n writePrincipalPolicyBundleInTransaction,\n} from \"../principalPolicy/principalPolicyPersistence\";\nimport { assertBundleMatchesVerifiedPolicy } from \"../principalPolicy/verifiedPrincipalPolicyBundle\";\nimport {\n accessManifestObjectKey,\n loadStoredAccessManifestCheckpoint,\n loadStoredPrincipalPolicyCheckpoint,\n principalPolicyKey,\n upsertAccessManifestCheckpointInTransaction,\n upsertPrincipalPolicyCheckpointInTransaction,\n} from \"./keyingCheckpointPersistence\";\n\nexport interface LocallyAcknowledgedAccessManifestHead {\n readonly checkpoint: AccessManifestCheckpoint;\n readonly previousManifestHash: string | null;\n}\n\nexport function locallyAuthoredAccessManifestHead(plan: {\n readonly manifest: AccessManifest;\n readonly manifestHash: string;\n}): LocallyAcknowledgedAccessManifestHead {\n return {\n checkpoint: accessManifestCheckpointFromManifest({\n manifest: plan.manifest,\n manifestHash: plan.manifestHash,\n }),\n previousManifestHash: plan.manifest.previousManifestHash,\n };\n}\n\nfunction validateAcknowledgedHead(\n head: LocallyAcknowledgedAccessManifestHead,\n localCheckpoint: AccessManifestCheckpoint | null,\n): void {\n if (!localCheckpoint) {\n if (head.checkpoint.epoch !== 1 || head.previousManifestHash !== null) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"locally acknowledged access manifest does not begin at epoch 1\",\n );\n }\n return;\n }\n\n verifyAccessManifestLocalCheckpoint({\n checkpointPredecessors: [],\n current: {\n ...head.checkpoint,\n previousManifestHash: head.previousManifestHash,\n },\n localCheckpoint,\n });\n}\n\nasync function validateAcknowledgedHeads(\n tx: ClientSQLiteTransactionScope,\n heads: readonly LocallyAcknowledgedAccessManifestHead[],\n): Promise<Map<string, AccessManifestCheckpoint>> {\n const pending = new Map<string, AccessManifestCheckpoint>();\n for (const head of heads) {\n await assertContainerNotRetired(tx, head.checkpoint);\n const key = accessManifestObjectKey(head.checkpoint);\n if (pending.has(key)) {\n throw new KeyingVerificationError(\n \"equivocation\",\n `locally acknowledged batch contains multiple heads for ${key}`,\n );\n }\n validateAcknowledgedHead(\n head,\n await loadStoredAccessManifestCheckpoint(tx, head.checkpoint),\n );\n pending.set(key, head.checkpoint);\n }\n return pending;\n}\n\nasync function writeAcknowledgedHeads(\n tx: ClientSQLiteTransactionScope,\n pending: ReadonlyMap<string, AccessManifestCheckpoint>,\n updatedAt: string,\n): Promise<void> {\n for (const checkpoint of pending.values()) {\n await upsertAccessManifestCheckpointInTransaction(\n tx,\n checkpoint,\n updatedAt,\n );\n }\n}\n\n/**\n * Commits only heads authored and signed by this client after an exact remote\n * acknowledgement check. Every non-initial head must directly extend the\n * latest durable pin; arbitrary remote projections must use the verified\n * projection checkpoint path instead.\n */\nexport async function advanceLocallyAcknowledgedAccessManifestHeadsAtomically(input: {\n readonly execSql: ExecSql;\n readonly heads: readonly LocallyAcknowledgedAccessManifestHead[];\n /** Optional optimistic read dependencies, checked inside the write transaction. */\n readonly expectedAccessManifestCheckpoints?: readonly AccessManifestCheckpoint[];\n readonly expectedPrincipalPolicyCheckpoints?: readonly PrincipalPolicyCheckpoint[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean> {\n await ensureSqlTables(input.execSql, keyingCheckpointTables);\n const updatedAt = new Date().toISOString();\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const acknowledge = async (tx: ClientSQLiteTransactionScope) => {\n for (const expected of input.expectedAccessManifestCheckpoints ?? []) {\n const current = await loadStoredAccessManifestCheckpoint(tx, expected);\n if (\n current?.epoch !== expected.epoch ||\n current.manifestHash !== expected.manifestHash\n ) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"A re-citation container checkpoint changed before acknowledgement\",\n );\n }\n }\n for (const expected of input.expectedPrincipalPolicyCheckpoints ?? []) {\n const current = await loadStoredPrincipalPolicyCheckpoint(tx, expected);\n if (\n current?.version !== expected.version ||\n current.stateHash !== expected.stateHash\n ) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"A re-citation principal policy checkpoint changed before acknowledgement\",\n );\n }\n }\n const pending = await validateAcknowledgedHeads(tx, input.heads);\n await writeAcknowledgedHeads(tx, pending, updatedAt);\n };\n if (input.stillCurrent) {\n return (\n await runtime.guardedTransaction(acknowledge, input.stillCurrent, {\n behavior: \"immediate\",\n })\n ).committed;\n }\n await runtime.transaction(acknowledge, { behavior: \"immediate\" });\n return true;\n}\n\nfunction validateAcknowledgedPolicy(\n policy: VerifiedPrincipalPolicy,\n checkpoint: PrincipalPolicyCheckpoint | null,\n): void {\n verifyPrincipalPolicyCheckpoint({\n chain: policy.history ?? [],\n currentState: policy.state,\n localCheckpoint: checkpoint,\n });\n if (!checkpoint && policy.version !== 1) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"locally acknowledged principal policy does not begin at version 1\",\n );\n }\n if (checkpoint && policy.version > checkpoint.version + 1) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"locally acknowledged principal policy does not directly extend the durable checkpoint\",\n );\n }\n}\n\ninterface LocallyAcknowledgedPrincipalPolicyBundle {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n}\n\nfunction assertUniqueAcknowledgedPolicies(\n entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[],\n): void {\n const seen = new Set<string>();\n for (const { policy } of entries) {\n const key = principalPolicyKey(policy);\n if (seen.has(key)) {\n throw new KeyingVerificationError(\n \"duplicate_entry\",\n `locally acknowledged policy batch repeats ${key}`,\n );\n }\n seen.add(key);\n }\n}\n\nasync function storeAcknowledgedPrincipalPolicyBundles(input: {\n readonly retiredContainers?:\n | AcknowledgedPrincipalGrantRetirements\n | undefined;\n readonly entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly placement: \"current\" | \"history\";\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n assertUniqueAcknowledgedPolicies(input.entries);\n await Promise.all(\n input.entries.map((entry) => assertBundleMatchesVerifiedPolicy(entry)),\n );\n await ensureSqlTables(input.execSql, [\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const store = async (tx: ClientSQLiteTransactionScope) => {\n for (const { policy } of input.entries) {\n validateAcknowledgedPolicy(\n policy,\n await loadStoredPrincipalPolicyCheckpoint(tx, policy),\n );\n }\n if (input.retiredContainers)\n await storePrincipalGrantRetirements(\n tx,\n input.retiredContainers,\n input.entries.map(({ policy }) => policy),\n input.organizationId,\n );\n for (const entry of input.entries) {\n if (input.placement === \"current\") {\n await writePrincipalPolicyBundleInTransaction(\n tx,\n entry.bundle,\n input.updatedAt,\n input.organizationId,\n );\n } else {\n await retainPrincipalPolicyBundleInTransaction(\n tx,\n entry.bundle,\n input.updatedAt,\n input.organizationId,\n );\n }\n }\n for (const { policy } of input.entries) {\n await upsertPrincipalPolicyCheckpointInTransaction(\n tx,\n policy.checkpoint,\n input.updatedAt,\n input.organizationId,\n );\n }\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(store, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(store, { behavior: \"immediate\" });\n}\n\n/** Atomically pins and caches exact full policy bundles acknowledged by the API. */\nexport function persistLocallyAcknowledgedPrincipalPolicyBundles(input: {\n readonly entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n return storeAcknowledgedPrincipalPolicyBundles({\n ...input,\n placement: \"current\",\n });\n}\n\nexport function persistLocallyAcknowledgedPrincipalPolicyBundle(\n input: LocallyAcknowledgedPrincipalPolicyBundle & {\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n },\n): Promise<void> {\n return persistLocallyAcknowledgedPrincipalPolicyBundles({\n entries: [input],\n execSql: input.execSql,\n organizationId: input.organizationId,\n stillCurrent: input.stillCurrent,\n updatedAt: input.updatedAt,\n });\n}\n\nexport function retainLocallyAcknowledgedPrincipalPolicyBundles(input: {\n readonly retiredContainers?:\n | AcknowledgedPrincipalGrantRetirements\n | undefined;\n readonly entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n return storeAcknowledgedPrincipalPolicyBundles({\n ...input,\n placement: \"history\",\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"locallyAcknowledgedCheckpointPersistence.js","sourceRoot":"","sources":["locallyAcknowledgedCheckpointPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AccessManifest,\n type AccessManifestCheckpoint,\n accessManifestCheckpointFromManifest,\n KeyingVerificationError,\n type PrincipalPolicyCheckpoint,\n verifyAccessManifestLocalCheckpoint,\n} from \"@tearleads/crypto\";\nimport { keyingCheckpointTables } from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../../sqlite/sqlSchema\";\nimport { assertContainerNotRetired } from \"../principalKeys/principalGrantRetirementPersistence\";\nimport {\n accessManifestObjectKey,\n loadStoredAccessManifestCheckpoint,\n loadStoredPrincipalPolicyCheckpoint,\n upsertAccessManifestCheckpointInTransaction,\n} from \"./keyingCheckpointPersistence\";\n\nexport interface LocallyAcknowledgedAccessManifestHead {\n readonly checkpoint: AccessManifestCheckpoint;\n readonly previousManifestHash: string | null;\n}\n\nexport function locallyAuthoredAccessManifestHead(plan: {\n readonly manifest: AccessManifest;\n readonly manifestHash: string;\n}): LocallyAcknowledgedAccessManifestHead {\n return {\n checkpoint: accessManifestCheckpointFromManifest({\n manifest: plan.manifest,\n manifestHash: plan.manifestHash,\n }),\n previousManifestHash: plan.manifest.previousManifestHash,\n };\n}\n\nfunction validateAcknowledgedHead(\n head: LocallyAcknowledgedAccessManifestHead,\n localCheckpoint: AccessManifestCheckpoint | null,\n): void {\n if (!localCheckpoint) {\n if (head.checkpoint.epoch !== 1 || head.previousManifestHash !== null) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"locally acknowledged access manifest does not begin at epoch 1\",\n );\n }\n return;\n }\n\n verifyAccessManifestLocalCheckpoint({\n checkpointPredecessors: [],\n current: {\n ...head.checkpoint,\n previousManifestHash: head.previousManifestHash,\n },\n localCheckpoint,\n });\n}\n\nasync function validateAcknowledgedHeads(\n tx: ClientSQLiteTransactionScope,\n heads: readonly LocallyAcknowledgedAccessManifestHead[],\n): Promise<Map<string, AccessManifestCheckpoint>> {\n const pending = new Map<string, AccessManifestCheckpoint>();\n for (const head of heads) {\n await assertContainerNotRetired(tx, head.checkpoint);\n const key = accessManifestObjectKey(head.checkpoint);\n if (pending.has(key)) {\n throw new KeyingVerificationError(\n \"equivocation\",\n `locally acknowledged batch contains multiple heads for ${key}`,\n );\n }\n validateAcknowledgedHead(\n head,\n await loadStoredAccessManifestCheckpoint(tx, head.checkpoint),\n );\n pending.set(key, head.checkpoint);\n }\n return pending;\n}\n\nasync function writeAcknowledgedHeads(\n tx: ClientSQLiteTransactionScope,\n pending: ReadonlyMap<string, AccessManifestCheckpoint>,\n updatedAt: string,\n): Promise<void> {\n for (const checkpoint of pending.values()) {\n await upsertAccessManifestCheckpointInTransaction(\n tx,\n checkpoint,\n updatedAt,\n );\n }\n}\n\n/**\n * Commits only heads authored and signed by this client after an exact remote\n * acknowledgement check. Every non-initial head must directly extend the\n * latest durable pin; arbitrary remote projections must use the verified\n * projection checkpoint path instead.\n */\nexport async function advanceLocallyAcknowledgedAccessManifestHeadsAtomically(input: {\n readonly execSql: ExecSql;\n readonly heads: readonly LocallyAcknowledgedAccessManifestHead[];\n /** Optional optimistic read dependencies, checked inside the write transaction. */\n readonly expectedAccessManifestCheckpoints?: readonly AccessManifestCheckpoint[];\n readonly expectedPrincipalPolicyCheckpoints?: readonly PrincipalPolicyCheckpoint[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean> {\n await ensureSqlTables(input.execSql, keyingCheckpointTables);\n const updatedAt = new Date().toISOString();\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const acknowledge = async (tx: ClientSQLiteTransactionScope) => {\n for (const expected of input.expectedAccessManifestCheckpoints ?? []) {\n const current = await loadStoredAccessManifestCheckpoint(tx, expected);\n if (\n current?.epoch !== expected.epoch ||\n current.manifestHash !== expected.manifestHash\n ) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"A re-citation container checkpoint changed before acknowledgement\",\n );\n }\n }\n for (const expected of input.expectedPrincipalPolicyCheckpoints ?? []) {\n const current = await loadStoredPrincipalPolicyCheckpoint(tx, expected);\n if (\n current?.version !== expected.version ||\n current.stateHash !== expected.stateHash\n ) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"A re-citation principal policy checkpoint changed before acknowledgement\",\n );\n }\n }\n const pending = await validateAcknowledgedHeads(tx, input.heads);\n await writeAcknowledgedHeads(tx, pending, updatedAt);\n };\n if (input.stillCurrent) {\n return (\n await runtime.guardedTransaction(acknowledge, input.stillCurrent, {\n behavior: \"immediate\",\n })\n ).committed;\n }\n await runtime.transaction(acknowledge, { behavior: \"immediate\" });\n return true;\n}\n"]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { KeyingVerificationError, verifyPrincipalPolicyCheckpoint, } from "../../../internal/crypto/index.js";
|
|
2
|
+
import { keyingCheckpointTables, principalPolicyTables, } from "../../sqlite/schema/index.js";
|
|
3
|
+
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
|
+
import { ensureSqlTables } from "../../sqlite/sqlSchema.js";
|
|
5
|
+
import { loadStoredPrincipalPolicyCheckpoint, principalPolicyKey, upsertPrincipalPolicyCheckpointInTransaction, } from "../keyingCheckpoints/keyingCheckpointPersistence.js";
|
|
6
|
+
import { storePrincipalGrantRetirements, } from "../principalKeys/principalGrantRetirementPersistence.js";
|
|
7
|
+
import { retainPrincipalPolicyBundleInTransaction, writePrincipalPolicyBundleInTransaction, } from "./principalPolicyPersistence.js";
|
|
8
|
+
import { assertBundleMatchesVerifiedPolicy } from "./verifiedPrincipalPolicyBundle.js";
|
|
9
|
+
function validateAcknowledgedPolicy(policy, checkpoint) {
|
|
10
|
+
verifyPrincipalPolicyCheckpoint({
|
|
11
|
+
chain: policy.history ?? [],
|
|
12
|
+
currentState: policy.state,
|
|
13
|
+
localCheckpoint: checkpoint,
|
|
14
|
+
});
|
|
15
|
+
if (!checkpoint && policy.version !== 1) {
|
|
16
|
+
throw new KeyingVerificationError("stale_predecessor", "locally acknowledged principal policy does not begin at version 1");
|
|
17
|
+
}
|
|
18
|
+
if (checkpoint && policy.version > checkpoint.version + 1) {
|
|
19
|
+
throw new KeyingVerificationError("stale_predecessor", "locally acknowledged principal policy does not directly extend the durable checkpoint");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function assertUniqueAcknowledgedPolicies(entries) {
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
for (const { policy } of entries) {
|
|
25
|
+
const key = principalPolicyKey(policy);
|
|
26
|
+
if (seen.has(key)) {
|
|
27
|
+
throw new KeyingVerificationError("duplicate_entry", `locally acknowledged policy batch repeats ${key}`);
|
|
28
|
+
}
|
|
29
|
+
seen.add(key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function storeAcknowledgedPrincipalPolicyBundles(input) {
|
|
33
|
+
assertUniqueAcknowledgedPolicies(input.entries);
|
|
34
|
+
await Promise.all(input.entries.map((entry) => assertBundleMatchesVerifiedPolicy(entry)));
|
|
35
|
+
await ensureSqlTables(input.execSql, [
|
|
36
|
+
...principalPolicyTables,
|
|
37
|
+
...keyingCheckpointTables,
|
|
38
|
+
]);
|
|
39
|
+
const runtime = getClientSQLitePersistenceRuntime(input.execSql);
|
|
40
|
+
const store = async (tx) => {
|
|
41
|
+
for (const { policy } of input.entries) {
|
|
42
|
+
validateAcknowledgedPolicy(policy, await loadStoredPrincipalPolicyCheckpoint(tx, policy));
|
|
43
|
+
}
|
|
44
|
+
if (input.retiredContainers)
|
|
45
|
+
await storePrincipalGrantRetirements(tx, input.retiredContainers, input.entries.map(({ policy }) => policy), input.organizationId);
|
|
46
|
+
for (const entry of input.entries) {
|
|
47
|
+
if (input.placement === "current") {
|
|
48
|
+
await writePrincipalPolicyBundleInTransaction(tx, entry.bundle, input.updatedAt, input.organizationId);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
await retainPrincipalPolicyBundleInTransaction(tx, entry.bundle, input.updatedAt, input.organizationId);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const { policy } of input.entries) {
|
|
55
|
+
await upsertPrincipalPolicyCheckpointInTransaction(tx, policy.checkpoint, input.updatedAt, input.organizationId);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
if (input.stillCurrent) {
|
|
59
|
+
await runtime.guardedTransaction(store, input.stillCurrent, {
|
|
60
|
+
behavior: "immediate",
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await runtime.transaction(store, { behavior: "immediate" });
|
|
65
|
+
}
|
|
66
|
+
/** Atomically pins and caches exact full policy bundles acknowledged by the API. */
|
|
67
|
+
export function persistLocallyAcknowledgedPrincipalPolicyBundles(input) {
|
|
68
|
+
return storeAcknowledgedPrincipalPolicyBundles({
|
|
69
|
+
...input,
|
|
70
|
+
placement: "current",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export function persistLocallyAcknowledgedPrincipalPolicyBundle(input) {
|
|
74
|
+
return persistLocallyAcknowledgedPrincipalPolicyBundles({
|
|
75
|
+
entries: [input],
|
|
76
|
+
execSql: input.execSql,
|
|
77
|
+
organizationId: input.organizationId,
|
|
78
|
+
stillCurrent: input.stillCurrent,
|
|
79
|
+
updatedAt: input.updatedAt,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export function retainLocallyAcknowledgedPrincipalPolicyBundles(input) {
|
|
83
|
+
return storeAcknowledgedPrincipalPolicyBundles({
|
|
84
|
+
...input,
|
|
85
|
+
placement: "history",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=locallyAcknowledgedPrincipalPolicyPersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locallyAcknowledgedPrincipalPolicyPersistence.js","sourceRoot":"","sources":["locallyAcknowledgedPrincipalPolicyPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicyCheckpoint,\n type VerifiedPrincipalPolicy,\n verifyPrincipalPolicyCheckpoint,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport {\n keyingCheckpointTables,\n principalPolicyTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../../sqlite/sqlSchema\";\nimport {\n loadStoredPrincipalPolicyCheckpoint,\n principalPolicyKey,\n upsertPrincipalPolicyCheckpointInTransaction,\n} from \"../keyingCheckpoints/keyingCheckpointPersistence\";\nimport {\n type AcknowledgedPrincipalGrantRetirements,\n storePrincipalGrantRetirements,\n} from \"../principalKeys/principalGrantRetirementPersistence\";\nimport {\n retainPrincipalPolicyBundleInTransaction,\n writePrincipalPolicyBundleInTransaction,\n} from \"./principalPolicyPersistence\";\nimport { assertBundleMatchesVerifiedPolicy } from \"./verifiedPrincipalPolicyBundle\";\n\nfunction validateAcknowledgedPolicy(\n policy: VerifiedPrincipalPolicy,\n checkpoint: PrincipalPolicyCheckpoint | null,\n): void {\n verifyPrincipalPolicyCheckpoint({\n chain: policy.history ?? [],\n currentState: policy.state,\n localCheckpoint: checkpoint,\n });\n if (!checkpoint && policy.version !== 1) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"locally acknowledged principal policy does not begin at version 1\",\n );\n }\n if (checkpoint && policy.version > checkpoint.version + 1) {\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"locally acknowledged principal policy does not directly extend the durable checkpoint\",\n );\n }\n}\n\ninterface LocallyAcknowledgedPrincipalPolicyBundle {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n}\n\nfunction assertUniqueAcknowledgedPolicies(\n entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[],\n): void {\n const seen = new Set<string>();\n for (const { policy } of entries) {\n const key = principalPolicyKey(policy);\n if (seen.has(key)) {\n throw new KeyingVerificationError(\n \"duplicate_entry\",\n `locally acknowledged policy batch repeats ${key}`,\n );\n }\n seen.add(key);\n }\n}\n\nasync function storeAcknowledgedPrincipalPolicyBundles(input: {\n readonly retiredContainers?:\n | AcknowledgedPrincipalGrantRetirements\n | undefined;\n readonly entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly placement: \"current\" | \"history\";\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n assertUniqueAcknowledgedPolicies(input.entries);\n await Promise.all(\n input.entries.map((entry) => assertBundleMatchesVerifiedPolicy(entry)),\n );\n await ensureSqlTables(input.execSql, [\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const store = async (tx: ClientSQLiteTransactionScope) => {\n for (const { policy } of input.entries) {\n validateAcknowledgedPolicy(\n policy,\n await loadStoredPrincipalPolicyCheckpoint(tx, policy),\n );\n }\n if (input.retiredContainers)\n await storePrincipalGrantRetirements(\n tx,\n input.retiredContainers,\n input.entries.map(({ policy }) => policy),\n input.organizationId,\n );\n for (const entry of input.entries) {\n if (input.placement === \"current\") {\n await writePrincipalPolicyBundleInTransaction(\n tx,\n entry.bundle,\n input.updatedAt,\n input.organizationId,\n );\n } else {\n await retainPrincipalPolicyBundleInTransaction(\n tx,\n entry.bundle,\n input.updatedAt,\n input.organizationId,\n );\n }\n }\n for (const { policy } of input.entries) {\n await upsertPrincipalPolicyCheckpointInTransaction(\n tx,\n policy.checkpoint,\n input.updatedAt,\n input.organizationId,\n );\n }\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(store, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(store, { behavior: \"immediate\" });\n}\n\n/** Atomically pins and caches exact full policy bundles acknowledged by the API. */\nexport function persistLocallyAcknowledgedPrincipalPolicyBundles(input: {\n readonly entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n return storeAcknowledgedPrincipalPolicyBundles({\n ...input,\n placement: \"current\",\n });\n}\n\nexport function persistLocallyAcknowledgedPrincipalPolicyBundle(\n input: LocallyAcknowledgedPrincipalPolicyBundle & {\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n },\n): Promise<void> {\n return persistLocallyAcknowledgedPrincipalPolicyBundles({\n entries: [input],\n execSql: input.execSql,\n organizationId: input.organizationId,\n stillCurrent: input.stillCurrent,\n updatedAt: input.updatedAt,\n });\n}\n\nexport function retainLocallyAcknowledgedPrincipalPolicyBundles(input: {\n readonly retiredContainers?:\n | AcknowledgedPrincipalGrantRetirements\n | undefined;\n readonly entries: readonly LocallyAcknowledgedPrincipalPolicyBundle[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n return storeAcknowledgedPrincipalPolicyBundles({\n ...input,\n placement: \"history\",\n });\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { KeyingVerificationError, } from "../../../internal/crypto/index.js";
|
|
2
|
+
import { keyingCheckpointTables, principalPolicyTables, } from "../../sqlite/schema/index.js";
|
|
3
|
+
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
|
+
import { ensureSqlTables } from "../../sqlite/sqlSchema.js";
|
|
5
|
+
import { validatePrincipalPolicyCheckpointAdvances, writePrincipalPolicyCheckpoints, } from "../keyingCheckpoints/keyingCheckpointAdvancePersistence.js";
|
|
6
|
+
import { loadStoredPrincipalPolicyCheckpoint, principalPolicyKey, } from "../keyingCheckpoints/keyingCheckpointPersistence.js";
|
|
7
|
+
import { assertPrincipalPolicyBundleStoredInTransaction, writePrincipalPolicyBundleInTransaction, } from "./principalPolicyPersistence.js";
|
|
8
|
+
import { assertBundleMatchesVerifiedPolicy } from "./verifiedPrincipalPolicyBundle.js";
|
|
9
|
+
/**
|
|
10
|
+
* Persists each verified full policy bundle together with its durable head.
|
|
11
|
+
* This prevents a crash or bundle-write failure from leaving a checkpoint
|
|
12
|
+
* without the exact same-head payload and member-envelope evidence.
|
|
13
|
+
*/
|
|
14
|
+
export async function persistVerifiedPrincipalPolicyBundlesAtomically(input) {
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
for (const entry of input.entries) {
|
|
17
|
+
const key = principalPolicyKey(entry.policy);
|
|
18
|
+
if (seen.has(key)) {
|
|
19
|
+
throw new KeyingVerificationError("duplicate_entry", `verified policy bundle batch repeats ${key}`);
|
|
20
|
+
}
|
|
21
|
+
seen.add(key);
|
|
22
|
+
}
|
|
23
|
+
await Promise.all(input.entries.map((entry) => assertBundleMatchesVerifiedPolicy(entry)));
|
|
24
|
+
await ensureSqlTables(input.execSql, [
|
|
25
|
+
...principalPolicyTables,
|
|
26
|
+
...keyingCheckpointTables,
|
|
27
|
+
]);
|
|
28
|
+
const runtime = getClientSQLitePersistenceRuntime(input.execSql);
|
|
29
|
+
const persist = async (tx) => {
|
|
30
|
+
const policies = await validatePrincipalPolicyCheckpointAdvances(tx, input.entries.map((entry) => entry.policy));
|
|
31
|
+
for (const entry of input.entries) {
|
|
32
|
+
await writePrincipalPolicyBundleInTransaction(tx, entry.bundle, input.updatedAt, input.organizationId);
|
|
33
|
+
await assertPrincipalPolicyBundleStoredInTransaction(tx, entry.bundle);
|
|
34
|
+
}
|
|
35
|
+
await writePrincipalPolicyCheckpoints(tx, policies, input.updatedAt, input.organizationId);
|
|
36
|
+
for (const policy of policies.values()) {
|
|
37
|
+
const checkpoint = await loadStoredPrincipalPolicyCheckpoint(tx, policy);
|
|
38
|
+
if (!checkpoint ||
|
|
39
|
+
checkpoint.version !== policy.version ||
|
|
40
|
+
checkpoint.stateHash !== policy.stateHash) {
|
|
41
|
+
throw new Error("Verified principal policy checkpoint was not persisted");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
if (input.stillCurrent) {
|
|
46
|
+
await runtime.guardedTransaction(persist, input.stillCurrent, {
|
|
47
|
+
behavior: "immediate",
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
await runtime.transaction(persist, { behavior: "immediate" });
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=verifiedPrincipalPolicyBundlePersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifiedPrincipalPolicyBundlePersistence.js","sourceRoot":"","sources":["verifiedPrincipalPolicyBundlePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedPrincipalPolicy,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport {\n keyingCheckpointTables,\n principalPolicyTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../../sqlite/sqlSchema\";\nimport {\n validatePrincipalPolicyCheckpointAdvances,\n writePrincipalPolicyCheckpoints,\n} from \"../keyingCheckpoints/keyingCheckpointAdvancePersistence\";\nimport {\n loadStoredPrincipalPolicyCheckpoint,\n principalPolicyKey,\n} from \"../keyingCheckpoints/keyingCheckpointPersistence\";\nimport {\n assertPrincipalPolicyBundleStoredInTransaction,\n writePrincipalPolicyBundleInTransaction,\n} from \"./principalPolicyPersistence\";\nimport { assertBundleMatchesVerifiedPolicy } from \"./verifiedPrincipalPolicyBundle\";\n\ninterface VerifiedPrincipalPolicyBundleEntry {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n}\n\n/**\n * Persists each verified full policy bundle together with its durable head.\n * This prevents a crash or bundle-write failure from leaving a checkpoint\n * without the exact same-head payload and member-envelope evidence.\n */\nexport async function persistVerifiedPrincipalPolicyBundlesAtomically(input: {\n readonly entries: readonly VerifiedPrincipalPolicyBundleEntry[];\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly updatedAt: string;\n}): Promise<void> {\n const seen = new Set<string>();\n for (const entry of input.entries) {\n const key = principalPolicyKey(entry.policy);\n if (seen.has(key)) {\n throw new KeyingVerificationError(\n \"duplicate_entry\",\n `verified policy bundle batch repeats ${key}`,\n );\n }\n seen.add(key);\n }\n await Promise.all(\n input.entries.map((entry) => assertBundleMatchesVerifiedPolicy(entry)),\n );\n await ensureSqlTables(input.execSql, [\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ]);\n\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const persist = async (tx: ClientSQLiteTransactionScope) => {\n const policies = await validatePrincipalPolicyCheckpointAdvances(\n tx,\n input.entries.map((entry) => entry.policy),\n );\n for (const entry of input.entries) {\n await writePrincipalPolicyBundleInTransaction(\n tx,\n entry.bundle,\n input.updatedAt,\n input.organizationId,\n );\n await assertPrincipalPolicyBundleStoredInTransaction(tx, entry.bundle);\n }\n await writePrincipalPolicyCheckpoints(\n tx,\n policies,\n input.updatedAt,\n input.organizationId,\n );\n for (const policy of policies.values()) {\n const checkpoint = await loadStoredPrincipalPolicyCheckpoint(tx, policy);\n if (\n !checkpoint ||\n checkpoint.version !== policy.version ||\n checkpoint.stateHash !== policy.stateHash\n ) {\n throw new Error(\n \"Verified principal policy checkpoint was not persisted\",\n );\n }\n }\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(persist, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(persist, { behavior: \"immediate\" });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DocumentSummary } from "../../data/documents/documentSummary.js";
|
|
2
|
-
import type { ContainerContentsStoreRuntime } from "../container-contents/
|
|
2
|
+
import type { ContainerContentsStoreRuntime } from "../container-contents/index.js";
|
|
3
3
|
import type { ContainerContentsStore } from "../container-contents/types.js";
|
|
4
4
|
import type { LocalProjectionReconciledDelta, LocalProjectionSnapshot } from "./types.js";
|
|
5
5
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadLocalContainerProjectionDocumentsFromRuntime } from "../../workflows/container-contents/projectionView.js";
|
|
2
2
|
import { didRegainSyncPrerequisites } from "../../workflows/container-contents/syncLane.js";
|
|
3
|
-
import { isReconcilableContainerNode, isRemoteBackedContainerNode, } from "../container-contents/
|
|
3
|
+
import { isReconcilableContainerNode, isRemoteBackedContainerNode, } from "../container-contents/index.js";
|
|
4
4
|
import { applyContainerSummaries, createSummaryCache, removeDocumentSummary, resetSummaryCache, snapshotLinkedContainerIdsByDocumentId, snapshotSummariesByContainerId, } from "./summaryCache.js";
|
|
5
5
|
const EMPTY_SNAPSHOT = {
|
|
6
6
|
ready: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localProjectionStore.js","sourceRoot":"","sources":["localProjectionStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gDAAgD,EAAE,MAAM,mDAAmD,CAAC;AACrH,OAAO,EAAE,0BAA0B,EAAE,MAAM,6CAA6C,CAAC;AACzF,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,4DAA4D,CAAC;AAGpE,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EAEjB,sCAAsC,EACtC,8BAA8B,GAC/B,MAAM,gBAAgB,CAAC;AAqExB,MAAM,cAAc,GAA4B;IAC9C,KAAK,EAAE,KAAK;IACZ,UAAU,EAAE,EAAE;IACd,8BAA8B,EAAE,IAAI,GAAG,EAAE;IACzC,8BAA8B,EAAE,IAAI,GAAG,EAAE;CAC1C,CAAC;AAEF,SAAS,eAAe,CACtB,KAAgC;IAEhC,MAAM,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;IAC7D,OAAO;QACL,KAAK,EAAE,iBAAiB,CAAC,KAAK;QAC9B,UAAU,EAAE,iBAAiB,CAAC,KAAK;QACnC,8BAA8B,EAAE,8BAA8B,CAAC,KAAK,CAAC,KAAK,CAAC;QAC3E,8BAA8B,EAAE,sCAAsC,CACpE,KAAK,CAAC,KAAK,CACZ;KACF,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CAAC,KAAgC;IAC5C,KAAK,CAAC,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,QAAQ,EAAE,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACtB,KAAgC,EAChC,MAAsC;IAEtC,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAgC,EAChC,WAAmB;IAEnB,IACE,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC;QACjD,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC;QAC1C,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,EACxC,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAuB;QACtC,aAAa,EAAE,KAAK;QACpB,WAAW,EAAE,KAAK;KACnB,CAAC;IACF,KAAK,gDAAgD,CAAC;QACpD,YAAY,EAAE,CAAC,WAAW,CAAC;QAC3B,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;SACC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;QAClB,uEAAuE;QACvE,kEAAkE;QAClE,IACE,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,WAAW;YAC1D,WAAW,CAAC,aAAa,EACzB,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,uBAAuB,CAAC,KAAK,CAAC,KAAK,EAAE;YACnD,WAAW;YACX,iBAAiB,EAAE,SAAS,CAAC,iBAAiB;YAC9C,8BAA8B,EAC5B,SAAS,CAAC,8BAA8B;SAC3C,CAAC,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE;QACV,0EAA0E;IAC5E,CAAC,CAAC;SACD,OAAO,CAAC,GAAG,EAAE;QACZ,IAAI,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,WAAW,EAAE,CAAC;YAC/D,OAAO;QACT,CAAC;QACD,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;YAC5B,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACrD,sBAAsB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,yBAAyB,CAChC,KAAgC,EAChC,WAAmB,EACnB,kBAAkB,GAAG,KAAK;IAE1B,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/D,IAAI,WAAW,EAAE,CAAC;QAChB,yEAAyE;QACzE,0EAA0E;QAC1E,WAAW,CAAC,WAAW,GAAG,IAAI,CAAC;QAC/B,WAAW,CAAC,aAAa,KAAK,kBAAkB,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,sBAAsB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAgC,EAChC,QAAyB,EACzB,gBAAgB,GAAG,KAAK;IAExB,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAC5B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/D,IACE,KAAK,CAAC,iBAAiB;QACvB,KAAK,CAAC,iBAAiB,KAAK,QAAQ,CAAC,WAAW,EAChD,CAAC;QACD,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,sBAAsB,EAAE,CAAC;QAC1E,IACE,WAAW,KAAK,QAAQ,CAAC,WAAW;YACpC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC,EACvD,CAAC;YACD,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAgC;IAC3D,IACE,KAAK,CAAC,0BAA0B;QAChC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO;QACxC,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,KAAK,EACzC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC;IACxC,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC5B,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,iCAAiC,CACxC,KAAgC;IAEhC,IACE,CAAC,KAAK,CAAC,4BAA4B;QACnC,CAAC,KAAK,CAAC,0BAA0B;QACjC,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,KAAK,EACzC,CAAC;QACD,OAAO;IACT,CAAC;IACD,KAAK,CAAC,4BAA4B,GAAG,KAAK,CAAC;IAC3C,eAAe,CAAC,KAAK,EAAE;QACrB,MAAM,EAAE,wBAAwB;QAChC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;KAC3C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAgC;IACxD,MAAM,eAAe,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,CAAC,CAAC;IACZ,IAAI,eAAe,EAAE,CAAC;QACpB,eAAe,CAAC,KAAK,EAAE;YACrB,MAAM,EAAE,UAAU;YAClB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;SAC3C,CAAC,CAAC;IACL,CAAC;IACD,4EAA4E;IAC5E,iCAAiC,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,SAAS,eAAe,CAAC,KAAgC;IACvD,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAC5B,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,KAAK,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAClC,KAAK,CAAC,0BAA0B,GAAG,KAAK,CAAC;AAC3C,CAAC;AAED,SAAS,wCAAwC,CAC/C,QAA+C,EAC/C,IAA2C,EAC3C,kBAAiC,EACjC,iBAAgC;IAEhC,MAAM,oBAAoB,GAAG,CAC3B,SAAwD,EACxD,EAAE,CAAC,2BAA2B,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,QAAQ,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAC7B,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CACtD,CACF,CAAC;IACF,IACE,IAAI,CAAC,IAAI,CACP,CAAC,SAAS,EAAE,EAAE,CACZ,oBAAoB,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CACpE,EACD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,qBAAqB,GAAG,QAAQ,CAAC,IAAI,CACzC,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,EAAE,KAAK,iBAAiB;QAClC,2BAA2B,CAAC,SAAS,CAAC,CACzC,CAAC;IACF,OAAO,CACL,CAAC,qBAAqB;QACtB,IAAI,CAAC,IAAI,CACP,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,EAAE,KAAK,iBAAiB;YAClC,2BAA2B,CAAC,SAAS,CAAC,CACzC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,gCAAgC,CACvC,KAAgC,EAChC,OAAe;IAEf,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,6EAA6E;IAC7E,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3D,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,qBAAqB,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,4BAA4B,CACnC,KAAgC,EAChC,OAAsC;IAEtC,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC;IACtC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,IACE,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,eAAe,CAAC,KAAK,CAAC,OAAO;QACvD,OAAO,CAAC,KAAK,CAAC,WAAW,KAAK,eAAe,CAAC,KAAK,CAAC,WAAW,EAC/D,CAAC;QACD,eAAe,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAE5C,uEAAuE;IACvE,kEAAkE;IAClE,uDAAuD;IACvD,IAAI,0BAA0B,CAAC,eAAe,EAAE,OAAO,CAAC,EAAE,CAAC;QACzD,KAAK,CAAC,4BAA4B,GAAG,IAAI,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACvC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,CAAC;QACZ,OAAO;IACT,CAAC;IAED,uEAAuE;IACvE,wEAAwE;IACxE,gBAAgB,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAG1C;IACC,MAAM,KAAK,GAA8B;QACvC,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,CAAC;QACnB,cAAc,EAAE,IAAI,OAAO,EAAE;QAC7B,KAAK,EAAE,kBAAkB,EAAE;QAC3B,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,0BAA0B,EAAE,KAAK;QACjC,SAAS,EAAE,IAAI,GAAG,EAAE;QACpB,4BAA4B,EAAE,KAAK;QACnC,kBAAkB,EAAE,IAAI,GAAG,EAAE;QAC7B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,cAAc;QACxB,mBAAmB,EAAE,IAAI,GAAG,EAAE;KAC/B,CAAC;IACF,KAAK,CAAC,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAExC,4EAA4E;IAC5E,0EAA0E;IAC1E,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,GAAG,EAAE;QAClC,MAAM,kBAAkB,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QACrD,MAAM,eAAe,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAChD,mEAAmE;QACnE,yEAAyE;QACzE,4EAA4E;QAC5E,wEAAwE;QACxE,6CAA6C;QAC7C,IACE,CAAC,eAAe;YAChB,wCAAwC,CACtC,kBAAkB,EAClB,KAAK,CAAC,QAAQ,CAAC,UAAU,EACzB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EACjC,KAAK,CAAC,iBAAiB,CACxB,EACD,CAAC;YACD,eAAe,CAAC,KAAK,EAAE;gBACrB,MAAM,EAAE,yBAAyB;gBACjC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;aAC3C,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ;QACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC9B,OAAO,GAAG,EAAE;gBACV,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC,CAAC;QACJ,CAAC;QACD,kBAAkB,EAAE,CAAC,WAAW,EAAE,EAAE;YAClC,IAAI,KAAK,CAAC,iBAAiB,KAAK,WAAW,EAAE,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,KAAK,CAAC,iBAAiB,GAAG,WAAW,CAAC;YACtC,IAAI,WAAW,EAAE,CAAC;gBAChB,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YAChD,CAAC;YACD,eAAe,CAAC,KAAK,EAAE;gBACrB,MAAM,EAAE,gBAAgB;gBACxB,iBAAiB,EAAE,WAAW;aAC/B,CAAC,CAAC;QACL,CAAC;QACD,oBAAoB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,iBAAiB;QACnD,kBAAkB,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;YACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,CAAC;YACxC,MAAM,SAAS,GAAG,MAAM,gDAAgD,CAAC;gBACvE,YAAY,EAAE,CAAC,WAAW,CAAC;gBAC3B,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC,CAAC;YACH,MAAM,KAAK,GAAG,EAAE,WAAW,EAAE,GAAG,SAAS,EAAE,CAAC;YAC5C,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC1C,OAAO,KAAK,CAAC;QACf,CAAC;QACD,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;YACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK,CAAC,gBAAgB,EAAE,CAAC;gBAClE,yBAAyB,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;gBAC1D,OAAO;YACT,CAAC;YACD,IAAI,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;gBACrD,yBAAyB,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YAC5D,CAAC;YACD,IAAI,uBAAuB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC;QACH,CAAC;QACD,uBAAuB,EAAE,CAAC,OAAO,EAAE,EAAE,CACnC,gCAAgC,CAAC,KAAK,EAAE,OAAO,CAAC;QAClD,wBAAwB,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE,CACvD,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,gBAAgB,CAAC;QAC7D,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,4BAA4B,CAAC,KAAK,EAAE,OAAO,CAAC;QACxE,iBAAiB,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC9B,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,OAAO,GAAG,EAAE;gBACV,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC5C,CAAC,CAAC;QACJ,CAAC;QACD,iBAAiB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc;KAC9C,CAAC;AACJ,CAAC","sourcesContent":["import type { DocumentSummary } from \"../../data/documents/documentSummary\";\nimport { loadLocalContainerProjectionDocumentsFromRuntime } from \"../../workflows/container-contents/projectionView\";\nimport { didRegainSyncPrerequisites } from \"../../workflows/container-contents/syncLane\";\nimport {\n isReconcilableContainerNode,\n isRemoteBackedContainerNode,\n} from \"../container-contents/containerState/reconcilableContainer\";\nimport type { ContainerContentsStoreRuntime } from \"../container-contents/syncAgent\";\nimport type { ContainerContentsStore } from \"../container-contents/types\";\nimport {\n applyContainerSummaries,\n createSummaryCache,\n removeDocumentSummary,\n resetSummaryCache,\n type SummaryCache,\n snapshotLinkedContainerIdsByDocumentId,\n snapshotSummariesByContainerId,\n} from \"./summaryCache\";\nimport type {\n LocalProjectionReconciledDelta,\n LocalProjectionSnapshot,\n} from \"./types\";\n\n/**\n * Signals the local projection store raises so the background reconciler\n * (Layer B) knows what to sync. The store never performs remote I/O itself.\n */\nexport interface LocalProjectionReconcileSignal {\n reason:\n | \"hydrated\"\n | \"active-changed\"\n | \"prerequisites-regained\"\n | \"remote-containers-added\";\n activeContainerId: string | null;\n}\n\nexport type LocalProjectionReconcileListener = (\n signal: LocalProjectionReconcileSignal,\n) => void;\n\nexport interface LocalProjectionStore {\n getSnapshot: () => LocalProjectionSnapshot;\n subscribe: (listener: () => void) => () => void;\n setActiveContainer: (containerId: string | null) => void;\n getActiveContainerId: () => string | null;\n applyReconciled: (delta: LocalProjectionReconciledDelta) => void;\n loadContainerDelta: (\n containerId: string,\n ) => Promise<LocalProjectionReconciledDelta>;\n removePersistedDocument: (localId: string) => void;\n refreshPersistedDocument: (\n document: DocumentSummary,\n placementChanged?: boolean,\n ) => void;\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n /** Registered by the reconciler; returns an unsubscribe handle. */\n onReconcileSignal: (listener: LocalProjectionReconcileListener) => () => void;\n getContainerStore: () => ContainerContentsStore;\n}\n\ninterface LocalProjectionStoreState {\n activeContainerId: string | null;\n documentRevision: number;\n deltaRevisions: WeakMap<LocalProjectionReconciledDelta, number>;\n cache: SummaryCache;\n containerStore: ContainerContentsStore;\n hydratedContainerSummaries: boolean;\n listeners: Set<() => void>;\n /**\n * A sync-prerequisite regain (auth, connectivity, or key pair) that arrived\n * before the container tree was ready. The signal's reset-and-backfill must\n * not be lost to startup ordering, so it is latched here and flushed once\n * hydration completes.\n */\n pendingPrerequisitesRegained: boolean;\n reconcileListeners: Set<LocalProjectionReconcileListener>;\n runtime: ContainerContentsStoreRuntime;\n snapshot: LocalProjectionSnapshot;\n pendingSummaryReads: Map<string, PendingSummaryRead>;\n}\n\ninterface PendingSummaryRead {\n discardResult: boolean;\n reloadAfter: boolean;\n}\n\nconst EMPTY_SNAPSHOT: LocalProjectionSnapshot = {\n ready: false,\n containers: [],\n documentSummariesByContainerId: new Map(),\n linkedContainerIdsByDocumentId: new Map(),\n};\n\nfunction computeSnapshot(\n state: LocalProjectionStoreState,\n): LocalProjectionSnapshot {\n const containerSnapshot = state.containerStore.getSnapshot();\n return {\n ready: containerSnapshot.ready,\n containers: containerSnapshot.nodes,\n documentSummariesByContainerId: snapshotSummariesByContainerId(state.cache),\n linkedContainerIdsByDocumentId: snapshotLinkedContainerIdsByDocumentId(\n state.cache,\n ),\n };\n}\n\nfunction emit(state: LocalProjectionStoreState): void {\n state.snapshot = computeSnapshot(state);\n for (const listener of state.listeners) {\n try {\n listener();\n } catch {\n // Keep one subscriber failure from blocking later subscribers.\n }\n }\n}\n\nfunction notifyReconcile(\n state: LocalProjectionStoreState,\n signal: LocalProjectionReconcileSignal,\n): void {\n for (const listener of state.reconcileListeners) {\n try {\n listener(signal);\n } catch {\n // Reconciler failures must not break the read path.\n }\n }\n}\n\nfunction loadContainerSummaries(\n state: LocalProjectionStoreState,\n containerId: string,\n): void {\n if (\n state.cache.hydratedContainerIds.has(containerId) ||\n state.pendingSummaryReads.has(containerId) ||\n state.runtime.infra.dbStatus !== \"ready\"\n ) {\n return;\n }\n\n const pendingRead: PendingSummaryRead = {\n discardResult: false,\n reloadAfter: false,\n };\n void loadLocalContainerProjectionDocumentsFromRuntime({\n containerIds: [containerId],\n runtime: state.runtime,\n })\n .then((documents) => {\n // A runtime reset (e.g. dbStatus loss) clears this entry and the cache\n // mid-flight; do not apply a stale read to a freshly reset cache.\n if (\n state.pendingSummaryReads.get(containerId) !== pendingRead ||\n pendingRead.discardResult\n ) {\n return;\n }\n const changed = applyContainerSummaries(state.cache, {\n containerId,\n documentSummaries: documents.documentSummaries,\n linkedContainerIdsByDocumentId:\n documents.linkedContainerIdsByDocumentId,\n });\n if (changed) {\n emit(state);\n }\n })\n .catch(() => {\n // Local read failures fall back to an empty list; the reconciler retries.\n })\n .finally(() => {\n if (state.pendingSummaryReads.get(containerId) !== pendingRead) {\n return;\n }\n state.pendingSummaryReads.delete(containerId);\n if (pendingRead.reloadAfter) {\n state.cache.hydratedContainerIds.delete(containerId);\n loadContainerSummaries(state, containerId);\n }\n });\n\n state.pendingSummaryReads.set(containerId, pendingRead);\n}\n\nfunction refreshContainerSummaries(\n state: LocalProjectionStoreState,\n containerId: string,\n discardPendingRead = false,\n): void {\n state.cache.hydratedContainerIds.delete(containerId);\n const pendingRead = state.pendingSummaryReads.get(containerId);\n if (pendingRead) {\n // Publish ordinary reads before the trailing refresh so autosaves cannot\n // starve first paint. Deletion and reconciliation must reject older rows.\n pendingRead.reloadAfter = true;\n pendingRead.discardResult ||= discardPendingRead;\n } else {\n loadContainerSummaries(state, containerId);\n }\n}\n\nfunction refreshPersistedDocument(\n state: LocalProjectionStoreState,\n document: DocumentSummary,\n placementChanged = false,\n): void {\n state.documentRevision += 1;\n const containerIds = new Set(state.pendingSummaryReads.keys());\n if (\n state.activeContainerId &&\n state.activeContainerId === document.containerId\n ) {\n containerIds.add(state.activeContainerId);\n }\n for (const [containerId, summaries] of state.cache.summariesByContainerId) {\n if (\n containerId === document.containerId ||\n summaries.some((summary) => summary.id === document.id)\n ) {\n containerIds.add(containerId);\n }\n }\n for (const containerId of containerIds) {\n refreshContainerSummaries(state, containerId, placementChanged);\n }\n}\n\nfunction markHydratedIfReady(state: LocalProjectionStoreState): boolean {\n if (\n state.hydratedContainerSummaries ||\n state.runtime.infra.dbStatus !== \"ready\" ||\n !state.containerStore.getSnapshot().ready\n ) {\n return false;\n }\n\n state.hydratedContainerSummaries = true;\n if (state.activeContainerId) {\n loadContainerSummaries(state, state.activeContainerId);\n }\n return true;\n}\n\nfunction flushPendingPrerequisitesRegained(\n state: LocalProjectionStoreState,\n): void {\n if (\n !state.pendingPrerequisitesRegained ||\n !state.hydratedContainerSummaries ||\n !state.containerStore.getSnapshot().ready\n ) {\n return;\n }\n state.pendingPrerequisitesRegained = false;\n notifyReconcile(state, {\n reason: \"prerequisites-regained\",\n activeContainerId: state.activeContainerId,\n });\n}\n\nfunction publishHydration(state: LocalProjectionStoreState): boolean {\n const didMarkHydrated = markHydratedIfReady(state);\n emit(state);\n if (didMarkHydrated) {\n notifyReconcile(state, {\n reason: \"hydrated\",\n activeContainerId: state.activeContainerId,\n });\n }\n // Backfills read getSnapshot(), so publish the tree before requesting them.\n flushPendingPrerequisitesRegained(state);\n return didMarkHydrated;\n}\n\nfunction resetProjection(state: LocalProjectionStoreState): void {\n state.documentRevision += 1;\n resetSummaryCache(state.cache);\n state.pendingSummaryReads.clear();\n state.hydratedContainerSummaries = false;\n}\n\nfunction hasRemoteBackedContainerMembershipGrowth(\n previous: LocalProjectionSnapshot[\"containers\"],\n next: LocalProjectionSnapshot[\"containers\"],\n homeOrganizationId: string | null,\n activeContainerId: string | null,\n): boolean {\n const isRemoteReconcilable = (\n container: LocalProjectionSnapshot[\"containers\"][number],\n ) => isReconcilableContainerNode(container, homeOrganizationId);\n const previousIds = new Set(\n previous.flatMap((container) =>\n isRemoteReconcilable(container) ? [container.id] : [],\n ),\n );\n if (\n next.some(\n (container) =>\n isRemoteReconcilable(container) && !previousIds.has(container.id),\n )\n ) {\n return true;\n }\n if (!activeContainerId) {\n return false;\n }\n const wasActiveRemoteBacked = previous.some(\n (container) =>\n container.id === activeContainerId &&\n isRemoteBackedContainerNode(container),\n );\n return (\n !wasActiveRemoteBacked &&\n next.some(\n (container) =>\n container.id === activeContainerId &&\n isRemoteBackedContainerNode(container),\n )\n );\n}\n\nfunction removePersistedDocumentFromCache(\n state: LocalProjectionStoreState,\n localId: string,\n): void {\n state.documentRevision += 1;\n // The deleted row may exist only in an in-flight first read, so invalidating\n // just containers that already cached it would allow it to reappear offline.\n for (const containerId of state.pendingSummaryReads.keys()) {\n refreshContainerSummaries(state, containerId, true);\n }\n if (removeDocumentSummary(state.cache, localId)) {\n emit(state);\n }\n}\n\nfunction updateLocalProjectionRuntime(\n state: LocalProjectionStoreState,\n runtime: ContainerContentsStoreRuntime,\n): void {\n const previousRuntime = state.runtime;\n state.runtime = runtime;\n if (\n runtime.infra.execSql !== previousRuntime.infra.execSql ||\n runtime.state.domainScope !== previousRuntime.state.domainScope\n ) {\n resetProjection(state);\n }\n state.containerStore.updateRuntime(runtime);\n\n // Latch before the readiness checks so a regain that arrives while the\n // database or container tree is still warming up is flushed after\n // hydration instead of being lost to startup ordering.\n if (didRegainSyncPrerequisites(previousRuntime, runtime)) {\n state.pendingPrerequisitesRegained = true;\n }\n\n if (runtime.infra.dbStatus !== \"ready\") {\n resetProjection(state);\n emit(state);\n return;\n }\n\n // Reload the active container's summaries when the local store becomes\n // ready (e.g. first DB attach) so first paint reflects cached contents.\n publishHydration(state);\n}\n\nexport function createLocalProjectionStore(input: {\n containerStore: ContainerContentsStore;\n runtime: ContainerContentsStoreRuntime;\n}): LocalProjectionStore {\n const state: LocalProjectionStoreState = {\n activeContainerId: null,\n documentRevision: 0,\n deltaRevisions: new WeakMap(),\n cache: createSummaryCache(),\n containerStore: input.containerStore,\n hydratedContainerSummaries: false,\n listeners: new Set(),\n pendingPrerequisitesRegained: false,\n reconcileListeners: new Set(),\n runtime: input.runtime,\n snapshot: EMPTY_SNAPSHOT,\n pendingSummaryReads: new Map(),\n };\n state.snapshot = computeSnapshot(state);\n\n // Re-emit whenever the underlying container tree changes (mutations, remote\n // hydration). This keeps the merged snapshot in step with the tree store.\n input.containerStore.subscribe(() => {\n const previousContainers = state.snapshot.containers;\n const didMarkHydrated = publishHydration(state);\n // Authentication can schedule the initial idle backfill before the\n // asynchronous remote tree crawl discovers this identity's real root and\n // system children. Re-arm backfill after those remotely-listable ids become\n // visible. Compare membership, not node objects, so metadata/sync-state\n // churn cannot create a reconciliation loop.\n if (\n !didMarkHydrated &&\n hasRemoteBackedContainerMembershipGrowth(\n previousContainers,\n state.snapshot.containers,\n state.runtime.auth.organizationId,\n state.activeContainerId,\n )\n ) {\n notifyReconcile(state, {\n reason: \"remote-containers-added\",\n activeContainerId: state.activeContainerId,\n });\n }\n });\n\n return {\n getSnapshot: () => state.snapshot,\n subscribe: (listener) => {\n state.listeners.add(listener);\n return () => {\n state.listeners.delete(listener);\n };\n },\n setActiveContainer: (containerId) => {\n if (state.activeContainerId === containerId) {\n return;\n }\n state.activeContainerId = containerId;\n if (containerId) {\n refreshContainerSummaries(state, containerId);\n }\n notifyReconcile(state, {\n reason: \"active-changed\",\n activeContainerId: containerId,\n });\n },\n getActiveContainerId: () => state.activeContainerId,\n loadContainerDelta: async (containerId) => {\n const revision = state.documentRevision;\n const documents = await loadLocalContainerProjectionDocumentsFromRuntime({\n containerIds: [containerId],\n runtime: state.runtime,\n });\n const delta = { containerId, ...documents };\n state.deltaRevisions.set(delta, revision);\n return delta;\n },\n applyReconciled: (delta) => {\n const revision = state.deltaRevisions.get(delta);\n if (revision !== undefined && revision !== state.documentRevision) {\n refreshContainerSummaries(state, delta.containerId, true);\n return;\n }\n if (state.pendingSummaryReads.has(delta.containerId)) {\n refreshContainerSummaries(state, delta.containerId, true);\n }\n if (applyContainerSummaries(state.cache, delta)) {\n emit(state);\n }\n },\n removePersistedDocument: (localId) =>\n removePersistedDocumentFromCache(state, localId),\n refreshPersistedDocument: (document, placementChanged) =>\n refreshPersistedDocument(state, document, placementChanged),\n updateRuntime: (runtime) => updateLocalProjectionRuntime(state, runtime),\n onReconcileSignal: (listener) => {\n state.reconcileListeners.add(listener);\n return () => {\n state.reconcileListeners.delete(listener);\n };\n },\n getContainerStore: () => state.containerStore,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"localProjectionStore.js","sourceRoot":"","sources":["localProjectionStore.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentSummary } from \"../../data/documents/documentSummary\";\nimport { loadLocalContainerProjectionDocumentsFromRuntime } from \"../../workflows/container-contents/projectionView\";\nimport { didRegainSyncPrerequisites } from \"../../workflows/container-contents/syncLane\";\nimport type { ContainerContentsStoreRuntime } from \"../container-contents\";\nimport {\n isReconcilableContainerNode,\n isRemoteBackedContainerNode,\n} from \"../container-contents\";\nimport type { ContainerContentsStore } from \"../container-contents/types\";\nimport {\n applyContainerSummaries,\n createSummaryCache,\n removeDocumentSummary,\n resetSummaryCache,\n type SummaryCache,\n snapshotLinkedContainerIdsByDocumentId,\n snapshotSummariesByContainerId,\n} from \"./summaryCache\";\nimport type {\n LocalProjectionReconciledDelta,\n LocalProjectionSnapshot,\n} from \"./types\";\n\n/**\n * Signals the local projection store raises so the background reconciler\n * (Layer B) knows what to sync. The store never performs remote I/O itself.\n */\nexport interface LocalProjectionReconcileSignal {\n reason:\n | \"hydrated\"\n | \"active-changed\"\n | \"prerequisites-regained\"\n | \"remote-containers-added\";\n activeContainerId: string | null;\n}\n\nexport type LocalProjectionReconcileListener = (\n signal: LocalProjectionReconcileSignal,\n) => void;\n\nexport interface LocalProjectionStore {\n getSnapshot: () => LocalProjectionSnapshot;\n subscribe: (listener: () => void) => () => void;\n setActiveContainer: (containerId: string | null) => void;\n getActiveContainerId: () => string | null;\n applyReconciled: (delta: LocalProjectionReconciledDelta) => void;\n loadContainerDelta: (\n containerId: string,\n ) => Promise<LocalProjectionReconciledDelta>;\n removePersistedDocument: (localId: string) => void;\n refreshPersistedDocument: (\n document: DocumentSummary,\n placementChanged?: boolean,\n ) => void;\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n /** Registered by the reconciler; returns an unsubscribe handle. */\n onReconcileSignal: (listener: LocalProjectionReconcileListener) => () => void;\n getContainerStore: () => ContainerContentsStore;\n}\n\ninterface LocalProjectionStoreState {\n activeContainerId: string | null;\n documentRevision: number;\n deltaRevisions: WeakMap<LocalProjectionReconciledDelta, number>;\n cache: SummaryCache;\n containerStore: ContainerContentsStore;\n hydratedContainerSummaries: boolean;\n listeners: Set<() => void>;\n /**\n * A sync-prerequisite regain (auth, connectivity, or key pair) that arrived\n * before the container tree was ready. The signal's reset-and-backfill must\n * not be lost to startup ordering, so it is latched here and flushed once\n * hydration completes.\n */\n pendingPrerequisitesRegained: boolean;\n reconcileListeners: Set<LocalProjectionReconcileListener>;\n runtime: ContainerContentsStoreRuntime;\n snapshot: LocalProjectionSnapshot;\n pendingSummaryReads: Map<string, PendingSummaryRead>;\n}\n\ninterface PendingSummaryRead {\n discardResult: boolean;\n reloadAfter: boolean;\n}\n\nconst EMPTY_SNAPSHOT: LocalProjectionSnapshot = {\n ready: false,\n containers: [],\n documentSummariesByContainerId: new Map(),\n linkedContainerIdsByDocumentId: new Map(),\n};\n\nfunction computeSnapshot(\n state: LocalProjectionStoreState,\n): LocalProjectionSnapshot {\n const containerSnapshot = state.containerStore.getSnapshot();\n return {\n ready: containerSnapshot.ready,\n containers: containerSnapshot.nodes,\n documentSummariesByContainerId: snapshotSummariesByContainerId(state.cache),\n linkedContainerIdsByDocumentId: snapshotLinkedContainerIdsByDocumentId(\n state.cache,\n ),\n };\n}\n\nfunction emit(state: LocalProjectionStoreState): void {\n state.snapshot = computeSnapshot(state);\n for (const listener of state.listeners) {\n try {\n listener();\n } catch {\n // Keep one subscriber failure from blocking later subscribers.\n }\n }\n}\n\nfunction notifyReconcile(\n state: LocalProjectionStoreState,\n signal: LocalProjectionReconcileSignal,\n): void {\n for (const listener of state.reconcileListeners) {\n try {\n listener(signal);\n } catch {\n // Reconciler failures must not break the read path.\n }\n }\n}\n\nfunction loadContainerSummaries(\n state: LocalProjectionStoreState,\n containerId: string,\n): void {\n if (\n state.cache.hydratedContainerIds.has(containerId) ||\n state.pendingSummaryReads.has(containerId) ||\n state.runtime.infra.dbStatus !== \"ready\"\n ) {\n return;\n }\n\n const pendingRead: PendingSummaryRead = {\n discardResult: false,\n reloadAfter: false,\n };\n void loadLocalContainerProjectionDocumentsFromRuntime({\n containerIds: [containerId],\n runtime: state.runtime,\n })\n .then((documents) => {\n // A runtime reset (e.g. dbStatus loss) clears this entry and the cache\n // mid-flight; do not apply a stale read to a freshly reset cache.\n if (\n state.pendingSummaryReads.get(containerId) !== pendingRead ||\n pendingRead.discardResult\n ) {\n return;\n }\n const changed = applyContainerSummaries(state.cache, {\n containerId,\n documentSummaries: documents.documentSummaries,\n linkedContainerIdsByDocumentId:\n documents.linkedContainerIdsByDocumentId,\n });\n if (changed) {\n emit(state);\n }\n })\n .catch(() => {\n // Local read failures fall back to an empty list; the reconciler retries.\n })\n .finally(() => {\n if (state.pendingSummaryReads.get(containerId) !== pendingRead) {\n return;\n }\n state.pendingSummaryReads.delete(containerId);\n if (pendingRead.reloadAfter) {\n state.cache.hydratedContainerIds.delete(containerId);\n loadContainerSummaries(state, containerId);\n }\n });\n\n state.pendingSummaryReads.set(containerId, pendingRead);\n}\n\nfunction refreshContainerSummaries(\n state: LocalProjectionStoreState,\n containerId: string,\n discardPendingRead = false,\n): void {\n state.cache.hydratedContainerIds.delete(containerId);\n const pendingRead = state.pendingSummaryReads.get(containerId);\n if (pendingRead) {\n // Publish ordinary reads before the trailing refresh so autosaves cannot\n // starve first paint. Deletion and reconciliation must reject older rows.\n pendingRead.reloadAfter = true;\n pendingRead.discardResult ||= discardPendingRead;\n } else {\n loadContainerSummaries(state, containerId);\n }\n}\n\nfunction refreshPersistedDocument(\n state: LocalProjectionStoreState,\n document: DocumentSummary,\n placementChanged = false,\n): void {\n state.documentRevision += 1;\n const containerIds = new Set(state.pendingSummaryReads.keys());\n if (\n state.activeContainerId &&\n state.activeContainerId === document.containerId\n ) {\n containerIds.add(state.activeContainerId);\n }\n for (const [containerId, summaries] of state.cache.summariesByContainerId) {\n if (\n containerId === document.containerId ||\n summaries.some((summary) => summary.id === document.id)\n ) {\n containerIds.add(containerId);\n }\n }\n for (const containerId of containerIds) {\n refreshContainerSummaries(state, containerId, placementChanged);\n }\n}\n\nfunction markHydratedIfReady(state: LocalProjectionStoreState): boolean {\n if (\n state.hydratedContainerSummaries ||\n state.runtime.infra.dbStatus !== \"ready\" ||\n !state.containerStore.getSnapshot().ready\n ) {\n return false;\n }\n\n state.hydratedContainerSummaries = true;\n if (state.activeContainerId) {\n loadContainerSummaries(state, state.activeContainerId);\n }\n return true;\n}\n\nfunction flushPendingPrerequisitesRegained(\n state: LocalProjectionStoreState,\n): void {\n if (\n !state.pendingPrerequisitesRegained ||\n !state.hydratedContainerSummaries ||\n !state.containerStore.getSnapshot().ready\n ) {\n return;\n }\n state.pendingPrerequisitesRegained = false;\n notifyReconcile(state, {\n reason: \"prerequisites-regained\",\n activeContainerId: state.activeContainerId,\n });\n}\n\nfunction publishHydration(state: LocalProjectionStoreState): boolean {\n const didMarkHydrated = markHydratedIfReady(state);\n emit(state);\n if (didMarkHydrated) {\n notifyReconcile(state, {\n reason: \"hydrated\",\n activeContainerId: state.activeContainerId,\n });\n }\n // Backfills read getSnapshot(), so publish the tree before requesting them.\n flushPendingPrerequisitesRegained(state);\n return didMarkHydrated;\n}\n\nfunction resetProjection(state: LocalProjectionStoreState): void {\n state.documentRevision += 1;\n resetSummaryCache(state.cache);\n state.pendingSummaryReads.clear();\n state.hydratedContainerSummaries = false;\n}\n\nfunction hasRemoteBackedContainerMembershipGrowth(\n previous: LocalProjectionSnapshot[\"containers\"],\n next: LocalProjectionSnapshot[\"containers\"],\n homeOrganizationId: string | null,\n activeContainerId: string | null,\n): boolean {\n const isRemoteReconcilable = (\n container: LocalProjectionSnapshot[\"containers\"][number],\n ) => isReconcilableContainerNode(container, homeOrganizationId);\n const previousIds = new Set(\n previous.flatMap((container) =>\n isRemoteReconcilable(container) ? [container.id] : [],\n ),\n );\n if (\n next.some(\n (container) =>\n isRemoteReconcilable(container) && !previousIds.has(container.id),\n )\n ) {\n return true;\n }\n if (!activeContainerId) {\n return false;\n }\n const wasActiveRemoteBacked = previous.some(\n (container) =>\n container.id === activeContainerId &&\n isRemoteBackedContainerNode(container),\n );\n return (\n !wasActiveRemoteBacked &&\n next.some(\n (container) =>\n container.id === activeContainerId &&\n isRemoteBackedContainerNode(container),\n )\n );\n}\n\nfunction removePersistedDocumentFromCache(\n state: LocalProjectionStoreState,\n localId: string,\n): void {\n state.documentRevision += 1;\n // The deleted row may exist only in an in-flight first read, so invalidating\n // just containers that already cached it would allow it to reappear offline.\n for (const containerId of state.pendingSummaryReads.keys()) {\n refreshContainerSummaries(state, containerId, true);\n }\n if (removeDocumentSummary(state.cache, localId)) {\n emit(state);\n }\n}\n\nfunction updateLocalProjectionRuntime(\n state: LocalProjectionStoreState,\n runtime: ContainerContentsStoreRuntime,\n): void {\n const previousRuntime = state.runtime;\n state.runtime = runtime;\n if (\n runtime.infra.execSql !== previousRuntime.infra.execSql ||\n runtime.state.domainScope !== previousRuntime.state.domainScope\n ) {\n resetProjection(state);\n }\n state.containerStore.updateRuntime(runtime);\n\n // Latch before the readiness checks so a regain that arrives while the\n // database or container tree is still warming up is flushed after\n // hydration instead of being lost to startup ordering.\n if (didRegainSyncPrerequisites(previousRuntime, runtime)) {\n state.pendingPrerequisitesRegained = true;\n }\n\n if (runtime.infra.dbStatus !== \"ready\") {\n resetProjection(state);\n emit(state);\n return;\n }\n\n // Reload the active container's summaries when the local store becomes\n // ready (e.g. first DB attach) so first paint reflects cached contents.\n publishHydration(state);\n}\n\nexport function createLocalProjectionStore(input: {\n containerStore: ContainerContentsStore;\n runtime: ContainerContentsStoreRuntime;\n}): LocalProjectionStore {\n const state: LocalProjectionStoreState = {\n activeContainerId: null,\n documentRevision: 0,\n deltaRevisions: new WeakMap(),\n cache: createSummaryCache(),\n containerStore: input.containerStore,\n hydratedContainerSummaries: false,\n listeners: new Set(),\n pendingPrerequisitesRegained: false,\n reconcileListeners: new Set(),\n runtime: input.runtime,\n snapshot: EMPTY_SNAPSHOT,\n pendingSummaryReads: new Map(),\n };\n state.snapshot = computeSnapshot(state);\n\n // Re-emit whenever the underlying container tree changes (mutations, remote\n // hydration). This keeps the merged snapshot in step with the tree store.\n input.containerStore.subscribe(() => {\n const previousContainers = state.snapshot.containers;\n const didMarkHydrated = publishHydration(state);\n // Authentication can schedule the initial idle backfill before the\n // asynchronous remote tree crawl discovers this identity's real root and\n // system children. Re-arm backfill after those remotely-listable ids become\n // visible. Compare membership, not node objects, so metadata/sync-state\n // churn cannot create a reconciliation loop.\n if (\n !didMarkHydrated &&\n hasRemoteBackedContainerMembershipGrowth(\n previousContainers,\n state.snapshot.containers,\n state.runtime.auth.organizationId,\n state.activeContainerId,\n )\n ) {\n notifyReconcile(state, {\n reason: \"remote-containers-added\",\n activeContainerId: state.activeContainerId,\n });\n }\n });\n\n return {\n getSnapshot: () => state.snapshot,\n subscribe: (listener) => {\n state.listeners.add(listener);\n return () => {\n state.listeners.delete(listener);\n };\n },\n setActiveContainer: (containerId) => {\n if (state.activeContainerId === containerId) {\n return;\n }\n state.activeContainerId = containerId;\n if (containerId) {\n refreshContainerSummaries(state, containerId);\n }\n notifyReconcile(state, {\n reason: \"active-changed\",\n activeContainerId: containerId,\n });\n },\n getActiveContainerId: () => state.activeContainerId,\n loadContainerDelta: async (containerId) => {\n const revision = state.documentRevision;\n const documents = await loadLocalContainerProjectionDocumentsFromRuntime({\n containerIds: [containerId],\n runtime: state.runtime,\n });\n const delta = { containerId, ...documents };\n state.deltaRevisions.set(delta, revision);\n return delta;\n },\n applyReconciled: (delta) => {\n const revision = state.deltaRevisions.get(delta);\n if (revision !== undefined && revision !== state.documentRevision) {\n refreshContainerSummaries(state, delta.containerId, true);\n return;\n }\n if (state.pendingSummaryReads.has(delta.containerId)) {\n refreshContainerSummaries(state, delta.containerId, true);\n }\n if (applyContainerSummaries(state.cache, delta)) {\n emit(state);\n }\n },\n removePersistedDocument: (localId) =>\n removePersistedDocumentFromCache(state, localId),\n refreshPersistedDocument: (document, placementChanged) =>\n refreshPersistedDocument(state, document, placementChanged),\n updateRuntime: (runtime) => updateLocalProjectionRuntime(state, runtime),\n onReconcileSignal: (listener) => {\n state.reconcileListeners.add(listener);\n return () => {\n state.reconcileListeners.delete(listener);\n };\n },\n getContainerStore: () => state.containerStore,\n };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DomainScope } from "../../data/shared/domainScope.js";
|
|
2
|
+
import type { ContainerContentsStoreRuntime } from "../container-contents/index.js";
|
|
2
3
|
import { type ContainerContentsStoreOptions } from "../container-contents/index.js";
|
|
3
|
-
import type { ContainerContentsStoreRuntime } from "../container-contents/syncAgent/index.js";
|
|
4
4
|
import { type LocalProjectionStore } from "./localProjectionStore.js";
|
|
5
5
|
/**
|
|
6
6
|
* Get (or lazily create) the device-first local projection store for a domain
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,iCAAiC,GAClC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,0BAA0B,GAE3B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,4BAA4B,GAAG,IAAI,OAAO,EAG7C,CAAC;AAEJ;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAAC,KAI/C;IACC,MAAM,QAAQ,GAAG,4BAA4B,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACrE,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,cAAc,GAAG,iCAAiC,CACtD,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,IAAI,EAAE,CACpB,CAAC;IACF,MAAM,KAAK,GAAG,0BAA0B,CAAC;QACvC,cAAc;QACd,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC,CAAC;IACH,4BAA4B,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { DomainScope } from \"../../data/shared/domainScope\";\nimport type { ContainerContentsStoreRuntime } from \"../container-contents\";\nimport {\n type ContainerContentsStoreOptions,\n getOrCreateContainerContentsStore,\n} from \"../container-contents\";\nimport {\n createLocalProjectionStore,\n type LocalProjectionStore,\n} from \"./localProjectionStore\";\n\nconst localProjectionStoresByScope = new WeakMap<\n DomainScope,\n LocalProjectionStore\n>();\n\n/**\n * Get (or lazily create) the device-first local projection store for a domain\n * scope. The store is cached per scope so every consumer in the same\n * storage/identity context shares one view — mirroring how the container\n * contents store is cached.\n */\nexport function getOrCreateLocalProjectionStore(input: {\n domainScope: DomainScope;\n runtime: ContainerContentsStoreRuntime;\n options?: ContainerContentsStoreOptions | undefined;\n}): LocalProjectionStore {\n const existing = localProjectionStoresByScope.get(input.domainScope);\n if (existing) {\n existing.updateRuntime(input.runtime);\n return existing;\n }\n\n const containerStore = getOrCreateContainerContentsStore(\n input.domainScope,\n input.runtime,\n input.options ?? {},\n );\n const store = createLocalProjectionStore({\n containerStore,\n runtime: input.runtime,\n });\n localProjectionStoresByScope.set(input.domainScope, store);\n return store;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DocumentSummary } from "../../data/documents/documentSummary.js";
|
|
2
|
-
import type { ContainerContentsStoreRuntime } from "../container-contents/
|
|
2
|
+
import type { ContainerContentsStoreRuntime } from "../container-contents/index.js";
|
|
3
3
|
import type { ContainerNode } from "../container-contents/types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Device-first, synchronously-readable view of one domain scope.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentSummary } from \"../../data/documents/documentSummary\";\nimport type { ContainerContentsStoreRuntime } from \"../container-contents
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentSummary } from \"../../data/documents/documentSummary\";\nimport type { ContainerContentsStoreRuntime } from \"../container-contents\";\nimport type { ContainerNode } from \"../container-contents/types\";\n\n/**\n * Device-first, synchronously-readable view of one domain scope.\n *\n * `ready` is a pure function of *local* hydration (SQLite/OPFS load). It is\n * never gated on authentication, network, or remote reconciliation — that is\n * the core invariant that keeps Explorer's first paint instant after register.\n */\nexport interface LocalProjectionSnapshot {\n /** True once the local container tree + summaries have loaded from SQLite. */\n ready: boolean;\n /** Container tree nodes, sorted, as produced by the container-contents store. */\n containers: ReadonlyArray<ContainerNode>;\n /** Document summaries grouped by the container they were discovered under. */\n documentSummariesByContainerId: ReadonlyMap<\n string,\n ReadonlyArray<DocumentSummary>\n >;\n /** Container links per document id (reverse index used by the explorer UI). */\n linkedContainerIdsByDocumentId: ReadonlyMap<string, ReadonlyArray<string>>;\n}\n\n/**\n * A patch applied by the background reconciler (Layer B) into the local\n * projection (Layer A). Summaries replace the prior set for each listed\n * container; links replace the prior set for each listed document.\n */\nexport interface LocalProjectionReconciledDelta {\n containerId: string;\n documentSummaries: ReadonlyArray<DocumentSummary>;\n linkedContainerIdsByDocumentId?:\n | ReadonlyMap<string, ReadonlyArray<string>>\n | undefined;\n}\n\n/** Read side of the app-facing `tearleads.deviceFirst.open()` handle. */\nexport interface LocalProjectionView {\n getSnapshot: () => LocalProjectionSnapshot;\n subscribe: (listener: () => void) => () => void;\n /**\n * Report which container the user is viewing so the reconciler can sync it\n * first. Passing `null` clears the active pointer.\n */\n setActiveContainer: (containerId: string | null) => void;\n /**\n * Push the latest workflow runtime into the view. Call this from an effect\n * (never during render): it may emit synchronously to subscribers.\n */\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n}\n"]}
|
|
@@ -8,8 +8,7 @@ import { assertDocumentWriterProjectionConsistent } from "../../../data/document
|
|
|
8
8
|
import { asWebCryptoBytes, readWriteHeader, uniqueSortedStrings, } from "../../../data/documents/shared/readers.js";
|
|
9
9
|
import { projectionVerificationOptions } from "../../../data/documents/shared/types.js";
|
|
10
10
|
import { readCanonicalRecord } from "../../../data/keying/canonicalJson.js";
|
|
11
|
-
import { readRecordString, requireProjectionUserKeyResolver, } from "../../../data/keyingProjectionVerification/index.js";
|
|
12
|
-
import { resolveEventContainerPaths } from "../../../data/keyingProjectionVerification/document/documentDependencyPaths.js";
|
|
11
|
+
import { readRecordString, requireProjectionUserKeyResolver, resolveEventContainerPaths, } from "../../../data/keyingProjectionVerification/index.js";
|
|
13
12
|
import { assertAttachmentBindingVerified } from "../verification/attachmentBindingVerification.js";
|
|
14
13
|
import { assertBlobWrapScopeVerified } from "../verification/verifiedWrapScope.js";
|
|
15
14
|
import { decryptBlobChunks } from "./blobChunkDecryption.js";
|