@tearleads/client-sdk 0.1.78 → 0.1.80
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/{sync → documents/shared/sync}/documentSyncOutgoingBatch.d.ts +1 -1
- package/data/{sync → documents/shared/sync}/documentSyncOutgoingBatch.js +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 +4 -0
- package/data/keyingProjectionVerification/index.js +5 -1
- package/data/keyingProjectionVerification/index.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence.d.ts +3 -0
- package/data/keyingProjectionVerification/principalPolicy/principalPolicyVerification.d.ts +24 -0
- 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/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/index.d.ts +1 -1
- package/workflows/documents/index.js +1 -1
- package/workflows/documents/index.js.map +1 -1
- package/workflows/documents/linkSet/linkSetProjectionSeed.js +1 -1
- package/workflows/documents/linkSet/linkSetProjectionSeed.js.map +1 -1
- package/workflows/documents/sync/readOnlySync.js +1 -1
- package/workflows/documents/sync/readOnlySync.js.map +1 -1
- package/workflows/documents/sync/syncAttemptPlanning.js +1 -1
- package/workflows/documents/sync/syncAttemptPlanning.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanMaterial.js +1 -1
- package/workflows/documents/syncPlan/syncPlanMaterial.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanRequestBounds.js +1 -1
- package/workflows/documents/syncPlan/syncPlanRequestBounds.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/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/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/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/{sync → documents/shared/sync}/documentSyncOutgoingBatch.js.map +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orphanSideRows.js","sourceRoot":"","sources":["orphanSideRows.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n and,\n asc,\n eq,\n inArray,\n isNotNull,\n lt,\n notExists,\n or,\n type SQL,\n} from \"drizzle-orm\";\nimport { documentOrphanBlobReclaims } from \"../../../sqlite/documentPersistence/documentOrphanBlobReclaims\";\nimport {\n documentAttachmentBlobProjection,\n documentHistoryCheckpoints,\n documentHistoryUpdates,\n documentPendingAttachments,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n runSerializedSqlMutation,\n} from \"../../../sqlite/sqlSchema\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\n\n// Crash residue gets a full day to outlive slow devices and wall-clock skew;\n// canonical-row absence is necessary but never sufficient for fresh writes.\nconst DOCUMENT_ORPHAN_SWEEP_MIN_AGE_MS = 24 * 60 * 60 * 1000;\nconst DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE = 32;\n\ntype DocumentSideLocalIdColumn =\n | typeof documentAttachmentBlobProjection.localId\n | typeof documentHistoryCheckpoints.localId\n | typeof documentHistoryUpdates.localId\n | typeof documentPendingAttachments.localId;\n\nfunction requirePredicate(predicate: SQL | undefined): SQL {\n if (!predicate) {\n throw new Error(\"Document orphan cleanup requires a SQL predicate\");\n }\n return predicate;\n}\n\nfunction hasNoDocument(\n tx: ClientSQLiteTransactionScope,\n localId: DocumentSideLocalIdColumn,\n appKind: string | null = DOCUMENTS_APP_KIND,\n): SQL {\n return notExists(\n tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n appKind === null\n ? eq(documents.localId, localId)\n : and(eq(documents.appKind, appKind), eq(documents.localId, localId)),\n ),\n );\n}\n\nexport async function queueDocumentAttachmentBlobReclaims(input: {\n localWhere: SQL;\n pendingWhere: SQL;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { localWhere, pendingWhere, tx } = input;\n const [pendingAttachmentRows, localAttachmentRows] = await Promise.all([\n tx\n .select({ storageKey: documentPendingAttachments.storageKey })\n .from(documentPendingAttachments)\n .where(pendingWhere),\n tx\n .select({ storageKey: documentAttachmentBlobProjection.storageKey })\n .from(documentAttachmentBlobProjection)\n .where(localWhere),\n ]);\n const storageKeys = [\n ...new Set(\n [...pendingAttachmentRows, ...localAttachmentRows].map(\n (row) => row.storageKey,\n ),\n ),\n ];\n await queueDocumentAttachmentStorageKeys(tx, storageKeys);\n}\n\nexport async function queueDocumentAttachmentStorageKeys(\n tx: ClientSQLiteTransactionScope,\n storageKeys: ReadonlyArray<string>,\n): Promise<void> {\n if (storageKeys.length > 0) {\n await tx\n .insert(documentOrphanBlobReclaims)\n .values(storageKeys.map((storageKey) => ({ storageKey })))\n .onConflictDoNothing()\n .run();\n }\n}\n\ninterface AttachmentSweepCandidate {\n localId: string;\n slotId: string;\n storageKey: string;\n}\n\nfunction pendingAttachmentCandidatesWhere(\n candidates: ReadonlyArray<AttachmentSweepCandidate>,\n): SQL {\n return requirePredicate(\n or(\n ...candidates.map((candidate) =>\n and(\n eq(documentPendingAttachments.localId, candidate.localId),\n eq(documentPendingAttachments.slotId, candidate.slotId),\n ),\n ),\n ),\n );\n}\n\nfunction localAttachmentCandidatesWhere(\n candidates: ReadonlyArray<AttachmentSweepCandidate>,\n): SQL {\n return requirePredicate(\n or(\n ...candidates.map((candidate) =>\n and(\n eq(documentAttachmentBlobProjection.localId, candidate.localId),\n eq(documentAttachmentBlobProjection.slotId, candidate.slotId),\n ),\n ),\n ),\n );\n}\n\ninterface HistorySweepCandidates {\n checkpoints: ReadonlyArray<{ localId: string }>;\n updates: ReadonlyArray<{ id: string | null }>;\n}\n\ninterface AttachmentSweepCandidates {\n local: ReadonlyArray<AttachmentSweepCandidate>;\n pending: ReadonlyArray<AttachmentSweepCandidate>;\n}\n\nasync function selectHistorySweepCandidates(\n tx: ClientSQLiteTransactionScope,\n olderThan: string,\n): Promise<HistorySweepCandidates> {\n const checkpoints = await tx\n .select({ localId: documentHistoryCheckpoints.localId })\n .from(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, DOCUMENTS_APP_KIND),\n lt(documentHistoryCheckpoints.updatedAt, olderThan),\n hasNoDocument(tx, documentHistoryCheckpoints.localId),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n const updates = await tx\n .select({ id: documentHistoryUpdates.id })\n .from(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, DOCUMENTS_APP_KIND),\n isNotNull(documentHistoryUpdates.id),\n lt(documentHistoryUpdates.createdAt, olderThan),\n hasNoDocument(tx, documentHistoryUpdates.localId),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n return { checkpoints, updates };\n}\n\nasync function selectAttachmentSweepCandidates(\n tx: ClientSQLiteTransactionScope,\n olderThan: string,\n): Promise<AttachmentSweepCandidates> {\n const pending = await tx\n .select({\n localId: documentPendingAttachments.localId,\n slotId: documentPendingAttachments.slotId,\n storageKey: documentPendingAttachments.storageKey,\n })\n .from(documentPendingAttachments)\n .where(\n and(\n lt(documentPendingAttachments.createdAt, olderThan),\n hasNoDocument(tx, documentPendingAttachments.localId, null),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n const local = await tx\n .select({\n localId: documentAttachmentBlobProjection.localId,\n slotId: documentAttachmentBlobProjection.slotId,\n storageKey: documentAttachmentBlobProjection.storageKey,\n })\n .from(documentAttachmentBlobProjection)\n .where(\n and(\n lt(documentAttachmentBlobProjection.updatedAt, olderThan),\n hasNoDocument(tx, documentAttachmentBlobProjection.localId, null),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n return { local, pending };\n}\n\nasync function deleteHistorySweepCandidates(\n tx: ClientSQLiteTransactionScope,\n candidates: HistorySweepCandidates,\n): Promise<void> {\n if (candidates.checkpoints.length > 0) {\n await tx\n .delete(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, DOCUMENTS_APP_KIND),\n inArray(\n documentHistoryCheckpoints.localId,\n candidates.checkpoints.map((row) => row.localId),\n ),\n ),\n )\n .run();\n }\n if (candidates.updates.length > 0) {\n await tx\n .delete(documentHistoryUpdates)\n .where(\n inArray(\n documentHistoryUpdates.id,\n candidates.updates.flatMap((row) =>\n row.id === null ? [] : [row.id],\n ),\n ),\n )\n .run();\n }\n}\n\nasync function deleteAttachmentSweepCandidates(\n tx: ClientSQLiteTransactionScope,\n candidates: AttachmentSweepCandidates,\n): Promise<void> {\n await queueDocumentAttachmentStorageKeys(tx, [\n ...new Set(\n [...candidates.pending, ...candidates.local].map((row) => row.storageKey),\n ),\n ]);\n if (candidates.pending.length > 0) {\n await tx\n .delete(documentPendingAttachments)\n .where(pendingAttachmentCandidatesWhere(candidates.pending))\n .run();\n }\n if (candidates.local.length > 0) {\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(localAttachmentCandidatesWhere(candidates.local))\n .run();\n }\n}\n\nfunction hasFullSweepBatch(\n history: HistorySweepCandidates,\n attachments: AttachmentSweepCandidates,\n): boolean {\n return [\n history.checkpoints,\n history.updates,\n attachments.pending,\n attachments.local,\n ].some((rows) => rows.length === DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n}\n\n/** Remove one bounded batch of aged side writes without a canonical row. */\nexport async function deleteOrphanedDocumentSideRows(\n execSql: ExecSql,\n options: { now?: Date | undefined } = {},\n): Promise<boolean> {\n const olderThan = new Date(\n (options.now?.getTime() ?? Date.now()) - DOCUMENT_ORPHAN_SWEEP_MIN_AGE_MS,\n ).toISOString();\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(async (tx) => {\n const history = await selectHistorySweepCandidates(tx, olderThan);\n const attachments = await selectAttachmentSweepCandidates(tx, olderThan);\n await deleteHistorySweepCandidates(tx, history);\n await deleteAttachmentSweepCandidates(tx, attachments);\n return hasFullSweepBatch(history, attachments);\n }),\n );\n}\n\nexport async function listDocumentOrphanBlobReclaims(\n execSql: ExecSql,\n limit: number,\n): Promise<ReadonlyArray<string>> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ storageKey: documentOrphanBlobReclaims.storageKey })\n .from(documentOrphanBlobReclaims)\n .orderBy(asc(documentOrphanBlobReclaims.storageKey))\n .limit(limit);\n return rows.map((row) => row.storageKey);\n}\n\nexport async function isDocumentBlobStorageKeyReferenced(\n execSql: ExecSql,\n storageKey: string,\n): Promise<boolean> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [pendingRows, localRows] = await Promise.all([\n db\n .select({ storageKey: documentPendingAttachments.storageKey })\n .from(documentPendingAttachments)\n .where(eq(documentPendingAttachments.storageKey, storageKey))\n .limit(1),\n db\n .select({ storageKey: documentAttachmentBlobProjection.storageKey })\n .from(documentAttachmentBlobProjection)\n .where(eq(documentAttachmentBlobProjection.storageKey, storageKey))\n .limit(1),\n ]);\n return pendingRows.length > 0 || localRows.length > 0;\n}\n\nexport async function acknowledgeDocumentOrphanBlobReclaim(\n execSql: ExecSql,\n storageKey: string,\n): Promise<void> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n await db\n .delete(documentOrphanBlobReclaims)\n .where(eq(documentOrphanBlobReclaims.storageKey, storageKey))\n .run();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"orphanSideRows.js","sourceRoot":"","sources":["orphanSideRows.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n and,\n asc,\n eq,\n inArray,\n isNotNull,\n lt,\n notExists,\n or,\n type SQL,\n} from \"drizzle-orm\";\nimport { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport { documentOrphanBlobReclaims } from \"../../../sqlite/documentPersistence/documentOrphanBlobReclaims\";\nimport {\n documentAttachmentBlobProjection,\n documentHistoryCheckpoints,\n documentHistoryUpdates,\n documentPendingAttachments,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n runSerializedSqlMutation,\n} from \"../../../sqlite/sqlSchema\";\n\n// Crash residue gets a full day to outlive slow devices and wall-clock skew;\n// canonical-row absence is necessary but never sufficient for fresh writes.\nconst DOCUMENT_ORPHAN_SWEEP_MIN_AGE_MS = 24 * 60 * 60 * 1000;\nconst DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE = 32;\n\ntype DocumentSideLocalIdColumn =\n | typeof documentAttachmentBlobProjection.localId\n | typeof documentHistoryCheckpoints.localId\n | typeof documentHistoryUpdates.localId\n | typeof documentPendingAttachments.localId;\n\nfunction requirePredicate(predicate: SQL | undefined): SQL {\n if (!predicate) {\n throw new Error(\"Document orphan cleanup requires a SQL predicate\");\n }\n return predicate;\n}\n\nfunction hasNoDocument(\n tx: ClientSQLiteTransactionScope,\n localId: DocumentSideLocalIdColumn,\n appKind: string | null = DOCUMENTS_APP_KIND,\n): SQL {\n return notExists(\n tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n appKind === null\n ? eq(documents.localId, localId)\n : and(eq(documents.appKind, appKind), eq(documents.localId, localId)),\n ),\n );\n}\n\nexport async function queueDocumentAttachmentBlobReclaims(input: {\n localWhere: SQL;\n pendingWhere: SQL;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { localWhere, pendingWhere, tx } = input;\n const [pendingAttachmentRows, localAttachmentRows] = await Promise.all([\n tx\n .select({ storageKey: documentPendingAttachments.storageKey })\n .from(documentPendingAttachments)\n .where(pendingWhere),\n tx\n .select({ storageKey: documentAttachmentBlobProjection.storageKey })\n .from(documentAttachmentBlobProjection)\n .where(localWhere),\n ]);\n const storageKeys = [\n ...new Set(\n [...pendingAttachmentRows, ...localAttachmentRows].map(\n (row) => row.storageKey,\n ),\n ),\n ];\n await queueDocumentAttachmentStorageKeys(tx, storageKeys);\n}\n\nexport async function queueDocumentAttachmentStorageKeys(\n tx: ClientSQLiteTransactionScope,\n storageKeys: ReadonlyArray<string>,\n): Promise<void> {\n if (storageKeys.length > 0) {\n await tx\n .insert(documentOrphanBlobReclaims)\n .values(storageKeys.map((storageKey) => ({ storageKey })))\n .onConflictDoNothing()\n .run();\n }\n}\n\ninterface AttachmentSweepCandidate {\n localId: string;\n slotId: string;\n storageKey: string;\n}\n\nfunction pendingAttachmentCandidatesWhere(\n candidates: ReadonlyArray<AttachmentSweepCandidate>,\n): SQL {\n return requirePredicate(\n or(\n ...candidates.map((candidate) =>\n and(\n eq(documentPendingAttachments.localId, candidate.localId),\n eq(documentPendingAttachments.slotId, candidate.slotId),\n ),\n ),\n ),\n );\n}\n\nfunction localAttachmentCandidatesWhere(\n candidates: ReadonlyArray<AttachmentSweepCandidate>,\n): SQL {\n return requirePredicate(\n or(\n ...candidates.map((candidate) =>\n and(\n eq(documentAttachmentBlobProjection.localId, candidate.localId),\n eq(documentAttachmentBlobProjection.slotId, candidate.slotId),\n ),\n ),\n ),\n );\n}\n\ninterface HistorySweepCandidates {\n checkpoints: ReadonlyArray<{ localId: string }>;\n updates: ReadonlyArray<{ id: string | null }>;\n}\n\ninterface AttachmentSweepCandidates {\n local: ReadonlyArray<AttachmentSweepCandidate>;\n pending: ReadonlyArray<AttachmentSweepCandidate>;\n}\n\nasync function selectHistorySweepCandidates(\n tx: ClientSQLiteTransactionScope,\n olderThan: string,\n): Promise<HistorySweepCandidates> {\n const checkpoints = await tx\n .select({ localId: documentHistoryCheckpoints.localId })\n .from(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, DOCUMENTS_APP_KIND),\n lt(documentHistoryCheckpoints.updatedAt, olderThan),\n hasNoDocument(tx, documentHistoryCheckpoints.localId),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n const updates = await tx\n .select({ id: documentHistoryUpdates.id })\n .from(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, DOCUMENTS_APP_KIND),\n isNotNull(documentHistoryUpdates.id),\n lt(documentHistoryUpdates.createdAt, olderThan),\n hasNoDocument(tx, documentHistoryUpdates.localId),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n return { checkpoints, updates };\n}\n\nasync function selectAttachmentSweepCandidates(\n tx: ClientSQLiteTransactionScope,\n olderThan: string,\n): Promise<AttachmentSweepCandidates> {\n const pending = await tx\n .select({\n localId: documentPendingAttachments.localId,\n slotId: documentPendingAttachments.slotId,\n storageKey: documentPendingAttachments.storageKey,\n })\n .from(documentPendingAttachments)\n .where(\n and(\n lt(documentPendingAttachments.createdAt, olderThan),\n hasNoDocument(tx, documentPendingAttachments.localId, null),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n const local = await tx\n .select({\n localId: documentAttachmentBlobProjection.localId,\n slotId: documentAttachmentBlobProjection.slotId,\n storageKey: documentAttachmentBlobProjection.storageKey,\n })\n .from(documentAttachmentBlobProjection)\n .where(\n and(\n lt(documentAttachmentBlobProjection.updatedAt, olderThan),\n hasNoDocument(tx, documentAttachmentBlobProjection.localId, null),\n ),\n )\n .limit(DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n return { local, pending };\n}\n\nasync function deleteHistorySweepCandidates(\n tx: ClientSQLiteTransactionScope,\n candidates: HistorySweepCandidates,\n): Promise<void> {\n if (candidates.checkpoints.length > 0) {\n await tx\n .delete(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, DOCUMENTS_APP_KIND),\n inArray(\n documentHistoryCheckpoints.localId,\n candidates.checkpoints.map((row) => row.localId),\n ),\n ),\n )\n .run();\n }\n if (candidates.updates.length > 0) {\n await tx\n .delete(documentHistoryUpdates)\n .where(\n inArray(\n documentHistoryUpdates.id,\n candidates.updates.flatMap((row) =>\n row.id === null ? [] : [row.id],\n ),\n ),\n )\n .run();\n }\n}\n\nasync function deleteAttachmentSweepCandidates(\n tx: ClientSQLiteTransactionScope,\n candidates: AttachmentSweepCandidates,\n): Promise<void> {\n await queueDocumentAttachmentStorageKeys(tx, [\n ...new Set(\n [...candidates.pending, ...candidates.local].map((row) => row.storageKey),\n ),\n ]);\n if (candidates.pending.length > 0) {\n await tx\n .delete(documentPendingAttachments)\n .where(pendingAttachmentCandidatesWhere(candidates.pending))\n .run();\n }\n if (candidates.local.length > 0) {\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(localAttachmentCandidatesWhere(candidates.local))\n .run();\n }\n}\n\nfunction hasFullSweepBatch(\n history: HistorySweepCandidates,\n attachments: AttachmentSweepCandidates,\n): boolean {\n return [\n history.checkpoints,\n history.updates,\n attachments.pending,\n attachments.local,\n ].some((rows) => rows.length === DOCUMENT_ORPHAN_SWEEP_BATCH_SIZE);\n}\n\n/** Remove one bounded batch of aged side writes without a canonical row. */\nexport async function deleteOrphanedDocumentSideRows(\n execSql: ExecSql,\n options: { now?: Date | undefined } = {},\n): Promise<boolean> {\n const olderThan = new Date(\n (options.now?.getTime() ?? Date.now()) - DOCUMENT_ORPHAN_SWEEP_MIN_AGE_MS,\n ).toISOString();\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(async (tx) => {\n const history = await selectHistorySweepCandidates(tx, olderThan);\n const attachments = await selectAttachmentSweepCandidates(tx, olderThan);\n await deleteHistorySweepCandidates(tx, history);\n await deleteAttachmentSweepCandidates(tx, attachments);\n return hasFullSweepBatch(history, attachments);\n }),\n );\n}\n\nexport async function listDocumentOrphanBlobReclaims(\n execSql: ExecSql,\n limit: number,\n): Promise<ReadonlyArray<string>> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ storageKey: documentOrphanBlobReclaims.storageKey })\n .from(documentOrphanBlobReclaims)\n .orderBy(asc(documentOrphanBlobReclaims.storageKey))\n .limit(limit);\n return rows.map((row) => row.storageKey);\n}\n\nexport async function isDocumentBlobStorageKeyReferenced(\n execSql: ExecSql,\n storageKey: string,\n): Promise<boolean> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [pendingRows, localRows] = await Promise.all([\n db\n .select({ storageKey: documentPendingAttachments.storageKey })\n .from(documentPendingAttachments)\n .where(eq(documentPendingAttachments.storageKey, storageKey))\n .limit(1),\n db\n .select({ storageKey: documentAttachmentBlobProjection.storageKey })\n .from(documentAttachmentBlobProjection)\n .where(eq(documentAttachmentBlobProjection.storageKey, storageKey))\n .limit(1),\n ]);\n return pendingRows.length > 0 || localRows.length > 0;\n}\n\nexport async function acknowledgeDocumentOrphanBlobReclaim(\n execSql: ExecSql,\n storageKey: string,\n): Promise<void> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n await db\n .delete(documentOrphanBlobReclaims)\n .where(eq(documentOrphanBlobReclaims.storageKey, storageKey))\n .run();\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { and, eq, isNull } from "drizzle-orm";
|
|
2
|
+
import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
|
|
2
3
|
import { deriveStableDocumentId } from "../../../documents/shared/stableDocumentId.js";
|
|
3
4
|
import { documentProjection, documents } from "../../../sqlite/schema/index.js";
|
|
4
5
|
import { getClientSQLitePersistenceRuntime } from "../../../sqlite/sqlitePersistenceRuntime.js";
|
|
5
|
-
import { DOCUMENTS_APP_KIND } from "./constants.js";
|
|
6
6
|
import { documentSummaryJoin, documentSummarySelection, mapDocumentSummary, } from "./documentProjectionRows.js";
|
|
7
7
|
/**
|
|
8
8
|
* Maps the stable remote document id each pending-create row would have sent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pendingCreateAdoption.js","sourceRoot":"","sources":["pendingCreateAdoption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pendingCreateAdoption.js","sourceRoot":"","sources":["pendingCreateAdoption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAE1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAE7F,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAgB;IAEhB,MAAM,EAAE,EAAE,EAAE,GAAG,iCAAiC,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;SACtC,IAAI,CAAC,SAAS,CAAC;SACf,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,kBAAkB,CAAC,EACzC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAC7B,CACF,CAAC;IAEJ,MAAM,0BAA0B,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,0BAA0B,CAAC,GAAG,CAC5B,MAAM,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,EACzC,GAAG,CAAC,OAAO,CACZ,CAAC;IACJ,CAAC;IACD,OAAO,0BAA0B,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAgB,EAChB,OAA2B;IAE3B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,EAAE,EAAE,EAAE,GAAG,iCAAiC,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;SACnB,MAAM,CAAC,wBAAwB,CAAC;SAChC,IAAI,CAAC,kBAAkB,CAAC;SACxB,SAAS,CAAC,SAAS,EAAE,mBAAmB,CAAC;SACzC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;SACxE,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,OAAO,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC","sourcesContent":["import { and, eq, isNull } from \"drizzle-orm\";\nimport { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport type { DocumentSummary } from \"../../../documents/documentSummary\";\nimport { deriveStableDocumentId } from \"../../../documents/shared/stableDocumentId\";\nimport { documentProjection, documents } from \"../../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n mapDocumentSummary,\n} from \"./documentProjectionRows\";\n\n/**\n * Maps the stable remote document id each pending-create row would have sent\n * to that row's localId. A remote create derives its document id from the\n * stable localId (deriveStableDocumentId), so when discovery lists a document\n * whose create this client committed but never saw the response for (e.g. a\n * reload mid-bootstrap), the orphaned row is recognizable by re-deriving the\n * id. Without this, discovery would mint a second row under localId=documentId\n * and the replayed create would adopt the same remote document onto the\n * original row — two local rows for one remote document.\n * This lookup prevents duplicates; discovery cannot authorize adoption. The\n * create retry must verify its signed container and organization scope first.\n */\nexport async function mapPendingCreateLocalIds(\n execSql: ExecSql,\n): Promise<ReadonlyMap<string, string>> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n isNull(documents.documentId),\n ),\n );\n\n const localIdsByStableDocumentId = new Map<string, string>();\n for (const row of rows) {\n localIdsByStableDocumentId.set(\n await deriveStableDocumentId(row.localId),\n row.localId,\n );\n }\n return localIdsByStableDocumentId;\n}\n\nexport async function loadPendingCreateSummary(\n execSql: ExecSql,\n localId: string | undefined,\n): Promise<DocumentSummary | null> {\n if (!localId) return null;\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [row] = await db\n .select(documentSummarySelection)\n .from(documentProjection)\n .innerJoin(documents, documentSummaryJoin)\n .where(and(eq(documents.localId, localId), isNull(documents.documentId)))\n .limit(1);\n return row ? mapDocumentSummary(row) : null;\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { desc, eq, notInArray } from "drizzle-orm";
|
|
2
|
+
import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
|
|
2
3
|
import { HIDDEN_DOCUMENT_SUMMARY_KINDS } from "../../../documents/documentSummary.js";
|
|
3
4
|
import { findLocalIdByDocumentId, loadDocumentRecord, } from "../../../sqlite/documentPersistence/index.js";
|
|
4
5
|
import { documentProjection, documentProjectionText, documents, } from "../../../sqlite/schema/index.js";
|
|
5
6
|
import { getClientSQLitePersistenceRuntime } from "../../../sqlite/sqlitePersistenceRuntime.js";
|
|
6
|
-
import { DOCUMENTS_APP_KIND } from "./constants.js";
|
|
7
7
|
import { documentSummaryJoin, documentSummarySelection, getProjectionContainerId, getProjectionDocumentKind, getProjectionText, getProjectionTitle, mapDocumentSummary, } from "./documentProjectionRows.js";
|
|
8
8
|
import { getDocumentScope, hasDocumentRow } from "./documentRows.js";
|
|
9
9
|
export const documentRowQueryPersistence = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rowQueryPersistence.js","sourceRoot":"","sources":["rowQueryPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,SAAS,GACV,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAE7F,OAAO,
|
|
1
|
+
{"version":3,"file":"rowQueryPersistence.js","sourceRoot":"","sources":["rowQueryPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { desc, eq, notInArray } from \"drizzle-orm\";\nimport { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport { HIDDEN_DOCUMENT_SUMMARY_KINDS } from \"../../../documents/documentSummary\";\nimport {\n findLocalIdByDocumentId,\n loadDocumentRecord,\n} from \"../../../sqlite/documentPersistence\";\nimport {\n documentProjection,\n documentProjectionText,\n documents,\n} from \"../../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { DocumentsPersistence } from \"../types\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n getProjectionContainerId,\n getProjectionDocumentKind,\n getProjectionText,\n getProjectionTitle,\n mapDocumentSummary,\n} from \"./documentProjectionRows\";\nimport { getDocumentScope, hasDocumentRow } from \"./documentRows\";\n\ntype DocumentRowQueryPersistence = Pick<\n DocumentsPersistence,\n | \"listDocuments\"\n | \"findDocumentLocalIdsByContainerId\"\n | \"findLocalIdByDocumentId\"\n | \"hasDocument\"\n | \"documentIdentityMatches\"\n | \"loadDocument\"\n | \"loadDocumentContainer\"\n>;\n\nexport const documentRowQueryPersistence: DocumentRowQueryPersistence = {\n async listDocuments(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(\n notInArray(documentProjection.documentKind, [\n ...HIDDEN_DOCUMENT_SUMMARY_KINDS,\n ]),\n )\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n },\n async findDocumentLocalIdsByContainerId(execSql, containerId) {\n // Unlike `listDocumentsByContainerIdsOrDocumentIds`, this deliberately does\n // NOT drop `HIDDEN_DOCUMENT_SUMMARY_KINDS` — it exists to reach the hidden\n // `organization_profile` document by the container it is linked to, which is\n // how a *foreign* org's display name is found on a member who synced the doc\n // under its server documentId rather than the provisioner-only local alias.\n // `documentProjection` is written and deleted in lockstep with the\n // `documents` rows (all DOCUMENTS_APP_KIND), so filtering by containerId\n // alone is sufficient — no join to `documents` is needed to select localId.\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ localId: documentProjection.localId })\n .from(documentProjection)\n .where(eq(documentProjection.containerId, containerId))\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n return rows\n .map((row) => row.localId)\n .filter((localId): localId is string => localId !== null);\n },\n findLocalIdByDocumentId: (execSql, documentId) =>\n findLocalIdByDocumentId(execSql, DOCUMENTS_APP_KIND, documentId),\n async hasDocument(execSql, localId) {\n return hasDocumentRow(execSql, localId);\n },\n async documentIdentityMatches(\n execSql,\n localId,\n expectedDocumentId,\n expectedRecoveryGeneration,\n ) {\n const record = await loadDocumentRecord(execSql, getDocumentScope(localId));\n return (\n record?.documentId === expectedDocumentId &&\n (record.recoveryGeneration ?? 0) === expectedRecoveryGeneration\n );\n },\n async loadDocument(execSql, localId) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [documentRecord, projectionRows] = await Promise.all([\n loadDocumentRecord(execSql, getDocumentScope(localId)),\n db\n .select({\n documentKind: documentProjection.documentKind,\n text: documentProjectionText.text,\n title: documentProjection.title,\n containerId: documentProjection.containerId,\n })\n .from(documentProjection)\n .leftJoin(\n documentProjectionText,\n eq(documentProjectionText.localId, documentProjection.localId),\n )\n .where(eq(documentProjection.localId, localId))\n .limit(1),\n ]);\n\n if (!documentRecord) {\n return null;\n }\n\n return {\n ...documentRecord,\n containerId: getProjectionContainerId(projectionRows[0]),\n documentKind: getProjectionDocumentKind(projectionRows[0]),\n text: getProjectionText(projectionRows[0]),\n title: getProjectionTitle(projectionRows[0]),\n };\n },\n async loadDocumentContainer(execSql, localId) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n // Select the row itself, not just its container, so an existing row with a\n // null container is reported as `{ containerId: null }` while a missing row\n // is reported as `undefined` — the caller relies on that distinction to know\n // whether the projection has authoritative placement to defer to.\n const projectionRows = await db\n .select({ containerId: documentProjection.containerId })\n .from(documentProjection)\n .where(eq(documentProjection.localId, localId))\n .limit(1);\n const projectionRow = projectionRows[0];\n if (!projectionRow) {\n return undefined;\n }\n\n return { containerId: projectionRow.containerId };\n },\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":"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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 {\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";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decrypt.js","sourceRoot":"","sources":["decrypt.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n blobContentMetadataHash,\n bytesToHex,\n CONTENT_RECORD_ENCRYPTION_SUITE,\n computeBlobAccessManifestHash,\n computeBlobContentKeyTargetHash,\n computeContentRecordNonceDomainHash,\n makeVerifiedBlobKekTargets,\n verifyWriteHeader,\n} from \"@tearleads/crypto\";\nimport type { BlobKekTargetsResponse } from \"@tearleads/validators/response\";\nimport { deriveBlobContentRecordKey } from \"../../../data/blobs/attachments/crypto\";\nimport { unwrapBlobContentKey } from \"../../../data/blobs/attachments/projection\";\nimport {\n parseBlobEncryptedBytes,\n readBlobKekTarget,\n readDocumentManifestIdentity,\n sortBlobTargets,\n} from \"../../../data/blobs/attachments/readers\";\nimport { assertBlobContentKeyBundleTargetHash } from \"../../../data/blobs/attachments/responses\";\nimport type {\n BlobEncryptedBytesHeader,\n DecryptDocumentAttachmentBlobInput,\n} from \"../../../data/blobs/attachments/types\";\nimport type { BlobBytes } from \"../../../data/blobs/blobContracts\";\nimport { importContentKeyMaterial } from \"../../../data/documents/shared/contentRecordKeys\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport {\n asWebCryptoBytes,\n readWriteHeader,\n uniqueSortedStrings,\n} from \"../../../data/documents/shared/readers\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\nimport type { DocumentWriterProjectionAuthorization } from \"../../../data/keyingProjectionVerification\";\nimport {\n readRecordString,\n requireProjectionUserKeyResolver,\n} from \"../../../data/keyingProjectionVerification\";\nimport { resolveEventContainerPaths } from \"../../../data/keyingProjectionVerification/document/documentDependencyPaths\";\n\nimport { assertAttachmentBindingVerified } from \"../verification/attachmentBindingVerification\";\nimport { assertBlobWrapScopeVerified } from \"../verification/verifiedWrapScope\";\nimport { decryptBlobChunks } from \"./blobChunkDecryption\";\n\nasync function assertBlobEncryptionMetadata(input: {\n readonly contentKeyBundle: DecryptDocumentAttachmentBlobInput[\"binding\"][\"contentKeyBundle\"];\n readonly encrypted: BlobEncryptedBytesHeader;\n readonly expectedBlobId: string;\n readonly organizationId: string;\n}): Promise<void> {\n const { contentKeyBundle, encrypted, expectedBlobId, organizationId } = input;\n if (\n encrypted.blobId !== expectedBlobId ||\n encrypted.contentRecordId !== expectedBlobId\n ) {\n throw new Error(\"Blob encrypted bytes blob id mismatch\");\n }\n if (\n encrypted.contentKeyEpoch !== contentKeyBundle.contentKeyEpoch ||\n contentKeyBundle.blobId !== expectedBlobId\n ) {\n throw new Error(\"Blob encrypted bytes content-key bundle mismatch\");\n }\n await assertBlobContentKeyBundleTargetHash(contentKeyBundle);\n\n const expectedNonceDomainHash = await computeContentRecordNonceDomainHash({\n version: 1,\n organizationId,\n objectKind: \"blob\",\n objectId: expectedBlobId,\n contentKeyEpoch: encrypted.contentKeyEpoch,\n encryptionSuite: CONTENT_RECORD_ENCRYPTION_SUITE,\n contentRecordId: encrypted.contentRecordId,\n });\n if (encrypted.nonceDomainHash !== expectedNonceDomainHash) {\n throw new Error(\"Blob encrypted bytes nonce domain mismatch\");\n }\n const expectedMetadataHash = await blobContentMetadataHash({\n blobId: expectedBlobId,\n byteLength: encrypted.byteLength,\n chunkCount: encrypted.chunkCount,\n chunkSize: encrypted.chunkSize,\n contentKeyEpoch: encrypted.contentKeyEpoch,\n });\n if (encrypted.metadataHash !== expectedMetadataHash) {\n throw new Error(\"Blob encrypted bytes metadata hash mismatch\");\n }\n}\n\nexport type AttachmentBlobDecryptionInput = Omit<\n DecryptDocumentAttachmentBlobInput,\n \"encryptedBytes\"\n> & {\n encrypted: BlobEncryptedBytesHeader;\n};\n\n/** Verifies metadata and authority; the caller must still authenticate ciphertext. */\nexport async function prepareDocumentAttachmentBlobDecryption({\n binding,\n encrypted,\n expectedDocumentId,\n expectedSlotId,\n execSql,\n resolveProjectionUserKey,\n targetSecretKey,\n stillCurrent,\n warmReferencedPrincipalPolicies,\n writerProjection,\n}: AttachmentBlobDecryptionInput): Promise<{\n contentKey: Uint8Array;\n recordKey: CryptoKey;\n organizationId: string;\n}> {\n const requiredResolveProjectionUserKey = requireProjectionUserKeyResolver(\n resolveProjectionUserKey,\n \"Document attachment blob decrypt\",\n );\n const verificationOptions = projectionVerificationOptions({\n execSql,\n stillCurrent,\n warmReferencedPrincipalPolicies,\n resolveProjectionUserKey: requiredResolveProjectionUserKey,\n });\n let documentAuthorization: DocumentWriterProjectionAuthorization | undefined;\n await assertDocumentWriterProjectionConsistent(writerProjection, {\n allowStaleContentKeyBundle: true,\n execSql,\n onVerifiedAuthorization: (authorization) => {\n documentAuthorization = authorization;\n },\n ...verificationOptions,\n });\n const { documentId, organizationId } =\n readDocumentManifestIdentity(writerProjection);\n await assertBlobEncryptionMetadata({\n contentKeyBundle: binding.contentKeyBundle,\n encrypted,\n expectedBlobId: binding.blobId,\n organizationId,\n });\n await assertAttachmentBindingVerified({\n authorization: documentAuthorization,\n binding,\n expectedDocumentId,\n expectedSlotId,\n resolveProjectionUserKey: requiredResolveProjectionUserKey,\n });\n await assertBlobWriteHeaderVerified({\n authorization: documentAuthorization,\n binding,\n encrypted,\n organizationId,\n resolveProjectionUserKey: requiredResolveProjectionUserKey,\n });\n\n if (!documentAuthorization)\n throw new Error(\"Blob document authorization is unavailable\");\n assertBlobWrapScopeVerified({\n authorization: documentAuthorization,\n binding,\n documentId,\n });\n const contentKey = await unwrapBlobContentKey({\n blobId: binding.blobId,\n contentKeyBundle: binding.contentKeyBundle,\n documentId,\n encrypted,\n execSql,\n expectedBindingId: binding.bindingId,\n secretKey: targetSecretKey,\n ...verificationOptions,\n writerProjection,\n });\n const contentKeyMaterial = await importContentKeyMaterial(contentKey);\n const recordKey = await deriveBlobContentRecordKey({\n blobId: binding.blobId,\n contentKeyEpoch: encrypted.contentKeyEpoch,\n contentKeyMaterial,\n contentRecordId: encrypted.contentRecordId,\n organizationId,\n usage: \"decrypt\",\n });\n return { contentKey, recordKey, organizationId };\n}\n\nasync function decryptDocumentAttachmentBlobWithKey(\n input: DecryptDocumentAttachmentBlobInput,\n): Promise<{ bytes: BlobBytes; contentKey: Uint8Array }> {\n const encrypted = parseBlobEncryptedBytes(input.encryptedBytes);\n const context = await prepareDocumentAttachmentBlobDecryption({\n ...input,\n encrypted,\n });\n const header = readWriteHeader(\n input.binding.writeHeader,\n \"Attachment blob write header\",\n );\n const ciphertextHash = bytesToHex(\n new Uint8Array(\n await crypto.subtle.digest(\n \"SHA-256\",\n asWebCryptoBytes(input.encryptedBytes),\n ),\n ),\n );\n if (header.ciphertextHash !== ciphertextHash)\n throw new Error(\"Attachment blob write header does not match ciphertext\");\n const bytes = await decryptBlobChunks({\n ...context,\n encrypted,\n expectedBlobId: input.binding.blobId,\n });\n return { bytes, contentKey: context.contentKey };\n}\n\nexport async function decryptDocumentAttachmentBlob(\n input: DecryptDocumentAttachmentBlobInput,\n): Promise<BlobBytes> {\n return (await decryptDocumentAttachmentBlobWithKey(input)).bytes;\n}\n\nfunction assertStringSetEquals(input: {\n readonly actual: readonly string[];\n readonly expected: readonly string[];\n readonly label: string;\n}): void {\n const actual = uniqueSortedStrings(input.actual);\n const expected = uniqueSortedStrings(input.expected);\n if (\n actual.length !== expected.length ||\n actual.some((value, index) => value !== expected[index])\n ) {\n throw new Error(`${input.label} is inconsistent`);\n }\n}\n\nasync function verifiedBlobKekTargetsForBinding(input: {\n readonly binding: DecryptDocumentAttachmentBlobInput[\"binding\"];\n readonly requireBindingMembership: boolean;\n readonly projection: BlobKekTargetsResponse | undefined;\n}) {\n const { binding, projection } = input;\n if (!projection) {\n throw new Error(\"Attachment binding lacks blob KEK verification material\");\n }\n const targets = sortBlobTargets(\n projection.targets.map((target, index) =>\n readBlobKekTarget(target, `Attachment blob KEK target[${index}]`),\n ),\n );\n const targetHash = await computeBlobContentKeyTargetHash(targets);\n if (\n targetHash !== projection.blobKeyTargetHash ||\n projection.blobId !== binding.blobId\n ) {\n throw new Error(\"Attachment blob KEK target hash is inconsistent\");\n }\n if (\n input.requireBindingMembership &&\n (!projection.activeBindingIds.includes(binding.bindingId) ||\n !targets.some(\n (target) =>\n target.bindingId === binding.bindingId &&\n target.documentId === attachmentBindingDocumentId(binding),\n ))\n ) {\n throw new Error(\"Attachment binding is absent from blob KEK targets\");\n }\n assertStringSetEquals({\n actual: projection.linkedContainerManifestHashes,\n expected: targets.map((target) => target.containerManifestHash),\n label: \"Attachment blob container manifests\",\n });\n assertStringSetEquals({\n actual: projection.linkedContainerKeyEpochIds,\n expected: targets.map((target) => target.containerKeyEpochId),\n label: \"Attachment blob container KEKs\",\n });\n const accessManifestHash = await computeBlobAccessManifestHash({\n version: 1,\n blobId: projection.blobId,\n organizationId: projection.organizationId,\n activeBindingIds: projection.activeBindingIds,\n documentManifestHashes: projection.documentManifestHashes,\n linkedContainerManifestHashes: projection.linkedContainerManifestHashes,\n linkedContainerKeyEpochIds: projection.linkedContainerKeyEpochIds,\n blobKeyTargetHash: projection.blobKeyTargetHash,\n });\n if (accessManifestHash !== projection.blobAccessManifestHash) {\n throw new Error(\"Attachment blob access manifest hash is inconsistent\");\n }\n return makeVerifiedBlobKekTargets({ ...projection, targets });\n}\n\nfunction attachmentBindingDocumentId(\n binding: DecryptDocumentAttachmentBlobInput[\"binding\"],\n): string {\n if (!binding.bindingEvent) {\n throw new Error(\"Attachment binding lacks a signed event\");\n }\n return readRecordString(\n readCanonicalRecord(\n binding.bindingEvent.body,\n \"Attachment binding event body\",\n ),\n \"documentId\",\n \"Attachment binding event body\",\n );\n}\n\nasync function assertBlobWriteHeaderVerified(input: {\n readonly authorization: DocumentWriterProjectionAuthorization | undefined;\n readonly binding: DecryptDocumentAttachmentBlobInput[\"binding\"];\n readonly encrypted: BlobEncryptedBytesHeader;\n readonly organizationId: string;\n readonly resolveProjectionUserKey: ReturnType<\n typeof requireProjectionUserKeyResolver\n >;\n}): Promise<void> {\n if (!input.authorization || !input.binding.writeHeader) {\n throw new Error(\"Attachment blob lacks verified write authority\");\n }\n const header = readWriteHeader(\n input.binding.writeHeader,\n \"Attachment blob write header\",\n );\n const writer = await input.resolveProjectionUserKey(header.writerUserId);\n if (!writer) {\n throw new Error(\"Attachment blob writer identity is unavailable\");\n }\n await verifiedBlobKekTargetsForBinding({\n binding: input.binding,\n projection: input.binding.blobKekTargets,\n requireBindingMembership: true,\n });\n const blobKekTargets = await verifiedBlobKekTargetsForBinding({\n binding: input.binding,\n projection: input.binding.writeAuthorization,\n // The signed binding proves which slot exposes the blob now. Writer\n // authorization describes the older target set committed when the bytes\n // were written, so a later valid binding need not appear in that set.\n requireBindingMembership: false,\n });\n if (\n header.metadataHash !== input.encrypted.metadataHash ||\n header.contentKeyEpoch !== input.encrypted.contentKeyEpoch ||\n header.contentRecordId !== input.encrypted.contentRecordId ||\n header.nonceDomainHash !== input.encrypted.nonceDomainHash\n ) {\n throw new Error(\"Attachment blob write header does not match ciphertext\");\n }\n const verified = await verifyWriteHeader({\n authorizationMembership: \"referenced\",\n blobAuthorization: {\n authorizingContainerPaths: resolveEventContainerPaths({\n containerPathByManifestHash:\n input.authorization.containerPathByManifestHash,\n dependencyManifestHashes: header.dependencyManifestHashes,\n }).dependencyContainerPaths,\n blobKekTargets,\n principalPolicies: input.authorization.principalPolicies,\n },\n expectedAccessManifestHash: blobKekTargets.blobAccessManifestHash,\n expectedObject: {\n objectKind: \"blob\",\n objectId: input.binding.blobId,\n organizationId: input.organizationId,\n },\n expectedTargetHash: blobKekTargets.blobKeyTargetHash,\n header,\n writerPublicKey: writer.signingPublicKey,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"decrypt.js","sourceRoot":"","sources":["decrypt.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n blobContentMetadataHash,\n bytesToHex,\n CONTENT_RECORD_ENCRYPTION_SUITE,\n computeBlobAccessManifestHash,\n computeBlobContentKeyTargetHash,\n computeContentRecordNonceDomainHash,\n makeVerifiedBlobKekTargets,\n verifyWriteHeader,\n} from \"@tearleads/crypto\";\nimport type { BlobKekTargetsResponse } from \"@tearleads/validators/response\";\nimport { deriveBlobContentRecordKey } from \"../../../data/blobs/attachments/crypto\";\nimport { unwrapBlobContentKey } from \"../../../data/blobs/attachments/projection\";\nimport {\n parseBlobEncryptedBytes,\n readBlobKekTarget,\n readDocumentManifestIdentity,\n sortBlobTargets,\n} from \"../../../data/blobs/attachments/readers\";\nimport { assertBlobContentKeyBundleTargetHash } from \"../../../data/blobs/attachments/responses\";\nimport type {\n BlobEncryptedBytesHeader,\n DecryptDocumentAttachmentBlobInput,\n} from \"../../../data/blobs/attachments/types\";\nimport type { BlobBytes } from \"../../../data/blobs/blobContracts\";\nimport { importContentKeyMaterial } from \"../../../data/documents/shared/contentRecordKeys\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport {\n asWebCryptoBytes,\n readWriteHeader,\n uniqueSortedStrings,\n} from \"../../../data/documents/shared/readers\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\nimport type { DocumentWriterProjectionAuthorization } from \"../../../data/keyingProjectionVerification\";\nimport {\n readRecordString,\n requireProjectionUserKeyResolver,\n resolveEventContainerPaths,\n} from \"../../../data/keyingProjectionVerification\";\n\nimport { assertAttachmentBindingVerified } from \"../verification/attachmentBindingVerification\";\nimport { assertBlobWrapScopeVerified } from \"../verification/verifiedWrapScope\";\nimport { decryptBlobChunks } from \"./blobChunkDecryption\";\n\nasync function assertBlobEncryptionMetadata(input: {\n readonly contentKeyBundle: DecryptDocumentAttachmentBlobInput[\"binding\"][\"contentKeyBundle\"];\n readonly encrypted: BlobEncryptedBytesHeader;\n readonly expectedBlobId: string;\n readonly organizationId: string;\n}): Promise<void> {\n const { contentKeyBundle, encrypted, expectedBlobId, organizationId } = input;\n if (\n encrypted.blobId !== expectedBlobId ||\n encrypted.contentRecordId !== expectedBlobId\n ) {\n throw new Error(\"Blob encrypted bytes blob id mismatch\");\n }\n if (\n encrypted.contentKeyEpoch !== contentKeyBundle.contentKeyEpoch ||\n contentKeyBundle.blobId !== expectedBlobId\n ) {\n throw new Error(\"Blob encrypted bytes content-key bundle mismatch\");\n }\n await assertBlobContentKeyBundleTargetHash(contentKeyBundle);\n\n const expectedNonceDomainHash = await computeContentRecordNonceDomainHash({\n version: 1,\n organizationId,\n objectKind: \"blob\",\n objectId: expectedBlobId,\n contentKeyEpoch: encrypted.contentKeyEpoch,\n encryptionSuite: CONTENT_RECORD_ENCRYPTION_SUITE,\n contentRecordId: encrypted.contentRecordId,\n });\n if (encrypted.nonceDomainHash !== expectedNonceDomainHash) {\n throw new Error(\"Blob encrypted bytes nonce domain mismatch\");\n }\n const expectedMetadataHash = await blobContentMetadataHash({\n blobId: expectedBlobId,\n byteLength: encrypted.byteLength,\n chunkCount: encrypted.chunkCount,\n chunkSize: encrypted.chunkSize,\n contentKeyEpoch: encrypted.contentKeyEpoch,\n });\n if (encrypted.metadataHash !== expectedMetadataHash) {\n throw new Error(\"Blob encrypted bytes metadata hash mismatch\");\n }\n}\n\nexport type AttachmentBlobDecryptionInput = Omit<\n DecryptDocumentAttachmentBlobInput,\n \"encryptedBytes\"\n> & {\n encrypted: BlobEncryptedBytesHeader;\n};\n\n/** Verifies metadata and authority; the caller must still authenticate ciphertext. */\nexport async function prepareDocumentAttachmentBlobDecryption({\n binding,\n encrypted,\n expectedDocumentId,\n expectedSlotId,\n execSql,\n resolveProjectionUserKey,\n targetSecretKey,\n stillCurrent,\n warmReferencedPrincipalPolicies,\n writerProjection,\n}: AttachmentBlobDecryptionInput): Promise<{\n contentKey: Uint8Array;\n recordKey: CryptoKey;\n organizationId: string;\n}> {\n const requiredResolveProjectionUserKey = requireProjectionUserKeyResolver(\n resolveProjectionUserKey,\n \"Document attachment blob decrypt\",\n );\n const verificationOptions = projectionVerificationOptions({\n execSql,\n stillCurrent,\n warmReferencedPrincipalPolicies,\n resolveProjectionUserKey: requiredResolveProjectionUserKey,\n });\n let documentAuthorization: DocumentWriterProjectionAuthorization | undefined;\n await assertDocumentWriterProjectionConsistent(writerProjection, {\n allowStaleContentKeyBundle: true,\n execSql,\n onVerifiedAuthorization: (authorization) => {\n documentAuthorization = authorization;\n },\n ...verificationOptions,\n });\n const { documentId, organizationId } =\n readDocumentManifestIdentity(writerProjection);\n await assertBlobEncryptionMetadata({\n contentKeyBundle: binding.contentKeyBundle,\n encrypted,\n expectedBlobId: binding.blobId,\n organizationId,\n });\n await assertAttachmentBindingVerified({\n authorization: documentAuthorization,\n binding,\n expectedDocumentId,\n expectedSlotId,\n resolveProjectionUserKey: requiredResolveProjectionUserKey,\n });\n await assertBlobWriteHeaderVerified({\n authorization: documentAuthorization,\n binding,\n encrypted,\n organizationId,\n resolveProjectionUserKey: requiredResolveProjectionUserKey,\n });\n\n if (!documentAuthorization)\n throw new Error(\"Blob document authorization is unavailable\");\n assertBlobWrapScopeVerified({\n authorization: documentAuthorization,\n binding,\n documentId,\n });\n const contentKey = await unwrapBlobContentKey({\n blobId: binding.blobId,\n contentKeyBundle: binding.contentKeyBundle,\n documentId,\n encrypted,\n execSql,\n expectedBindingId: binding.bindingId,\n secretKey: targetSecretKey,\n ...verificationOptions,\n writerProjection,\n });\n const contentKeyMaterial = await importContentKeyMaterial(contentKey);\n const recordKey = await deriveBlobContentRecordKey({\n blobId: binding.blobId,\n contentKeyEpoch: encrypted.contentKeyEpoch,\n contentKeyMaterial,\n contentRecordId: encrypted.contentRecordId,\n organizationId,\n usage: \"decrypt\",\n });\n return { contentKey, recordKey, organizationId };\n}\n\nasync function decryptDocumentAttachmentBlobWithKey(\n input: DecryptDocumentAttachmentBlobInput,\n): Promise<{ bytes: BlobBytes; contentKey: Uint8Array }> {\n const encrypted = parseBlobEncryptedBytes(input.encryptedBytes);\n const context = await prepareDocumentAttachmentBlobDecryption({\n ...input,\n encrypted,\n });\n const header = readWriteHeader(\n input.binding.writeHeader,\n \"Attachment blob write header\",\n );\n const ciphertextHash = bytesToHex(\n new Uint8Array(\n await crypto.subtle.digest(\n \"SHA-256\",\n asWebCryptoBytes(input.encryptedBytes),\n ),\n ),\n );\n if (header.ciphertextHash !== ciphertextHash)\n throw new Error(\"Attachment blob write header does not match ciphertext\");\n const bytes = await decryptBlobChunks({\n ...context,\n encrypted,\n expectedBlobId: input.binding.blobId,\n });\n return { bytes, contentKey: context.contentKey };\n}\n\nexport async function decryptDocumentAttachmentBlob(\n input: DecryptDocumentAttachmentBlobInput,\n): Promise<BlobBytes> {\n return (await decryptDocumentAttachmentBlobWithKey(input)).bytes;\n}\n\nfunction assertStringSetEquals(input: {\n readonly actual: readonly string[];\n readonly expected: readonly string[];\n readonly label: string;\n}): void {\n const actual = uniqueSortedStrings(input.actual);\n const expected = uniqueSortedStrings(input.expected);\n if (\n actual.length !== expected.length ||\n actual.some((value, index) => value !== expected[index])\n ) {\n throw new Error(`${input.label} is inconsistent`);\n }\n}\n\nasync function verifiedBlobKekTargetsForBinding(input: {\n readonly binding: DecryptDocumentAttachmentBlobInput[\"binding\"];\n readonly requireBindingMembership: boolean;\n readonly projection: BlobKekTargetsResponse | undefined;\n}) {\n const { binding, projection } = input;\n if (!projection) {\n throw new Error(\"Attachment binding lacks blob KEK verification material\");\n }\n const targets = sortBlobTargets(\n projection.targets.map((target, index) =>\n readBlobKekTarget(target, `Attachment blob KEK target[${index}]`),\n ),\n );\n const targetHash = await computeBlobContentKeyTargetHash(targets);\n if (\n targetHash !== projection.blobKeyTargetHash ||\n projection.blobId !== binding.blobId\n ) {\n throw new Error(\"Attachment blob KEK target hash is inconsistent\");\n }\n if (\n input.requireBindingMembership &&\n (!projection.activeBindingIds.includes(binding.bindingId) ||\n !targets.some(\n (target) =>\n target.bindingId === binding.bindingId &&\n target.documentId === attachmentBindingDocumentId(binding),\n ))\n ) {\n throw new Error(\"Attachment binding is absent from blob KEK targets\");\n }\n assertStringSetEquals({\n actual: projection.linkedContainerManifestHashes,\n expected: targets.map((target) => target.containerManifestHash),\n label: \"Attachment blob container manifests\",\n });\n assertStringSetEquals({\n actual: projection.linkedContainerKeyEpochIds,\n expected: targets.map((target) => target.containerKeyEpochId),\n label: \"Attachment blob container KEKs\",\n });\n const accessManifestHash = await computeBlobAccessManifestHash({\n version: 1,\n blobId: projection.blobId,\n organizationId: projection.organizationId,\n activeBindingIds: projection.activeBindingIds,\n documentManifestHashes: projection.documentManifestHashes,\n linkedContainerManifestHashes: projection.linkedContainerManifestHashes,\n linkedContainerKeyEpochIds: projection.linkedContainerKeyEpochIds,\n blobKeyTargetHash: projection.blobKeyTargetHash,\n });\n if (accessManifestHash !== projection.blobAccessManifestHash) {\n throw new Error(\"Attachment blob access manifest hash is inconsistent\");\n }\n return makeVerifiedBlobKekTargets({ ...projection, targets });\n}\n\nfunction attachmentBindingDocumentId(\n binding: DecryptDocumentAttachmentBlobInput[\"binding\"],\n): string {\n if (!binding.bindingEvent) {\n throw new Error(\"Attachment binding lacks a signed event\");\n }\n return readRecordString(\n readCanonicalRecord(\n binding.bindingEvent.body,\n \"Attachment binding event body\",\n ),\n \"documentId\",\n \"Attachment binding event body\",\n );\n}\n\nasync function assertBlobWriteHeaderVerified(input: {\n readonly authorization: DocumentWriterProjectionAuthorization | undefined;\n readonly binding: DecryptDocumentAttachmentBlobInput[\"binding\"];\n readonly encrypted: BlobEncryptedBytesHeader;\n readonly organizationId: string;\n readonly resolveProjectionUserKey: ReturnType<\n typeof requireProjectionUserKeyResolver\n >;\n}): Promise<void> {\n if (!input.authorization || !input.binding.writeHeader) {\n throw new Error(\"Attachment blob lacks verified write authority\");\n }\n const header = readWriteHeader(\n input.binding.writeHeader,\n \"Attachment blob write header\",\n );\n const writer = await input.resolveProjectionUserKey(header.writerUserId);\n if (!writer) {\n throw new Error(\"Attachment blob writer identity is unavailable\");\n }\n await verifiedBlobKekTargetsForBinding({\n binding: input.binding,\n projection: input.binding.blobKekTargets,\n requireBindingMembership: true,\n });\n const blobKekTargets = await verifiedBlobKekTargetsForBinding({\n binding: input.binding,\n projection: input.binding.writeAuthorization,\n // The signed binding proves which slot exposes the blob now. Writer\n // authorization describes the older target set committed when the bytes\n // were written, so a later valid binding need not appear in that set.\n requireBindingMembership: false,\n });\n if (\n header.metadataHash !== input.encrypted.metadataHash ||\n header.contentKeyEpoch !== input.encrypted.contentKeyEpoch ||\n header.contentRecordId !== input.encrypted.contentRecordId ||\n header.nonceDomainHash !== input.encrypted.nonceDomainHash\n ) {\n throw new Error(\"Attachment blob write header does not match ciphertext\");\n }\n const verified = await verifyWriteHeader({\n authorizationMembership: \"referenced\",\n blobAuthorization: {\n authorizingContainerPaths: resolveEventContainerPaths({\n containerPathByManifestHash:\n input.authorization.containerPathByManifestHash,\n dependencyManifestHashes: header.dependencyManifestHashes,\n }).dependencyContainerPaths,\n blobKekTargets,\n principalPolicies: input.authorization.principalPolicies,\n },\n expectedAccessManifestHash: blobKekTargets.blobAccessManifestHash,\n expectedObject: {\n objectKind: \"blob\",\n objectId: input.binding.blobId,\n organizationId: input.organizationId,\n },\n expectedTargetHash: blobKekTargets.blobKeyTargetHash,\n header,\n writerPublicKey: writer.signingPublicKey,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BlobBytesResponse, RequestResultOptions } from "../../../internal/api-client/index.js";
|
|
2
2
|
import type { BlobAttachmentSummary, DocumentWriterProjectionResponse, ListDocumentAttachmentsResponse } from "../../../internal/validators/response/index.js";
|
|
3
3
|
import type { BlobBytes } from "../../../data/blobs/blobContracts.js";
|
|
4
|
-
import type { DocumentAttachment } from "../../../data/documents/
|
|
4
|
+
import type { DocumentAttachment } from "../../../data/documents/index.js";
|
|
5
5
|
import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../../data/keyingProjectionVerification/index.js";
|
|
6
6
|
import type { SecurityIncidentReporter } from "../../../data/shared/securityIncidents.js";
|
|
7
7
|
import type { ExecSql } from "../../../data/sqlite/sqlSchema.js";
|