@tearleads/client-sdk 0.1.58 → 0.1.59

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.
Files changed (380) hide show
  1. package/Tearleads.d.ts +2 -2
  2. package/Tearleads.js +1 -1
  3. package/Tearleads.js.map +1 -1
  4. package/client/blobs.d.ts +1 -1
  5. package/client/blobs.js.map +1 -1
  6. package/client/deviceFirst.js.map +1 -1
  7. package/client/identity.js +1 -1
  8. package/client/identity.js.map +1 -1
  9. package/client/index.d.ts +1 -1
  10. package/client/index.js +1 -1
  11. package/client/index.js.map +1 -1
  12. package/client/organizations/organizationAccessRestoration.js.map +1 -1
  13. package/client/organizations/organizationDataUsage.js.map +1 -1
  14. package/client/organizations/organizationGroupNameHydration.js.map +1 -1
  15. package/client/organizations/organizationMetadataProfileSync.js +1 -1
  16. package/client/organizations/organizationMetadataProfileSync.js.map +1 -1
  17. package/client/organizations/organizationReadModels.js.map +1 -1
  18. package/client/organizations/organizationWorkflowRuntime.js.map +1 -1
  19. package/client/rootContainerAdoption.js.map +1 -1
  20. package/client/securityIncidents.d.ts +1 -1
  21. package/client/securityIncidents.js.map +1 -1
  22. package/client/session/sessionLoginRefusal.js.map +1 -1
  23. package/client/session/sessionRootAuthority.js.map +1 -1
  24. package/client/session/sessionTypes.d.ts +1 -1
  25. package/client/session/sessionTypes.js.map +1 -1
  26. package/client/userIdentities.d.ts +1 -1
  27. package/client/userIdentities.js.map +1 -1
  28. package/client/workflowRuntime.d.ts +2 -2
  29. package/client/workflowRuntime.js.map +1 -1
  30. package/data/blobs/createBlobStore.d.ts +1 -1
  31. package/data/blobs/createBlobStore.js.map +1 -1
  32. package/data/blobs/encryptedBlobByteSource.js +1 -1
  33. package/data/blobs/encryptedBlobByteSource.js.map +1 -1
  34. package/data/blobs/encryptedBlobEnvelope.d.ts +1 -1
  35. package/data/blobs/encryptedBlobEnvelope.js +2 -2
  36. package/data/blobs/encryptedBlobEnvelope.js.map +1 -1
  37. package/data/blobs/encryptedBlobStore.d.ts +1 -1
  38. package/data/blobs/encryptedBlobStore.js +1 -1
  39. package/data/blobs/encryptedBlobStore.js.map +1 -1
  40. package/data/blobs/memoryBlobStore.d.ts +1 -1
  41. package/data/blobs/memoryBlobStore.js +1 -1
  42. package/data/blobs/memoryBlobStore.js.map +1 -1
  43. package/data/blobs/opfsBlobStore.d.ts +1 -1
  44. package/data/blobs/opfsBlobStore.js +1 -1
  45. package/data/blobs/opfsBlobStore.js.map +1 -1
  46. package/data/containers/containerMetadataDocument.js +1 -1
  47. package/data/containers/containerMetadataDocument.js.map +1 -1
  48. package/data/containers/shared/events.js +1 -1
  49. package/data/containers/shared/events.js.map +1 -1
  50. package/data/containers/shared/heldContainerHeads.js +1 -1
  51. package/data/containers/shared/heldContainerHeads.js.map +1 -1
  52. package/data/containers/shared/mutationAcknowledgement.js +1 -1
  53. package/data/containers/shared/mutationAcknowledgement.js.map +1 -1
  54. package/data/containers/shared/principalPolicies.js +1 -1
  55. package/data/containers/shared/principalPolicies.js.map +1 -1
  56. package/data/containers/shared/readers.js +2 -2
  57. package/data/containers/shared/readers.js.map +1 -1
  58. package/data/documents/attachmentContentIdentity.js +1 -1
  59. package/data/documents/attachmentContentIdentity.js.map +1 -1
  60. package/data/documents/blob/shared/blobEnvelopeStream.js.map +1 -1
  61. package/data/documents/blob/shared/blobSourceSnapshot.d.ts +1 -1
  62. package/data/documents/blob/shared/blobSourceSnapshot.js.map +1 -1
  63. package/data/documents/blob/shared/chunkedBlobCrypto.js.map +1 -1
  64. package/data/documents/blob/shared/encryptedUploadParts.js.map +1 -1
  65. package/data/documents/blob/shared/events.js +1 -1
  66. package/data/documents/blob/shared/events.js.map +1 -1
  67. package/data/documents/blob/shared/types.d.ts +2 -2
  68. package/data/documents/blob/shared/types.js.map +1 -1
  69. package/data/documents/shared/containerKekPathHistory.js +1 -1
  70. package/data/documents/shared/containerKekPathHistory.js.map +1 -1
  71. package/data/documents/shared/containerKekPathVerification.d.ts +1 -1
  72. package/data/documents/shared/containerKekPathVerification.js +1 -1
  73. package/data/documents/shared/events.js +1 -1
  74. package/data/documents/shared/events.js.map +1 -1
  75. package/data/documents/shared/manifestBundleReaders.js +2 -2
  76. package/data/documents/shared/manifestBundleReaders.js.map +1 -1
  77. package/data/documents/shared/projection.d.ts +1 -1
  78. package/data/documents/shared/projection.js +2 -2
  79. package/data/documents/shared/projection.js.map +1 -1
  80. package/data/documents/shared/projectionContentKeys.d.ts +1 -1
  81. package/data/documents/shared/readers.js +3 -3
  82. package/data/documents/shared/readers.js.map +1 -1
  83. package/data/documents/shared/stableDocumentId.js +1 -1
  84. package/data/documents/shared/stableDocumentId.js.map +1 -1
  85. package/data/documents/shared/types.d.ts +1 -1
  86. package/data/documents/shared/types.js +1 -1
  87. package/data/{keyingCanonicalJson.js → keying/canonicalJson.js} +3 -3
  88. package/data/keying/canonicalJson.js.map +1 -0
  89. package/data/keyingProjectionVerification/bundleVerification.js +1 -1
  90. package/data/keyingProjectionVerification/bundleVerification.js.map +1 -1
  91. package/data/keyingProjectionVerification/containerAncestorCitations.js +1 -1
  92. package/data/keyingProjectionVerification/containerAncestorCitations.js.map +1 -1
  93. package/data/keyingProjectionVerification/containerManifestVerification.js +1 -1
  94. package/data/keyingProjectionVerification/containerManifestVerification.js.map +1 -1
  95. package/data/keyingProjectionVerification/documentManifestVerification.js +1 -1
  96. package/data/keyingProjectionVerification/documentManifestVerification.js.map +1 -1
  97. package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js +1 -1
  98. package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js.map +1 -1
  99. package/data/keyingProjectionVerification/error.js +1 -1
  100. package/data/keyingProjectionVerification/error.js.map +1 -1
  101. package/data/keyingProjectionVerification/index.d.ts +9 -0
  102. package/data/{keyingProjectionVerification.js → keyingProjectionVerification/index.js} +8 -8
  103. package/data/keyingProjectionVerification/index.js.map +1 -0
  104. package/data/keyingProjectionVerification/principalPolicyCache.js +1 -1
  105. package/data/keyingProjectionVerification/principalPolicyCache.js.map +1 -1
  106. package/data/keyingProjectionVerification/principalPolicyVerification.js +1 -1
  107. package/data/keyingProjectionVerification/principalPolicyVerification.js.map +1 -1
  108. package/data/keyingProjectionVerification/readers.d.ts +1 -1
  109. package/data/keyingProjectionVerification/readers.js +3 -3
  110. package/data/keyingProjectionVerification/readers.js.map +1 -1
  111. package/data/keyingProjectionVerification/userKeyResolver.d.ts +1 -1
  112. package/data/keyingProjectionVerification/userKeyResolver.js.map +1 -1
  113. package/data/persistence/containers/containerPersistence.js +1 -1
  114. package/data/persistence/containers/containerPersistence.js.map +1 -1
  115. package/data/persistence/documents/documentDiscoveryCandidate.js +1 -1
  116. package/data/persistence/documents/documentDiscoveryCandidate.js.map +1 -1
  117. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +1 -1
  118. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  119. package/data/persistence/documents/internal/documentProjectionRows.js +1 -1
  120. package/data/persistence/documents/internal/documentProjectionRows.js.map +1 -1
  121. package/data/persistence/documents/internal/documentRows.js +1 -1
  122. package/data/persistence/documents/internal/documentRows.js.map +1 -1
  123. package/data/persistence/principalPolicyBundleIntegrity.js +1 -1
  124. package/data/persistence/principalPolicyBundleIntegrity.js.map +1 -1
  125. package/data/persistence/principalPolicyReferenceCheckpoint.js +1 -1
  126. package/data/persistence/principalPolicyReferenceCheckpoint.js.map +1 -1
  127. package/data/persistence/principalPolicyReferenceIndexPersistence.js +1 -1
  128. package/data/persistence/principalPolicyReferenceIndexPersistence.js.map +1 -1
  129. package/data/persistence/principalPolicyReferencePersistence.js +1 -1
  130. package/data/persistence/principalPolicyReferencePersistence.js.map +1 -1
  131. package/data/persistence/securityIncidentPersistence.js.map +1 -1
  132. package/data/persistence/verifiedPrincipalPolicyBundle.js +1 -1
  133. package/data/persistence/verifiedPrincipalPolicyBundle.js.map +1 -1
  134. package/data/persistence/verifiedPrincipalPolicyCurrent.js +1 -1
  135. package/data/persistence/verifiedPrincipalPolicyCurrent.js.map +1 -1
  136. package/data/principals/principalMutationJournal.js +1 -1
  137. package/data/principals/principalMutationJournal.js.map +1 -1
  138. package/data/{securityIncidents.d.ts → shared/securityIncidents.d.ts} +1 -1
  139. package/data/sqlite/documentRecordPersistence.js +1 -1
  140. package/data/sqlite/documentRecordPersistence.js.map +1 -1
  141. package/data/sync/crdtPeerSeed.d.ts +18 -0
  142. package/data/sync/originatedDocuments.d.ts +1 -1
  143. package/data/sync/originatedDocuments.js.map +1 -1
  144. package/data/sync/syncCoordinator.d.ts +1 -1
  145. package/data/sync/syncCoordinator.js.map +1 -1
  146. package/package.json +1 -1
  147. package/stores/container-contents/backgroundHydration.js +1 -1
  148. package/stores/container-contents/backgroundHydration.js.map +1 -1
  149. package/stores/container-contents/containerContentsStore.d.ts +1 -1
  150. package/stores/container-contents/containerContentsStore.js.map +1 -1
  151. package/stores/container-contents/localRefresh.js +1 -1
  152. package/stores/container-contents/localRefresh.js.map +1 -1
  153. package/stores/container-contents/remoteContainerIngestion.js +1 -1
  154. package/stores/container-contents/remoteContainerIngestion.js.map +1 -1
  155. package/stores/container-contents/remoteWriteQueue.js +1 -1
  156. package/stores/container-contents/remoteWriteQueue.js.map +1 -1
  157. package/stores/container-contents/systemContainerHydration.js +1 -1
  158. package/stores/container-contents/systemContainerHydration.js.map +1 -1
  159. package/stores/container-contents/utils.js +1 -1
  160. package/stores/container-contents/utils.js.map +1 -1
  161. package/stores/documents/documentStore/attachmentIntents.js +1 -1
  162. package/stores/documents/documentStore/attachmentIntents.js.map +1 -1
  163. package/stores/documents/documentStore/attachmentSourceUpload.js.map +1 -1
  164. package/stores/documents/documentStore/attachmentStaging.js +1 -1
  165. package/stores/documents/documentStore/attachmentStaging.js.map +1 -1
  166. package/stores/documents/documentStore/attachmentUploadLane.js.map +1 -1
  167. package/stores/documents/documentStore/persistence.js +2 -2
  168. package/stores/documents/documentStore/persistence.js.map +1 -1
  169. package/stores/documents/documentStore/state.js +1 -1
  170. package/stores/documents/documentStore/state.js.map +1 -1
  171. package/stores/documents/documentStore/storedDocument.js +1 -1
  172. package/stores/documents/documentStore/storedDocument.js.map +1 -1
  173. package/stores/documents/documentStore/syncAttachments.js.map +1 -1
  174. package/stores/documents/documentStore.d.ts +1 -1
  175. package/stores/documents/documentStore.js.map +1 -1
  176. package/stores/documents/registry.d.ts +1 -1
  177. package/stores/documents/registry.js.map +1 -1
  178. package/stores/documents/types.d.ts +1 -1
  179. package/stores/documents/types.js.map +1 -1
  180. package/stores/local-projection/registry.d.ts +1 -1
  181. package/stores/local-projection/registry.js.map +1 -1
  182. package/sync/reconciliation/serviceTypes.d.ts +1 -1
  183. package/sync/reconciliation/serviceTypes.js.map +1 -1
  184. package/sync/reconciliation/triggers.d.ts +1 -1
  185. package/sync/reconciliation/triggers.js.map +1 -1
  186. package/workflows/blobs/attachmentBindingVerification.js +2 -2
  187. package/workflows/blobs/attachmentBindingVerification.js.map +1 -1
  188. package/workflows/blobs/blobChunkDecryption.js.map +1 -1
  189. package/workflows/blobs/decrypt.d.ts +1 -1
  190. package/workflows/blobs/decrypt.js +2 -2
  191. package/workflows/blobs/decrypt.js.map +1 -1
  192. package/workflows/blobs/detach.js +2 -2
  193. package/workflows/blobs/detach.js.map +1 -1
  194. package/workflows/blobs/hydrate.d.ts +3 -3
  195. package/workflows/blobs/hydrate.js +1 -1
  196. package/workflows/blobs/hydrate.js.map +1 -1
  197. package/workflows/blobs/hydrationResults.js.map +1 -1
  198. package/workflows/blobs/index.d.ts +2 -2
  199. package/workflows/blobs/index.js +1 -1
  200. package/workflows/blobs/index.js.map +1 -1
  201. package/workflows/blobs/multipartFirstParts.js.map +1 -1
  202. package/workflows/blobs/retainedAttachmentVerification.js +1 -1
  203. package/workflows/blobs/upload.js +3 -3
  204. package/workflows/blobs/upload.js.map +1 -1
  205. package/workflows/container-contents/container-state/createAdoption.js +1 -1
  206. package/workflows/container-contents/container-state/createAdoption.js.map +1 -1
  207. package/workflows/container-contents/container-state/createChild.js +1 -1
  208. package/workflows/container-contents/container-state/createChild.js.map +1 -1
  209. package/workflows/container-contents/container-state/createIntentSync.js +1 -1
  210. package/workflows/container-contents/container-state/createIntentSync.js.map +1 -1
  211. package/workflows/container-contents/container-state/groupGrantVerification.js +1 -1
  212. package/workflows/container-contents/container-state/moveIntentSync.js +1 -1
  213. package/workflows/container-contents/container-state/moveIntentSync.js.map +1 -1
  214. package/workflows/container-contents/container-state/purgeTreeScope.js +1 -1
  215. package/workflows/container-contents/container-state/purgeTreeScope.js.map +1 -1
  216. package/workflows/container-contents/container-state/share.js +1 -1
  217. package/workflows/container-contents/documentDiscoveryInputs.js +1 -1
  218. package/workflows/container-contents/documentDiscoveryInputs.js.map +1 -1
  219. package/workflows/container-contents/documentInfo.d.ts +1 -1
  220. package/workflows/container-contents/documentInfo.js.map +1 -1
  221. package/workflows/container-contents/documentLinks.d.ts +1 -1
  222. package/workflows/container-contents/documentLinks.js +1 -1
  223. package/workflows/container-contents/documentLinks.js.map +1 -1
  224. package/workflows/container-contents/documentMoveIntentSync.js +1 -1
  225. package/workflows/container-contents/documentMoveIntentSync.js.map +1 -1
  226. package/workflows/container-contents/documentPurge.d.ts +1 -1
  227. package/workflows/container-contents/documentPurge.js +1 -1
  228. package/workflows/container-contents/documentPurge.js.map +1 -1
  229. package/workflows/container-contents/documentQueries/rows.js +1 -1
  230. package/workflows/container-contents/documentQueries/rows.js.map +1 -1
  231. package/workflows/container-contents/metadata.d.ts +1 -1
  232. package/workflows/container-contents/metadataMutationPreparation.js +1 -1
  233. package/workflows/container-contents/metadataMutationPreparation.js.map +1 -1
  234. package/workflows/container-contents/metadataRemoteSync.d.ts +1 -1
  235. package/workflows/container-contents/metadataSyncErrors.js.map +1 -1
  236. package/workflows/container-contents/projectionKeys.d.ts +1 -1
  237. package/workflows/container-contents/syncLane.d.ts +1 -1
  238. package/workflows/container-contents/syncLane.js.map +1 -1
  239. package/workflows/containers/child/carriedDescendantRekeys.js +1 -1
  240. package/workflows/containers/child/create.d.ts +1 -1
  241. package/workflows/containers/child/create.js +2 -2
  242. package/workflows/containers/child/create.js.map +1 -1
  243. package/workflows/containers/child/createProjection.js +1 -1
  244. package/workflows/containers/child/createProjection.js.map +1 -1
  245. package/workflows/containers/child/createSubmission.d.ts +2 -2
  246. package/workflows/containers/child/createSubmission.js.map +1 -1
  247. package/workflows/containers/child/move.d.ts +2 -2
  248. package/workflows/containers/child/move.js +2 -2
  249. package/workflows/containers/child/move.js.map +1 -1
  250. package/workflows/containers/child/moveWraps.js +1 -1
  251. package/workflows/containers/child/mutationRequestCore.js +1 -1
  252. package/workflows/containers/child/mutationRequestCore.js.map +1 -1
  253. package/workflows/containers/child/mutationSubmit.js.map +1 -1
  254. package/workflows/containers/child/recite.js.map +1 -1
  255. package/workflows/containers/child/recitePlan.js +1 -1
  256. package/workflows/containers/child/recitePlan.js.map +1 -1
  257. package/workflows/containers/child/rekey.d.ts +1 -1
  258. package/workflows/containers/child/rekey.js +2 -2
  259. package/workflows/containers/child/rekey.js.map +1 -1
  260. package/workflows/containers/child/rekeyProjection.js +1 -1
  261. package/workflows/containers/child/rekeyProjection.js.map +1 -1
  262. package/workflows/containers/child/rekeyRemote.d.ts +2 -2
  263. package/workflows/containers/child/rekeyRemote.js.map +1 -1
  264. package/workflows/containers/child/revoke.d.ts +2 -2
  265. package/workflows/containers/child/revoke.js +2 -2
  266. package/workflows/containers/child/revoke.js.map +1 -1
  267. package/workflows/containers/child/rotationPrincipalPolicies.js +1 -1
  268. package/workflows/containers/child/runtimeCurrentGroupShare.js +1 -1
  269. package/workflows/containers/child/share.d.ts +2 -2
  270. package/workflows/containers/child/share.js +1 -1
  271. package/workflows/containers/child/share.js.map +1 -1
  272. package/workflows/containers/child/shareAncestorRepair.js.map +1 -1
  273. package/workflows/containers/child/shareMaterialization.d.ts +1 -1
  274. package/workflows/containers/child/sharePlanCore.d.ts +1 -1
  275. package/workflows/containers/child/sharePlanCore.js +1 -1
  276. package/workflows/containers/root/create.js +1 -1
  277. package/workflows/containers/root/create.js.map +1 -1
  278. package/workflows/containers/root/initialGroupPolicy.js +1 -1
  279. package/workflows/containers/root/initialGroupPolicy.js.map +1 -1
  280. package/workflows/documents/create.d.ts +1 -1
  281. package/workflows/documents/create.js +1 -1
  282. package/workflows/documents/documentMutationPreparation.js +1 -1
  283. package/workflows/documents/documentMutationPreparation.js.map +1 -1
  284. package/workflows/documents/historyContent.js +1 -1
  285. package/workflows/documents/historyContent.js.map +1 -1
  286. package/workflows/documents/linkSet.js +1 -1
  287. package/workflows/documents/linkSet.js.map +1 -1
  288. package/workflows/documents/linkSetAuthority.js +1 -1
  289. package/workflows/documents/linkSetBlobRewraps.js +2 -2
  290. package/workflows/documents/linkSetBlobRewraps.js.map +1 -1
  291. package/workflows/documents/linkSetRemote.d.ts +1 -1
  292. package/workflows/documents/linkSetRemote.js +1 -1
  293. package/workflows/documents/orphanBlobReclaims.js +1 -1
  294. package/workflows/documents/orphanBlobReclaims.js.map +1 -1
  295. package/workflows/documents/projectionKeys.d.ts +1 -1
  296. package/workflows/documents/purge.d.ts +1 -1
  297. package/workflows/documents/purge.js +2 -2
  298. package/workflows/documents/purge.js.map +1 -1
  299. package/workflows/documents/readOnlySync.d.ts +1 -1
  300. package/workflows/documents/readOnlySync.js +1 -1
  301. package/workflows/documents/readOnlySync.js.map +1 -1
  302. package/workflows/documents/sync.js +1 -1
  303. package/workflows/documents/syncContainerRekeyPreparation.js +1 -1
  304. package/workflows/documents/syncLane.d.ts +1 -1
  305. package/workflows/documents/syncLane.js.map +1 -1
  306. package/workflows/documents/syncPlanIdentity.js +1 -1
  307. package/workflows/documents/syncPlanIdentity.js.map +1 -1
  308. package/workflows/documents/syncRepairAccess.js +1 -1
  309. package/workflows/documents/syncSubmittedResult.js +1 -1
  310. package/workflows/organizations/authoredPrincipalPolicyWarmer.js +1 -1
  311. package/workflows/organizations/authoredPrincipalPolicyWarmer.js.map +1 -1
  312. package/workflows/organizations/containerGrantRevocation.d.ts +2 -2
  313. package/workflows/organizations/containerGrantRevocation.js.map +1 -1
  314. package/workflows/organizations/createCurrentOrganizationGroup.js.map +1 -1
  315. package/workflows/organizations/currentOrganizationGroupNames.js.map +1 -1
  316. package/workflows/organizations/currentPolicyMutationAcknowledgement.js +1 -1
  317. package/workflows/organizations/currentPolicyMutationAcknowledgement.js.map +1 -1
  318. package/workflows/organizations/groupCreation.d.ts +1 -1
  319. package/workflows/organizations/groupCreation.js.map +1 -1
  320. package/workflows/organizations/groupMetadataAccess.d.ts +1 -1
  321. package/workflows/organizations/groupMetadataContainerAuthority.js.map +1 -1
  322. package/workflows/organizations/groupMetadataRuntime.js.map +1 -1
  323. package/workflows/organizations/groupNameUniqueness.js.map +1 -1
  324. package/workflows/organizations/groupPolicyMutationAcknowledgement.js +1 -1
  325. package/workflows/organizations/groupPolicyMutationAcknowledgement.js.map +1 -1
  326. package/workflows/organizations/groupPolicyRequests.js.map +1 -1
  327. package/workflows/organizations/loadPolicyHistoryDetails.js.map +1 -1
  328. package/workflows/organizations/organizationGroupDirectory.js.map +1 -1
  329. package/workflows/organizations/organizationProfile.js +1 -1
  330. package/workflows/organizations/organizationProfile.js.map +1 -1
  331. package/workflows/organizations/policyHistoryCache.js.map +1 -1
  332. package/workflows/organizations/principalContainerRematerialization.js +1 -1
  333. package/workflows/organizations/principalContainerRematerializationPlanning.js.map +1 -1
  334. package/workflows/organizations/principalMutationJournalManagement.js +1 -1
  335. package/workflows/organizations/principalMutationJournalManagement.js.map +1 -1
  336. package/workflows/organizations/principalMutationReceipt.js +1 -1
  337. package/workflows/organizations/principalMutationReceipt.js.map +1 -1
  338. package/workflows/organizations/principalPolicy.d.ts +1 -1
  339. package/workflows/organizations/principalPolicy.js.map +1 -1
  340. package/workflows/organizations/principalPolicyReceiptArtifacts.js +1 -1
  341. package/workflows/organizations/principalPolicyReceiptArtifacts.js.map +1 -1
  342. package/workflows/organizations/rosterProfileContainer.js +1 -1
  343. package/workflows/organizations/rosterProfileContainer.js.map +1 -1
  344. package/workflows/principals/policyCache.d.ts +1 -1
  345. package/workflows/principals/policyCache.js +2 -2
  346. package/workflows/principals/policyCache.js.map +1 -1
  347. package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
  348. package/workflows/principals/runtimePolicyWarmer.js +1 -1
  349. package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
  350. package/workflows/registration/persistRegistrationBootstrap.js +1 -1
  351. package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
  352. package/workflows/runtimeInput.d.ts +3 -3
  353. package/workflows/runtimeInput.js.map +1 -1
  354. package/workflows/sync/index.d.ts +2 -1
  355. package/workflows/sync/index.js +2 -1
  356. package/workflows/sync/index.js.map +1 -1
  357. package/data/keyingCanonicalJson.js.map +0 -1
  358. package/data/keyingProjectionVerification.d.ts +0 -9
  359. package/data/keyingProjectionVerification.js.map +0 -1
  360. /package/data/{blobContracts.d.ts → blobs/blobContracts.d.ts} +0 -0
  361. /package/data/{blobContracts.js → blobs/blobContracts.js} +0 -0
  362. /package/data/{blobContracts.js.map → blobs/blobContracts.js.map} +0 -0
  363. /package/data/{accessLevel.js → keying/accessLevel.js} +0 -0
  364. /package/data/{accessLevel.js.map → keying/accessLevel.js.map} +0 -0
  365. /package/data/{stableUuid.js → keying/stableUuid.js} +0 -0
  366. /package/data/{stableUuid.js.map → keying/stableUuid.js.map} +0 -0
  367. /package/data/{principalPolicyStates.js → principals/principalPolicyStates.js} +0 -0
  368. /package/data/{principalPolicyStates.js.map → principals/principalPolicyStates.js.map} +0 -0
  369. /package/data/{domainScope.d.ts → shared/domainScope.d.ts} +0 -0
  370. /package/data/{domainScope.js → shared/domainScope.js} +0 -0
  371. /package/data/{domainScope.js.map → shared/domainScope.js.map} +0 -0
  372. /package/data/{errorMessage.js → shared/errorMessage.js} +0 -0
  373. /package/data/{errorMessage.js.map → shared/errorMessage.js.map} +0 -0
  374. /package/data/{recordReaders.d.ts → shared/recordReaders.d.ts} +0 -0
  375. /package/data/{recordReaders.js → shared/recordReaders.js} +0 -0
  376. /package/data/{recordReaders.js.map → shared/recordReaders.js.map} +0 -0
  377. /package/data/{securityIncidents.js → shared/securityIncidents.js} +0 -0
  378. /package/data/{securityIncidents.js.map → shared/securityIncidents.js.map} +0 -0
  379. /package/data/{crdtPeerSeed.js → sync/crdtPeerSeed.js} +0 -0
  380. /package/data/{crdtPeerSeed.js.map → sync/crdtPeerSeed.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"encryptedBlobByteSource.js","sourceRoot":"","sources":["encryptedBlobByteSource.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n assertReadRange,\n type BlobByteSource,\n type BlobBytes,\n readExactBlobBytes,\n} from \"../blobContracts\";\nimport {\n AES_GCM_TAG_BYTES,\n chunkAdditionalData,\n deriveChunkIv,\n ENCRYPTED_BLOB_CHUNK_SIZE,\n type EncryptedBlobEnvelope,\n getChunkPlaintextByteLength,\n type ParsedEncryptedBlobEnvelope,\n} from \"./encryptedBlobEnvelope\";\n\ninterface BlobEncryptionContext {\n readonly headerBytes: BlobBytes;\n readonly iv: BlobBytes;\n readonly key: CryptoKey;\n readonly namespace: string;\n readonly storageKey: string;\n}\n\ninterface CreateEncryptedBlobByteSourceInput extends BlobEncryptionContext {\n readonly envelope: EncryptedBlobEnvelope;\n readonly plaintextSource: BlobByteSource;\n readonly prefixBytes: BlobBytes;\n}\n\ninterface CreateDecryptedBlobByteSourceInput extends BlobEncryptionContext {\n readonly encryptedSource: BlobByteSource;\n readonly parsed: ParsedEncryptedBlobEnvelope;\n}\n\nfunction ciphertextOffset(\n prefixByteLength: number,\n chunkIndex: number,\n): number {\n return (\n prefixByteLength +\n chunkIndex * (ENCRYPTED_BLOB_CHUNK_SIZE + AES_GCM_TAG_BYTES)\n );\n}\n\nfunction chunkCiphertextByteLength(\n plaintextByteLength: number,\n chunkIndex: number,\n): number {\n return (\n getChunkPlaintextByteLength(plaintextByteLength, chunkIndex) +\n AES_GCM_TAG_BYTES\n );\n}\n\nfunction encryptionAlgorithm(\n context: BlobEncryptionContext,\n chunkIndex: number,\n): AesGcmParams {\n return {\n name: \"AES-GCM\",\n iv: deriveChunkIv(context.iv, chunkIndex),\n additionalData: chunkAdditionalData({\n chunkIndex,\n headerBytes: context.headerBytes,\n namespace: context.namespace,\n storageKey: context.storageKey,\n }),\n };\n}\n\nasync function encryptChunk(\n input: CreateEncryptedBlobByteSourceInput,\n chunkIndex: number,\n): Promise<BlobBytes> {\n const plaintextByteLength = getChunkPlaintextByteLength(\n input.envelope.plaintextByteLength,\n chunkIndex,\n );\n const plaintext = await readExactBlobBytes(\n input.plaintextSource,\n chunkIndex * ENCRYPTED_BLOB_CHUNK_SIZE,\n plaintextByteLength,\n );\n return new Uint8Array(\n await crypto.subtle.encrypt(\n encryptionAlgorithm(input, chunkIndex),\n input.key,\n plaintext,\n ),\n );\n}\n\nasync function decryptChunk(\n input: CreateDecryptedBlobByteSourceInput,\n chunkIndex: number,\n): Promise<BlobBytes> {\n const { envelope, prefixByteLength } = input.parsed;\n const ciphertext = await readExactBlobBytes(\n input.encryptedSource,\n ciphertextOffset(prefixByteLength, chunkIndex),\n chunkCiphertextByteLength(envelope.plaintextByteLength, chunkIndex),\n );\n try {\n const plaintext = new Uint8Array(\n await crypto.subtle.decrypt(\n encryptionAlgorithm(input, chunkIndex),\n input.key,\n ciphertext,\n ),\n );\n const expectedByteLength = getChunkPlaintextByteLength(\n envelope.plaintextByteLength,\n chunkIndex,\n );\n if (plaintext.byteLength !== expectedByteLength) {\n throw new Error(\"Unexpected plaintext length.\");\n }\n return plaintext;\n } catch {\n throw new Error(\"Encrypted blob store payload could not be decrypted.\");\n }\n}\n\nfunction copyIntersection(input: {\n chunk: BlobBytes;\n chunkOffset: number;\n output: BlobBytes;\n readByteLength: number;\n readOffset: number;\n}): void {\n const intersectionStart = Math.max(input.readOffset, input.chunkOffset);\n const intersectionEnd = Math.min(\n input.readOffset + input.readByteLength,\n input.chunkOffset + input.chunk.byteLength,\n );\n if (intersectionStart >= intersectionEnd) {\n return;\n }\n input.output.set(\n input.chunk.subarray(\n intersectionStart - input.chunkOffset,\n intersectionEnd - input.chunkOffset,\n ),\n intersectionStart - input.readOffset,\n );\n}\n\nasync function readEncryptedRange(\n input: CreateEncryptedBlobByteSourceInput,\n offset: number,\n byteLength: number,\n getEncryptedChunk: (chunkIndex: number) => Promise<BlobBytes>,\n): Promise<BlobBytes> {\n const output = new Uint8Array(byteLength);\n copyIntersection({\n chunk: input.prefixBytes,\n chunkOffset: 0,\n output,\n readByteLength: byteLength,\n readOffset: offset,\n });\n\n const encryptedStart = Math.max(offset, input.prefixBytes.byteLength);\n const encryptedEnd = offset + byteLength;\n if (encryptedStart >= encryptedEnd) {\n return output;\n }\n const relativeStart = encryptedStart - input.prefixBytes.byteLength;\n const firstChunk = Math.floor(\n relativeStart / (ENCRYPTED_BLOB_CHUNK_SIZE + AES_GCM_TAG_BYTES),\n );\n const relativeEnd = encryptedEnd - input.prefixBytes.byteLength;\n const lastChunk = Math.min(\n input.envelope.chunkCount - 1,\n Math.floor(\n Math.max(0, relativeEnd - 1) /\n (ENCRYPTED_BLOB_CHUNK_SIZE + AES_GCM_TAG_BYTES),\n ),\n );\n\n for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; chunkIndex += 1) {\n const ciphertext = await getEncryptedChunk(chunkIndex);\n copyIntersection({\n chunk: ciphertext,\n chunkOffset: ciphertextOffset(input.prefixBytes.byteLength, chunkIndex),\n output,\n readByteLength: byteLength,\n readOffset: offset,\n });\n }\n return output;\n}\n\nasync function readDecryptedRange(\n input: CreateDecryptedBlobByteSourceInput,\n offset: number,\n byteLength: number,\n): Promise<BlobBytes> {\n const output = new Uint8Array(byteLength);\n if (byteLength === 0) {\n if (input.parsed.envelope.plaintextByteLength === 0) {\n await decryptChunk(input, 0);\n }\n return output;\n }\n const firstChunk = Math.floor(offset / ENCRYPTED_BLOB_CHUNK_SIZE);\n const lastChunk = Math.floor(\n (offset + byteLength - 1) / ENCRYPTED_BLOB_CHUNK_SIZE,\n );\n for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; chunkIndex += 1) {\n const plaintext = await decryptChunk(input, chunkIndex);\n copyIntersection({\n chunk: plaintext,\n chunkOffset: chunkIndex * ENCRYPTED_BLOB_CHUNK_SIZE,\n output,\n readByteLength: byteLength,\n readOffset: offset,\n });\n }\n return output;\n}\n\nexport function createEncryptedBlobByteSource(\n input: CreateEncryptedBlobByteSourceInput,\n): BlobByteSource {\n let cachedChunkIndex = -1;\n let cachedChunkPromise: Promise<BlobBytes> | null = null;\n\n function getEncryptedChunk(chunkIndex: number): Promise<BlobBytes> {\n if (chunkIndex !== cachedChunkIndex || !cachedChunkPromise) {\n cachedChunkIndex = chunkIndex;\n cachedChunkPromise = encryptChunk(input, chunkIndex);\n }\n return cachedChunkPromise;\n }\n\n return {\n byteLength:\n input.prefixBytes.byteLength +\n input.envelope.plaintextByteLength +\n input.envelope.chunkCount * AES_GCM_TAG_BYTES,\n async read(offset, byteLength) {\n assertReadRange(this.byteLength, offset, byteLength);\n return readEncryptedRange(input, offset, byteLength, getEncryptedChunk);\n },\n };\n}\n\nexport function createDecryptedBlobByteSource(\n input: CreateDecryptedBlobByteSourceInput,\n): BlobByteSource {\n return {\n byteLength: input.parsed.envelope.plaintextByteLength,\n async read(offset, byteLength) {\n assertReadRange(this.byteLength, offset, byteLength);\n return readDecryptedRange(input, offset, byteLength);\n },\n };\n}\n"]}
