@tearleads/client-sdk 0.1.58 → 0.1.60

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 (477) hide show
  1. package/Tearleads.d.ts +17 -17
  2. package/Tearleads.js +15 -15
  3. package/Tearleads.js.map +1 -1
  4. package/client/{blobs.d.ts → blobs/index.d.ts} +1 -1
  5. package/client/{blobs.js → blobs/index.js} +3 -3
  6. package/client/blobs/index.js.map +1 -0
  7. package/client/{containerDocumentDiscovery.js → containerContents/documentDiscovery.js} +11 -11
  8. package/client/containerContents/documentDiscovery.js.map +1 -0
  9. package/client/{containerContents.d.ts → containerContents/index.d.ts} +13 -13
  10. package/client/{containerContents.js → containerContents/index.js} +18 -18
  11. package/client/containerContents/index.js.map +1 -0
  12. package/client/{containerContentsTypes.d.ts → containerContents/types.d.ts} +14 -14
  13. package/client/containerContents/types.js +2 -0
  14. package/client/containerContents/types.js.map +1 -0
  15. package/client/{deviceFirst.d.ts → deviceFirst/index.d.ts} +7 -7
  16. package/client/{deviceFirst.js → deviceFirst/index.js} +11 -11
  17. package/client/deviceFirst/index.js.map +1 -0
  18. package/client/{reconciledDocumentContentPull.js → deviceFirst/reconciledDocumentContentPull.js} +1 -1
  19. package/client/deviceFirst/reconciledDocumentContentPull.js.map +1 -0
  20. package/client/{documents.d.ts → documents/index.d.ts} +5 -5
  21. package/client/{documents.js → documents/index.js} +5 -5
  22. package/client/documents/index.js.map +1 -0
  23. package/client/{identity.d.ts → identity/index.d.ts} +2 -2
  24. package/client/{identity.js → identity/index.js} +5 -5
  25. package/client/identity/index.js.map +1 -0
  26. package/client/{identityKeyPackage.d.ts → identity/keyPackage.d.ts} +1 -1
  27. package/client/{identityKeyPackage.js → identity/keyPackage.js} +4 -4
  28. package/client/identity/keyPackage.js.map +1 -0
  29. package/client/{userIdentities.d.ts → identity/userIdentities.d.ts} +2 -2
  30. package/client/{userIdentities.js → identity/userIdentities.js} +4 -4
  31. package/client/identity/userIdentities.js.map +1 -0
  32. package/client/index.d.ts +18 -18
  33. package/client/index.js +9 -9
  34. package/client/index.js.map +1 -1
  35. package/client/organizations/currentPrincipalMutations.js.map +1 -1
  36. package/client/organizations/index.d.ts +2 -2
  37. package/client/organizations/index.js.map +1 -1
  38. package/client/organizations/organizationAccessRestoration.js.map +1 -1
  39. package/client/organizations/organizationDataUsage.d.ts +1 -1
  40. package/client/organizations/organizationDataUsage.js.map +1 -1
  41. package/client/organizations/organizationGroupNameHydration.js.map +1 -1
  42. package/client/organizations/organizationGroupPresentation.d.ts +1 -1
  43. package/client/organizations/organizationGroupPresentation.js.map +1 -1
  44. package/client/organizations/organizationMetadataProfileSync.js +1 -1
  45. package/client/organizations/organizationMetadataProfileSync.js.map +1 -1
  46. package/client/organizations/organizationReadModels.d.ts +1 -1
  47. package/client/organizations/organizationReadModels.js.map +1 -1
  48. package/client/organizations/organizationWorkflowRuntime.js.map +1 -1
  49. package/client/organizations/organizationsTypes.d.ts +1 -1
  50. package/client/organizations/organizationsTypes.js.map +1 -1
  51. package/client/organizations/principalContainerMutations.js.map +1 -1
  52. package/client/organizations/principalMutationRecovery.d.ts +1 -1
  53. package/client/organizations/principalMutationRecovery.js.map +1 -1
  54. package/client/organizations/principalMutationScope.js.map +1 -1
  55. package/client/organizations/principalMutations.d.ts +2 -2
  56. package/client/organizations/principalMutations.js.map +1 -1
  57. package/client/root/index.d.ts +1 -1
  58. package/client/root/index.js.map +1 -1
  59. package/client/{database.d.ts → runtime/database.d.ts} +1 -1
  60. package/client/{database.js → runtime/database.js} +1 -1
  61. package/client/runtime/database.js.map +1 -0
  62. package/client/{principalHistoryProtection.d.ts → runtime/principalHistoryProtection.d.ts} +1 -1
  63. package/client/{principalHistoryProtection.js → runtime/principalHistoryProtection.js} +2 -2
  64. package/client/runtime/principalHistoryProtection.js.map +1 -0
  65. package/client/{principalMutationApi.d.ts → runtime/principalMutationApi.d.ts} +4 -4
  66. package/client/{principalMutationApi.js → runtime/principalMutationApi.js} +2 -2
  67. package/client/runtime/principalMutationApi.js.map +1 -0
  68. package/client/{principalMutationDispatch.js → runtime/principalMutationDispatch.js} +2 -2
  69. package/client/runtime/principalMutationDispatch.js.map +1 -0
  70. package/client/runtime/rootContainerAdoption.js.map +1 -0
  71. package/client/{workflowRuntime.d.ts → runtime/workflowRuntime.d.ts} +12 -12
  72. package/client/{workflowRuntime.js → runtime/workflowRuntime.js} +5 -5
  73. package/client/runtime/workflowRuntime.js.map +1 -0
  74. package/client/{securityIncidents.d.ts → securityIncidents/index.d.ts} +3 -3
  75. package/client/{securityIncidents.js → securityIncidents/index.js} +5 -5
  76. package/client/securityIncidents/index.js.map +1 -0
  77. package/client/session/index.js +1 -1
  78. package/client/session/index.js.map +1 -1
  79. package/client/session/sessionIdentityTrust.d.ts +1 -1
  80. package/client/session/sessionLoginRefusal.js.map +1 -1
  81. package/client/session/sessionOrganizationCreation.js.map +1 -1
  82. package/client/session/sessionPurgeRecovery.js.map +1 -1
  83. package/client/session/sessionRootAuthority.js.map +1 -1
  84. package/client/session/sessionTypes.d.ts +3 -3
  85. package/client/session/sessionTypes.js.map +1 -1
  86. package/data/blobs/createBlobStore.d.ts +1 -1
  87. package/data/blobs/createBlobStore.js.map +1 -1
  88. package/data/blobs/encryptedBlobByteSource.js +1 -1
  89. package/data/blobs/encryptedBlobByteSource.js.map +1 -1
  90. package/data/blobs/encryptedBlobEnvelope.d.ts +1 -1
  91. package/data/blobs/encryptedBlobEnvelope.js +2 -2
  92. package/data/blobs/encryptedBlobEnvelope.js.map +1 -1
  93. package/data/blobs/encryptedBlobStore.d.ts +1 -1
  94. package/data/blobs/encryptedBlobStore.js +1 -1
  95. package/data/blobs/encryptedBlobStore.js.map +1 -1
  96. package/data/blobs/memoryBlobStore.d.ts +1 -1
  97. package/data/blobs/memoryBlobStore.js +1 -1
  98. package/data/blobs/memoryBlobStore.js.map +1 -1
  99. package/data/blobs/opfsBlobStore.d.ts +1 -1
  100. package/data/blobs/opfsBlobStore.js +1 -1
  101. package/data/blobs/opfsBlobStore.js.map +1 -1
  102. package/data/containers/containerMetadataDocument.js +1 -1
  103. package/data/containers/containerMetadataDocument.js.map +1 -1
  104. package/data/containers/shared/events.js +1 -1
  105. package/data/containers/shared/events.js.map +1 -1
  106. package/data/containers/shared/heldContainerHeads.js +1 -1
  107. package/data/containers/shared/heldContainerHeads.js.map +1 -1
  108. package/data/containers/shared/mutationAcknowledgement.js +1 -1
  109. package/data/containers/shared/mutationAcknowledgement.js.map +1 -1
  110. package/data/containers/shared/principalPolicies.js +1 -1
  111. package/data/containers/shared/principalPolicies.js.map +1 -1
  112. package/data/containers/shared/readers.js +2 -2
  113. package/data/containers/shared/readers.js.map +1 -1
  114. package/data/documents/attachmentContentIdentity.js +1 -1
  115. package/data/documents/attachmentContentIdentity.js.map +1 -1
  116. package/data/documents/blob/shared/blobEnvelopeStream.js.map +1 -1
  117. package/data/documents/blob/shared/blobSourceSnapshot.d.ts +1 -1
  118. package/data/documents/blob/shared/blobSourceSnapshot.js.map +1 -1
  119. package/data/documents/blob/shared/chunkedBlobCrypto.js.map +1 -1
  120. package/data/documents/blob/shared/encryptedUploadParts.js.map +1 -1
  121. package/data/documents/blob/shared/events.js +1 -1
  122. package/data/documents/blob/shared/events.js.map +1 -1
  123. package/data/documents/blob/shared/types.d.ts +2 -2
  124. package/data/documents/blob/shared/types.js.map +1 -1
  125. package/data/documents/shared/containerKekPathHistory.js +1 -1
  126. package/data/documents/shared/containerKekPathHistory.js.map +1 -1
  127. package/data/documents/shared/containerKekPathVerification.d.ts +1 -1
  128. package/data/documents/shared/containerKekPathVerification.js +1 -1
  129. package/data/documents/shared/events.js +1 -1
  130. package/data/documents/shared/events.js.map +1 -1
  131. package/data/documents/shared/manifestBundleReaders.js +2 -2
  132. package/data/documents/shared/manifestBundleReaders.js.map +1 -1
  133. package/data/documents/shared/projection.d.ts +1 -1
  134. package/data/documents/shared/projection.js +2 -2
  135. package/data/documents/shared/projection.js.map +1 -1
  136. package/data/documents/shared/projectionContentKeys.d.ts +1 -1
  137. package/data/documents/shared/readers.js +3 -3
  138. package/data/documents/shared/readers.js.map +1 -1
  139. package/data/documents/shared/stableDocumentId.js +1 -1
  140. package/data/documents/shared/stableDocumentId.js.map +1 -1
  141. package/data/documents/shared/types.d.ts +1 -1
  142. package/data/documents/shared/types.js +1 -1
  143. package/data/{keyingCanonicalJson.js → keying/canonicalJson.js} +3 -3
  144. package/data/keying/canonicalJson.js.map +1 -0
  145. package/data/keyingProjectionVerification/bundleVerification.js +1 -1
  146. package/data/keyingProjectionVerification/bundleVerification.js.map +1 -1
  147. package/data/keyingProjectionVerification/containerAncestorCitations.js +1 -1
  148. package/data/keyingProjectionVerification/containerAncestorCitations.js.map +1 -1
  149. package/data/keyingProjectionVerification/containerManifestVerification.js +1 -1
  150. package/data/keyingProjectionVerification/containerManifestVerification.js.map +1 -1
  151. package/data/keyingProjectionVerification/documentManifestVerification.js +1 -1
  152. package/data/keyingProjectionVerification/documentManifestVerification.js.map +1 -1
  153. package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js +1 -1
  154. package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js.map +1 -1
  155. package/data/keyingProjectionVerification/error.js +1 -1
  156. package/data/keyingProjectionVerification/error.js.map +1 -1
  157. package/data/keyingProjectionVerification/index.d.ts +9 -0
  158. package/data/{keyingProjectionVerification.js → keyingProjectionVerification/index.js} +8 -8
  159. package/data/keyingProjectionVerification/index.js.map +1 -0
  160. package/data/keyingProjectionVerification/principalPolicyCache.js +1 -1
  161. package/data/keyingProjectionVerification/principalPolicyCache.js.map +1 -1
  162. package/data/keyingProjectionVerification/principalPolicyVerification.js +1 -1
  163. package/data/keyingProjectionVerification/principalPolicyVerification.js.map +1 -1
  164. package/data/keyingProjectionVerification/readers.d.ts +1 -1
  165. package/data/keyingProjectionVerification/readers.js +3 -3
  166. package/data/keyingProjectionVerification/readers.js.map +1 -1
  167. package/data/keyingProjectionVerification/userKeyResolver.d.ts +1 -1
  168. package/data/keyingProjectionVerification/userKeyResolver.js.map +1 -1
  169. package/data/persistence/containers/containerPersistence.js +1 -1
  170. package/data/persistence/containers/containerPersistence.js.map +1 -1
  171. package/data/persistence/documents/documentDiscoveryCandidate.js +1 -1
  172. package/data/persistence/documents/documentDiscoveryCandidate.js.map +1 -1
  173. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +1 -1
  174. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  175. package/data/persistence/documents/internal/documentProjectionRows.js +1 -1
  176. package/data/persistence/documents/internal/documentProjectionRows.js.map +1 -1
  177. package/data/persistence/documents/internal/documentRows.js +1 -1
  178. package/data/persistence/documents/internal/documentRows.js.map +1 -1
  179. package/data/persistence/principalPolicyBundleIntegrity.js +1 -1
  180. package/data/persistence/principalPolicyBundleIntegrity.js.map +1 -1
  181. package/data/persistence/principalPolicyReferenceCheckpoint.js +1 -1
  182. package/data/persistence/principalPolicyReferenceCheckpoint.js.map +1 -1
  183. package/data/persistence/principalPolicyReferenceIndexPersistence.js +1 -1
  184. package/data/persistence/principalPolicyReferenceIndexPersistence.js.map +1 -1
  185. package/data/persistence/principalPolicyReferencePersistence.js +1 -1
  186. package/data/persistence/principalPolicyReferencePersistence.js.map +1 -1
  187. package/data/persistence/securityIncidentPersistence.js.map +1 -1
  188. package/data/persistence/verifiedPrincipalPolicyBundle.js +1 -1
  189. package/data/persistence/verifiedPrincipalPolicyBundle.js.map +1 -1
  190. package/data/persistence/verifiedPrincipalPolicyCurrent.js +1 -1
  191. package/data/persistence/verifiedPrincipalPolicyCurrent.js.map +1 -1
  192. package/data/principals/principalMutationJournal.js +1 -1
  193. package/data/principals/principalMutationJournal.js.map +1 -1
  194. package/data/{securityIncidents.d.ts → shared/securityIncidents.d.ts} +1 -1
  195. package/data/sqlite/documentRecordPersistence.js +1 -1
  196. package/data/sqlite/documentRecordPersistence.js.map +1 -1
  197. package/data/sync/crdtPeerSeed.d.ts +18 -0
  198. package/data/sync/originatedDocuments.d.ts +1 -1
  199. package/data/sync/originatedDocuments.js.map +1 -1
  200. package/data/sync/syncCoordinator.d.ts +1 -1
  201. package/data/sync/syncCoordinator.js.map +1 -1
  202. package/package.json +1 -1
  203. package/stores/container-contents/backgroundHydration.js +1 -1
  204. package/stores/container-contents/backgroundHydration.js.map +1 -1
  205. package/stores/container-contents/containerContentsStore.d.ts +1 -1
  206. package/stores/container-contents/containerContentsStore.js.map +1 -1
  207. package/stores/container-contents/localRefresh.js +1 -1
  208. package/stores/container-contents/localRefresh.js.map +1 -1
  209. package/stores/container-contents/remoteContainerIngestion.js +1 -1
  210. package/stores/container-contents/remoteContainerIngestion.js.map +1 -1
  211. package/stores/container-contents/remoteWriteQueue.js +1 -1
  212. package/stores/container-contents/remoteWriteQueue.js.map +1 -1
  213. package/stores/container-contents/systemContainerHydration.js +1 -1
  214. package/stores/container-contents/systemContainerHydration.js.map +1 -1
  215. package/stores/container-contents/utils.js +1 -1
  216. package/stores/container-contents/utils.js.map +1 -1
  217. package/stores/documents/documentStore/attachmentIntents.js +1 -1
  218. package/stores/documents/documentStore/attachmentIntents.js.map +1 -1
  219. package/stores/documents/documentStore/attachmentSourceUpload.js.map +1 -1
  220. package/stores/documents/documentStore/attachmentStaging.js +1 -1
  221. package/stores/documents/documentStore/attachmentStaging.js.map +1 -1
  222. package/stores/documents/documentStore/attachmentUploadLane.js.map +1 -1
  223. package/stores/documents/documentStore/persistence.js +2 -2
  224. package/stores/documents/documentStore/persistence.js.map +1 -1
  225. package/stores/documents/documentStore/state.js +1 -1
  226. package/stores/documents/documentStore/state.js.map +1 -1
  227. package/stores/documents/documentStore/storedDocument.js +1 -1
  228. package/stores/documents/documentStore/storedDocument.js.map +1 -1
  229. package/stores/documents/documentStore/syncAttachments.js.map +1 -1
  230. package/stores/documents/documentStore.d.ts +1 -1
  231. package/stores/documents/documentStore.js.map +1 -1
  232. package/stores/documents/registry.d.ts +1 -1
  233. package/stores/documents/registry.js.map +1 -1
  234. package/stores/documents/types.d.ts +1 -1
  235. package/stores/documents/types.js.map +1 -1
  236. package/stores/local-projection/registry.d.ts +1 -1
  237. package/stores/local-projection/registry.js.map +1 -1
  238. package/sync/reconciliation/serviceTypes.d.ts +1 -1
  239. package/sync/reconciliation/serviceTypes.js.map +1 -1
  240. package/sync/reconciliation/triggers.d.ts +1 -1
  241. package/sync/reconciliation/triggers.js.map +1 -1
  242. package/workflows/blobs/attachmentBindingVerification.js +2 -2
  243. package/workflows/blobs/attachmentBindingVerification.js.map +1 -1
  244. package/workflows/blobs/blobChunkDecryption.js.map +1 -1
  245. package/workflows/blobs/decrypt.d.ts +1 -1
  246. package/workflows/blobs/decrypt.js +2 -2
  247. package/workflows/blobs/decrypt.js.map +1 -1
  248. package/workflows/blobs/detach.js +2 -2
  249. package/workflows/blobs/detach.js.map +1 -1
  250. package/workflows/blobs/hydrate.d.ts +3 -3
  251. package/workflows/blobs/hydrate.js +1 -1
  252. package/workflows/blobs/hydrate.js.map +1 -1
  253. package/workflows/blobs/hydrationResults.js.map +1 -1
  254. package/workflows/blobs/index.d.ts +2 -2
  255. package/workflows/blobs/index.js +1 -1
  256. package/workflows/blobs/index.js.map +1 -1
  257. package/workflows/blobs/multipartFirstParts.js.map +1 -1
  258. package/workflows/blobs/retainedAttachmentVerification.js +1 -1
  259. package/workflows/blobs/upload.js +3 -3
  260. package/workflows/blobs/upload.js.map +1 -1
  261. package/workflows/container-contents/container-state/createAdoption.js +1 -1
  262. package/workflows/container-contents/container-state/createAdoption.js.map +1 -1
  263. package/workflows/container-contents/container-state/createChild.js +1 -1
  264. package/workflows/container-contents/container-state/createChild.js.map +1 -1
  265. package/workflows/container-contents/container-state/createIntentSync.js +1 -1
  266. package/workflows/container-contents/container-state/createIntentSync.js.map +1 -1
  267. package/workflows/container-contents/container-state/groupGrantVerification.js +1 -1
  268. package/workflows/container-contents/container-state/moveIntentSync.js +1 -1
  269. package/workflows/container-contents/container-state/moveIntentSync.js.map +1 -1
  270. package/workflows/container-contents/container-state/purgeTreeScope.js +1 -1
  271. package/workflows/container-contents/container-state/purgeTreeScope.js.map +1 -1
  272. package/workflows/container-contents/container-state/share.js +1 -1
  273. package/workflows/container-contents/documentDiscoveryInputs.js +1 -1
  274. package/workflows/container-contents/documentDiscoveryInputs.js.map +1 -1
  275. package/workflows/container-contents/documentInfo.d.ts +1 -1
  276. package/workflows/container-contents/documentInfo.js.map +1 -1
  277. package/workflows/container-contents/documentLinks.d.ts +1 -1
  278. package/workflows/container-contents/documentLinks.js +1 -1
  279. package/workflows/container-contents/documentLinks.js.map +1 -1
  280. package/workflows/container-contents/documentMoveIntentSync.js +1 -1
  281. package/workflows/container-contents/documentMoveIntentSync.js.map +1 -1
  282. package/workflows/container-contents/documentPurge.d.ts +1 -1
  283. package/workflows/container-contents/documentPurge.js +1 -1
  284. package/workflows/container-contents/documentPurge.js.map +1 -1
  285. package/workflows/container-contents/documentQueries/rows.js +1 -1
  286. package/workflows/container-contents/documentQueries/rows.js.map +1 -1
  287. package/workflows/container-contents/metadata.d.ts +1 -1
  288. package/workflows/container-contents/metadataMutationPreparation.js +1 -1
  289. package/workflows/container-contents/metadataMutationPreparation.js.map +1 -1
  290. package/workflows/container-contents/metadataRemoteSync.d.ts +1 -1
  291. package/workflows/container-contents/metadataSyncErrors.js.map +1 -1
  292. package/workflows/container-contents/projectionKeys.d.ts +1 -1
  293. package/workflows/container-contents/syncLane.d.ts +1 -1
  294. package/workflows/container-contents/syncLane.js.map +1 -1
  295. package/workflows/containers/child/carriedDescendantRekeys.js +1 -1
  296. package/workflows/containers/child/create.d.ts +1 -1
  297. package/workflows/containers/child/create.js +2 -2
  298. package/workflows/containers/child/create.js.map +1 -1
  299. package/workflows/containers/child/createProjection.js +1 -1
  300. package/workflows/containers/child/createProjection.js.map +1 -1
  301. package/workflows/containers/child/createSubmission.d.ts +2 -2
  302. package/workflows/containers/child/createSubmission.js.map +1 -1
  303. package/workflows/containers/child/move.d.ts +2 -2
  304. package/workflows/containers/child/move.js +2 -2
  305. package/workflows/containers/child/move.js.map +1 -1
  306. package/workflows/containers/child/moveWraps.js +1 -1
  307. package/workflows/containers/child/mutationRequestCore.js +1 -1
  308. package/workflows/containers/child/mutationRequestCore.js.map +1 -1
  309. package/workflows/containers/child/mutationSubmit.js.map +1 -1
  310. package/workflows/containers/child/recite.js.map +1 -1
  311. package/workflows/containers/child/recitePlan.js +1 -1
  312. package/workflows/containers/child/recitePlan.js.map +1 -1
  313. package/workflows/containers/child/rekey.d.ts +1 -1
  314. package/workflows/containers/child/rekey.js +2 -2
  315. package/workflows/containers/child/rekey.js.map +1 -1
  316. package/workflows/containers/child/rekeyProjection.js +1 -1
  317. package/workflows/containers/child/rekeyProjection.js.map +1 -1
  318. package/workflows/containers/child/rekeyRemote.d.ts +2 -2
  319. package/workflows/containers/child/rekeyRemote.js.map +1 -1
  320. package/workflows/containers/child/revoke.d.ts +2 -2
  321. package/workflows/containers/child/revoke.js +2 -2
  322. package/workflows/containers/child/revoke.js.map +1 -1
  323. package/workflows/containers/child/rotationPrincipalPolicies.js +1 -1
  324. package/workflows/containers/child/runtimeCurrentGroupShare.js +1 -1
  325. package/workflows/containers/child/share.d.ts +2 -2
  326. package/workflows/containers/child/share.js +1 -1
  327. package/workflows/containers/child/share.js.map +1 -1
  328. package/workflows/containers/child/shareAncestorRepair.js.map +1 -1
  329. package/workflows/containers/child/shareMaterialization.d.ts +1 -1
  330. package/workflows/containers/child/sharePlanCore.d.ts +1 -1
  331. package/workflows/containers/child/sharePlanCore.js +1 -1
  332. package/workflows/containers/root/create.js +1 -1
  333. package/workflows/containers/root/create.js.map +1 -1
  334. package/workflows/containers/root/initialGroupPolicy.js +1 -1
  335. package/workflows/containers/root/initialGroupPolicy.js.map +1 -1
  336. package/workflows/documents/create.d.ts +1 -1
  337. package/workflows/documents/create.js +1 -1
  338. package/workflows/documents/documentMutationPreparation.js +1 -1
  339. package/workflows/documents/documentMutationPreparation.js.map +1 -1
  340. package/workflows/documents/historyContent.js +1 -1
  341. package/workflows/documents/historyContent.js.map +1 -1
  342. package/workflows/documents/linkSet.js +1 -1
  343. package/workflows/documents/linkSet.js.map +1 -1
  344. package/workflows/documents/linkSetAuthority.js +1 -1
  345. package/workflows/documents/linkSetBlobRewraps.js +2 -2
  346. package/workflows/documents/linkSetBlobRewraps.js.map +1 -1
  347. package/workflows/documents/linkSetRemote.d.ts +1 -1
  348. package/workflows/documents/linkSetRemote.js +1 -1
  349. package/workflows/documents/orphanBlobReclaims.js +1 -1
  350. package/workflows/documents/orphanBlobReclaims.js.map +1 -1
  351. package/workflows/documents/projectionKeys.d.ts +1 -1
  352. package/workflows/documents/purge.d.ts +1 -1
  353. package/workflows/documents/purge.js +2 -2
  354. package/workflows/documents/purge.js.map +1 -1
  355. package/workflows/documents/readOnlySync.d.ts +1 -1
  356. package/workflows/documents/readOnlySync.js +1 -1
  357. package/workflows/documents/readOnlySync.js.map +1 -1
  358. package/workflows/documents/sync.js +1 -1
  359. package/workflows/documents/syncContainerRekeyPreparation.js +1 -1
  360. package/workflows/documents/syncLane.d.ts +1 -1
  361. package/workflows/documents/syncLane.js.map +1 -1
  362. package/workflows/documents/syncPlanIdentity.js +1 -1
  363. package/workflows/documents/syncPlanIdentity.js.map +1 -1
  364. package/workflows/documents/syncRepairAccess.js +1 -1
  365. package/workflows/documents/syncSubmittedResult.js +1 -1
  366. package/workflows/organizations/authoredPrincipalPolicyWarmer.js +1 -1
  367. package/workflows/organizations/authoredPrincipalPolicyWarmer.js.map +1 -1
  368. package/workflows/organizations/containerGrantRevocation.d.ts +2 -2
  369. package/workflows/organizations/containerGrantRevocation.js.map +1 -1
  370. package/workflows/organizations/createCurrentOrganizationGroup.js.map +1 -1
  371. package/workflows/organizations/currentOrganizationGroupNames.js.map +1 -1
  372. package/workflows/organizations/currentPolicyMutationAcknowledgement.js +1 -1
  373. package/workflows/organizations/currentPolicyMutationAcknowledgement.js.map +1 -1
  374. package/workflows/organizations/groupCreation.d.ts +1 -1
  375. package/workflows/organizations/groupCreation.js.map +1 -1
  376. package/workflows/organizations/groupMetadataAccess.d.ts +1 -1
  377. package/workflows/organizations/groupMetadataContainerAuthority.js.map +1 -1
  378. package/workflows/organizations/groupMetadataRuntime.js.map +1 -1
  379. package/workflows/organizations/groupNameUniqueness.js.map +1 -1
  380. package/workflows/organizations/groupPolicyMutationAcknowledgement.js +1 -1
  381. package/workflows/organizations/groupPolicyMutationAcknowledgement.js.map +1 -1
  382. package/workflows/organizations/groupPolicyRequests.js.map +1 -1
  383. package/workflows/organizations/loadPolicyHistoryDetails.js.map +1 -1
  384. package/workflows/organizations/organizationGroupDirectory.js.map +1 -1
  385. package/workflows/organizations/organizationProfile.js +1 -1
  386. package/workflows/organizations/organizationProfile.js.map +1 -1
  387. package/workflows/organizations/policyHistoryCache.js.map +1 -1
  388. package/workflows/organizations/principalContainerRematerialization.js +1 -1
  389. package/workflows/organizations/principalContainerRematerializationPlanning.js.map +1 -1
  390. package/workflows/organizations/principalMutationJournalManagement.js +1 -1
  391. package/workflows/organizations/principalMutationJournalManagement.js.map +1 -1
  392. package/workflows/organizations/principalMutationReceipt.js +1 -1
  393. package/workflows/organizations/principalMutationReceipt.js.map +1 -1
  394. package/workflows/organizations/principalPolicy.d.ts +1 -1
  395. package/workflows/organizations/principalPolicy.js.map +1 -1
  396. package/workflows/organizations/principalPolicyReceiptArtifacts.js +1 -1
  397. package/workflows/organizations/principalPolicyReceiptArtifacts.js.map +1 -1
  398. package/workflows/organizations/rosterProfileContainer.js +1 -1
  399. package/workflows/organizations/rosterProfileContainer.js.map +1 -1
  400. package/workflows/principals/policyCache.d.ts +1 -1
  401. package/workflows/principals/policyCache.js +2 -2
  402. package/workflows/principals/policyCache.js.map +1 -1
  403. package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
  404. package/workflows/principals/runtimePolicyWarmer.js +1 -1
  405. package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
  406. package/workflows/registration/persistRegistrationBootstrap.js +1 -1
  407. package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
  408. package/workflows/runtimeInput.d.ts +3 -3
  409. package/workflows/runtimeInput.js.map +1 -1
  410. package/workflows/sync/index.d.ts +2 -1
  411. package/workflows/sync/index.js +2 -1
  412. package/workflows/sync/index.js.map +1 -1
  413. package/client/blobs.js.map +0 -1
  414. package/client/containerContents.js.map +0 -1
  415. package/client/containerContentsTypes.js +0 -2
  416. package/client/containerContentsTypes.js.map +0 -1
  417. package/client/containerDocumentDiscovery.js.map +0 -1
  418. package/client/database.js.map +0 -1
  419. package/client/deviceFirst.js.map +0 -1
  420. package/client/documents.js.map +0 -1
  421. package/client/identity.js.map +0 -1
  422. package/client/identityKeyPackage.js.map +0 -1
  423. package/client/principalHistoryProtection.js.map +0 -1
  424. package/client/principalMutationApi.js.map +0 -1
  425. package/client/principalMutationDispatch.js.map +0 -1
  426. package/client/reconciledDocumentContentPull.js.map +0 -1
  427. package/client/rootContainerAdoption.js.map +0 -1
  428. package/client/securityIncidents.js.map +0 -1
  429. package/client/userIdentities.js.map +0 -1
  430. package/client/workflowRuntime.js.map +0 -1
  431. package/data/keyingCanonicalJson.js.map +0 -1
  432. package/data/keyingProjectionVerification.d.ts +0 -9
  433. package/data/keyingProjectionVerification.js.map +0 -1
  434. /package/client/{fileSaver.d.ts → host/fileSaver.d.ts} +0 -0
  435. /package/client/{fileSaver.js → host/fileSaver.js} +0 -0
  436. /package/client/{fileSaver.js.map → host/fileSaver.js.map} +0 -0
  437. /package/client/{logger.d.ts → host/logger.d.ts} +0 -0
  438. /package/client/{logger.js → host/logger.js} +0 -0
  439. /package/client/{logger.js.map → host/logger.js.map} +0 -0
  440. /package/client/{apiVersion.d.ts → runtime/apiVersion.d.ts} +0 -0
  441. /package/client/{apiVersion.js → runtime/apiVersion.js} +0 -0
  442. /package/client/{apiVersion.js.map → runtime/apiVersion.js.map} +0 -0
  443. /package/client/{events.d.ts → runtime/events.d.ts} +0 -0
  444. /package/client/{events.js → runtime/events.js} +0 -0
  445. /package/client/{events.js.map → runtime/events.js.map} +0 -0
  446. /package/client/{listenerSet.js → runtime/listenerSet.js} +0 -0
  447. /package/client/{listenerSet.js.map → runtime/listenerSet.js.map} +0 -0
  448. /package/client/{network.d.ts → runtime/network.d.ts} +0 -0
  449. /package/client/{network.js → runtime/network.js} +0 -0
  450. /package/client/{network.js.map → runtime/network.js.map} +0 -0
  451. /package/client/{principalMutationDeadline.js → runtime/principalMutationDeadline.js} +0 -0
  452. /package/client/{principalMutationDeadline.js.map → runtime/principalMutationDeadline.js.map} +0 -0
  453. /package/client/{rootContainerAdoption.js → runtime/rootContainerAdoption.js} +0 -0
  454. /package/client/{syncBillingGate.d.ts → runtime/syncBillingGate.d.ts} +0 -0
  455. /package/client/{syncBillingGate.js → runtime/syncBillingGate.js} +0 -0
  456. /package/client/{syncBillingGate.js.map → runtime/syncBillingGate.js.map} +0 -0
  457. /package/data/{blobContracts.d.ts → blobs/blobContracts.d.ts} +0 -0
  458. /package/data/{blobContracts.js → blobs/blobContracts.js} +0 -0
  459. /package/data/{blobContracts.js.map → blobs/blobContracts.js.map} +0 -0
  460. /package/data/{accessLevel.js → keying/accessLevel.js} +0 -0
  461. /package/data/{accessLevel.js.map → keying/accessLevel.js.map} +0 -0
  462. /package/data/{stableUuid.js → keying/stableUuid.js} +0 -0
  463. /package/data/{stableUuid.js.map → keying/stableUuid.js.map} +0 -0
  464. /package/data/{principalPolicyStates.js → principals/principalPolicyStates.js} +0 -0
  465. /package/data/{principalPolicyStates.js.map → principals/principalPolicyStates.js.map} +0 -0
  466. /package/data/{domainScope.d.ts → shared/domainScope.d.ts} +0 -0
  467. /package/data/{domainScope.js → shared/domainScope.js} +0 -0
  468. /package/data/{domainScope.js.map → shared/domainScope.js.map} +0 -0
  469. /package/data/{errorMessage.js → shared/errorMessage.js} +0 -0
  470. /package/data/{errorMessage.js.map → shared/errorMessage.js.map} +0 -0
  471. /package/data/{recordReaders.d.ts → shared/recordReaders.d.ts} +0 -0
  472. /package/data/{recordReaders.js → shared/recordReaders.js} +0 -0
  473. /package/data/{recordReaders.js.map → shared/recordReaders.js.map} +0 -0
  474. /package/data/{securityIncidents.js → shared/securityIncidents.js} +0 -0
  475. /package/data/{securityIncidents.js.map → shared/securityIncidents.js.map} +0 -0
  476. /package/data/{crdtPeerSeed.js → sync/crdtPeerSeed.js} +0 -0
  477. /package/data/{crdtPeerSeed.js.map → sync/crdtPeerSeed.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"sessionLoginRefusal.js","sourceRoot":"","sources":["sessionLoginRefusal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AAGxG;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAc,EACd,MAAc,EACd,OAGC;IAED,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,MAAM,uCAAuC,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QACnE,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,eAAe;KAC3B,CAAC,CAAC;IACH,MAAM,KAAK,CAAC;AACd,CAAC","sourcesContent":["import { reportAndRethrowKeyingVerificationError } from \"../../data/keyingProjectionVerification/error\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\n\n/**\n * A server answering this identity with another account, or an identity\n * whose durable pin no longer matches, is evidence, not a login failure: the\n * session is cleared, the keying error is recorded, and the error propagates.\n */\nexport async function refuseSessionLogin(\n error: unknown,\n userId: string,\n session: {\n readonly clear: () => void;\n readonly report: SecurityIncidentReporter | undefined;\n },\n): Promise<never> {\n session.clear();\n await reportAndRethrowKeyingVerificationError(error, session.report, {\n objectId: userId,\n objectKind: \"user\",\n operation: \"session.login\",\n });\n throw error;\n}\n"]}
1
+ {"version":3,"file":"sessionLoginRefusal.js","sourceRoot":"","sources":["sessionLoginRefusal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AAGxG;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAc,EACd,MAAc,EACd,OAGC;IAED,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,MAAM,uCAAuC,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QACnE,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,eAAe;KAC3B,CAAC,CAAC;IACH,MAAM,KAAK,CAAC;AACd,CAAC","sourcesContent":["import { reportAndRethrowKeyingVerificationError } from \"../../data/keyingProjectionVerification/error\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\n\n/**\n * A server answering this identity with another account, or an identity\n * whose durable pin no longer matches, is evidence, not a login failure: the\n * session is cleared, the keying error is recorded, and the error propagates.\n */\nexport async function refuseSessionLogin(\n error: unknown,\n userId: string,\n session: {\n readonly clear: () => void;\n readonly report: SecurityIncidentReporter | undefined;\n },\n): Promise<never> {\n session.clear();\n await reportAndRethrowKeyingVerificationError(error, session.report, {\n objectId: userId,\n objectKind: \"user\",\n operation: \"session.login\",\n });\n throw error;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sessionOrganizationCreation.js","sourceRoot":"","sources":["sessionOrganizationCreation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,IAAI,0BAA0B,EAAE,MAAM,kDAAkD,CAAC;AAyBpH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,YAAqD,EACrD,KAKC;IAED,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,YAAY,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACxD,MAAM,EAAE,oBAAoB,EAAE,cAAc,EAAE,GAAG,gBAAgB,CAAC;IAClE,IAAI,CAAC,cAAc,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC7C,YAAY,CAAC,GAAG,CACd,4DAA4D,CAC7D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,YAAY,CAAC,GAAG,CACd,6DAA6D,CAC9D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAgE,CAAC;IACrE,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,0BAA0B,CAAC;YAC1C,SAAS,EAAE,YAAY,CAAC,GAAG;YAC3B,QAAQ;YACR,kBAAkB,EAAE,YAAY,CAAC,kBAAkB;YACnD,oBAAoB;YACpB,iBAAiB,EAAE,GAAG,EAAE,CACtB,YAAY,CAAC,QAAQ,CAAC,QAAQ,KAAK,gBAAgB;YACrD,GAAG,EAAE,YAAY,CAAC,GAAG;YACrB,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;YAC1D,uBAAuB,EAAE,KAAK,CAAC,OAAO,EAAE,uBAAuB;YAC/D,qBAAqB,EAAE,YAAY,CAAC,gCAAgC;YACpE,2BAA2B,EAAE,YAAY,CAAC,2BAA2B;YACrE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,qBAAqB,EAAE,KAAK,CAAC,OAAO,EAAE,qBAAqB;YAC3D,cAAc;YACd,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,YAAY,CAAC,QAAQ,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QAC7D,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,YAAY,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,oEAAoE;IACpE,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,eAAe;QACrC,cAAc,EAAE,QAAQ,CAAC,cAAc;KACxC,CAAC;AACJ,CAAC","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport { createOrganization as createOrganizationWorkflow } from \"../../workflows/organizations/createOrganization\";\nimport type { ProvisionedSystemContainerSpec } from \"../../workflows/registration\";\nimport type { ProvisionedPrincipalHistoryPrimer } from \"../../workflows/registration/provisionedPrincipalHistory\";\nimport type { Database } from \"../database\";\nimport type { Identity } from \"../identity\";\nimport type {\n CreateOrganizationOptions,\n SessionCreateOrganizationResult,\n} from \"./sessionTypes\";\n\ninterface SessionOrganizationCreationDependencies {\n readonly api: ApiClient;\n readonly database: Database;\n readonly documentProjectors?: DocumentProjectorRegistryInput | undefined;\n readonly identity: Identity;\n readonly log: (message: string) => void;\n readonly logError: (message: string | Error, cause?: unknown) => void;\n readonly primeProvisionedPrincipalHistory?:\n | ProvisionedPrincipalHistoryPrimer\n | undefined;\n readonly provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n}\n\nexport async function createSessionOrganization(\n dependencies: SessionOrganizationCreationDependencies,\n input: {\n readonly nativeSubscriptionRestore?: boolean | undefined;\n readonly options?: CreateOrganizationOptions | undefined;\n readonly replacesOrganizationId?: string | undefined;\n readonly userId: string | null;\n },\n): Promise<SessionCreateOrganizationResult | null> {\n if (!input.userId) {\n dependencies.log(\"Create organization skipped: user id is unavailable\");\n return null;\n }\n\n const identitySnapshot = dependencies.identity.snapshot;\n const { encapsulationKeyPair, signingKeyPair } = identitySnapshot;\n if (!signingKeyPair || !encapsulationKeyPair) {\n dependencies.log(\n \"Create organization skipped: identity keys are unavailable\",\n );\n return null;\n }\n\n const dbClient = dependencies.database.client;\n if (!dbClient) {\n dependencies.log(\n \"Create organization skipped: database client is unavailable\",\n );\n return null;\n }\n\n let response: Awaited<ReturnType<typeof createOrganizationWorkflow>>;\n try {\n response = await createOrganizationWorkflow({\n apiClient: dependencies.api,\n dbClient,\n documentProjectors: dependencies.documentProjectors,\n encapsulationKeyPair,\n isIdentityCurrent: () =>\n dependencies.identity.snapshot === identitySnapshot,\n log: dependencies.log,\n logError: dependencies.logError,\n nativeSubscriptionRestore: input.nativeSubscriptionRestore,\n organizationProfileName: input.options?.organizationProfileName,\n primePrincipalHistory: dependencies.primeProvisionedPrincipalHistory,\n provisionedSystemContainers: dependencies.provisionedSystemContainers,\n replacesOrganizationId: input.replacesOrganizationId,\n rosterProfileNickname: input.options?.rosterProfileNickname,\n signingKeyPair,\n userId: input.userId,\n });\n } catch (error: unknown) {\n dependencies.logError(\"Organization creation failed\", error);\n throw error;\n }\n\n if (dependencies.identity.snapshot !== identitySnapshot) return null;\n if (!response) {\n dependencies.log(\"Organization creation failed\");\n return null;\n }\n // Creating an organization does not switch the active organization.\n return {\n containerId: response.rootContainerId,\n organizationId: response.organizationId,\n };\n}\n"]}
1
+ {"version":3,"file":"sessionOrganizationCreation.js","sourceRoot":"","sources":["sessionOrganizationCreation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,IAAI,0BAA0B,EAAE,MAAM,kDAAkD,CAAC;AAyBpH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,YAAqD,EACrD,KAKC;IAED,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,YAAY,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACxD,MAAM,EAAE,oBAAoB,EAAE,cAAc,EAAE,GAAG,gBAAgB,CAAC;IAClE,IAAI,CAAC,cAAc,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC7C,YAAY,CAAC,GAAG,CACd,4DAA4D,CAC7D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,YAAY,CAAC,GAAG,CACd,6DAA6D,CAC9D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAgE,CAAC;IACrE,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,0BAA0B,CAAC;YAC1C,SAAS,EAAE,YAAY,CAAC,GAAG;YAC3B,QAAQ;YACR,kBAAkB,EAAE,YAAY,CAAC,kBAAkB;YACnD,oBAAoB;YACpB,iBAAiB,EAAE,GAAG,EAAE,CACtB,YAAY,CAAC,QAAQ,CAAC,QAAQ,KAAK,gBAAgB;YACrD,GAAG,EAAE,YAAY,CAAC,GAAG;YACrB,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;YAC1D,uBAAuB,EAAE,KAAK,CAAC,OAAO,EAAE,uBAAuB;YAC/D,qBAAqB,EAAE,YAAY,CAAC,gCAAgC;YACpE,2BAA2B,EAAE,YAAY,CAAC,2BAA2B;YACrE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,qBAAqB,EAAE,KAAK,CAAC,OAAO,EAAE,qBAAqB;YAC3D,cAAc;YACd,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,YAAY,CAAC,QAAQ,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QAC7D,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,YAAY,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,oEAAoE;IACpE,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,eAAe;QACrC,cAAc,EAAE,QAAQ,CAAC,cAAc;KACxC,CAAC;AACJ,CAAC","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport { createOrganization as createOrganizationWorkflow } from \"../../workflows/organizations/createOrganization\";\nimport type { ProvisionedSystemContainerSpec } from \"../../workflows/registration\";\nimport type { ProvisionedPrincipalHistoryPrimer } from \"../../workflows/registration/provisionedPrincipalHistory\";\nimport type { Identity } from \"../identity\";\nimport type { Database } from \"../runtime/database\";\nimport type {\n CreateOrganizationOptions,\n SessionCreateOrganizationResult,\n} from \"./sessionTypes\";\n\ninterface SessionOrganizationCreationDependencies {\n readonly api: ApiClient;\n readonly database: Database;\n readonly documentProjectors?: DocumentProjectorRegistryInput | undefined;\n readonly identity: Identity;\n readonly log: (message: string) => void;\n readonly logError: (message: string | Error, cause?: unknown) => void;\n readonly primeProvisionedPrincipalHistory?:\n | ProvisionedPrincipalHistoryPrimer\n | undefined;\n readonly provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n}\n\nexport async function createSessionOrganization(\n dependencies: SessionOrganizationCreationDependencies,\n input: {\n readonly nativeSubscriptionRestore?: boolean | undefined;\n readonly options?: CreateOrganizationOptions | undefined;\n readonly replacesOrganizationId?: string | undefined;\n readonly userId: string | null;\n },\n): Promise<SessionCreateOrganizationResult | null> {\n if (!input.userId) {\n dependencies.log(\"Create organization skipped: user id is unavailable\");\n return null;\n }\n\n const identitySnapshot = dependencies.identity.snapshot;\n const { encapsulationKeyPair, signingKeyPair } = identitySnapshot;\n if (!signingKeyPair || !encapsulationKeyPair) {\n dependencies.log(\n \"Create organization skipped: identity keys are unavailable\",\n );\n return null;\n }\n\n const dbClient = dependencies.database.client;\n if (!dbClient) {\n dependencies.log(\n \"Create organization skipped: database client is unavailable\",\n );\n return null;\n }\n\n let response: Awaited<ReturnType<typeof createOrganizationWorkflow>>;\n try {\n response = await createOrganizationWorkflow({\n apiClient: dependencies.api,\n dbClient,\n documentProjectors: dependencies.documentProjectors,\n encapsulationKeyPair,\n isIdentityCurrent: () =>\n dependencies.identity.snapshot === identitySnapshot,\n log: dependencies.log,\n logError: dependencies.logError,\n nativeSubscriptionRestore: input.nativeSubscriptionRestore,\n organizationProfileName: input.options?.organizationProfileName,\n primePrincipalHistory: dependencies.primeProvisionedPrincipalHistory,\n provisionedSystemContainers: dependencies.provisionedSystemContainers,\n replacesOrganizationId: input.replacesOrganizationId,\n rosterProfileNickname: input.options?.rosterProfileNickname,\n signingKeyPair,\n userId: input.userId,\n });\n } catch (error: unknown) {\n dependencies.logError(\"Organization creation failed\", error);\n throw error;\n }\n\n if (dependencies.identity.snapshot !== identitySnapshot) return null;\n if (!response) {\n dependencies.log(\"Organization creation failed\");\n return null;\n }\n // Creating an organization does not switch the active organization.\n return {\n containerId: response.rootContainerId,\n organizationId: response.organizationId,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sessionPurgeRecovery.js","sourceRoot":"","sources":["sessionPurgeRecovery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport { resolveOrganizationBillingView } from \"../../workflows/organizations/billing\";\nimport {\n loadOrganizationReplacementFinalizationRequest,\n removeOrganizationProvisioningAttempt,\n} from \"../../workflows/organizations/organizationProvisioningAttempt\";\nimport { verifyOrganizationReplacementResponse } from \"../../workflows/organizations/organizationReplacementVerification\";\nimport { clearRemoteSyncState } from \"../../workflows/sync\";\nimport type { Database } from \"../database\";\nimport type { Identity } from \"../identity\";\nimport { PurgedOrganizationRecoveryBillingRequiredError } from \"./sessionRecoveryErrors\";\nimport type {\n CreateOrganizationOptions,\n SessionContext,\n SessionCreateOrganizationResult,\n SessionRecoverOrganizationResult,\n} from \"./sessionTypes\";\n\ninterface SessionPurgeRecoveryDependencies {\n api: Pick<ApiClient, \"clearWriterProjectionCaches\">;\n database: Pick<Database, \"requireExecSql\">;\n identity: Pick<Identity, \"snapshot\">;\n log: (message: string) => void;\n}\n\ninterface SessionPurgeRecoveryContext {\n createOrganization: (\n options?: CreateOrganizationOptions,\n replacesOrganizationId?: string,\n ) => Promise<SessionCreateOrganizationResult | null>;\n organizationId: string | null;\n setContext: (context: SessionContext) => void;\n userId: string | null;\n}\n\nfunction requireReplacementCanSync(\n replacement: SessionCreateOrganizationResult,\n billing: Awaited<ReturnType<ApiClient[\"getOrganizationBilling\"]>>,\n): void {\n if (!billing) {\n throw new Error(\"Replacement organization billing could not be loaded\");\n }\n if (!resolveOrganizationBillingView(billing, Date.now()).canSync) {\n throw new PurgedOrganizationRecoveryBillingRequiredError(\n replacement.organizationId,\n billing.status,\n replacement.containerId,\n );\n }\n}\n\nexport async function clearSessionRemoteSyncState(\n dependencies: SessionPurgeRecoveryDependencies,\n session: SessionPurgeRecoveryContext,\n organizationId: string,\n) {\n const execSql = dependencies.database.requireExecSql(\"clearRemoteSyncState\");\n const result = await clearRemoteSyncState(execSql, {\n organizationId,\n });\n dependencies.api.clearWriterProjectionCaches();\n if (session.organizationId === organizationId) {\n session.setContext({ containerId: null, organizationId: null });\n }\n dependencies.log(\"Remote sync state cleared\");\n return result;\n}\n\nfunction verifyFinalizedReplacement(\n finalizedReplacement: Awaited<ReturnType<ApiClient[\"createOrganization\"]>>,\n replacement: SessionCreateOrganizationResult,\n replacesOrganizationId: string,\n userId: string,\n signingKeyPair: Identity[\"snapshot\"][\"signingKeyPair\"],\n): void {\n if (\n !finalizedReplacement ||\n finalizedReplacement.organizationId !== replacement.organizationId ||\n finalizedReplacement.rootContainerId !== replacement.containerId ||\n finalizedReplacement.userId !== userId\n ) {\n throw new Error(\"Organization replacement finalization was inconsistent\");\n }\n if (!signingKeyPair) {\n throw new Error(\n \"Organization replacement requires the current signing identity\",\n );\n }\n verifyOrganizationReplacementResponse({\n replacesOrganizationId,\n response: finalizedReplacement,\n signingPublicKey: signingKeyPair.signingPublicKey,\n userId,\n });\n}\n\nexport async function recoverPurgedSessionOrganization(\n dependencies: SessionPurgeRecoveryDependencies & {\n api: Pick<\n ApiClient,\n | \"clearWriterProjectionCaches\"\n | \"createOrganization\"\n | \"getOrganizationBilling\"\n >;\n },\n session: SessionPurgeRecoveryContext,\n organizationId: string,\n options: CreateOrganizationOptions | undefined,\n): Promise<SessionRecoverOrganizationResult | null> {\n const identitySnapshot = dependencies.identity.snapshot;\n const sessionOrganizationId = session.organizationId;\n const userId = session.userId;\n if (!userId) {\n throw new Error(\"Purged organization recovery requires a current user\");\n }\n const isRecoveryCurrent = () =>\n dependencies.identity.snapshot === identitySnapshot &&\n session.organizationId === sessionOrganizationId &&\n session.userId === userId;\n const billing = await dependencies.api.getOrganizationBilling(organizationId);\n if (billing?.status !== \"purged\") {\n throw new Error(\n `Organization ${organizationId} cannot be recovered before its purge finishes`,\n );\n }\n if (!isRecoveryCurrent()) return null;\n const replacement = await session.createOrganization(options, organizationId);\n if (!replacement) return null;\n if (!isRecoveryCurrent()) return null;\n const replacementBilling = await dependencies.api.getOrganizationBilling(\n replacement.organizationId,\n );\n if (!isRecoveryCurrent()) return null;\n requireReplacementCanSync(replacement, replacementBilling);\n const execSql = dependencies.database.requireExecSql(\n \"recoverPurgedOrganization\",\n );\n const reset = await clearRemoteSyncState(\n execSql,\n {\n organizationId,\n replacement: {\n organizationId: replacement.organizationId,\n rootContainerId: replacement.containerId,\n },\n },\n isRecoveryCurrent,\n );\n if (!isRecoveryCurrent()) return null;\n const finalizationRequest =\n await loadOrganizationReplacementFinalizationRequest({\n execSql,\n replacedOrganizationId: organizationId,\n userId,\n });\n if (!isRecoveryCurrent()) return null;\n const finalizedReplacement =\n await dependencies.api.createOrganization(finalizationRequest);\n if (!isRecoveryCurrent()) return null;\n verifyFinalizedReplacement(\n finalizedReplacement,\n replacement,\n organizationId,\n userId,\n identitySnapshot.signingKeyPair,\n );\n const attemptRemoved = await removeOrganizationProvisioningAttempt({\n canCommit: isRecoveryCurrent,\n execSql,\n replacedOrganizationId: organizationId,\n userId,\n });\n if (!attemptRemoved || !isRecoveryCurrent()) return null;\n dependencies.api.clearWriterProjectionCaches();\n session.setContext({\n containerId: replacement.containerId,\n defaultOrganizationId: replacement.organizationId,\n organizationId: replacement.organizationId,\n });\n dependencies.log(\n `Purged organization replaced (${replacement.organizationId})`,\n );\n return {\n ...replacement,\n replacedOrganizationId: organizationId,\n reset,\n };\n}\n"]}
1
+ {"version":3,"file":"sessionPurgeRecovery.js","sourceRoot":"","sources":["sessionPurgeRecovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EACL,8CAA8C,EAC9C,qCAAqC,GACtC,MAAM,+DAA+D,CAAC;AACvE,OAAO,EAAE,qCAAqC,EAAE,MAAM,mEAAmE,CAAC;AAC1H,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,8CAA8C,EAAE,MAAM,yBAAyB,CAAC;AAyBzF,SAAS,yBAAyB,CAChC,WAA4C,EAC5C,OAAiE;IAEjE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,CAAC,8BAA8B,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACjE,MAAM,IAAI,8CAA8C,CACtD,WAAW,CAAC,cAAc,EAC1B,OAAO,CAAC,MAAM,EACd,WAAW,CAAC,WAAW,CACxB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,YAA8C,EAC9C,OAAoC,EACpC,cAAsB;IAEtB,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE;QACjD,cAAc;KACf,CAAC,CAAC;IACH,YAAY,CAAC,GAAG,CAAC,2BAA2B,EAAE,CAAC;IAC/C,IAAI,OAAO,CAAC,cAAc,KAAK,cAAc,EAAE,CAAC;QAC9C,OAAO,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAC9C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,0BAA0B,CACjC,oBAA0E,EAC1E,WAA4C,EAC5C,sBAA8B,EAC9B,MAAc,EACd,cAAsD;IAEtD,IACE,CAAC,oBAAoB;QACrB,oBAAoB,CAAC,cAAc,KAAK,WAAW,CAAC,cAAc;QAClE,oBAAoB,CAAC,eAAe,KAAK,WAAW,CAAC,WAAW;QAChE,oBAAoB,CAAC,MAAM,KAAK,MAAM,EACtC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;IACJ,CAAC;IACD,qCAAqC,CAAC;QACpC,sBAAsB;QACtB,QAAQ,EAAE,oBAAoB;QAC9B,gBAAgB,EAAE,cAAc,CAAC,gBAAgB;QACjD,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,YAOC,EACD,OAAoC,EACpC,cAAsB,EACtB,OAA8C;IAE9C,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACxD,MAAM,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,iBAAiB,GAAG,GAAG,EAAE,CAC7B,YAAY,CAAC,QAAQ,CAAC,QAAQ,KAAK,gBAAgB;QACnD,OAAO,CAAC,cAAc,KAAK,qBAAqB;QAChD,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC;IAC5B,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;IAC9E,IAAI,OAAO,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,gBAAgB,cAAc,gDAAgD,CAC/E,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC9E,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,sBAAsB,CACtE,WAAW,CAAC,cAAc,CAC3B,CAAC;IACF,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtC,yBAAyB,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,cAAc,CAClD,2BAA2B,CAC5B,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,oBAAoB,CACtC,OAAO,EACP;QACE,cAAc;QACd,WAAW,EAAE;YACX,cAAc,EAAE,WAAW,CAAC,cAAc;YAC1C,eAAe,EAAE,WAAW,CAAC,WAAW;SACzC;KACF,EACD,iBAAiB,CAClB,CAAC;IACF,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,mBAAmB,GACvB,MAAM,8CAA8C,CAAC;QACnD,OAAO;QACP,sBAAsB,EAAE,cAAc;QACtC,MAAM;KACP,CAAC,CAAC;IACL,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,oBAAoB,GACxB,MAAM,YAAY,CAAC,GAAG,CAAC,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;IACjE,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtC,0BAA0B,CACxB,oBAAoB,EACpB,WAAW,EACX,cAAc,EACd,MAAM,EACN,gBAAgB,CAAC,cAAc,CAChC,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,qCAAqC,CAAC;QACjE,SAAS,EAAE,iBAAiB;QAC5B,OAAO;QACP,sBAAsB,EAAE,cAAc;QACtC,MAAM;KACP,CAAC,CAAC;IACH,IAAI,CAAC,cAAc,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,IAAI,CAAC;IACzD,YAAY,CAAC,GAAG,CAAC,2BAA2B,EAAE,CAAC;IAC/C,OAAO,CAAC,UAAU,CAAC;QACjB,WAAW,EAAE,WAAW,CAAC,WAAW;QACpC,qBAAqB,EAAE,WAAW,CAAC,cAAc;QACjD,cAAc,EAAE,WAAW,CAAC,cAAc;KAC3C,CAAC,CAAC;IACH,YAAY,CAAC,GAAG,CACd,iCAAiC,WAAW,CAAC,cAAc,GAAG,CAC/D,CAAC;IACF,OAAO;QACL,GAAG,WAAW;QACd,sBAAsB,EAAE,cAAc;QACtC,KAAK;KACN,CAAC;AACJ,CAAC","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport { resolveOrganizationBillingView } from \"../../workflows/organizations/billing\";\nimport {\n loadOrganizationReplacementFinalizationRequest,\n removeOrganizationProvisioningAttempt,\n} from \"../../workflows/organizations/organizationProvisioningAttempt\";\nimport { verifyOrganizationReplacementResponse } from \"../../workflows/organizations/organizationReplacementVerification\";\nimport { clearRemoteSyncState } from \"../../workflows/sync\";\nimport type { Identity } from \"../identity\";\nimport type { Database } from \"../runtime/database\";\nimport { PurgedOrganizationRecoveryBillingRequiredError } from \"./sessionRecoveryErrors\";\nimport type {\n CreateOrganizationOptions,\n SessionContext,\n SessionCreateOrganizationResult,\n SessionRecoverOrganizationResult,\n} from \"./sessionTypes\";\n\ninterface SessionPurgeRecoveryDependencies {\n api: Pick<ApiClient, \"clearWriterProjectionCaches\">;\n database: Pick<Database, \"requireExecSql\">;\n identity: Pick<Identity, \"snapshot\">;\n log: (message: string) => void;\n}\n\ninterface SessionPurgeRecoveryContext {\n createOrganization: (\n options?: CreateOrganizationOptions,\n replacesOrganizationId?: string,\n ) => Promise<SessionCreateOrganizationResult | null>;\n organizationId: string | null;\n setContext: (context: SessionContext) => void;\n userId: string | null;\n}\n\nfunction requireReplacementCanSync(\n replacement: SessionCreateOrganizationResult,\n billing: Awaited<ReturnType<ApiClient[\"getOrganizationBilling\"]>>,\n): void {\n if (!billing) {\n throw new Error(\"Replacement organization billing could not be loaded\");\n }\n if (!resolveOrganizationBillingView(billing, Date.now()).canSync) {\n throw new PurgedOrganizationRecoveryBillingRequiredError(\n replacement.organizationId,\n billing.status,\n replacement.containerId,\n );\n }\n}\n\nexport async function clearSessionRemoteSyncState(\n dependencies: SessionPurgeRecoveryDependencies,\n session: SessionPurgeRecoveryContext,\n organizationId: string,\n) {\n const execSql = dependencies.database.requireExecSql(\"clearRemoteSyncState\");\n const result = await clearRemoteSyncState(execSql, {\n organizationId,\n });\n dependencies.api.clearWriterProjectionCaches();\n if (session.organizationId === organizationId) {\n session.setContext({ containerId: null, organizationId: null });\n }\n dependencies.log(\"Remote sync state cleared\");\n return result;\n}\n\nfunction verifyFinalizedReplacement(\n finalizedReplacement: Awaited<ReturnType<ApiClient[\"createOrganization\"]>>,\n replacement: SessionCreateOrganizationResult,\n replacesOrganizationId: string,\n userId: string,\n signingKeyPair: Identity[\"snapshot\"][\"signingKeyPair\"],\n): void {\n if (\n !finalizedReplacement ||\n finalizedReplacement.organizationId !== replacement.organizationId ||\n finalizedReplacement.rootContainerId !== replacement.containerId ||\n finalizedReplacement.userId !== userId\n ) {\n throw new Error(\"Organization replacement finalization was inconsistent\");\n }\n if (!signingKeyPair) {\n throw new Error(\n \"Organization replacement requires the current signing identity\",\n );\n }\n verifyOrganizationReplacementResponse({\n replacesOrganizationId,\n response: finalizedReplacement,\n signingPublicKey: signingKeyPair.signingPublicKey,\n userId,\n });\n}\n\nexport async function recoverPurgedSessionOrganization(\n dependencies: SessionPurgeRecoveryDependencies & {\n api: Pick<\n ApiClient,\n | \"clearWriterProjectionCaches\"\n | \"createOrganization\"\n | \"getOrganizationBilling\"\n >;\n },\n session: SessionPurgeRecoveryContext,\n organizationId: string,\n options: CreateOrganizationOptions | undefined,\n): Promise<SessionRecoverOrganizationResult | null> {\n const identitySnapshot = dependencies.identity.snapshot;\n const sessionOrganizationId = session.organizationId;\n const userId = session.userId;\n if (!userId) {\n throw new Error(\"Purged organization recovery requires a current user\");\n }\n const isRecoveryCurrent = () =>\n dependencies.identity.snapshot === identitySnapshot &&\n session.organizationId === sessionOrganizationId &&\n session.userId === userId;\n const billing = await dependencies.api.getOrganizationBilling(organizationId);\n if (billing?.status !== \"purged\") {\n throw new Error(\n `Organization ${organizationId} cannot be recovered before its purge finishes`,\n );\n }\n if (!isRecoveryCurrent()) return null;\n const replacement = await session.createOrganization(options, organizationId);\n if (!replacement) return null;\n if (!isRecoveryCurrent()) return null;\n const replacementBilling = await dependencies.api.getOrganizationBilling(\n replacement.organizationId,\n );\n if (!isRecoveryCurrent()) return null;\n requireReplacementCanSync(replacement, replacementBilling);\n const execSql = dependencies.database.requireExecSql(\n \"recoverPurgedOrganization\",\n );\n const reset = await clearRemoteSyncState(\n execSql,\n {\n organizationId,\n replacement: {\n organizationId: replacement.organizationId,\n rootContainerId: replacement.containerId,\n },\n },\n isRecoveryCurrent,\n );\n if (!isRecoveryCurrent()) return null;\n const finalizationRequest =\n await loadOrganizationReplacementFinalizationRequest({\n execSql,\n replacedOrganizationId: organizationId,\n userId,\n });\n if (!isRecoveryCurrent()) return null;\n const finalizedReplacement =\n await dependencies.api.createOrganization(finalizationRequest);\n if (!isRecoveryCurrent()) return null;\n verifyFinalizedReplacement(\n finalizedReplacement,\n replacement,\n organizationId,\n userId,\n identitySnapshot.signingKeyPair,\n );\n const attemptRemoved = await removeOrganizationProvisioningAttempt({\n canCommit: isRecoveryCurrent,\n execSql,\n replacedOrganizationId: organizationId,\n userId,\n });\n if (!attemptRemoved || !isRecoveryCurrent()) return null;\n dependencies.api.clearWriterProjectionCaches();\n session.setContext({\n containerId: replacement.containerId,\n defaultOrganizationId: replacement.organizationId,\n organizationId: replacement.organizationId,\n });\n dependencies.log(\n `Purged organization replaced (${replacement.organizationId})`,\n );\n return {\n ...replacement,\n replacedOrganizationId: organizationId,\n reset,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sessionRootAuthority.js","sourceRoot":"","sources":["sessionRootAuthority.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,yCAAyC,EAAE,MAAM,+CAA+C,CAAC;AAU1G;;;;;;;;GAQG;AACH,SAAS,iCAAiC,CACxC,QAAiD,EACjD,KAA8B;IAE9B,IACE,CAAC,QAAQ;QACT,QAAQ,CAAC,eAAe,KAAK,KAAK,CAAC,eAAe;QAClD,KAAK,CAAC,eAAe,KAAK,IAAI,EAC9B,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,uEAAuE,CACxE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAA0B,EAC1B,KAA8B,EAC9B,kBAAiC;IAEjC,IAAI,CAAC,kBAAkB;QACrB,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,EACpB,0DAA0D,CAC3D,CAAC;IACJ,MAAM,eAAe,GAAG,CAAC,KAAkC,EAAE,EAAE,CAC7D,KAAK,CAAC,kBAAkB,KAAK,kBAAkB;QAC/C,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC;IAChC,iCAAiC,CAC/B,KAAK,CAAC,IAAI,CACR,CAAC,KAAK,EAAE,EAAE,CACR,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,cAAc,KAAK,KAAK,CAAC,cAAc,CAC1E,EACD,KAAK,CACN,CAAC;IACF,OAAO;QACL,GAAG,KAAK,CAAC,MAAM,CACb,CAAC,KAAK,EAAE,EAAE,CACR,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,cAAc,KAAK,KAAK,CAAC,cAAc,CAC1E;QACD;YACE,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,kBAAkB;SACnB;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,KAOrD;IACC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC;IACvE,IAAI,mBAAwC,CAAC;IAC7C,IAAI,CAAC;QACH,mBAAmB,GAAG,sBAAsB,CAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,EACpC,IAAI,EACJ,kBAAkB,CACnB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;QACpB,IAAI,kBAAkB,EAAE,CAAC;YACvB,MAAM,yCAAyC,CAAC,KAAK,EAAE,QAAQ,EAAE;gBAC/D,QAAQ,EAAE,IAAI,CAAC,eAAe;gBAC9B,UAAU,EAAE,WAAW;gBACvB,SAAS,EAAE,0BAA0B;gBACrC,cAAc,EAAE,IAAI,CAAC,cAAc;aACpC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CACjC,KAA0B,EAC1B,QAAyC,EACzC,kBAAiC,EACjC,MAAqB;IAErB,MAAM,OAAO,GAAG,CAAC,KAAkC,EAAE,EAAE,CACrD,KAAK,CAAC,kBAAkB,KAAK,kBAAkB,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC;IAC7E,IAAI,QAAQ,EAAE,CAAC;QACb,IACE,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;YACxB,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI;gBACzD,QAAQ,CAAC,MAAM,EACjB,CAAC;YACD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,gDAAgD,CACjD,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,OAAgB,EAChB,kBAAiC;IAEjC,OAAO,CACL,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,CACvC,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,kBAAkB,KAAK,kBAAkB;QAC/C,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;QAC/B,KAAK,CAAC,cAAc,KAAK,OAAO,CAAC,cAAc,CAClD,EAAE,eAAe,IAAI,IAAI,CAC3B,CAAC;AACJ,CAAC","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { reportKeyingVerificationErrorInCauseChain } from \"../../data/keyingProjectionVerification/error\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { Session, SessionContext, SessionSnapshot } from \"./sessionTypes\";\n\ntype RootAcknowledgments = SessionSnapshot[\"rootAcknowledgments\"];\ntype RootAcknowledgmentInput = Omit<\n RootAcknowledgments[number],\n \"signingFingerprint\"\n>;\n\n/**\n * The login, registration and organization-creation responses that carry a\n * root id are unsigned. An organization's root row is created once, in the\n * provisioning transaction, and only ever disappears through a purge, so an\n * honest server can re-acknowledge the same root or report it gone (null) but\n * never presents a different root for an organization this identity already\n * acknowledged. A different id is a substitution attempt: the previous root\n * stays authoritative and the caller records a security incident.\n */\nfunction assertRootAcknowledgmentUnchanged(\n previous: RootAcknowledgments[number] | undefined,\n input: RootAcknowledgmentInput,\n): void {\n if (\n !previous ||\n previous.rootContainerId === input.rootContainerId ||\n input.rootContainerId === null\n ) {\n return;\n }\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Session root acknowledgement changed for an acknowledged organization\",\n );\n}\n\nexport function acknowledgeSessionRoot(\n known: RootAcknowledgments,\n input: RootAcknowledgmentInput,\n signingFingerprint: string | null,\n): RootAcknowledgments {\n if (!signingFingerprint)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Session root acknowledgement requires a signing identity\",\n );\n const matchesIdentity = (entry: RootAcknowledgments[number]) =>\n entry.signingFingerprint === signingFingerprint &&\n entry.userId === input.userId;\n assertRootAcknowledgmentUnchanged(\n known.find(\n (entry) =>\n matchesIdentity(entry) && entry.organizationId === input.organizationId,\n ),\n input,\n );\n return [\n ...known.filter(\n (entry) =>\n matchesIdentity(entry) && entry.organizationId !== input.organizationId,\n ),\n {\n userId: input.userId,\n organizationId: input.organizationId,\n rootContainerId: input.rootContainerId,\n signingFingerprint,\n },\n ];\n}\n\n/**\n * Decides and commits an acknowledgement against the session's CURRENT\n * snapshot in one synchronous step: reading `rootAcknowledgments`, deciding,\n * and `setContext` happen with no await between them, so an overlapping login,\n * registration or organization creation can never overwrite this entry with a\n * stale copy (a lost acknowledgement would erase that organization's root-swap\n * protection). Only the incident report for a refusal is asynchronous, and it\n * runs after the decision has been made and before the error propagates;\n * `onRefused` runs synchronously with the decision, ahead of that report.\n */\nexport async function commitSessionRootAcknowledgment(input: {\n readonly context?: Omit<SessionContext, \"rootAcknowledgments\"> | undefined;\n readonly onRefused?: (() => void) | undefined;\n readonly reporter: SecurityIncidentReporter | undefined;\n readonly root: RootAcknowledgmentInput;\n readonly session: Pick<Session, \"setContext\" | \"snapshot\">;\n readonly signingFingerprint: string | null;\n}): Promise<void> {\n const { context, reporter, root, session, signingFingerprint } = input;\n let rootAcknowledgments: RootAcknowledgments;\n try {\n rootAcknowledgments = acknowledgeSessionRoot(\n session.snapshot.rootAcknowledgments,\n root,\n signingFingerprint,\n );\n } catch (error) {\n input.onRefused?.();\n if (signingFingerprint) {\n await reportKeyingVerificationErrorInCauseChain(error, reporter, {\n objectId: root.rootContainerId,\n objectKind: \"container\",\n operation: \"session.root.acknowledge\",\n organizationId: root.organizationId,\n });\n }\n throw error;\n }\n session.setContext({ ...context, rootAcknowledgments });\n}\n\n/** Only the encrypted host restore may supply previously acknowledged roots. */\nexport function restoreSessionRoots(\n known: RootAcknowledgments,\n restored: RootAcknowledgments | undefined,\n signingFingerprint: string | null,\n userId: string | null,\n): RootAcknowledgments {\n const matches = (entry: RootAcknowledgments[number]) =>\n entry.signingFingerprint === signingFingerprint && entry.userId === userId;\n if (restored) {\n if (\n !restored.every(matches) ||\n new Set(restored.map((entry) => entry.organizationId)).size !==\n restored.length\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Restored roots differ from the active identity\",\n );\n }\n return restored.map((entry) => ({ ...entry }));\n }\n return known.every(matches) ? known : known.filter(matches);\n}\n\nexport function acknowledgedSessionRoot(\n session: Session,\n signingFingerprint: string | null,\n): string | null {\n return (\n session.snapshot.rootAcknowledgments.find(\n (entry) =>\n entry.signingFingerprint === signingFingerprint &&\n entry.userId === session.userId &&\n entry.organizationId === session.organizationId,\n )?.rootContainerId ?? null\n );\n}\n"]}
1
+ {"version":3,"file":"sessionRootAuthority.js","sourceRoot":"","sources":["sessionRootAuthority.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { reportKeyingVerificationErrorInCauseChain } from \"../../data/keyingProjectionVerification/error\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\nimport type { Session, SessionContext, SessionSnapshot } from \"./sessionTypes\";\n\ntype RootAcknowledgments = SessionSnapshot[\"rootAcknowledgments\"];\ntype RootAcknowledgmentInput = Omit<\n RootAcknowledgments[number],\n \"signingFingerprint\"\n>;\n\n/**\n * The login, registration and organization-creation responses that carry a\n * root id are unsigned. An organization's root row is created once, in the\n * provisioning transaction, and only ever disappears through a purge, so an\n * honest server can re-acknowledge the same root or report it gone (null) but\n * never presents a different root for an organization this identity already\n * acknowledged. A different id is a substitution attempt: the previous root\n * stays authoritative and the caller records a security incident.\n */\nfunction assertRootAcknowledgmentUnchanged(\n previous: RootAcknowledgments[number] | undefined,\n input: RootAcknowledgmentInput,\n): void {\n if (\n !previous ||\n previous.rootContainerId === input.rootContainerId ||\n input.rootContainerId === null\n ) {\n return;\n }\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Session root acknowledgement changed for an acknowledged organization\",\n );\n}\n\nexport function acknowledgeSessionRoot(\n known: RootAcknowledgments,\n input: RootAcknowledgmentInput,\n signingFingerprint: string | null,\n): RootAcknowledgments {\n if (!signingFingerprint)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Session root acknowledgement requires a signing identity\",\n );\n const matchesIdentity = (entry: RootAcknowledgments[number]) =>\n entry.signingFingerprint === signingFingerprint &&\n entry.userId === input.userId;\n assertRootAcknowledgmentUnchanged(\n known.find(\n (entry) =>\n matchesIdentity(entry) && entry.organizationId === input.organizationId,\n ),\n input,\n );\n return [\n ...known.filter(\n (entry) =>\n matchesIdentity(entry) && entry.organizationId !== input.organizationId,\n ),\n {\n userId: input.userId,\n organizationId: input.organizationId,\n rootContainerId: input.rootContainerId,\n signingFingerprint,\n },\n ];\n}\n\n/**\n * Decides and commits an acknowledgement against the session's CURRENT\n * snapshot in one synchronous step: reading `rootAcknowledgments`, deciding,\n * and `setContext` happen with no await between them, so an overlapping login,\n * registration or organization creation can never overwrite this entry with a\n * stale copy (a lost acknowledgement would erase that organization's root-swap\n * protection). Only the incident report for a refusal is asynchronous, and it\n * runs after the decision has been made and before the error propagates;\n * `onRefused` runs synchronously with the decision, ahead of that report.\n */\nexport async function commitSessionRootAcknowledgment(input: {\n readonly context?: Omit<SessionContext, \"rootAcknowledgments\"> | undefined;\n readonly onRefused?: (() => void) | undefined;\n readonly reporter: SecurityIncidentReporter | undefined;\n readonly root: RootAcknowledgmentInput;\n readonly session: Pick<Session, \"setContext\" | \"snapshot\">;\n readonly signingFingerprint: string | null;\n}): Promise<void> {\n const { context, reporter, root, session, signingFingerprint } = input;\n let rootAcknowledgments: RootAcknowledgments;\n try {\n rootAcknowledgments = acknowledgeSessionRoot(\n session.snapshot.rootAcknowledgments,\n root,\n signingFingerprint,\n );\n } catch (error) {\n input.onRefused?.();\n if (signingFingerprint) {\n await reportKeyingVerificationErrorInCauseChain(error, reporter, {\n objectId: root.rootContainerId,\n objectKind: \"container\",\n operation: \"session.root.acknowledge\",\n organizationId: root.organizationId,\n });\n }\n throw error;\n }\n session.setContext({ ...context, rootAcknowledgments });\n}\n\n/** Only the encrypted host restore may supply previously acknowledged roots. */\nexport function restoreSessionRoots(\n known: RootAcknowledgments,\n restored: RootAcknowledgments | undefined,\n signingFingerprint: string | null,\n userId: string | null,\n): RootAcknowledgments {\n const matches = (entry: RootAcknowledgments[number]) =>\n entry.signingFingerprint === signingFingerprint && entry.userId === userId;\n if (restored) {\n if (\n !restored.every(matches) ||\n new Set(restored.map((entry) => entry.organizationId)).size !==\n restored.length\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Restored roots differ from the active identity\",\n );\n }\n return restored.map((entry) => ({ ...entry }));\n }\n return known.every(matches) ? known : known.filter(matches);\n}\n\nexport function acknowledgedSessionRoot(\n session: Session,\n signingFingerprint: string | null,\n): string | null {\n return (\n session.snapshot.rootAcknowledgments.find(\n (entry) =>\n entry.signingFingerprint === signingFingerprint &&\n entry.userId === session.userId &&\n entry.organizationId === session.organizationId,\n )?.rootContainerId ?? null\n );\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import type { ApiClient } from "../../internal/api-client/index.js";
2
2
  import type { DocumentProjectorRegistryInput } from "../../data/documents/documentKinds.js";
3
- import type { SecurityIncidentReporter } from "../../data/securityIncidents.js";
3
+ import type { SecurityIncidentReporter } from "../../data/shared/securityIncidents.js";
4
4
  import type { ProvisionedSystemContainerSpec } from "../../workflows/registration/index.js";
5
5
  import type { ProvisionedPrincipalHistoryPrimer } from "../../workflows/registration/provisionedPrincipalHistory.js";
6
6
  import type { ClearRemoteSyncStateResult } from "../../workflows/sync/index.js";
7
- import type { Database } from "../database.js";
8
- import type { Identity } from "../identity.js";
7
+ import type { Identity } from "../identity/index.js";
8
+ import type { Database } from "../runtime/database.js";
9
9
  import type { BoundUserIdLookup, SessionRegistrationRefusal, UserIdentityAvailable } from "./sessionIdentityTrust.js";
10
10
  export type { SessionRegistrationRefusal } from "./sessionIdentityTrust.js";
11
11
  export interface SessionDependencies {
@@ -1 +1 @@
1
- {"version":3,"file":"sessionTypes.js","sourceRoot":"","sources":["sessionTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ProvisionedSystemContainerSpec } from \"../../workflows/registration\";\nimport type { ProvisionedPrincipalHistoryPrimer } from \"../../workflows/registration/provisionedPrincipalHistory\";\nimport type { ClearRemoteSyncStateResult } from \"../../workflows/sync\";\nimport type { Database } from \"../database\";\nimport type { Identity } from \"../identity\";\nimport type {\n BoundUserIdLookup,\n SessionRegistrationRefusal,\n UserIdentityAvailable,\n} from \"./sessionIdentityTrust\";\n\nexport type { SessionRegistrationRefusal } from \"./sessionIdentityTrust\";\n\nexport interface SessionDependencies {\n api: ApiClient;\n database: Database;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n identity: Identity;\n log: (message: string) => void;\n logError: (message: string | Error, cause?: unknown) => void;\n /** The user this device's trust store already binds a signing key to. */\n boundUserIdForSigningKey?: BoundUserIdLookup | undefined;\n onUserIdentityAvailable?: UserIdentityAvailable | undefined;\n /** Seeds verified recovery progress for a new organization's founding heads. */\n primeProvisionedPrincipalHistory?:\n | ProvisionedPrincipalHistoryPrimer\n | undefined;\n /** App-owned system containers provisioned with each new organization. */\n provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n /**\n * Records a refused login (a different account than acknowledged) or a\n * refused root acknowledgement; absent in bare test harnesses.\n */\n reportSecurityIncident?: SecurityIncidentReporter | undefined;\n}\n\nexport interface SessionContext {\n /** Fingerprint-bound host restore only; view selections never acknowledge roots. */\n rootAcknowledgments?: SessionSnapshot[\"rootAcknowledgments\"] | undefined;\n authToken?: string | null | undefined;\n containerId?: string | null | undefined;\n /** Server-backed personal organization; independent of the active org. */\n defaultOrganizationId?: string | null | undefined;\n isAuthenticated?: boolean | undefined;\n /** Platform-operator flag reported by the server at login. */\n isRoot?: boolean | undefined;\n organizationId?: string | null | undefined;\n userId?: string | null | undefined;\n}\n\nexport interface SessionSnapshot {\n /**\n * Server acknowledgements retained independently of the selected container.\n * Bound to (signing fingerprint, user, organization): once acknowledged, an\n * organization's root id may only be re-acknowledged or reported purged.\n */\n rootAcknowledgments: ReadonlyArray<{\n readonly signingFingerprint: string;\n readonly userId: string;\n readonly organizationId: string;\n readonly rootContainerId: string | null;\n }>;\n authToken: string | null;\n containerId: string | null;\n /** Server-backed personal organization; independent of the active org. */\n defaultOrganizationId: string | null;\n isAuthenticated: boolean;\n /** Platform-operator flag reported by the server at login. */\n isRoot: boolean;\n organizationId: string | null;\n userId: string | null;\n}\n\nexport type SessionListener = () => void;\n\nexport interface SessionRegistrationResult {\n readonly challenge: string;\n readonly containerId: string;\n readonly organizationId: string;\n readonly userId: string;\n}\n\nexport interface SessionCreateOrganizationResult {\n readonly containerId: string;\n readonly organizationId: string;\n}\n\nexport interface SessionRecoverOrganizationResult\n extends SessionCreateOrganizationResult {\n readonly reset: ClearRemoteSyncStateResult;\n readonly replacedOrganizationId: string;\n}\n\nexport interface CreateOrganizationOptions {\n /** Overrides the seeded organization profile name; see registration. */\n readonly organizationProfileName?: string | undefined;\n /** Overrides the seeded self roster-profile nickname; see registration. */\n readonly rosterProfileNickname?: string | undefined;\n}\n\nexport interface RegisterIdentityOptions {\n /**\n * Overrides the seeded personal-organization profile name. Optional; when\n * omitted the default personal-org name is used. The demo host passes each\n * pane's peer-labeled org name (\"Peer 1's Org\").\n */\n readonly organizationProfileName?: string | undefined;\n /**\n * Overrides the seeded self roster-profile nickname. Optional; when omitted\n * the default (\"You\") is used. The demo host passes each pane's peer-labeled\n * self name (\"Peer 1 (You)\").\n */\n readonly rosterProfileNickname?: string | undefined;\n}\n\nexport interface UserSession {\n readonly createdAt: string;\n readonly id: string;\n readonly ipAddresses: string[];\n readonly isCurrent: boolean;\n readonly lastActiveAt: string;\n readonly lastActiveIp: string | null;\n readonly signingKeyFingerprint: string;\n}\n\nexport interface Session {\n readonly authToken: string | null;\n readonly containerId: string | null;\n /** Server-backed personal organization; independent of the active org. */\n readonly defaultOrganizationId: string | null;\n readonly isAuthenticated: boolean;\n /**\n * Platform-operator flag reported by the server at login. It only decides\n * whether the root console is offered; the API enforces root access itself.\n */\n readonly isRoot: boolean;\n readonly organizationId: string | null;\n readonly snapshot: SessionSnapshot;\n /** Controls server replication without changing network connectivity. */\n readonly syncEnabled: boolean;\n readonly userId: string | null;\n /**\n * Whether `userId` was acknowledged by the server for the active signing\n * identity (a successful login or a fingerprint-bound host restore). A user\n * ID chosen locally through `setUserId` is not, and hosts must not persist\n * it as this identity's account.\n */\n readonly userIdAcknowledged: boolean;\n bootstrapLocalRootContainer(): Promise<{\n containerId: string;\n created: boolean;\n }>;\n clearRemoteSyncState(\n organizationId: string,\n ): Promise<ClearRemoteSyncStateResult>;\n createOrganization(\n options?: CreateOrganizationOptions,\n ): Promise<SessionCreateOrganizationResult | null>;\n completeNativeSubscriptionRestoreOrganization(\n organizationId: string,\n ): Promise<boolean>;\n destroySession(sessionId: string): Promise<boolean>;\n listSessions(): Promise<UserSession[]>;\n login(challengeHex?: string | undefined): Promise<boolean>;\n logout(): void;\n logoutRemote(): Promise<boolean>;\n prepareNativeSubscriptionRestoreOrganization(\n options?: CreateOrganizationOptions,\n ): Promise<SessionCreateOrganizationResult | null>;\n registerIdentity(\n options?: RegisterIdentityOptions,\n ): Promise<SessionRegistrationResult | SessionRegistrationRefusal | null>;\n recoverPurgedOrganization(\n organizationId: string,\n options?: CreateOrganizationOptions,\n ): Promise<SessionRecoverOrganizationResult | null>;\n setAuthToken(authToken: string | null): void;\n setContainerId(containerId: string | null): void;\n /** Host-restored context must match the active signing identity; conflicting user acknowledgments throw. */\n setContext(context: SessionContext): void;\n setOrganizationId(organizationId: string | null): void;\n setSyncEnabled(enabled: boolean): void;\n setUserId(userId: string | null): void;\n subscribe(listener: SessionListener): () => void;\n}\n"]}
1
+ {"version":3,"file":"sessionTypes.js","sourceRoot":"","sources":["sessionTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\nimport type { ProvisionedSystemContainerSpec } from \"../../workflows/registration\";\nimport type { ProvisionedPrincipalHistoryPrimer } from \"../../workflows/registration/provisionedPrincipalHistory\";\nimport type { ClearRemoteSyncStateResult } from \"../../workflows/sync\";\nimport type { Identity } from \"../identity\";\nimport type { Database } from \"../runtime/database\";\nimport type {\n BoundUserIdLookup,\n SessionRegistrationRefusal,\n UserIdentityAvailable,\n} from \"./sessionIdentityTrust\";\n\nexport type { SessionRegistrationRefusal } from \"./sessionIdentityTrust\";\n\nexport interface SessionDependencies {\n api: ApiClient;\n database: Database;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n identity: Identity;\n log: (message: string) => void;\n logError: (message: string | Error, cause?: unknown) => void;\n /** The user this device's trust store already binds a signing key to. */\n boundUserIdForSigningKey?: BoundUserIdLookup | undefined;\n onUserIdentityAvailable?: UserIdentityAvailable | undefined;\n /** Seeds verified recovery progress for a new organization's founding heads. */\n primeProvisionedPrincipalHistory?:\n | ProvisionedPrincipalHistoryPrimer\n | undefined;\n /** App-owned system containers provisioned with each new organization. */\n provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n /**\n * Records a refused login (a different account than acknowledged) or a\n * refused root acknowledgement; absent in bare test harnesses.\n */\n reportSecurityIncident?: SecurityIncidentReporter | undefined;\n}\n\nexport interface SessionContext {\n /** Fingerprint-bound host restore only; view selections never acknowledge roots. */\n rootAcknowledgments?: SessionSnapshot[\"rootAcknowledgments\"] | undefined;\n authToken?: string | null | undefined;\n containerId?: string | null | undefined;\n /** Server-backed personal organization; independent of the active org. */\n defaultOrganizationId?: string | null | undefined;\n isAuthenticated?: boolean | undefined;\n /** Platform-operator flag reported by the server at login. */\n isRoot?: boolean | undefined;\n organizationId?: string | null | undefined;\n userId?: string | null | undefined;\n}\n\nexport interface SessionSnapshot {\n /**\n * Server acknowledgements retained independently of the selected container.\n * Bound to (signing fingerprint, user, organization): once acknowledged, an\n * organization's root id may only be re-acknowledged or reported purged.\n */\n rootAcknowledgments: ReadonlyArray<{\n readonly signingFingerprint: string;\n readonly userId: string;\n readonly organizationId: string;\n readonly rootContainerId: string | null;\n }>;\n authToken: string | null;\n containerId: string | null;\n /** Server-backed personal organization; independent of the active org. */\n defaultOrganizationId: string | null;\n isAuthenticated: boolean;\n /** Platform-operator flag reported by the server at login. */\n isRoot: boolean;\n organizationId: string | null;\n userId: string | null;\n}\n\nexport type SessionListener = () => void;\n\nexport interface SessionRegistrationResult {\n readonly challenge: string;\n readonly containerId: string;\n readonly organizationId: string;\n readonly userId: string;\n}\n\nexport interface SessionCreateOrganizationResult {\n readonly containerId: string;\n readonly organizationId: string;\n}\n\nexport interface SessionRecoverOrganizationResult\n extends SessionCreateOrganizationResult {\n readonly reset: ClearRemoteSyncStateResult;\n readonly replacedOrganizationId: string;\n}\n\nexport interface CreateOrganizationOptions {\n /** Overrides the seeded organization profile name; see registration. */\n readonly organizationProfileName?: string | undefined;\n /** Overrides the seeded self roster-profile nickname; see registration. */\n readonly rosterProfileNickname?: string | undefined;\n}\n\nexport interface RegisterIdentityOptions {\n /**\n * Overrides the seeded personal-organization profile name. Optional; when\n * omitted the default personal-org name is used. The demo host passes each\n * pane's peer-labeled org name (\"Peer 1's Org\").\n */\n readonly organizationProfileName?: string | undefined;\n /**\n * Overrides the seeded self roster-profile nickname. Optional; when omitted\n * the default (\"You\") is used. The demo host passes each pane's peer-labeled\n * self name (\"Peer 1 (You)\").\n */\n readonly rosterProfileNickname?: string | undefined;\n}\n\nexport interface UserSession {\n readonly createdAt: string;\n readonly id: string;\n readonly ipAddresses: string[];\n readonly isCurrent: boolean;\n readonly lastActiveAt: string;\n readonly lastActiveIp: string | null;\n readonly signingKeyFingerprint: string;\n}\n\nexport interface Session {\n readonly authToken: string | null;\n readonly containerId: string | null;\n /** Server-backed personal organization; independent of the active org. */\n readonly defaultOrganizationId: string | null;\n readonly isAuthenticated: boolean;\n /**\n * Platform-operator flag reported by the server at login. It only decides\n * whether the root console is offered; the API enforces root access itself.\n */\n readonly isRoot: boolean;\n readonly organizationId: string | null;\n readonly snapshot: SessionSnapshot;\n /** Controls server replication without changing network connectivity. */\n readonly syncEnabled: boolean;\n readonly userId: string | null;\n /**\n * Whether `userId` was acknowledged by the server for the active signing\n * identity (a successful login or a fingerprint-bound host restore). A user\n * ID chosen locally through `setUserId` is not, and hosts must not persist\n * it as this identity's account.\n */\n readonly userIdAcknowledged: boolean;\n bootstrapLocalRootContainer(): Promise<{\n containerId: string;\n created: boolean;\n }>;\n clearRemoteSyncState(\n organizationId: string,\n ): Promise<ClearRemoteSyncStateResult>;\n createOrganization(\n options?: CreateOrganizationOptions,\n ): Promise<SessionCreateOrganizationResult | null>;\n completeNativeSubscriptionRestoreOrganization(\n organizationId: string,\n ): Promise<boolean>;\n destroySession(sessionId: string): Promise<boolean>;\n listSessions(): Promise<UserSession[]>;\n login(challengeHex?: string | undefined): Promise<boolean>;\n logout(): void;\n logoutRemote(): Promise<boolean>;\n prepareNativeSubscriptionRestoreOrganization(\n options?: CreateOrganizationOptions,\n ): Promise<SessionCreateOrganizationResult | null>;\n registerIdentity(\n options?: RegisterIdentityOptions,\n ): Promise<SessionRegistrationResult | SessionRegistrationRefusal | null>;\n recoverPurgedOrganization(\n organizationId: string,\n options?: CreateOrganizationOptions,\n ): Promise<SessionRecoverOrganizationResult | null>;\n setAuthToken(authToken: string | null): void;\n setContainerId(containerId: string | null): void;\n /** Host-restored context must match the active signing identity; conflicting user acknowledgments throw. */\n setContext(context: SessionContext): void;\n setOrganizationId(organizationId: string | null): void;\n setSyncEnabled(enabled: boolean): void;\n setUserId(userId: string | null): void;\n subscribe(listener: SessionListener): () => void;\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 createBlobStore(namespace: string): BlobStore;
@@ -1 +1 @@
1
- {"version":3,"file":"createBlobStore.js","sourceRoot":"","sources":["createBlobStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE1D,6DAA6D;AAC7D,4BAA4B;AAC5B,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9D,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,MAAM,aAAa,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACrD,oBAAoB,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACnD,OAAO,aAAa,CAAC;AACvB,CAAC","sourcesContent":["import type { BlobStore } from \"../blobContracts\";\nimport { createOpfsBlobStore, isOpfsBlobStoreSupported } from \"./opfsBlobStore\";\n\nconst opfsStoreByNamespace = new Map<string, BlobStore>();\n\n// namespace is a 64-character hex SHA-256 fingerprint of the\n// signing public key bytes.\nexport function createBlobStore(namespace: string): BlobStore {\n if (!isOpfsBlobStoreSupported()) {\n throw new Error(\"OPFS blob store is not supported.\");\n }\n\n const existingOpfsStore = opfsStoreByNamespace.get(namespace);\n if (existingOpfsStore) {\n return existingOpfsStore;\n }\n\n const nextOpfsStore = createOpfsBlobStore(namespace);\n opfsStoreByNamespace.set(namespace, nextOpfsStore);\n return nextOpfsStore;\n}\n"]}
1
+ {"version":3,"file":"createBlobStore.js","sourceRoot":"","sources":["createBlobStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE1D,6DAA6D;AAC7D,4BAA4B;AAC5B,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9D,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,MAAM,aAAa,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACrD,oBAAoB,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACnD,OAAO,aAAa,CAAC;AACvB,CAAC","sourcesContent":["import type { BlobStore } from \"./blobContracts\";\nimport { createOpfsBlobStore, isOpfsBlobStoreSupported } from \"./opfsBlobStore\";\n\nconst opfsStoreByNamespace = new Map<string, BlobStore>();\n\n// namespace is a 64-character hex SHA-256 fingerprint of the\n// signing public key bytes.\nexport function createBlobStore(namespace: string): BlobStore {\n if (!isOpfsBlobStoreSupported()) {\n throw new Error(\"OPFS blob store is not supported.\");\n }\n\n const existingOpfsStore = opfsStoreByNamespace.get(namespace);\n if (existingOpfsStore) {\n return existingOpfsStore;\n }\n\n const nextOpfsStore = createOpfsBlobStore(namespace);\n opfsStoreByNamespace.set(namespace, nextOpfsStore);\n return nextOpfsStore;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { assertReadRange, readExactBlobBytes, } from "../blobContracts.js";
1
+ import { assertReadRange, readExactBlobBytes, } from "./blobContracts.js";
2
2
  import { AES_GCM_TAG_BYTES, chunkAdditionalData, deriveChunkIv, ENCRYPTED_BLOB_CHUNK_SIZE, getChunkPlaintextByteLength, } from "./encryptedBlobEnvelope.js";
3
3
  function ciphertextOffset(prefixByteLength, chunkIndex) {
4
4
  return (prefixByteLength +
@@ -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":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAGL,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AA6B1B,MAAM,CAAC,MAAM,2BAA2B,GACtC,sCAAsC,CAAC;AACzC,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAC9C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAEpC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,sBAAsB,GAAG,OAAO,CAAC;AACvC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AACnC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAC1C,yCAAyC,CAC1C,CAAC;AACF,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,YAAY,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/D,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC;AAEvC,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,WAAW,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,KAAa;IAC/C,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,KAA8B,EAC9B,GAAW,EACX,KAAa;IAEb,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,GAAG,kBAAkB,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,MAA0B;IAE1B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QACrD,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,4CAA4C,MAAM,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,UAA8B;IACnE,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,sBAAsB,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAI3C;IACC,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAC9B,sCAAsC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS,EAAE,CACxE,CAAC;IACF,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAChC,KAAc;IAEd,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC;IACvE,IACE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,oCAAoC,CAAC;QACtE,eAAe,EACf,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,IACE,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,oCAAoC,CAAC;SAClE,UAAU,KAAK,CAAC,EACnB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,UAAU,EAAE,6BAA6B,CACvC,MAAM,EACN,YAAY,EACZ,oCAAoC,CACrC;QACD,IAAI,EAAE,gBAAgB,CACpB,MAAM,EACN,MAAM,EACN,oCAAoC,CACrC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,WAAsB;IAIzC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,KAAK,GAAG,6BAA6B,CAAC;IAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzC,IACE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,2BAA2B,EACzE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,6BAA6B,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,SAAS,GAAG,6BAA6B,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;IAC5E,IAAI,SAAS,KAAK,yBAAyB,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,mBAAmB,GAAG,wBAAwB,CAClD,MAAM,EACN,qBAAqB,EACrB,KAAK,CACN,CAAC;IACF,MAAM,UAAU,GAAG,6BAA6B,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;IAC9E,IAAI,UAAU,KAAK,aAAa,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,EAAE,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,UAAU,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IACjC,OAAO;QACL,QAAQ,EAAE;YACR,UAAU;YACV,SAAS;YACT,MAAM,EAAE,eAAe,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YAClE,MAAM,EAAE,2BAA2B;YACnC,EAAE,EAAE,gBAAgB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC;YACzC,aAAa,EAAE,yBAAyB,CAAC,aAAa,CAAC;YACvD,mBAAmB;YACnB,OAAO,EAAE,4BAA4B;SACtC;QACD,EAAE;KACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,mBAA2B;IACvD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,mBAAmB,CAAC,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CACb,CAAC,EACD,IAAI,CAAC,IAAI,CAAC,mBAAmB,GAAG,yBAAyB,CAAC,CAC3D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,mBAA2B,EAC3B,UAAkB;IAElB,MAAM,UAAU,GAAG,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACtD,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC;QACjC,UAAU,GAAG,CAAC;QACd,UAAU,IAAI,UAAU,EACxB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,UAAU,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,yBAAyB,CAAC;IACnC,CAAC;IACD,OAAO,mBAAmB,GAAG,UAAU,GAAG,yBAAyB,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,QAA+B;IAE/B,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClE,IAAI,WAAW,CAAC,UAAU,GAAG,gBAAgB,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,UAAU,CAChC,WAAW,CAAC,UAAU,GAAG,mBAAmB,GAAG,WAAW,CAAC,UAAU,CACtE,CAAC;IACF,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,SAAS,CACxC,WAAW,CAAC,UAAU,EACtB,WAAW,CAAC,UAAU,CACvB,CAAC;IACF,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,UAAU,GAAG,mBAAmB,CAAC,CAAC;IAC3E,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,UAAU,CAAC,IAAgB,EAAE,KAAiB;IACrD,OAAO,CACL,IAAI,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAsB;IAEtB,MAAM,iBAAiB,GAAG,WAAW,CAAC,UAAU,GAAG,mBAAmB,CAAC;IACvE,IAAI,MAAM,CAAC,UAAU,GAAG,iBAAiB,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC3E,IACE,CAAC,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,EACzE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,gBAAgB,GAAG,IAAI,QAAQ,CACnC,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,UAAU,EACtB,WAAW,CAAC,UAAU,CACvB,CAAC,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACpC,IAAI,gBAAgB,KAAK,CAAC,IAAI,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IAC9D,IAAI,MAAM,CAAC,UAAU,GAAG,gBAAgB,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAC1C,MAAM,EACN,iBAAiB,EACjB,gBAAgB,CACjB,CAAC;IACF,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,mBAAmB,GACvB,gBAAgB;QAChB,QAAQ,CAAC,mBAAmB;QAC5B,QAAQ,CAAC,UAAU,GAAG,iBAAiB,CAAC;IAC1C,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,mBAAmB,CAAC;QAC1C,MAAM,CAAC,UAAU,KAAK,mBAAmB,EACzC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO;QACL,mBAAmB;QACnB,QAAQ;QACR,WAAW;QACX,EAAE;QACF,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAC9B,MAAkB,EAClB,MAAc,EACd,KAAa;IAEb,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9B,OAAO,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAKnC;IACC,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,UAAU,CAC1B,CAAC;QACC,cAAc,CAAC,UAAU;QACzB,CAAC;QACD,eAAe,CAAC,UAAU;QAC1B,CAAC;QACD,KAAK,CAAC,WAAW,CAAC,UAAU,CAC/B,CAAC;IACF,IAAI,MAAM,GAAG,uBAAuB,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,MAAM,GAAG,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAClE,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/D,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAAiB,EACjB,UAAkB;IAElB,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC;QACjC,UAAU,GAAG,CAAC;QACd,UAAU,GAAG,WAAW,EACxB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;IACnE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;IAClD,OAAO,EAAE,CAAC;AACZ,CAAC","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;