1
+ {"version":3,"file":"encryptedBlobByteSource.js","sourceRoot":"","sources":["encryptedBlobByteSource.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n assertReadRange,\n type BlobByteSource,\n type BlobBytes,\n readExactBlobBytes,\n} from \"./blobContracts\";\nimport {\n AES_GCM_TAG_BYTES,\n chunkAdditionalData,\n deriveChunkIv,\n ENCRYPTED_BLOB_CHUNK_SIZE,\n type EncryptedBlobEnvelope,\n getChunkPlaintextByteLength,\n type ParsedEncryptedBlobEnvelope,\n} from \"./encryptedBlobEnvelope\";\n\ninterface BlobEncryptionContext {\n readonly headerBytes: BlobBytes;\n readonly iv: BlobBytes;\n readonly key: CryptoKey;\n readonly namespace: string;\n readonly storageKey: string;\n}\n\ninterface CreateEncryptedBlobByteSourceInput extends BlobEncryptionContext {\n readonly envelope: EncryptedBlobEnvelope;\n readonly plaintextSource: BlobByteSource;\n readonly prefixBytes: BlobBytes;\n}\n\ninterface CreateDecryptedBlobByteSourceInput extends BlobEncryptionContext {\n readonly encryptedSource: BlobByteSource;\n readonly parsed: ParsedEncryptedBlobEnvelope;\n}\n\nfunction ciphertextOffset(\n prefixByteLength: number,\n chunkIndex: number,\n): number {\n return (\n prefixByteLength +\n chunkIndex * (ENCRYPTED_BLOB_CHUNK_SIZE + AES_GCM_TAG_BYTES)\n );\n}\n\nfunction chunkCiphertextByteLength(\n plaintextByteLength: number,\n chunkIndex: number,\n): number {\n return (\n getChunkPlaintextByteLength(plaintextByteLength, chunkIndex) +\n AES_GCM_TAG_BYTES\n );\n}\n\nfunction encryptionAlgorithm(\n context: BlobEncryptionContext,\n chunkIndex: number,\n): AesGcmParams {\n return {\n name: \"AES-GCM\",\n iv: deriveChunkIv(context.iv, chunkIndex),\n additionalData: chunkAdditionalData({\n chunkIndex,\n headerBytes: context.headerBytes,\n namespace: context.namespace,\n storageKey: context.storageKey,\n }),\n };\n}\n\nasync function encryptChunk(\n input: CreateEncryptedBlobByteSourceInput,\n chunkIndex: number,\n): Promise<BlobBytes> {\n const plaintextByteLength = getChunkPlaintextByteLength(\n input.envelope.plaintextByteLength,\n chunkIndex,\n );\n const plaintext = await readExactBlobBytes(\n input.plaintextSource,\n chunkIndex * ENCRYPTED_BLOB_CHUNK_SIZE,\n plaintextByteLength,\n );\n return new Uint8Array(\n await crypto.subtle.encrypt(\n encryptionAlgorithm(input, chunkIndex),\n input.key,\n plaintext,\n ),\n );\n}\n\nasync function decryptChunk(\n input: CreateDecryptedBlobByteSourceInput,\n chunkIndex: number,\n): Promise<BlobBytes> {\n const { envelope, prefixByteLength } = input.parsed;\n const ciphertext = await readExactBlobBytes(\n input.encryptedSource,\n ciphertextOffset(prefixByteLength, chunkIndex),\n chunkCiphertextByteLength(envelope.plaintextByteLength, chunkIndex),\n );\n try {\n const plaintext = new Uint8Array(\n await crypto.subtle.decrypt(\n encryptionAlgorithm(input, chunkIndex),\n input.key,\n ciphertext,\n ),\n );\n const expectedByteLength = getChunkPlaintextByteLength(\n envelope.plaintextByteLength,\n chunkIndex,\n );\n if (plaintext.byteLength !== expectedByteLength) {\n throw new Error(\"Unexpected plaintext length.\");\n }\n return plaintext;\n } catch {\n throw new Error(\"Encrypted blob store payload could not be decrypted.\");\n }\n}\n\nfunction copyIntersection(input: {\n chunk: BlobBytes;\n chunkOffset: number;\n output: BlobBytes;\n readByteLength: number;\n readOffset: number;\n}): void {\n const intersectionStart = Math.max(input.readOffset, input.chunkOffset);\n const intersectionEnd = Math.min(\n input.readOffset + input.readByteLength,\n input.chunkOffset + input.chunk.byteLength,\n );\n if (intersectionStart >= intersectionEnd) {\n return;\n }\n input.output.set(\n input.chunk.subarray(\n intersectionStart - input.chunkOffset,\n intersectionEnd - input.chunkOffset,\n ),\n intersectionStart - input.readOffset,\n );\n}\n\nasync function readEncryptedRange(\n input: CreateEncryptedBlobByteSourceInput,\n offset: number,\n byteLength: number,\n getEncryptedChunk: (chunkIndex: number) => Promise<BlobBytes>,\n): Promise<BlobBytes> {\n const output = new Uint8Array(byteLength);\n copyIntersection({\n chunk: input.prefixBytes,\n chunkOffset: 0,\n output,\n readByteLength: byteLength,\n readOffset: offset,\n });\n\n const encryptedStart = Math.max(offset, input.prefixBytes.byteLength);\n const encryptedEnd = offset + byteLength;\n if (encryptedStart >= encryptedEnd) {\n return output;\n }\n const relativeStart = encryptedStart - input.prefixBytes.byteLength;\n const firstChunk = Math.floor(\n relativeStart / (ENCRYPTED_BLOB_CHUNK_SIZE + AES_GCM_TAG_BYTES),\n );\n const relativeEnd = encryptedEnd - input.prefixBytes.byteLength;\n const lastChunk = Math.min(\n input.envelope.chunkCount - 1,\n Math.floor(\n Math.max(0, relativeEnd - 1) /\n (ENCRYPTED_BLOB_CHUNK_SIZE + AES_GCM_TAG_BYTES),\n ),\n );\n\n for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; chunkIndex += 1) {\n const ciphertext = await getEncryptedChunk(chunkIndex);\n copyIntersection({\n chunk: ciphertext,\n chunkOffset: ciphertextOffset(input.prefixBytes.byteLength, chunkIndex),\n output,\n readByteLength: byteLength,\n readOffset: offset,\n });\n }\n return output;\n}\n\nasync function readDecryptedRange(\n input: CreateDecryptedBlobByteSourceInput,\n offset: number,\n byteLength: number,\n): Promise<BlobBytes> {\n const output = new Uint8Array(byteLength);\n if (byteLength === 0) {\n if (input.parsed.envelope.plaintextByteLength === 0) {\n await decryptChunk(input, 0);\n }\n return output;\n }\n const firstChunk = Math.floor(offset / ENCRYPTED_BLOB_CHUNK_SIZE);\n const lastChunk = Math.floor(\n (offset + byteLength - 1) / ENCRYPTED_BLOB_CHUNK_SIZE,\n );\n for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; chunkIndex += 1) {\n const plaintext = await decryptChunk(input, chunkIndex);\n copyIntersection({\n chunk: plaintext,\n chunkOffset: chunkIndex * ENCRYPTED_BLOB_CHUNK_SIZE,\n output,\n readByteLength: byteLength,\n readOffset: offset,\n });\n }\n return output;\n}\n\nexport function createEncryptedBlobByteSource(\n input: CreateEncryptedBlobByteSourceInput,\n): BlobByteSource {\n let cachedChunkIndex = -1;\n let cachedChunkPromise: Promise<BlobBytes> | null = null;\n\n function getEncryptedChunk(chunkIndex: number): Promise<BlobBytes> {\n if (chunkIndex !== cachedChunkIndex || !cachedChunkPromise) {\n cachedChunkIndex = chunkIndex;\n cachedChunkPromise = encryptChunk(input, chunkIndex);\n }\n return cachedChunkPromise;\n }\n\n return {\n byteLength:\n input.prefixBytes.byteLength +\n input.envelope.plaintextByteLength +\n input.envelope.chunkCount * AES_GCM_TAG_BYTES,\n async read(offset, byteLength) {\n assertReadRange(this.byteLength, offset, byteLength);\n return readEncryptedRange(input, offset, byteLength, getEncryptedChunk);\n },\n };\n}\n\nexport function createDecryptedBlobByteSource(\n input: CreateDecryptedBlobByteSourceInput,\n): BlobByteSource {\n return {\n byteLength: input.parsed.envelope.plaintextByteLength,\n async read(offset, byteLength) {\n assertReadRange(this.byteLength, offset, byteLength);\n return readDecryptedRange(input, offset, byteLength);\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { type BlobByteSource, type BlobBytes } from "../blobContracts.js";
1
+ import { type BlobByteSource, type BlobBytes } from "./blobContracts.js";
2
2
  export type EncryptedBlobStoreCipher = "aes-256-gcm";
3
3
  export interface KeyDerivationEnvelope {
4
4
  name: "pbkdf2-sha256";
@@ -1,7 +1,7 @@
1
1
  import { base64ToBytes, bytesToBase64 } from "../../internal/encoding/index.js";
2
2
  import { isPlainObject } from "../../internal/validators/isPlainObject.js";
3
- import { readExactBlobBytes, } from "../blobContracts.js";
4
- import { readRecordSafeByteLength, readRecordSafePositiveInteger, readRecordString, } from "../recordReaders.js";
3
+ import { readRecordSafeByteLength, readRecordSafePositiveInteger, readRecordString, } from "../shared/recordReaders.js";
4
+ import { readExactBlobBytes, } from "./blobContracts.js";
5
5
  export const ENCRYPTED_BLOB_STORE_FORMAT = "tearleads.local-blob-store.encrypted";
6
6
  export const ENCRYPTED_BLOB_STORE_VERSION = 2;
7
7
  export const ENCRYPTED_BLOB_CHUNK_SIZE = 5 * 1024 * 1024;
@@ -1 +1 @@
1
- {"version":3,"file":"encryptedBlobEnvelope.js","sourceRoot":"","sources":["encryptedBlobEnvelope.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport { isPlainObject } from \"@tearleads/validators/isPlainObject\";\nimport {\n type BlobByteSource,\n type BlobBytes,\n readExactBlobBytes,\n} from \"../blobContracts\";\nimport {\n readRecordSafeByteLength,\n readRecordSafePositiveInteger,\n readRecordString,\n} from \"../recordReaders\";\n\nexport type EncryptedBlobStoreCipher = \"aes-256-gcm\";\n\nexport interface KeyDerivationEnvelope {\n name: \"pbkdf2-sha256\";\n iterations: number;\n salt: string;\n}\n\nexport interface EncryptedBlobEnvelope {\n chunkCount: number;\n chunkSize: number;\n cipher: EncryptedBlobStoreCipher;\n format: typeof ENCRYPTED_BLOB_STORE_FORMAT;\n iv: string;\n keyDerivation: KeyDerivationEnvelope | null;\n plaintextByteLength: number;\n version: typeof ENCRYPTED_BLOB_STORE_VERSION;\n}\n\nexport interface ParsedEncryptedBlobEnvelope {\n encryptedByteLength: number;\n envelope: EncryptedBlobEnvelope;\n headerBytes: BlobBytes;\n iv: BlobBytes;\n prefixByteLength: number;\n}\n\nexport const ENCRYPTED_BLOB_STORE_FORMAT =\n \"tearleads.local-blob-store.encrypted\";\nexport const ENCRYPTED_BLOB_STORE_VERSION = 2;\nexport const ENCRYPTED_BLOB_CHUNK_SIZE = 5 * 1024 * 1024;\nexport const AES_GCM_TAG_BYTES = 16;\n\nconst AES_GCM_IV_BYTES = 12;\nconst DEFAULT_KDF_ITERATIONS = 310_000;\nconst MAX_HEADER_BYTES = 64 * 1024;\nconst MAGIC_BYTES = new TextEncoder().encode(\n \"tearleads.local-blob-store.encrypted.v2\",\n);\nconst HEADER_LENGTH_BYTES = 4;\nconst TEXT_DECODER = new TextDecoder(\"utf-8\", { fatal: true });\nconst TEXT_ENCODER = new TextEncoder();\n\nexport function asBlobBytes(bytes: Uint8Array): BlobBytes {\n if (!(bytes.buffer instanceof ArrayBuffer)) {\n throw new Error(\"Encrypted blob store bytes must be ArrayBuffer-backed.\");\n }\n return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n}\n\nfunction readRecord(value: unknown, label: string): Record<string, unknown> {\n if (!isPlainObject(value)) {\n throw new Error(`${label} must be an object.`);\n }\n return value;\n}\n\nexport function readBase64Bytes(\n value: Record<string, unknown>,\n key: string,\n label: string,\n): BlobBytes {\n const encoded = readRecordString(value, key, label);\n try {\n return asBlobBytes(base64ToBytes(encoded));\n } catch {\n throw new Error(`${label}.${key} must be base64.`);\n }\n}\n\nexport function normalizeCipher(\n cipher: string | undefined,\n): EncryptedBlobStoreCipher {\n if (cipher === undefined || cipher === \"aes-256-gcm\") {\n return \"aes-256-gcm\";\n }\n throw new Error(`Unsupported encrypted blob store cipher: ${cipher}`);\n}\n\nexport function normalizeKdfIterations(iterations: number | undefined): number {\n if (iterations === undefined) {\n return DEFAULT_KDF_ITERATIONS;\n }\n if (!Number.isSafeInteger(iterations) || iterations <= 0) {\n throw new Error(\n \"Encrypted blob store KDF iterations must be a positive integer.\",\n );\n }\n return iterations;\n}\n\nexport function assertNamespace(namespace: string): void {\n if (namespace.length === 0) {\n throw new Error(\"Encrypted blob store namespace must be non-empty.\");\n }\n}\n\nexport function createAesGcmIv(): BlobBytes {\n return crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES));\n}\n\nexport function createKeyDerivationEnvelope(input: {\n cipher: EncryptedBlobStoreCipher;\n iterations: number;\n namespace: string;\n}): KeyDerivationEnvelope {\n const salt = TEXT_ENCODER.encode(\n `tearleads.local-opfs-blob-store.v2.${input.cipher}.${input.namespace}`,\n );\n return {\n name: \"pbkdf2-sha256\",\n iterations: input.iterations,\n salt: bytesToBase64(salt),\n };\n}\n\nfunction readKeyDerivationEnvelope(\n value: unknown,\n): KeyDerivationEnvelope | null {\n if (value === null || value === undefined) {\n return null;\n }\n const record = readRecord(value, \"Encrypted blob store keyDerivation\");\n if (\n readRecordString(record, \"name\", \"Encrypted blob store keyDerivation\") !==\n \"pbkdf2-sha256\"\n ) {\n throw new Error(\"Encrypted blob store key derivation is unsupported.\");\n }\n if (\n readBase64Bytes(record, \"salt\", \"Encrypted blob store keyDerivation\")\n .byteLength === 0\n ) {\n throw new Error(\"Encrypted blob store key derivation salt is empty.\");\n }\n return {\n name: \"pbkdf2-sha256\",\n iterations: readRecordSafePositiveInteger(\n record,\n \"iterations\",\n \"Encrypted blob store keyDerivation\",\n ),\n salt: readRecordString(\n record,\n \"salt\",\n \"Encrypted blob store keyDerivation\",\n ),\n };\n}\n\nfunction parseHeader(headerBytes: BlobBytes): {\n envelope: EncryptedBlobEnvelope;\n iv: BlobBytes;\n} {\n let parsed: unknown;\n try {\n parsed = JSON.parse(TEXT_DECODER.decode(headerBytes));\n } catch {\n throw new Error(\"Encrypted blob store header is invalid JSON.\");\n }\n const label = \"Encrypted blob store header\";\n const record = readRecord(parsed, label);\n if (\n readRecordString(record, \"format\", label) !== ENCRYPTED_BLOB_STORE_FORMAT\n ) {\n throw new Error(\"Encrypted blob store payload format is invalid.\");\n }\n if (readRecordSafePositiveInteger(record, \"version\", label) !== 2) {\n throw new Error(\"Encrypted blob store payload version is invalid.\");\n }\n const chunkSize = readRecordSafePositiveInteger(record, \"chunkSize\", label);\n if (chunkSize !== ENCRYPTED_BLOB_CHUNK_SIZE) {\n throw new Error(\"Encrypted blob store payload chunk size is invalid.\");\n }\n const plaintextByteLength = readRecordSafeByteLength(\n record,\n \"plaintextByteLength\",\n label,\n );\n const chunkCount = readRecordSafePositiveInteger(record, \"chunkCount\", label);\n if (chunkCount !== getChunkCount(plaintextByteLength)) {\n throw new Error(\"Encrypted blob store payload chunk count is invalid.\");\n }\n const iv = readBase64Bytes(record, \"iv\", label);\n if (iv.byteLength !== AES_GCM_IV_BYTES) {\n throw new Error(\"Encrypted blob store payload IV is invalid.\");\n }\n const { keyDerivation } = record;\n return {\n envelope: {\n chunkCount,\n chunkSize,\n cipher: normalizeCipher(readRecordString(record, \"cipher\", label)),\n format: ENCRYPTED_BLOB_STORE_FORMAT,\n iv: readRecordString(record, \"iv\", label),\n keyDerivation: readKeyDerivationEnvelope(keyDerivation),\n plaintextByteLength,\n version: ENCRYPTED_BLOB_STORE_VERSION,\n },\n iv,\n };\n}\n\nexport function getChunkCount(plaintextByteLength: number): number {\n if (!Number.isSafeInteger(plaintextByteLength) || plaintextByteLength < 0) {\n throw new Error(\"Encrypted blob store byte length is invalid.\");\n }\n return Math.max(\n 1,\n Math.ceil(plaintextByteLength / ENCRYPTED_BLOB_CHUNK_SIZE),\n );\n}\n\nexport function getChunkPlaintextByteLength(\n plaintextByteLength: number,\n chunkIndex: number,\n): number {\n const chunkCount = getChunkCount(plaintextByteLength);\n if (\n !Number.isSafeInteger(chunkIndex) ||\n chunkIndex < 0 ||\n chunkIndex >= chunkCount\n ) {\n throw new Error(\"Encrypted blob store chunk index is invalid.\");\n }\n if (chunkIndex < chunkCount - 1) {\n return ENCRYPTED_BLOB_CHUNK_SIZE;\n }\n return plaintextByteLength - chunkIndex * ENCRYPTED_BLOB_CHUNK_SIZE;\n}\n\nexport function serializeEncryptedBlobEnvelope(\n envelope: EncryptedBlobEnvelope,\n): { headerBytes: BlobBytes; prefixBytes: BlobBytes } {\n const headerBytes = TEXT_ENCODER.encode(JSON.stringify(envelope));\n if (headerBytes.byteLength > MAX_HEADER_BYTES) {\n throw new Error(\"Encrypted blob store header is too large.\");\n }\n const prefixBytes = new Uint8Array(\n MAGIC_BYTES.byteLength + HEADER_LENGTH_BYTES + headerBytes.byteLength,\n );\n prefixBytes.set(MAGIC_BYTES);\n new DataView(prefixBytes.buffer).setUint32(\n MAGIC_BYTES.byteLength,\n headerBytes.byteLength,\n );\n prefixBytes.set(headerBytes, MAGIC_BYTES.byteLength + HEADER_LENGTH_BYTES);\n return { headerBytes, prefixBytes };\n}\n\nfunction equalBytes(left: Uint8Array, right: Uint8Array): boolean {\n return (\n left.byteLength === right.byteLength && left.every((v, i) => v === right[i])\n );\n}\n\nexport async function readEncryptedBlobEnvelope(\n source: BlobByteSource,\n): Promise<ParsedEncryptedBlobEnvelope> {\n const fixedPrefixLength = MAGIC_BYTES.byteLength + HEADER_LENGTH_BYTES;\n if (source.byteLength < fixedPrefixLength) {\n throw new Error(\"Encrypted blob store payload is too short.\");\n }\n const fixedPrefix = await readExactBlobBytes(source, 0, fixedPrefixLength);\n if (\n !equalBytes(fixedPrefix.subarray(0, MAGIC_BYTES.byteLength), MAGIC_BYTES)\n ) {\n throw new Error(\"Encrypted blob store payload format is invalid.\");\n }\n const headerByteLength = new DataView(\n fixedPrefix.buffer,\n fixedPrefix.byteOffset,\n fixedPrefix.byteLength,\n ).getUint32(MAGIC_BYTES.byteLength);\n if (headerByteLength === 0 || headerByteLength > MAX_HEADER_BYTES) {\n throw new Error(\"Encrypted blob store header length is invalid.\");\n }\n const prefixByteLength = fixedPrefixLength + headerByteLength;\n if (source.byteLength < prefixByteLength) {\n throw new Error(\"Encrypted blob store payload is truncated.\");\n }\n const headerBytes = await readExactBlobBytes(\n source,\n fixedPrefixLength,\n headerByteLength,\n );\n const { envelope, iv } = parseHeader(headerBytes);\n const encryptedByteLength =\n prefixByteLength +\n envelope.plaintextByteLength +\n envelope.chunkCount * AES_GCM_TAG_BYTES;\n if (\n !Number.isSafeInteger(encryptedByteLength) ||\n source.byteLength !== encryptedByteLength\n ) {\n throw new Error(\"Encrypted blob store payload length is invalid.\");\n }\n return {\n encryptedByteLength,\n envelope,\n headerBytes,\n iv,\n prefixByteLength,\n };\n}\n\nfunction writeLengthPrefixedText(\n target: Uint8Array,\n offset: number,\n value: string,\n): number {\n const bytes = TEXT_ENCODER.encode(value);\n new DataView(target.buffer).setUint32(offset, bytes.byteLength);\n target.set(bytes, offset + 4);\n return offset + 4 + bytes.byteLength;\n}\n\nexport function chunkAdditionalData(input: {\n chunkIndex: number;\n headerBytes: BlobBytes;\n namespace: string;\n storageKey: string;\n}): BlobBytes {\n const namespaceBytes = TEXT_ENCODER.encode(input.namespace);\n const storageKeyBytes = TEXT_ENCODER.encode(input.storageKey);\n const bytes = new Uint8Array(\n 4 +\n namespaceBytes.byteLength +\n 4 +\n storageKeyBytes.byteLength +\n 4 +\n input.headerBytes.byteLength,\n );\n let offset = writeLengthPrefixedText(bytes, 0, input.namespace);\n offset = writeLengthPrefixedText(bytes, offset, input.storageKey);\n new DataView(bytes.buffer).setUint32(offset, input.chunkIndex);\n bytes.set(input.headerBytes, offset + 4);\n return bytes;\n}\n\nexport function deriveChunkIv(\n baseIv: BlobBytes,\n chunkIndex: number,\n): BlobBytes {\n if (\n !Number.isSafeInteger(chunkIndex) ||\n chunkIndex < 0 ||\n chunkIndex > 0xffff_ffff\n ) {\n throw new Error(\"Encrypted blob store chunk index exceeds the IV domain.\");\n }\n const iv = baseIv.slice();\n const view = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);\n view.setUint32(8, view.getUint32(8) ^ chunkIndex);\n return iv;\n}\n"]}
1
+ {"version":3,"file":"encryptedBlobEnvelope.js","sourceRoot":"","sources":["encryptedBlobEnvelope.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport { isPlainObject } from \"@tearleads/validators/isPlainObject\";\nimport {\n readRecordSafeByteLength,\n readRecordSafePositiveInteger,\n readRecordString,\n} from \"../shared/recordReaders\";\nimport {\n type BlobByteSource,\n type BlobBytes,\n readExactBlobBytes,\n} from \"./blobContracts\";\n\nexport type EncryptedBlobStoreCipher = \"aes-256-gcm\";\n\nexport interface KeyDerivationEnvelope {\n name: \"pbkdf2-sha256\";\n iterations: number;\n salt: string;\n}\n\nexport interface EncryptedBlobEnvelope {\n chunkCount: number;\n chunkSize: number;\n cipher: EncryptedBlobStoreCipher;\n format: typeof ENCRYPTED_BLOB_STORE_FORMAT;\n iv: string;\n keyDerivation: KeyDerivationEnvelope | null;\n plaintextByteLength: number;\n version: typeof ENCRYPTED_BLOB_STORE_VERSION;\n}\n\nexport interface ParsedEncryptedBlobEnvelope {\n encryptedByteLength: number;\n envelope: EncryptedBlobEnvelope;\n headerBytes: BlobBytes;\n iv: BlobBytes;\n prefixByteLength: number;\n}\n\nexport const ENCRYPTED_BLOB_STORE_FORMAT =\n \"tearleads.local-blob-store.encrypted\";\nexport const ENCRYPTED_BLOB_STORE_VERSION = 2;\nexport const ENCRYPTED_BLOB_CHUNK_SIZE = 5 * 1024 * 1024;\nexport const AES_GCM_TAG_BYTES = 16;\n\nconst AES_GCM_IV_BYTES = 12;\nconst DEFAULT_KDF_ITERATIONS = 310_000;\nconst MAX_HEADER_BYTES = 64 * 1024;\nconst MAGIC_BYTES = new TextEncoder().encode(\n \"tearleads.local-blob-store.encrypted.v2\",\n);\nconst HEADER_LENGTH_BYTES = 4;\nconst TEXT_DECODER = new TextDecoder(\"utf-8\", { fatal: true });\nconst TEXT_ENCODER = new TextEncoder();\n\nexport function asBlobBytes(bytes: Uint8Array): BlobBytes {\n if (!(bytes.buffer instanceof ArrayBuffer)) {\n throw new Error(\"Encrypted blob store bytes must be ArrayBuffer-backed.\");\n }\n return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n}\n\nfunction readRecord(value: unknown, label: string): Record<string, unknown> {\n if (!isPlainObject(value)) {\n throw new Error(`${label} must be an object.`);\n }\n return value;\n}\n\nexport function readBase64Bytes(\n value: Record<string, unknown>,\n key: string,\n label: string,\n): BlobBytes {\n const encoded = readRecordString(value, key, label);\n try {\n return asBlobBytes(base64ToBytes(encoded));\n } catch {\n throw new Error(`${label}.${key} must be base64.`);\n }\n}\n\nexport function normalizeCipher(\n cipher: string | undefined,\n): EncryptedBlobStoreCipher {\n if (cipher === undefined || cipher === \"aes-256-gcm\") {\n return \"aes-256-gcm\";\n }\n throw new Error(`Unsupported encrypted blob store cipher: ${cipher}`);\n}\n\nexport function normalizeKdfIterations(iterations: number | undefined): number {\n if (iterations === undefined) {\n return DEFAULT_KDF_ITERATIONS;\n }\n if (!Number.isSafeInteger(iterations) || iterations <= 0) {\n throw new Error(\n \"Encrypted blob store KDF iterations must be a positive integer.\",\n );\n }\n return iterations;\n}\n\nexport function assertNamespace(namespace: string): void {\n if (namespace.length === 0) {\n throw new Error(\"Encrypted blob store namespace must be non-empty.\");\n }\n}\n\nexport function createAesGcmIv(): BlobBytes {\n return crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES));\n}\n\nexport function createKeyDerivationEnvelope(input: {\n cipher: EncryptedBlobStoreCipher;\n iterations: number;\n namespace: string;\n}): KeyDerivationEnvelope {\n const salt = TEXT_ENCODER.encode(\n `tearleads.local-opfs-blob-store.v2.${input.cipher}.${input.namespace}`,\n );\n return {\n name: \"pbkdf2-sha256\",\n iterations: input.iterations,\n salt: bytesToBase64(salt),\n };\n}\n\nfunction readKeyDerivationEnvelope(\n value: unknown,\n): KeyDerivationEnvelope | null {\n if (value === null || value === undefined) {\n return null;\n }\n const record = readRecord(value, \"Encrypted blob store keyDerivation\");\n if (\n readRecordString(record, \"name\", \"Encrypted blob store keyDerivation\") !==\n \"pbkdf2-sha256\"\n ) {\n throw new Error(\"Encrypted blob store key derivation is unsupported.\");\n }\n if (\n readBase64Bytes(record, \"salt\", \"Encrypted blob store keyDerivation\")\n .byteLength === 0\n ) {\n throw new Error(\"Encrypted blob store key derivation salt is empty.\");\n }\n return {\n name: \"pbkdf2-sha256\",\n iterations: readRecordSafePositiveInteger(\n record,\n \"iterations\",\n \"Encrypted blob store keyDerivation\",\n ),\n salt: readRecordString(\n record,\n \"salt\",\n \"Encrypted blob store keyDerivation\",\n ),\n };\n}\n\nfunction parseHeader(headerBytes: BlobBytes): {\n envelope: EncryptedBlobEnvelope;\n iv: BlobBytes;\n} {\n let parsed: unknown;\n try {\n parsed = JSON.parse(TEXT_DECODER.decode(headerBytes));\n } catch {\n throw new Error(\"Encrypted blob store header is invalid JSON.\");\n }\n const label = \"Encrypted blob store header\";\n const record = readRecord(parsed, label);\n if (\n readRecordString(record, \"format\", label) !== ENCRYPTED_BLOB_STORE_FORMAT\n ) {\n throw new Error(\"Encrypted blob store payload format is invalid.\");\n }\n if (readRecordSafePositiveInteger(record, \"version\", label) !== 2) {\n throw new Error(\"Encrypted blob store payload version is invalid.\");\n }\n const chunkSize = readRecordSafePositiveInteger(record, \"chunkSize\", label);\n if (chunkSize !== ENCRYPTED_BLOB_CHUNK_SIZE) {\n throw new Error(\"Encrypted blob store payload chunk size is invalid.\");\n }\n const plaintextByteLength = readRecordSafeByteLength(\n record,\n \"plaintextByteLength\",\n label,\n );\n const chunkCount = readRecordSafePositiveInteger(record, \"chunkCount\", label);\n if (chunkCount !== getChunkCount(plaintextByteLength)) {\n throw new Error(\"Encrypted blob store payload chunk count is invalid.\");\n }\n const iv = readBase64Bytes(record, \"iv\", label);\n if (iv.byteLength !== AES_GCM_IV_BYTES) {\n throw new Error(\"Encrypted blob store payload IV is invalid.\");\n }\n const { keyDerivation } = record;\n return {\n envelope: {\n chunkCount,\n chunkSize,\n cipher: normalizeCipher(readRecordString(record, \"cipher\", label)),\n format: ENCRYPTED_BLOB_STORE_FORMAT,\n iv: readRecordString(record, \"iv\", label),\n keyDerivation: readKeyDerivationEnvelope(keyDerivation),\n plaintextByteLength,\n version: ENCRYPTED_BLOB_STORE_VERSION,\n },\n iv,\n };\n}\n\nexport function getChunkCount(plaintextByteLength: number): number {\n if (!Number.isSafeInteger(plaintextByteLength) || plaintextByteLength < 0) {\n throw new Error(\"Encrypted blob store byte length is invalid.\");\n }\n return Math.max(\n 1,\n Math.ceil(plaintextByteLength / ENCRYPTED_BLOB_CHUNK_SIZE),\n );\n}\n\nexport function getChunkPlaintextByteLength(\n plaintextByteLength: number,\n chunkIndex: number,\n): number {\n const chunkCount = getChunkCount(plaintextByteLength);\n if (\n !Number.isSafeInteger(chunkIndex) ||\n chunkIndex < 0 ||\n chunkIndex >= chunkCount\n ) {\n throw new Error(\"Encrypted blob store chunk index is invalid.\");\n }\n if (chunkIndex < chunkCount - 1) {\n return ENCRYPTED_BLOB_CHUNK_SIZE;\n }\n return plaintextByteLength - chunkIndex * ENCRYPTED_BLOB_CHUNK_SIZE;\n}\n\nexport function serializeEncryptedBlobEnvelope(\n envelope: EncryptedBlobEnvelope,\n): { headerBytes: BlobBytes; prefixBytes: BlobBytes } {\n const headerBytes = TEXT_ENCODER.encode(JSON.stringify(envelope));\n if (headerBytes.byteLength > MAX_HEADER_BYTES) {\n throw new Error(\"Encrypted blob store header is too large.\");\n }\n const prefixBytes = new Uint8Array(\n MAGIC_BYTES.byteLength + HEADER_LENGTH_BYTES + headerBytes.byteLength,\n );\n prefixBytes.set(MAGIC_BYTES);\n new DataView(prefixBytes.buffer).setUint32(\n MAGIC_BYTES.byteLength,\n headerBytes.byteLength,\n );\n prefixBytes.set(headerBytes, MAGIC_BYTES.byteLength + HEADER_LENGTH_BYTES);\n return { headerBytes, prefixBytes };\n}\n\nfunction equalBytes(left: Uint8Array, right: Uint8Array): boolean {\n return (\n left.byteLength === right.byteLength && left.every((v, i) => v === right[i])\n );\n}\n\nexport async function readEncryptedBlobEnvelope(\n source: BlobByteSource,\n): Promise<ParsedEncryptedBlobEnvelope> {\n const fixedPrefixLength = MAGIC_BYTES.byteLength + HEADER_LENGTH_BYTES;\n if (source.byteLength < fixedPrefixLength) {\n throw new Error(\"Encrypted blob store payload is too short.\");\n }\n const fixedPrefix = await readExactBlobBytes(source, 0, fixedPrefixLength);\n if (\n !equalBytes(fixedPrefix.subarray(0, MAGIC_BYTES.byteLength), MAGIC_BYTES)\n ) {\n throw new Error(\"Encrypted blob store payload format is invalid.\");\n }\n const headerByteLength = new DataView(\n fixedPrefix.buffer,\n fixedPrefix.byteOffset,\n fixedPrefix.byteLength,\n ).getUint32(MAGIC_BYTES.byteLength);\n if (headerByteLength === 0 || headerByteLength > MAX_HEADER_BYTES) {\n throw new Error(\"Encrypted blob store header length is invalid.\");\n }\n const prefixByteLength = fixedPrefixLength + headerByteLength;\n if (source.byteLength < prefixByteLength) {\n throw new Error(\"Encrypted blob store payload is truncated.\");\n }\n const headerBytes = await readExactBlobBytes(\n source,\n fixedPrefixLength,\n headerByteLength,\n );\n const { envelope, iv } = parseHeader(headerBytes);\n const encryptedByteLength =\n prefixByteLength +\n envelope.plaintextByteLength +\n envelope.chunkCount * AES_GCM_TAG_BYTES;\n if (\n !Number.isSafeInteger(encryptedByteLength) ||\n source.byteLength !== encryptedByteLength\n ) {\n throw new Error(\"Encrypted blob store payload length is invalid.\");\n }\n return {\n encryptedByteLength,\n envelope,\n headerBytes,\n iv,\n prefixByteLength,\n };\n}\n\nfunction writeLengthPrefixedText(\n target: Uint8Array,\n offset: number,\n value: string,\n): number {\n const bytes = TEXT_ENCODER.encode(value);\n new DataView(target.buffer).setUint32(offset, bytes.byteLength);\n target.set(bytes, offset + 4);\n return offset + 4 + bytes.byteLength;\n}\n\nexport function chunkAdditionalData(input: {\n chunkIndex: number;\n headerBytes: BlobBytes;\n namespace: string;\n storageKey: string;\n}): BlobBytes {\n const namespaceBytes = TEXT_ENCODER.encode(input.namespace);\n const storageKeyBytes = TEXT_ENCODER.encode(input.storageKey);\n const bytes = new Uint8Array(\n 4 +\n namespaceBytes.byteLength +\n 4 +\n storageKeyBytes.byteLength +\n 4 +\n input.headerBytes.byteLength,\n );\n let offset = writeLengthPrefixedText(bytes, 0, input.namespace);\n offset = writeLengthPrefixedText(bytes, offset, input.storageKey);\n new DataView(bytes.buffer).setUint32(offset, input.chunkIndex);\n bytes.set(input.headerBytes, offset + 4);\n return bytes;\n}\n\nexport function deriveChunkIv(\n baseIv: BlobBytes,\n chunkIndex: number,\n): BlobBytes {\n if (\n !Number.isSafeInteger(chunkIndex) ||\n chunkIndex < 0 ||\n chunkIndex > 0xffff_ffff\n ) {\n throw new Error(\"Encrypted blob store chunk index exceeds the IV domain.\");\n }\n const iv = baseIv.slice();\n const view = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);\n view.setUint32(8, view.getUint32(8) ^ chunkIndex);\n return iv;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { type BlobStore } from "../blobContracts.js";
1
+ import { type BlobStore } from "./blobContracts.js";
2
2
  import { type EncryptedBlobStoreCipher } from "./encryptedBlobEnvelope.js";
3
3
  export type { EncryptedBlobStoreCipher };
4
4
  export type EncryptedBlobStoreKey = string | Uint8Array | CryptoKey;
@@ -1,5 +1,5 @@
1
1
  import { bytesToBase64 } from "../../internal/encoding/index.js";
2
- import { createBlobByteSource, readBlobByteSource, } from "../blobContracts.js";
2
+ import { createBlobByteSource, readBlobByteSource, } from "./blobContracts.js";
3
3
  import { createDecryptedBlobByteSource, createEncryptedBlobByteSource, } from "./encryptedBlobByteSource.js";
4
4
  import { asBlobBytes, assertNamespace, createAesGcmIv, createKeyDerivationEnvelope, ENCRYPTED_BLOB_CHUNK_SIZE, ENCRYPTED_BLOB_STORE_FORMAT, ENCRYPTED_BLOB_STORE_VERSION, getChunkCount, normalizeCipher, normalizeKdfIterations, readBase64Bytes, readEncryptedBlobEnvelope, serializeEncryptedBlobEnvelope, } from "./encryptedBlobEnvelope.js";
5
5
  import { createOpfsBlobStore, isOpfsBlobStoreSupported } from "./opfsBlobStore.js";
@@ -1 +1 @@
1
- {"version":3,"file":"encryptedBlobStore.js","sourceRoot":"","sources":["encryptedBlobStore.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n createBlobByteSource,\n readBlobByteSource,\n} from \"../blobContracts\";\nimport {\n createDecryptedBlobByteSource,\n createEncryptedBlobByteSource,\n} from \"./encryptedBlobByteSource\";\nimport {\n asBlobBytes,\n assertNamespace,\n createAesGcmIv,\n createKeyDerivationEnvelope,\n ENCRYPTED_BLOB_CHUNK_SIZE,\n ENCRYPTED_BLOB_STORE_FORMAT,\n ENCRYPTED_BLOB_STORE_VERSION,\n type EncryptedBlobEnvelope,\n type EncryptedBlobStoreCipher,\n getChunkCount,\n type KeyDerivationEnvelope,\n normalizeCipher,\n normalizeKdfIterations,\n readBase64Bytes,\n readEncryptedBlobEnvelope,\n serializeEncryptedBlobEnvelope,\n} from \"./encryptedBlobEnvelope\";\nimport { createOpfsBlobStore, isOpfsBlobStoreSupported } from \"./opfsBlobStore\";\n\nexport type { EncryptedBlobStoreCipher };\nexport type EncryptedBlobStoreKey = string | Uint8Array | CryptoKey;\n\nexport interface EncryptedBlobStoreOptions {\n cipher?: EncryptedBlobStoreCipher | undefined;\n kdfIterations?: number | undefined;\n key: EncryptedBlobStoreKey;\n}\n\nexport interface WrapEncryptedBlobStoreOptions\n extends EncryptedBlobStoreOptions {\n namespace: string;\n}\n\nconst AES_256_KEY_BYTES = 32;\nconst TEXT_ENCODER = new TextEncoder();\n\nfunction isCryptoKey(value: unknown): value is CryptoKey {\n return typeof CryptoKey !== \"undefined\" && value instanceof CryptoKey;\n}\n\nfunction assertCryptoKey(key: CryptoKey): void {\n if (key.type !== \"secret\" || key.algorithm.name !== \"AES-GCM\") {\n throw new Error(\n \"Encrypted blob store CryptoKey must be an AES-GCM secret.\",\n );\n }\n if (!key.usages.includes(\"encrypt\") || !key.usages.includes(\"decrypt\")) {\n throw new Error(\n \"Encrypted blob store CryptoKey must allow encrypt and decrypt.\",\n );\n }\n}\n\nasync function importRawAesKey(key: Uint8Array): Promise<CryptoKey> {\n if (key.byteLength !== AES_256_KEY_BYTES) {\n throw new Error(\"Encrypted blob store AES-256-GCM key must be 32 bytes.\");\n }\n\n return crypto.subtle.importKey(\"raw\", asBlobBytes(key), \"AES-GCM\", false, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\nclass EncryptedBlobStore implements BlobStore {\n private readonly cipher: EncryptedBlobStoreCipher;\n private readonly derivedKeyByEnvelope = new Map<string, Promise<CryptoKey>>();\n private readonly kdfIterations: number;\n private readonly namespace: string;\n private readonly passphraseMaterialPromise: Promise<CryptoKey> | null;\n private readonly rawKeyPromise: Promise<CryptoKey> | null;\n\n constructor(\n private readonly innerStore: BlobStore,\n options: WrapEncryptedBlobStoreOptions,\n ) {\n if (!options || !(\"key\" in options)) {\n throw new Error(\"Encrypted blob store key is required.\");\n }\n assertNamespace(options.namespace);\n this.namespace = options.namespace;\n this.cipher = normalizeCipher(options.cipher);\n this.kdfIterations = normalizeKdfIterations(options.kdfIterations);\n\n if (typeof options.key === \"string\") {\n if (options.key.length === 0) {\n throw new Error(\"Encrypted blob store key must be non-empty.\");\n }\n this.rawKeyPromise = null;\n this.passphraseMaterialPromise = crypto.subtle.importKey(\n \"raw\",\n TEXT_ENCODER.encode(options.key),\n \"PBKDF2\",\n false,\n [\"deriveKey\"],\n );\n return;\n }\n\n this.passphraseMaterialPromise = null;\n if (isCryptoKey(options.key)) {\n assertCryptoKey(options.key);\n this.rawKeyPromise = Promise.resolve(options.key);\n return;\n }\n\n if (!(options.key instanceof Uint8Array)) {\n throw new Error(\n \"Encrypted blob store key must be a string, Uint8Array, or CryptoKey.\",\n );\n }\n\n this.rawKeyPromise = importRawAesKey(options.key);\n }\n\n async deleteBytes(storageKey: string): Promise<void> {\n await this.innerStore.deleteBytes(storageKey);\n }\n\n async openByteSource(storageKey: string): Promise<BlobByteSource | null> {\n const encryptedSource = await this.innerStore.openByteSource(storageKey);\n if (!encryptedSource) {\n return null;\n }\n\n const parsed = await readEncryptedBlobEnvelope(encryptedSource);\n const key = await this.getCipherKey(parsed.envelope.keyDerivation);\n return createDecryptedBlobByteSource({\n encryptedSource,\n headerBytes: parsed.headerBytes,\n iv: parsed.iv,\n key,\n namespace: this.namespace,\n parsed,\n storageKey,\n });\n }\n\n async readBytes(storageKey: string): Promise<BlobBytes | null> {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async writeByteSource(\n storageKey: string,\n source: BlobByteSource,\n ): Promise<void> {\n const keyDerivation = this.createKeyDerivationEnvelope();\n const key = await this.getCipherKey(keyDerivation);\n const iv = createAesGcmIv();\n const envelope: EncryptedBlobEnvelope = {\n chunkCount: getChunkCount(source.byteLength),\n chunkSize: ENCRYPTED_BLOB_CHUNK_SIZE,\n cipher: this.cipher,\n format: ENCRYPTED_BLOB_STORE_FORMAT,\n iv: bytesToBase64(iv),\n keyDerivation,\n plaintextByteLength: source.byteLength,\n version: ENCRYPTED_BLOB_STORE_VERSION,\n };\n const { headerBytes, prefixBytes } =\n serializeEncryptedBlobEnvelope(envelope);\n await this.innerStore.writeByteSource(\n storageKey,\n createEncryptedBlobByteSource({\n envelope,\n headerBytes,\n iv,\n key,\n namespace: this.namespace,\n plaintextSource: source,\n prefixBytes,\n storageKey,\n }),\n );\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes): Promise<void> {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n\n private createKeyDerivationEnvelope(): KeyDerivationEnvelope | null {\n if (!this.passphraseMaterialPromise) {\n return null;\n }\n\n return createKeyDerivationEnvelope({\n cipher: this.cipher,\n iterations: this.kdfIterations,\n namespace: this.namespace,\n });\n }\n\n private async getCipherKey(\n keyDerivation: KeyDerivationEnvelope | null,\n ): Promise<CryptoKey> {\n if (!keyDerivation) {\n if (!this.rawKeyPromise) {\n throw new Error(\n \"Encrypted blob store payload was not written with passphrase key derivation.\",\n );\n }\n\n return this.rawKeyPromise;\n }\n\n if (!this.passphraseMaterialPromise) {\n throw new Error(\n \"Encrypted blob store payload requires a passphrase key.\",\n );\n }\n\n const cacheKey = JSON.stringify(keyDerivation);\n let derivedKeyPromise = this.derivedKeyByEnvelope.get(cacheKey);\n if (!derivedKeyPromise) {\n derivedKeyPromise = this.derivePassphraseKey(keyDerivation);\n derivedKeyPromise.catch(() => {\n if (this.derivedKeyByEnvelope.get(cacheKey) === derivedKeyPromise) {\n this.derivedKeyByEnvelope.delete(cacheKey);\n }\n });\n this.derivedKeyByEnvelope.set(cacheKey, derivedKeyPromise);\n }\n\n return derivedKeyPromise;\n }\n\n private async derivePassphraseKey(\n keyDerivation: KeyDerivationEnvelope,\n ): Promise<CryptoKey> {\n const passphraseMaterial = await this.passphraseMaterialPromise;\n if (!passphraseMaterial) {\n throw new Error(\"Encrypted blob store passphrase material is missing.\");\n }\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n hash: \"SHA-256\",\n iterations: keyDerivation.iterations,\n salt: readBase64Bytes(\n { salt: keyDerivation.salt },\n \"salt\",\n \"Encrypted blob store keyDerivation\",\n ),\n },\n passphraseMaterial,\n {\n name: \"AES-GCM\",\n length: 256,\n },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n}\n\nexport function wrapEncryptedBlobStore(\n store: BlobStore,\n options: WrapEncryptedBlobStoreOptions,\n): BlobStore {\n return new EncryptedBlobStore(store, options);\n}\n\nexport function createEncryptedBlobStore(\n namespace: string,\n options: EncryptedBlobStoreOptions,\n): BlobStore {\n if (!isOpfsBlobStoreSupported()) {\n throw new Error(\"OPFS blob store is not supported.\");\n }\n\n return wrapEncryptedBlobStore(createOpfsBlobStore(namespace), {\n ...options,\n namespace,\n });\n}\n\nexport function createLazyEncryptedBlobStore(\n namespace: string,\n keyProvider: () => Promise<EncryptedBlobStoreKey>,\n): BlobStore {\n let innerStorePromise: Promise<BlobStore> | null = null;\n\n function getStore(): Promise<BlobStore> {\n if (!innerStorePromise) {\n innerStorePromise = (async () => {\n const key = await keyProvider();\n return createEncryptedBlobStore(namespace, { key });\n })().catch((error: unknown) => {\n // Run cleanup after assignment, even if keyProvider throws synchronously.\n innerStorePromise = null;\n throw error;\n });\n }\n\n return innerStorePromise;\n }\n\n return {\n deleteBytes: async (storageKey) => {\n const store = await getStore();\n return store.deleteBytes(storageKey);\n },\n openByteSource: async (storageKey) => {\n const store = await getStore();\n return store.openByteSource(storageKey);\n },\n readBytes: async (storageKey) => {\n const store = await getStore();\n return store.readBytes(storageKey);\n },\n writeByteSource: async (storageKey, source) => {\n const store = await getStore();\n return store.writeByteSource(storageKey, source);\n },\n writeBytes: async (storageKey, bytes) => {\n const store = await getStore();\n return store.writeBytes(storageKey, bytes);\n },\n };\n}\n"]}
1
+ {"version":3,"file":"encryptedBlobStore.js","sourceRoot":"","sources":["encryptedBlobStore.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n createBlobByteSource,\n readBlobByteSource,\n} from \"./blobContracts\";\nimport {\n createDecryptedBlobByteSource,\n createEncryptedBlobByteSource,\n} from \"./encryptedBlobByteSource\";\nimport {\n asBlobBytes,\n assertNamespace,\n createAesGcmIv,\n createKeyDerivationEnvelope,\n ENCRYPTED_BLOB_CHUNK_SIZE,\n ENCRYPTED_BLOB_STORE_FORMAT,\n ENCRYPTED_BLOB_STORE_VERSION,\n type EncryptedBlobEnvelope,\n type EncryptedBlobStoreCipher,\n getChunkCount,\n type KeyDerivationEnvelope,\n normalizeCipher,\n normalizeKdfIterations,\n readBase64Bytes,\n readEncryptedBlobEnvelope,\n serializeEncryptedBlobEnvelope,\n} from \"./encryptedBlobEnvelope\";\nimport { createOpfsBlobStore, isOpfsBlobStoreSupported } from \"./opfsBlobStore\";\n\nexport type { EncryptedBlobStoreCipher };\nexport type EncryptedBlobStoreKey = string | Uint8Array | CryptoKey;\n\nexport interface EncryptedBlobStoreOptions {\n cipher?: EncryptedBlobStoreCipher | undefined;\n kdfIterations?: number | undefined;\n key: EncryptedBlobStoreKey;\n}\n\nexport interface WrapEncryptedBlobStoreOptions\n extends EncryptedBlobStoreOptions {\n namespace: string;\n}\n\nconst AES_256_KEY_BYTES = 32;\nconst TEXT_ENCODER = new TextEncoder();\n\nfunction isCryptoKey(value: unknown): value is CryptoKey {\n return typeof CryptoKey !== \"undefined\" && value instanceof CryptoKey;\n}\n\nfunction assertCryptoKey(key: CryptoKey): void {\n if (key.type !== \"secret\" || key.algorithm.name !== \"AES-GCM\") {\n throw new Error(\n \"Encrypted blob store CryptoKey must be an AES-GCM secret.\",\n );\n }\n if (!key.usages.includes(\"encrypt\") || !key.usages.includes(\"decrypt\")) {\n throw new Error(\n \"Encrypted blob store CryptoKey must allow encrypt and decrypt.\",\n );\n }\n}\n\nasync function importRawAesKey(key: Uint8Array): Promise<CryptoKey> {\n if (key.byteLength !== AES_256_KEY_BYTES) {\n throw new Error(\"Encrypted blob store AES-256-GCM key must be 32 bytes.\");\n }\n\n return crypto.subtle.importKey(\"raw\", asBlobBytes(key), \"AES-GCM\", false, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\nclass EncryptedBlobStore implements BlobStore {\n private readonly cipher: EncryptedBlobStoreCipher;\n private readonly derivedKeyByEnvelope = new Map<string, Promise<CryptoKey>>();\n private readonly kdfIterations: number;\n private readonly namespace: string;\n private readonly passphraseMaterialPromise: Promise<CryptoKey> | null;\n private readonly rawKeyPromise: Promise<CryptoKey> | null;\n\n constructor(\n private readonly innerStore: BlobStore,\n options: WrapEncryptedBlobStoreOptions,\n ) {\n if (!options || !(\"key\" in options)) {\n throw new Error(\"Encrypted blob store key is required.\");\n }\n assertNamespace(options.namespace);\n this.namespace = options.namespace;\n this.cipher = normalizeCipher(options.cipher);\n this.kdfIterations = normalizeKdfIterations(options.kdfIterations);\n\n if (typeof options.key === \"string\") {\n if (options.key.length === 0) {\n throw new Error(\"Encrypted blob store key must be non-empty.\");\n }\n this.rawKeyPromise = null;\n this.passphraseMaterialPromise = crypto.subtle.importKey(\n \"raw\",\n TEXT_ENCODER.encode(options.key),\n \"PBKDF2\",\n false,\n [\"deriveKey\"],\n );\n return;\n }\n\n this.passphraseMaterialPromise = null;\n if (isCryptoKey(options.key)) {\n assertCryptoKey(options.key);\n this.rawKeyPromise = Promise.resolve(options.key);\n return;\n }\n\n if (!(options.key instanceof Uint8Array)) {\n throw new Error(\n \"Encrypted blob store key must be a string, Uint8Array, or CryptoKey.\",\n );\n }\n\n this.rawKeyPromise = importRawAesKey(options.key);\n }\n\n async deleteBytes(storageKey: string): Promise<void> {\n await this.innerStore.deleteBytes(storageKey);\n }\n\n async openByteSource(storageKey: string): Promise<BlobByteSource | null> {\n const encryptedSource = await this.innerStore.openByteSource(storageKey);\n if (!encryptedSource) {\n return null;\n }\n\n const parsed = await readEncryptedBlobEnvelope(encryptedSource);\n const key = await this.getCipherKey(parsed.envelope.keyDerivation);\n return createDecryptedBlobByteSource({\n encryptedSource,\n headerBytes: parsed.headerBytes,\n iv: parsed.iv,\n key,\n namespace: this.namespace,\n parsed,\n storageKey,\n });\n }\n\n async readBytes(storageKey: string): Promise<BlobBytes | null> {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async writeByteSource(\n storageKey: string,\n source: BlobByteSource,\n ): Promise<void> {\n const keyDerivation = this.createKeyDerivationEnvelope();\n const key = await this.getCipherKey(keyDerivation);\n const iv = createAesGcmIv();\n const envelope: EncryptedBlobEnvelope = {\n chunkCount: getChunkCount(source.byteLength),\n chunkSize: ENCRYPTED_BLOB_CHUNK_SIZE,\n cipher: this.cipher,\n format: ENCRYPTED_BLOB_STORE_FORMAT,\n iv: bytesToBase64(iv),\n keyDerivation,\n plaintextByteLength: source.byteLength,\n version: ENCRYPTED_BLOB_STORE_VERSION,\n };\n const { headerBytes, prefixBytes } =\n serializeEncryptedBlobEnvelope(envelope);\n await this.innerStore.writeByteSource(\n storageKey,\n createEncryptedBlobByteSource({\n envelope,\n headerBytes,\n iv,\n key,\n namespace: this.namespace,\n plaintextSource: source,\n prefixBytes,\n storageKey,\n }),\n );\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes): Promise<void> {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n\n private createKeyDerivationEnvelope(): KeyDerivationEnvelope | null {\n if (!this.passphraseMaterialPromise) {\n return null;\n }\n\n return createKeyDerivationEnvelope({\n cipher: this.cipher,\n iterations: this.kdfIterations,\n namespace: this.namespace,\n });\n }\n\n private async getCipherKey(\n keyDerivation: KeyDerivationEnvelope | null,\n ): Promise<CryptoKey> {\n if (!keyDerivation) {\n if (!this.rawKeyPromise) {\n throw new Error(\n \"Encrypted blob store payload was not written with passphrase key derivation.\",\n );\n }\n\n return this.rawKeyPromise;\n }\n\n if (!this.passphraseMaterialPromise) {\n throw new Error(\n \"Encrypted blob store payload requires a passphrase key.\",\n );\n }\n\n const cacheKey = JSON.stringify(keyDerivation);\n let derivedKeyPromise = this.derivedKeyByEnvelope.get(cacheKey);\n if (!derivedKeyPromise) {\n derivedKeyPromise = this.derivePassphraseKey(keyDerivation);\n derivedKeyPromise.catch(() => {\n if (this.derivedKeyByEnvelope.get(cacheKey) === derivedKeyPromise) {\n this.derivedKeyByEnvelope.delete(cacheKey);\n }\n });\n this.derivedKeyByEnvelope.set(cacheKey, derivedKeyPromise);\n }\n\n return derivedKeyPromise;\n }\n\n private async derivePassphraseKey(\n keyDerivation: KeyDerivationEnvelope,\n ): Promise<CryptoKey> {\n const passphraseMaterial = await this.passphraseMaterialPromise;\n if (!passphraseMaterial) {\n throw new Error(\"Encrypted blob store passphrase material is missing.\");\n }\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n hash: \"SHA-256\",\n iterations: keyDerivation.iterations,\n salt: readBase64Bytes(\n { salt: keyDerivation.salt },\n \"salt\",\n \"Encrypted blob store keyDerivation\",\n ),\n },\n passphraseMaterial,\n {\n name: \"AES-GCM\",\n length: 256,\n },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n}\n\nexport function wrapEncryptedBlobStore(\n store: BlobStore,\n options: WrapEncryptedBlobStoreOptions,\n): BlobStore {\n return new EncryptedBlobStore(store, options);\n}\n\nexport function createEncryptedBlobStore(\n namespace: string,\n options: EncryptedBlobStoreOptions,\n): BlobStore {\n if (!isOpfsBlobStoreSupported()) {\n throw new Error(\"OPFS blob store is not supported.\");\n }\n\n return wrapEncryptedBlobStore(createOpfsBlobStore(namespace), {\n ...options,\n namespace,\n });\n}\n\nexport function createLazyEncryptedBlobStore(\n namespace: string,\n keyProvider: () => Promise<EncryptedBlobStoreKey>,\n): BlobStore {\n let innerStorePromise: Promise<BlobStore> | null = null;\n\n function getStore(): Promise<BlobStore> {\n if (!innerStorePromise) {\n innerStorePromise = (async () => {\n const key = await keyProvider();\n return createEncryptedBlobStore(namespace, { key });\n })().catch((error: unknown) => {\n // Run cleanup after assignment, even if keyProvider throws synchronously.\n innerStorePromise = null;\n throw error;\n });\n }\n\n return innerStorePromise;\n }\n\n return {\n deleteBytes: async (storageKey) => {\n const store = await getStore();\n return store.deleteBytes(storageKey);\n },\n openByteSource: async (storageKey) => {\n const store = await getStore();\n return store.openByteSource(storageKey);\n },\n readBytes: async (storageKey) => {\n const store = await getStore();\n return store.readBytes(storageKey);\n },\n writeByteSource: async (storageKey, source) => {\n const store = await getStore();\n return store.writeByteSource(storageKey, source);\n },\n writeBytes: async (storageKey, bytes) => {\n const store = await getStore();\n return store.writeBytes(storageKey, bytes);\n },\n };\n}\n"]}
@@ -1,2 +1,2 @@
1
- import { type BlobStore } from "../blobContracts.js";
1
+ import { type BlobStore } from "./blobContracts.js";
2
2
  export declare function createMemoryBlobStore(): BlobStore;
@@ -1,4 +1,4 @@
1
- import { createBlobByteSource, readBlobByteSource, } from "../blobContracts.js";
1
+ import { createBlobByteSource, readBlobByteSource, } from "./blobContracts.js";
2
2
  class MemoryBlobStore {
3
3
  bytesByKey = new Map();
4
4
  async deleteBytes(storageKey) {
@@ -1 +1 @@
1
- {"version":3,"file":"memoryBlobStore.js","sourceRoot":"","sources":["memoryBlobStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,eAAe;IACF,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE3D,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9C,OAAO,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAAkB;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACrD,OAAO,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,UAAkB,EAAE,MAAsB;QAC9D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,KAAgB;QACnD,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;CACF;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,eAAe,EAAE,CAAC;AAC/B,CAAC","sourcesContent":["import {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n createBlobByteSource,\n readBlobByteSource,\n} from \"../blobContracts\";\n\nclass MemoryBlobStore implements BlobStore {\n private readonly bytesByKey = new Map<string, BlobBytes>();\n\n async deleteBytes(storageKey: string) {\n this.bytesByKey.delete(storageKey);\n }\n\n async openByteSource(storageKey: string) {\n const bytes = this.bytesByKey.get(storageKey);\n return bytes ? createBlobByteSource(bytes) : null;\n }\n\n async readBytes(storageKey: string) {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async writeByteSource(storageKey: string, source: BlobByteSource) {\n this.bytesByKey.set(storageKey, await readBlobByteSource(source));\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes) {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n}\n\nexport function createMemoryBlobStore(): BlobStore {\n return new MemoryBlobStore();\n}\n"]}
1
+ {"version":3,"file":"memoryBlobStore.js","sourceRoot":"","sources":["memoryBlobStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,eAAe;IACF,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE3D,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9C,OAAO,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAAkB;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACrD,OAAO,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,UAAkB,EAAE,MAAsB;QAC9D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,KAAgB;QACnD,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;CACF;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,eAAe,EAAE,CAAC;AAC/B,CAAC","sourcesContent":["import {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n createBlobByteSource,\n readBlobByteSource,\n} from \"./blobContracts\";\n\nclass MemoryBlobStore implements BlobStore {\n private readonly bytesByKey = new Map<string, BlobBytes>();\n\n async deleteBytes(storageKey: string) {\n this.bytesByKey.delete(storageKey);\n }\n\n async openByteSource(storageKey: string) {\n const bytes = this.bytesByKey.get(storageKey);\n return bytes ? createBlobByteSource(bytes) : null;\n }\n\n async readBytes(storageKey: string) {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async writeByteSource(storageKey: string, source: BlobByteSource) {\n this.bytesByKey.set(storageKey, await readBlobByteSource(source));\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes) {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n}\n\nexport function createMemoryBlobStore(): BlobStore {\n return new MemoryBlobStore();\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { type BlobStore } from "../blobContracts.js";
1
+ import { type BlobStore } from "./blobContracts.js";
2
2
  export declare function isOpfsBlobStoreSupported(): boolean;
3
3
  export declare function createOpfsBlobStore(namespace: string): BlobStore;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { blobByteSourceInputLength, createBlobByteSource, readBlobByteSource, } from "../blobContracts.js";
1
+ import { blobByteSourceInputLength, createBlobByteSource, readBlobByteSource, } from "./blobContracts.js";
2
2
  const OPFS_WRITE_CHUNK_SIZE = 5 * 1024 * 1024;
3
3
  class OpfsBlobStore {
4
4
  namespace;
@@ -1 +1 @@
1
- {"version":3,"file":"opfsBlobStore.js","sourceRoot":"","sources":["opfsBlobStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n blobByteSourceInputLength,\n createBlobByteSource,\n readBlobByteSource,\n} from \"../blobContracts\";\n\ninterface StorageDirectoryProvider {\n getDirectory: () => Promise<FileSystemDirectoryHandle>;\n}\n\nconst OPFS_WRITE_CHUNK_SIZE = 5 * 1024 * 1024;\n\nclass OpfsBlobStore implements BlobStore {\n private directoryPromise: Promise<FileSystemDirectoryHandle> | null = null;\n\n constructor(private readonly namespace: string) {}\n\n async deleteBytes(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n await directory.removeEntry(this.getFileName(storageKey));\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n\n throw error;\n }\n }\n\n async readBytes(storageKey: string) {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async openByteSource(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n );\n const file = await fileHandle.getFile();\n return createBlobByteSource(file);\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return null;\n }\n\n throw error;\n }\n }\n\n async writeByteSource(storageKey: string, source: BlobByteSource) {\n const sourceByteLength = blobByteSourceInputLength(source);\n const directory = await this.getDirectory();\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n { create: true },\n );\n const writable = await fileHandle.createWritable();\n\n try {\n for (let offset = 0; offset < sourceByteLength; ) {\n const byteLength = Math.min(\n OPFS_WRITE_CHUNK_SIZE,\n sourceByteLength - offset,\n );\n const chunk = await source.read(offset, byteLength);\n if (chunk.byteLength !== byteLength) {\n throw new Error(\"Blob byte source returned an incomplete read.\");\n }\n await writable.write(chunk);\n offset += byteLength;\n }\n await writable.close();\n } catch (error) {\n await writable.abort(error).catch(() => undefined);\n throw error;\n }\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes) {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n\n private getFileName(storageKey: string): string {\n return `${encodeURIComponent(storageKey)}.blob`;\n }\n\n private async getDirectory() {\n if (!this.directoryPromise) {\n this.directoryPromise = this.createDirectory().catch((error: unknown) => {\n this.directoryPromise = null;\n throw error;\n });\n }\n\n return this.directoryPromise;\n }\n\n private async createDirectory() {\n const rootDirectory = await navigator.storage.getDirectory();\n const appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\", {\n create: true,\n });\n\n return appDirectory.getDirectoryHandle(this.namespace, { create: true });\n }\n}\n\nfunction hasStorageDirectory(\n storage: StorageManager | undefined,\n): storage is StorageManager & StorageDirectoryProvider {\n return (\n storage !== undefined &&\n \"getDirectory\" in storage &&\n typeof storage.getDirectory === \"function\"\n );\n}\n\nexport function isOpfsBlobStoreSupported(): boolean {\n return (\n typeof navigator === \"object\" && hasStorageDirectory(navigator.storage)\n );\n}\n\nexport function createOpfsBlobStore(namespace: string): BlobStore {\n return new OpfsBlobStore(namespace);\n}\n\n/**\n * Permanently remove the OPFS directory backing a namespace's blob store\n * (`tearleads/<namespace>`), discarding every stored blob for that namespace.\n * Used to forget local data on logout. No-op when OPFS is unavailable or the\n * directory was never created; never throws on a missing directory.\n */\nexport async function purgeOpfsBlobStore(namespace: string): Promise<void> {\n if (!isOpfsBlobStoreSupported()) {\n return;\n }\n\n const rootDirectory = await navigator.storage.getDirectory();\n let appDirectory: FileSystemDirectoryHandle;\n try {\n appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\");\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n\n try {\n await appDirectory.removeEntry(namespace, { recursive: true });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n}\n"]}
1
+ {"version":3,"file":"opfsBlobStore.js","sourceRoot":"","sources":["opfsBlobStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n blobByteSourceInputLength,\n createBlobByteSource,\n readBlobByteSource,\n} from \"./blobContracts\";\n\ninterface StorageDirectoryProvider {\n getDirectory: () => Promise<FileSystemDirectoryHandle>;\n}\n\nconst OPFS_WRITE_CHUNK_SIZE = 5 * 1024 * 1024;\n\nclass OpfsBlobStore implements BlobStore {\n private directoryPromise: Promise<FileSystemDirectoryHandle> | null = null;\n\n constructor(private readonly namespace: string) {}\n\n async deleteBytes(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n await directory.removeEntry(this.getFileName(storageKey));\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n\n throw error;\n }\n }\n\n async readBytes(storageKey: string) {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async openByteSource(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n );\n const file = await fileHandle.getFile();\n return createBlobByteSource(file);\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return null;\n }\n\n throw error;\n }\n }\n\n async writeByteSource(storageKey: string, source: BlobByteSource) {\n const sourceByteLength = blobByteSourceInputLength(source);\n const directory = await this.getDirectory();\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n { create: true },\n );\n const writable = await fileHandle.createWritable();\n\n try {\n for (let offset = 0; offset < sourceByteLength; ) {\n const byteLength = Math.min(\n OPFS_WRITE_CHUNK_SIZE,\n sourceByteLength - offset,\n );\n const chunk = await source.read(offset, byteLength);\n if (chunk.byteLength !== byteLength) {\n throw new Error(\"Blob byte source returned an incomplete read.\");\n }\n await writable.write(chunk);\n offset += byteLength;\n }\n await writable.close();\n } catch (error) {\n await writable.abort(error).catch(() => undefined);\n throw error;\n }\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes) {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n\n private getFileName(storageKey: string): string {\n return `${encodeURIComponent(storageKey)}.blob`;\n }\n\n private async getDirectory() {\n if (!this.directoryPromise) {\n this.directoryPromise = this.createDirectory().catch((error: unknown) => {\n this.directoryPromise = null;\n throw error;\n });\n }\n\n return this.directoryPromise;\n }\n\n private async createDirectory() {\n const rootDirectory = await navigator.storage.getDirectory();\n const appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\", {\n create: true,\n });\n\n return appDirectory.getDirectoryHandle(this.namespace, { create: true });\n }\n}\n\nfunction hasStorageDirectory(\n storage: StorageManager | undefined,\n): storage is StorageManager & StorageDirectoryProvider {\n return (\n storage !== undefined &&\n \"getDirectory\" in storage &&\n typeof storage.getDirectory === \"function\"\n );\n}\n\nexport function isOpfsBlobStoreSupported(): boolean {\n return (\n typeof navigator === \"object\" && hasStorageDirectory(navigator.storage)\n );\n}\n\nexport function createOpfsBlobStore(namespace: string): BlobStore {\n return new OpfsBlobStore(namespace);\n}\n\n/**\n * Permanently remove the OPFS directory backing a namespace's blob store\n * (`tearleads/<namespace>`), discarding every stored blob for that namespace.\n * Used to forget local data on logout. No-op when OPFS is unavailable or the\n * directory was never created; never throws on a missing directory.\n */\nexport async function purgeOpfsBlobStore(namespace: string): Promise<void> {\n if (!isOpfsBlobStoreSupported()) {\n return;\n }\n\n const rootDirectory = await navigator.storage.getDirectory();\n let appDirectory: FileSystemDirectoryHandle;\n try {\n appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\");\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n\n try {\n await appDirectory.removeEntry(namespace, { recursive: true });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { createDocument, exportAllUpdates } from "../../internal/loro/index.js";
2
- import { getScopedPeerSeed } from "../crdtPeerSeed.js";
2
+ import { getScopedPeerSeed } from "../sync/crdtPeerSeed.js";
3
3
  export function getDefaultContainerName(parentId) {
4
4
  return parentId === null ? "/" : "Untitled";
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"containerMetadataDocument.js","sourceRoot":"","sources":["containerMetadataDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAWpD,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC7D,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,YAAoB;IAEpB,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,OAAO,cAAc,CAAC,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0CAA0C,CAC9D,WAAmB,EACnB,KAA6B;IAK7B,MAAM,GAAG,GAAG,MAAM,+BAA+B,CAAC,WAAW,CAAC,CAAC;IAC/D,2BAA2B,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAExC,OAAO;QACL,GAAG;QACH,aAAa,EAAE,gBAAgB,CAAC,GAAG,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,GAA8B,EAC9B,WAAmB;IAEnB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO;QACL,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YACrD,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,IAAI;QACV,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC5D,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,WAAW;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,GAA8B,EAC9B,KAA6B;IAE7B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["import { createDocument, exportAllUpdates } from \"@tearleads/loro\";\nimport { getScopedPeerSeed } from \"../crdtPeerSeed\";\n\ninterface ContainerMetadataValue {\n icon: string | null;\n name: string;\n}\n\nexport type ContainerMetadataDocument = Awaited<\n ReturnType<typeof createDocument>\n>;\n\nexport function getDefaultContainerName(parentId: string | null): string {\n return parentId === null ? \"/\" : \"Untitled\";\n}\n\nexport async function createContainerMetadataDocument(\n _containerId: string,\n): Promise<ContainerMetadataDocument> {\n // A single static scope for all container-metadata docs: they are separate\n // CRDTs, so they can share one device peer, and a per-container scope would\n // hold a distinct device-peer lock (and cache entry) per container for the\n // tab's lifetime, accumulating without bound as containers are browsed.\n return createDocument(await getScopedPeerSeed(\"container-metadata\"));\n}\n\nexport async function createInitializedContainerMetadataDocument(\n containerId: string,\n value: ContainerMetadataValue,\n): Promise<{\n doc: ContainerMetadataDocument;\n initialUpdate: Uint8Array;\n}> {\n const doc = await createContainerMetadataDocument(containerId);\n writeContainerMetadataValue(doc, value);\n\n return {\n doc,\n initialUpdate: exportAllUpdates(doc),\n };\n}\n\nexport function readContainerMetadataValue(\n doc: ContainerMetadataDocument,\n defaultName: string,\n): ContainerMetadataValue {\n const metadata = doc.getMap(\"container\");\n const storedName = metadata.get(\"name\");\n const storedIcon = metadata.get(\"icon\");\n\n return {\n icon:\n typeof storedIcon === \"string\" && storedIcon.length > 0\n ? storedIcon\n : null,\n name:\n typeof storedName === \"string\" && storedName.trim().length > 0\n ? storedName\n : defaultName,\n };\n}\n\nexport function writeContainerMetadataValue(\n doc: ContainerMetadataDocument,\n value: ContainerMetadataValue,\n): void {\n const metadata = doc.getMap(\"container\");\n\n metadata.set(\"name\", value.name);\n\n if (value.icon) {\n metadata.set(\"icon\", value.icon);\n return;\n }\n\n metadata.delete(\"icon\");\n}\n"]}
1
+ {"version":3,"file":"containerMetadataDocument.js","sourceRoot":"","sources":["containerMetadataDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAWzD,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC7D,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,YAAoB;IAEpB,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,OAAO,cAAc,CAAC,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0CAA0C,CAC9D,WAAmB,EACnB,KAA6B;IAK7B,MAAM,GAAG,GAAG,MAAM,+BAA+B,CAAC,WAAW,CAAC,CAAC;IAC/D,2BAA2B,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAExC,OAAO;QACL,GAAG;QACH,aAAa,EAAE,gBAAgB,CAAC,GAAG,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,GAA8B,EAC9B,WAAmB;IAEnB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO;QACL,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YACrD,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,IAAI;QACV,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC5D,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,WAAW;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,GAA8B,EAC9B,KAA6B;IAE7B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["import { createDocument, exportAllUpdates } from \"@tearleads/loro\";\nimport { getScopedPeerSeed } from \"../sync/crdtPeerSeed\";\n\ninterface ContainerMetadataValue {\n icon: string | null;\n name: string;\n}\n\nexport type ContainerMetadataDocument = Awaited<\n ReturnType<typeof createDocument>\n>;\n\nexport function getDefaultContainerName(parentId: string | null): string {\n return parentId === null ? \"/\" : \"Untitled\";\n}\n\nexport async function createContainerMetadataDocument(\n _containerId: string,\n): Promise<ContainerMetadataDocument> {\n // A single static scope for all container-metadata docs: they are separate\n // CRDTs, so they can share one device peer, and a per-container scope would\n // hold a distinct device-peer lock (and cache entry) per container for the\n // tab's lifetime, accumulating without bound as containers are browsed.\n return createDocument(await getScopedPeerSeed(\"container-metadata\"));\n}\n\nexport async function createInitializedContainerMetadataDocument(\n containerId: string,\n value: ContainerMetadataValue,\n): Promise<{\n doc: ContainerMetadataDocument;\n initialUpdate: Uint8Array;\n}> {\n const doc = await createContainerMetadataDocument(containerId);\n writeContainerMetadataValue(doc, value);\n\n return {\n doc,\n initialUpdate: exportAllUpdates(doc),\n };\n}\n\nexport function readContainerMetadataValue(\n doc: ContainerMetadataDocument,\n defaultName: string,\n): ContainerMetadataValue {\n const metadata = doc.getMap(\"container\");\n const storedName = metadata.get(\"name\");\n const storedIcon = metadata.get(\"icon\");\n\n return {\n icon:\n typeof storedIcon === \"string\" && storedIcon.length > 0\n ? storedIcon\n : null,\n name:\n typeof storedName === \"string\" && storedName.trim().length > 0\n ? storedName\n : defaultName,\n };\n}\n\nexport function writeContainerMetadataValue(\n doc: ContainerMetadataDocument,\n value: ContainerMetadataValue,\n): void {\n const metadata = doc.getMap(\"container\");\n\n metadata.set(\"name\", value.name);\n\n if (value.icon) {\n metadata.set(\"icon\", value.icon);\n return;\n }\n\n metadata.delete(\"icon\");\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { computeAccessEventBodyHash, computeAccessEventHash, computeAccessManifestHash, computeContainerKekMaterialId, deriveContainerAccessManifest, signAccessEvent, } from "../../../internal/crypto/index.js";
2
- import { readCanonicalJson } from "../../keyingCanonicalJson.js";
2
+ import { readCanonicalJson } from "../../keying/canonicalJson.js";
3
3
  import { uniqueSortedManifestHashes } from "./projection.js";
4
4
  export function buildContainerCreateBody(input) {
5
5
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerAccessManifestState,\n type ContainerCreateAccessEventBody,\n type ContainerGrantAccessEventBody,\n type ContainerKekRecipientTarget,\n type ContainerKeyEpoch,\n type ContainerMoveAccessEventBody,\n type ContainerReciteAccessEventBody,\n type ContainerRekeyAccessEventBody,\n type ContainerRevokeAccessEventBody,\n computeAccessEventBodyHash,\n computeAccessEventHash,\n computeAccessManifestHash,\n computeContainerKekMaterialId,\n deriveContainerAccessManifest,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readCanonicalJson } from \"../../keyingCanonicalJson\";\nimport { uniqueSortedManifestHashes } from \"./projection\";\nimport type {\n ContainerCreatePlan,\n ContainerMovePlan,\n ContainerMutationAuthor,\n ContainerRevokePlan,\n ContainerSharePlan,\n} from \"./types\";\n\nexport function buildContainerCreateBody(input: {\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n}): ContainerCreateAccessEventBody {\n return {\n systemSlot: input.systemSlot ?? null,\n eventType: \"container.create\",\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: [],\n referencedPrincipalHeads: [],\n };\n}\n\nexport async function signContainerCreateEvent(input: {\n author: ContainerMutationAuthor;\n body: ContainerCreateAccessEventBody;\n containerId: string;\n eventId: string;\n // The organization the new container belongs to — always the parent\n // container's org, NOT the author's. A member writing under another org's\n // shared root creates a container owned by that org; only the signer identity\n // comes from the author. The server trusts this signed field, so it is the\n // load-bearing org for the create.\n organizationId: string;\n parentPath: ContainerWriterProjectionResponse[\"path\"];\n signedAt: string;\n}): Promise<Pick<ContainerCreatePlan, \"event\" | \"eventHash\">> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container create body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: \"container.create\",\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.organizationId,\n previousManifestHash: null,\n dependencyManifestHashes: uniqueSortedManifestHashes(input.parentPath),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function signContainerMutationEvent(input: {\n author: ContainerMutationAuthor;\n body:\n | ContainerGrantAccessEventBody\n | ContainerMoveAccessEventBody\n | ContainerRekeyAccessEventBody\n | ContainerReciteAccessEventBody\n | ContainerRevokeAccessEventBody;\n containerId: string;\n dependencyManifestHashes: readonly string[];\n eventId: string;\n previousManifestHash: string;\n signedAt: string;\n}): Promise<\n Pick<\n ContainerSharePlan | ContainerMovePlan | ContainerRevokePlan,\n \"event\" | \"eventHash\"\n >\n> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container mutation body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: input.body.eventType,\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.author.organizationId,\n previousManifestHash: input.previousManifestHash,\n dependencyManifestHashes: [\n ...new Set(input.dependencyManifestHashes),\n ].sort(),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function deriveContainerCreateManifest(input: {\n containerId: string;\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n // Grants baked into the create manifest. Defaults to none. A child container\n // born with a managed-principal (group/organization) grant — e.g. the org\n // public metadata container granted to the Members group — supplies both the\n // grant and its referenced principal head here so the manifest hash reconciles\n // with the signed event body and the server can derive the KEK recipient target.\n directGrants?: ContainerCreateAccessEventBody[\"directGrants\"] | undefined;\n eventHash: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n // The parent container's org (see signContainerCreateEvent). Must match the\n // signed event's org or the manifest hash will not reconcile server-side.\n organizationId: string;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n referencedPrincipalHeads?:\n | ContainerCreateAccessEventBody[\"referencedPrincipalHeads\"]\n | undefined;\n}): Promise<Pick<ContainerCreatePlan, \"manifest\" | \"manifestHash\" | \"state\">> {\n const state: ContainerAccessManifestState = {\n systemSlot: input.systemSlot ?? null,\n version: 1,\n containerId: input.containerId,\n organizationId: input.organizationId,\n epoch: 1,\n previousManifestHash: null,\n eventHash: input.eventHash,\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: input.directGrants ? [...input.directGrants] : [],\n referencedPrincipalHeads: input.referencedPrincipalHeads\n ? [...input.referencedPrincipalHeads]\n : [],\n };\n const manifest = await deriveContainerAccessManifest(state);\n\n return {\n manifest,\n manifestHash: await computeAccessManifestHash(manifest),\n state,\n };\n}\n\nexport function buildContainerCreateKeyEpoch(input: {\n containerId: string;\n containerKeyEpochId: string;\n eventHash: string;\n /** Defaults to the creation epoch; rotations pass their next epoch. */\n keyEpoch?: number | undefined;\n manifestHash: string;\n parentContainerKeyEpochId: string | null;\n}): ContainerKeyEpoch {\n return {\n id: input.containerKeyEpochId,\n containerId: input.containerId,\n keyEpoch: input.keyEpoch ?? 1,\n accessManifestHash: input.manifestHash,\n parentContainerKeyEpochId: input.parentContainerKeyEpochId,\n createdByEventHash: input.eventHash,\n createdByManifestHash: input.manifestHash,\n };\n}\n\nexport function buildParentRecipientTargets(\n parentKek: ContainerKekResponse,\n): ContainerKekRecipientTarget[] {\n return [\n {\n recipientKind: \"container\",\n recipientId: parentKek.containerId,\n recipientKeyEpochId: parentKek.containerKeyEpochId,\n recipientKeyFingerprint: parentKek.keyEpochHash,\n },\n ];\n}\n\nexport async function resolveContainerKekEpochId(input: {\n containerId: string;\n keyEpoch: number;\n keyMaterial: Uint8Array;\n override?: string | undefined;\n}): Promise<string> {\n const materialId = await computeContainerKekMaterialId({\n containerId: input.containerId,\n keyEpoch: input.keyEpoch,\n keyMaterial: input.keyMaterial,\n });\n if (input.override !== undefined && input.override !== materialId) {\n throw new Error(\n \"Container key epoch id does not match the committed KEK material\",\n );\n }\n\n return materialId;\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerAccessManifestState,\n type ContainerCreateAccessEventBody,\n type ContainerGrantAccessEventBody,\n type ContainerKekRecipientTarget,\n type ContainerKeyEpoch,\n type ContainerMoveAccessEventBody,\n type ContainerReciteAccessEventBody,\n type ContainerRekeyAccessEventBody,\n type ContainerRevokeAccessEventBody,\n computeAccessEventBodyHash,\n computeAccessEventHash,\n computeAccessManifestHash,\n computeContainerKekMaterialId,\n deriveContainerAccessManifest,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readCanonicalJson } from \"../../keying/canonicalJson\";\nimport { uniqueSortedManifestHashes } from \"./projection\";\nimport type {\n ContainerCreatePlan,\n ContainerMovePlan,\n ContainerMutationAuthor,\n ContainerRevokePlan,\n ContainerSharePlan,\n} from \"./types\";\n\nexport function buildContainerCreateBody(input: {\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n}): ContainerCreateAccessEventBody {\n return {\n systemSlot: input.systemSlot ?? null,\n eventType: \"container.create\",\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: [],\n referencedPrincipalHeads: [],\n };\n}\n\nexport async function signContainerCreateEvent(input: {\n author: ContainerMutationAuthor;\n body: ContainerCreateAccessEventBody;\n containerId: string;\n eventId: string;\n // The organization the new container belongs to — always the parent\n // container's org, NOT the author's. A member writing under another org's\n // shared root creates a container owned by that org; only the signer identity\n // comes from the author. The server trusts this signed field, so it is the\n // load-bearing org for the create.\n organizationId: string;\n parentPath: ContainerWriterProjectionResponse[\"path\"];\n signedAt: string;\n}): Promise<Pick<ContainerCreatePlan, \"event\" | \"eventHash\">> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container create body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: \"container.create\",\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.organizationId,\n previousManifestHash: null,\n dependencyManifestHashes: uniqueSortedManifestHashes(input.parentPath),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function signContainerMutationEvent(input: {\n author: ContainerMutationAuthor;\n body:\n | ContainerGrantAccessEventBody\n | ContainerMoveAccessEventBody\n | ContainerRekeyAccessEventBody\n | ContainerReciteAccessEventBody\n | ContainerRevokeAccessEventBody;\n containerId: string;\n dependencyManifestHashes: readonly string[];\n eventId: string;\n previousManifestHash: string;\n signedAt: string;\n}): Promise<\n Pick<\n ContainerSharePlan | ContainerMovePlan | ContainerRevokePlan,\n \"event\" | \"eventHash\"\n >\n> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container mutation body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: input.body.eventType,\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.author.organizationId,\n previousManifestHash: input.previousManifestHash,\n dependencyManifestHashes: [\n ...new Set(input.dependencyManifestHashes),\n ].sort(),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function deriveContainerCreateManifest(input: {\n containerId: string;\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n // Grants baked into the create manifest. Defaults to none. A child container\n // born with a managed-principal (group/organization) grant — e.g. the org\n // public metadata container granted to the Members group — supplies both the\n // grant and its referenced principal head here so the manifest hash reconciles\n // with the signed event body and the server can derive the KEK recipient target.\n directGrants?: ContainerCreateAccessEventBody[\"directGrants\"] | undefined;\n eventHash: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n // The parent container's org (see signContainerCreateEvent). Must match the\n // signed event's org or the manifest hash will not reconcile server-side.\n organizationId: string;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n referencedPrincipalHeads?:\n | ContainerCreateAccessEventBody[\"referencedPrincipalHeads\"]\n | undefined;\n}): Promise<Pick<ContainerCreatePlan, \"manifest\" | \"manifestHash\" | \"state\">> {\n const state: ContainerAccessManifestState = {\n systemSlot: input.systemSlot ?? null,\n version: 1,\n containerId: input.containerId,\n organizationId: input.organizationId,\n epoch: 1,\n previousManifestHash: null,\n eventHash: input.eventHash,\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: input.directGrants ? [...input.directGrants] : [],\n referencedPrincipalHeads: input.referencedPrincipalHeads\n ? [...input.referencedPrincipalHeads]\n : [],\n };\n const manifest = await deriveContainerAccessManifest(state);\n\n return {\n manifest,\n manifestHash: await computeAccessManifestHash(manifest),\n state,\n };\n}\n\nexport function buildContainerCreateKeyEpoch(input: {\n containerId: string;\n containerKeyEpochId: string;\n eventHash: string;\n /** Defaults to the creation epoch; rotations pass their next epoch. */\n keyEpoch?: number | undefined;\n manifestHash: string;\n parentContainerKeyEpochId: string | null;\n}): ContainerKeyEpoch {\n return {\n id: input.containerKeyEpochId,\n containerId: input.containerId,\n keyEpoch: input.keyEpoch ?? 1,\n accessManifestHash: input.manifestHash,\n parentContainerKeyEpochId: input.parentContainerKeyEpochId,\n createdByEventHash: input.eventHash,\n createdByManifestHash: input.manifestHash,\n };\n}\n\nexport function buildParentRecipientTargets(\n parentKek: ContainerKekResponse,\n): ContainerKekRecipientTarget[] {\n return [\n {\n recipientKind: \"container\",\n recipientId: parentKek.containerId,\n recipientKeyEpochId: parentKek.containerKeyEpochId,\n recipientKeyFingerprint: parentKek.keyEpochHash,\n },\n ];\n}\n\nexport async function resolveContainerKekEpochId(input: {\n containerId: string;\n keyEpoch: number;\n keyMaterial: Uint8Array;\n override?: string | undefined;\n}): Promise<string> {\n const materialId = await computeContainerKekMaterialId({\n containerId: input.containerId,\n keyEpoch: input.keyEpoch,\n keyMaterial: input.keyMaterial,\n });\n if (input.override !== undefined && input.override !== materialId) {\n throw new Error(\n \"Container key epoch id does not match the committed KEK material\",\n );\n }\n\n return materialId;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { MAX_CONTAINER_PATH_LENGTH } from "../../../internal/validators/util/index.js";
2
- import { readCanonicalRecord } from "../../keyingCanonicalJson.js";
2
+ import { readCanonicalRecord } from "../../keying/canonicalJson.js";
3
3
  import { resolveCanonicalExecSql } from "../../sqlite/sqlSchema.js";
4
4
  // Opportunistic, process-local evidence, not a persistent cache or freshness
5
5
  // oracle. No secret keys are retained. Eviction merely limits cascade coverage.
@@ -1 +1 @@
1
- {"version":3,"file":"heldContainerHeads.js","sourceRoot":"","sources":["heldContainerHeads.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerAccessManifestState,\n VerifiedContainerAccessManifest,\n} from \"@tearleads/crypto\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport { MAX_CONTAINER_PATH_LENGTH } from \"@tearleads/validators/util\";\nimport { readCanonicalRecord } from \"../../keyingCanonicalJson\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../../principals/principalPolicyEvidence\";\nimport { type ExecSql, resolveCanonicalExecSql } from \"../../sqlite/sqlSchema\";\nimport type { AuthoredContainerMutationHead } from \"./mutationAcknowledgement\";\n\nexport interface HeldContainerHead {\n readonly bundle: AccessManifestBundleWire;\n readonly state: ContainerAccessManifestState;\n}\n\ninterface HeldContainers {\n readonly heads: Map<string, HeldContainerHead>;\n readonly policies: Map<\n string,\n {\n readonly organizationId: string;\n readonly policy: PrincipalPolicyCheckpointEvidence;\n }\n >;\n}\n\n// Opportunistic, process-local evidence, not a persistent cache or freshness\n// oracle. No secret keys are retained. Eviction merely limits cascade coverage.\nconst heldByDatabase = new WeakMap<ExecSql, HeldContainers>();\n// Executor-wide limits: another organization's activity may evict evidence,\n// which only skips optional recitations and never changes durable checkpoints.\nconst MAX_HEADS = 256;\nconst MAX_POLICIES = 512;\n\nfunction heldContainers(execSql: ExecSql): HeldContainers {\n const canonical = resolveCanonicalExecSql(execSql);\n let held = heldByDatabase.get(canonical);\n if (!held) {\n held = { heads: new Map(), policies: new Map() };\n heldByDatabase.set(canonical, held);\n }\n return held;\n}\n\nfunction boundedSet<T>(\n map: Map<string, T>,\n key: string,\n value: T,\n max: number,\n) {\n map.delete(key);\n map.set(key, value);\n if (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest !== undefined) map.delete(oldest);\n }\n}\n\nfunction rememberHead(\n execSql: ExecSql,\n head: Pick<VerifiedContainerAccessManifest, \"state\" | \"manifestHash\">,\n build: () => HeldContainerHead,\n): void {\n const heads = heldContainers(execSql).heads;\n const previous = heads.get(head.state.containerId);\n if (previous && previous.state.epoch >= head.state.epoch) {\n if (previous.bundle.manifestHash === head.manifestHash) {\n boundedSet(heads, head.state.containerId, previous, MAX_HEADS);\n }\n return;\n }\n boundedSet(\n heads,\n head.state.containerId,\n structuredClone(build()),\n MAX_HEADS,\n );\n}\n\n/** Called only after the complete projection and its durable pins validate. */\nexport function rememberVerifiedContainerHeads(input: {\n readonly organizationId: string;\n readonly execSql: ExecSql;\n readonly heads: readonly VerifiedContainerAccessManifest[];\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n}): void {\n for (const policy of input.policies) {\n if (\n policy.principalType === \"organization\" &&\n policy.principalId !== input.organizationId\n ) {\n throw new Error(\"Held principal policy belongs to another organization\");\n }\n }\n // Group signed states contain no organization ID. Their scope is supplied\n // by the already-verified projection/policy caller, not inferred here.\n for (const head of input.heads) {\n if (head.state.organizationId !== input.organizationId) {\n throw new Error(\"Held container head belongs to another organization\");\n }\n }\n for (const head of input.heads) {\n rememberHead(input.execSql, head, () => ({\n state: head.state,\n bundle: {\n event: readCanonicalRecord(head.event, \"Verified container event\"),\n manifest: readCanonicalRecord(\n head.manifest,\n \"Verified container manifest\",\n ),\n manifestHash: head.manifestHash,\n state: readCanonicalRecord(head.state, \"Verified container state\"),\n },\n }));\n }\n const policies = heldContainers(input.execSql).policies;\n for (const policy of input.policies) {\n const key = `${input.organizationId}:${policy.principalType}:${policy.principalId}`;\n const previous = policies.get(key);\n if (previous && previous.policy.version > policy.version) continue;\n if (\n previous?.policy.version === policy.version &&\n previous.policy.stateHash !== policy.stateHash\n )\n continue;\n boundedSet(\n policies,\n key,\n { organizationId: input.organizationId, policy: structuredClone(policy) },\n MAX_POLICIES,\n );\n }\n}\n\n/** Caller must first correlate the exact response and durably acknowledge it. */\nexport function rememberAcknowledgedContainerHead(\n execSql: ExecSql,\n plan: Pick<\n AuthoredContainerMutationHead,\n \"body\" | \"event\" | \"eventHash\" | \"manifest\" | \"manifestHash\" | \"state\"\n >,\n): HeldContainerHead {\n const head: HeldContainerHead = {\n state: plan.state,\n bundle: {\n event: readCanonicalRecord(\n {\n event: plan.event,\n eventHash: plan.eventHash,\n body: plan.body,\n },\n \"Acknowledged container event\",\n ),\n manifest: readCanonicalRecord(\n plan.manifest,\n \"Acknowledged container manifest\",\n ),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Acknowledged container state\"),\n },\n };\n rememberHead(execSql, plan, () => head);\n return head;\n}\n\nexport function heldContainerSnapshot(\n execSql: ExecSql,\n organizationId: string,\n) {\n const held = heldContainers(execSql);\n return {\n heads: new Map(\n [...held.heads]\n .filter(([, head]) => head.state.organizationId === organizationId)\n .map(([id, head]) => [id, structuredClone(head)] as const),\n ),\n policies: [...held.policies.values()]\n .filter((entry) => entry.organizationId === organizationId)\n .map((entry) => structuredClone(entry.policy)),\n };\n}\n\n/** Resolve parent edges only; parentManifestHash is historical keying evidence. */\nexport function heldContainerPath(\n heads: ReadonlyMap<string, HeldContainerHead>,\n containerId: string,\n): HeldContainerHead[] | null {\n const path: HeldContainerHead[] = [];\n const seen = new Set<string>();\n let id: string | null = containerId;\n while (id !== null) {\n if (seen.has(id) || path.length >= MAX_CONTAINER_PATH_LENGTH) return null;\n seen.add(id);\n const head = heads.get(id);\n if (!head) return null;\n path.unshift(head);\n id = head.state.parentContainerId;\n }\n return path;\n}\n"]}
1
+ {"version":3,"file":"heldContainerHeads.js","sourceRoot":"","sources":["heldContainerHeads.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerAccessManifestState,\n VerifiedContainerAccessManifest,\n} from \"@tearleads/crypto\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport { MAX_CONTAINER_PATH_LENGTH } from \"@tearleads/validators/util\";\nimport { readCanonicalRecord } from \"../../keying/canonicalJson\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../../principals/principalPolicyEvidence\";\nimport { type ExecSql, resolveCanonicalExecSql } from \"../../sqlite/sqlSchema\";\nimport type { AuthoredContainerMutationHead } from \"./mutationAcknowledgement\";\n\nexport interface HeldContainerHead {\n readonly bundle: AccessManifestBundleWire;\n readonly state: ContainerAccessManifestState;\n}\n\ninterface HeldContainers {\n readonly heads: Map<string, HeldContainerHead>;\n readonly policies: Map<\n string,\n {\n readonly organizationId: string;\n readonly policy: PrincipalPolicyCheckpointEvidence;\n }\n >;\n}\n\n// Opportunistic, process-local evidence, not a persistent cache or freshness\n// oracle. No secret keys are retained. Eviction merely limits cascade coverage.\nconst heldByDatabase = new WeakMap<ExecSql, HeldContainers>();\n// Executor-wide limits: another organization's activity may evict evidence,\n// which only skips optional recitations and never changes durable checkpoints.\nconst MAX_HEADS = 256;\nconst MAX_POLICIES = 512;\n\nfunction heldContainers(execSql: ExecSql): HeldContainers {\n const canonical = resolveCanonicalExecSql(execSql);\n let held = heldByDatabase.get(canonical);\n if (!held) {\n held = { heads: new Map(), policies: new Map() };\n heldByDatabase.set(canonical, held);\n }\n return held;\n}\n\nfunction boundedSet<T>(\n map: Map<string, T>,\n key: string,\n value: T,\n max: number,\n) {\n map.delete(key);\n map.set(key, value);\n if (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest !== undefined) map.delete(oldest);\n }\n}\n\nfunction rememberHead(\n execSql: ExecSql,\n head: Pick<VerifiedContainerAccessManifest, \"state\" | \"manifestHash\">,\n build: () => HeldContainerHead,\n): void {\n const heads = heldContainers(execSql).heads;\n const previous = heads.get(head.state.containerId);\n if (previous && previous.state.epoch >= head.state.epoch) {\n if (previous.bundle.manifestHash === head.manifestHash) {\n boundedSet(heads, head.state.containerId, previous, MAX_HEADS);\n }\n return;\n }\n boundedSet(\n heads,\n head.state.containerId,\n structuredClone(build()),\n MAX_HEADS,\n );\n}\n\n/** Called only after the complete projection and its durable pins validate. */\nexport function rememberVerifiedContainerHeads(input: {\n readonly organizationId: string;\n readonly execSql: ExecSql;\n readonly heads: readonly VerifiedContainerAccessManifest[];\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n}): void {\n for (const policy of input.policies) {\n if (\n policy.principalType === \"organization\" &&\n policy.principalId !== input.organizationId\n ) {\n throw new Error(\"Held principal policy belongs to another organization\");\n }\n }\n // Group signed states contain no organization ID. Their scope is supplied\n // by the already-verified projection/policy caller, not inferred here.\n for (const head of input.heads) {\n if (head.state.organizationId !== input.organizationId) {\n throw new Error(\"Held container head belongs to another organization\");\n }\n }\n for (const head of input.heads) {\n rememberHead(input.execSql, head, () => ({\n state: head.state,\n bundle: {\n event: readCanonicalRecord(head.event, \"Verified container event\"),\n manifest: readCanonicalRecord(\n head.manifest,\n \"Verified container manifest\",\n ),\n manifestHash: head.manifestHash,\n state: readCanonicalRecord(head.state, \"Verified container state\"),\n },\n }));\n }\n const policies = heldContainers(input.execSql).policies;\n for (const policy of input.policies) {\n const key = `${input.organizationId}:${policy.principalType}:${policy.principalId}`;\n const previous = policies.get(key);\n if (previous && previous.policy.version > policy.version) continue;\n if (\n previous?.policy.version === policy.version &&\n previous.policy.stateHash !== policy.stateHash\n )\n continue;\n boundedSet(\n policies,\n key,\n { organizationId: input.organizationId, policy: structuredClone(policy) },\n MAX_POLICIES,\n );\n }\n}\n\n/** Caller must first correlate the exact response and durably acknowledge it. */\nexport function rememberAcknowledgedContainerHead(\n execSql: ExecSql,\n plan: Pick<\n AuthoredContainerMutationHead,\n \"body\" | \"event\" | \"eventHash\" | \"manifest\" | \"manifestHash\" | \"state\"\n >,\n): HeldContainerHead {\n const head: HeldContainerHead = {\n state: plan.state,\n bundle: {\n event: readCanonicalRecord(\n {\n event: plan.event,\n eventHash: plan.eventHash,\n body: plan.body,\n },\n \"Acknowledged container event\",\n ),\n manifest: readCanonicalRecord(\n plan.manifest,\n \"Acknowledged container manifest\",\n ),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Acknowledged container state\"),\n },\n };\n rememberHead(execSql, plan, () => head);\n return head;\n}\n\nexport function heldContainerSnapshot(\n execSql: ExecSql,\n organizationId: string,\n) {\n const held = heldContainers(execSql);\n return {\n heads: new Map(\n [...held.heads]\n .filter(([, head]) => head.state.organizationId === organizationId)\n .map(([id, head]) => [id, structuredClone(head)] as const),\n ),\n policies: [...held.policies.values()]\n .filter((entry) => entry.organizationId === organizationId)\n .map((entry) => structuredClone(entry.policy)),\n };\n}\n\n/** Resolve parent edges only; parentManifestHash is historical keying evidence. */\nexport function heldContainerPath(\n heads: ReadonlyMap<string, HeldContainerHead>,\n containerId: string,\n): HeldContainerHead[] | null {\n const path: HeldContainerHead[] = [];\n const seen = new Set<string>();\n let id: string | null = containerId;\n while (id !== null) {\n if (seen.has(id) || path.length >= MAX_CONTAINER_PATH_LENGTH) return null;\n seen.add(id);\n const head = heads.get(id);\n if (!head) return null;\n path.unshift(head);\n id = head.state.parentContainerId;\n }\n return path;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { accessManifestCheckpointFromManifest, compareCanonicalStrings, computeContainerKekKeyringHash, computeContainerKekRecipientTargetHash, computeContainerKeyEpochHash, } from "../../../internal/crypto/index.js";
2
- import { canonicalKeyingJsonString } from "../../keyingCanonicalJson.js";
2
+ import { canonicalKeyingJsonString } from "../../keying/canonicalJson.js";
3
3
  import { advanceLocallyAcknowledgedAccessManifestHeadsAtomically, } from "../../persistence/locallyAcknowledgedCheckpointPersistence.js";
4
4
  function assertCanonicalMatch(input) {
5
5
  if (canonicalKeyingJsonString(input.actual, `${input.label} response`) !==