@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":"opfsBlobStore.js","sourceRoot":"","sources":["opfsBlobStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n blobByteSourceInputLength,\n createBlobByteSource,\n readBlobByteSource,\n} from \"../blobContracts\";\n\ninterface StorageDirectoryProvider {\n getDirectory: () => Promise<FileSystemDirectoryHandle>;\n}\n\nconst OPFS_WRITE_CHUNK_SIZE = 5 * 1024 * 1024;\n\nclass OpfsBlobStore implements BlobStore {\n private directoryPromise: Promise<FileSystemDirectoryHandle> | null = null;\n\n constructor(private readonly namespace: string) {}\n\n async deleteBytes(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n await directory.removeEntry(this.getFileName(storageKey));\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n\n throw error;\n }\n }\n\n async readBytes(storageKey: string) {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async openByteSource(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n );\n const file = await fileHandle.getFile();\n return createBlobByteSource(file);\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return null;\n }\n\n throw error;\n }\n }\n\n async writeByteSource(storageKey: string, source: BlobByteSource) {\n const sourceByteLength = blobByteSourceInputLength(source);\n const directory = await this.getDirectory();\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n { create: true },\n );\n const writable = await fileHandle.createWritable();\n\n try {\n for (let offset = 0; offset < sourceByteLength; ) {\n const byteLength = Math.min(\n OPFS_WRITE_CHUNK_SIZE,\n sourceByteLength - offset,\n );\n const chunk = await source.read(offset, byteLength);\n if (chunk.byteLength !== byteLength) {\n throw new Error(\"Blob byte source returned an incomplete read.\");\n }\n await writable.write(chunk);\n offset += byteLength;\n }\n await writable.close();\n } catch (error) {\n await writable.abort(error).catch(() => undefined);\n throw error;\n }\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes) {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n\n private getFileName(storageKey: string): string {\n return `${encodeURIComponent(storageKey)}.blob`;\n }\n\n private async getDirectory() {\n if (!this.directoryPromise) {\n this.directoryPromise = this.createDirectory().catch((error: unknown) => {\n this.directoryPromise = null;\n throw error;\n });\n }\n\n return this.directoryPromise;\n }\n\n private async createDirectory() {\n const rootDirectory = await navigator.storage.getDirectory();\n const appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\", {\n create: true,\n });\n\n return appDirectory.getDirectoryHandle(this.namespace, { create: true });\n }\n}\n\nfunction hasStorageDirectory(\n storage: StorageManager | undefined,\n): storage is StorageManager & StorageDirectoryProvider {\n return (\n storage !== undefined &&\n \"getDirectory\" in storage &&\n typeof storage.getDirectory === \"function\"\n );\n}\n\nexport function isOpfsBlobStoreSupported(): boolean {\n return (\n typeof navigator === \"object\" && hasStorageDirectory(navigator.storage)\n );\n}\n\nexport function createOpfsBlobStore(namespace: string): BlobStore {\n return new OpfsBlobStore(namespace);\n}\n\n/**\n * Permanently remove the OPFS directory backing a namespace's blob store\n * (`tearleads/<namespace>`), discarding every stored blob for that namespace.\n * Used to forget local data on logout. No-op when OPFS is unavailable or the\n * directory was never created; never throws on a missing directory.\n */\nexport async function purgeOpfsBlobStore(namespace: string): Promise<void> {\n if (!isOpfsBlobStoreSupported()) {\n return;\n }\n\n const rootDirectory = await navigator.storage.getDirectory();\n let appDirectory: FileSystemDirectoryHandle;\n try {\n appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\");\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n\n try {\n await appDirectory.removeEntry(namespace, { recursive: true });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n}\n"]}
1
+ {"version":3,"file":"opfsBlobStore.js","sourceRoot":"","sources":["opfsBlobStore.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type BlobByteSource,\n type BlobBytes,\n type BlobStore,\n blobByteSourceInputLength,\n createBlobByteSource,\n readBlobByteSource,\n} from \"./blobContracts\";\n\ninterface StorageDirectoryProvider {\n getDirectory: () => Promise<FileSystemDirectoryHandle>;\n}\n\nconst OPFS_WRITE_CHUNK_SIZE = 5 * 1024 * 1024;\n\nclass OpfsBlobStore implements BlobStore {\n private directoryPromise: Promise<FileSystemDirectoryHandle> | null = null;\n\n constructor(private readonly namespace: string) {}\n\n async deleteBytes(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n await directory.removeEntry(this.getFileName(storageKey));\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n\n throw error;\n }\n }\n\n async readBytes(storageKey: string) {\n const source = await this.openByteSource(storageKey);\n return source ? readBlobByteSource(source) : null;\n }\n\n async openByteSource(storageKey: string) {\n const directory = await this.getDirectory();\n\n try {\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n );\n const file = await fileHandle.getFile();\n return createBlobByteSource(file);\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return null;\n }\n\n throw error;\n }\n }\n\n async writeByteSource(storageKey: string, source: BlobByteSource) {\n const sourceByteLength = blobByteSourceInputLength(source);\n const directory = await this.getDirectory();\n const fileHandle = await directory.getFileHandle(\n this.getFileName(storageKey),\n { create: true },\n );\n const writable = await fileHandle.createWritable();\n\n try {\n for (let offset = 0; offset < sourceByteLength; ) {\n const byteLength = Math.min(\n OPFS_WRITE_CHUNK_SIZE,\n sourceByteLength - offset,\n );\n const chunk = await source.read(offset, byteLength);\n if (chunk.byteLength !== byteLength) {\n throw new Error(\"Blob byte source returned an incomplete read.\");\n }\n await writable.write(chunk);\n offset += byteLength;\n }\n await writable.close();\n } catch (error) {\n await writable.abort(error).catch(() => undefined);\n throw error;\n }\n }\n\n async writeBytes(storageKey: string, bytes: BlobBytes) {\n await this.writeByteSource(storageKey, createBlobByteSource(bytes));\n }\n\n private getFileName(storageKey: string): string {\n return `${encodeURIComponent(storageKey)}.blob`;\n }\n\n private async getDirectory() {\n if (!this.directoryPromise) {\n this.directoryPromise = this.createDirectory().catch((error: unknown) => {\n this.directoryPromise = null;\n throw error;\n });\n }\n\n return this.directoryPromise;\n }\n\n private async createDirectory() {\n const rootDirectory = await navigator.storage.getDirectory();\n const appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\", {\n create: true,\n });\n\n return appDirectory.getDirectoryHandle(this.namespace, { create: true });\n }\n}\n\nfunction hasStorageDirectory(\n storage: StorageManager | undefined,\n): storage is StorageManager & StorageDirectoryProvider {\n return (\n storage !== undefined &&\n \"getDirectory\" in storage &&\n typeof storage.getDirectory === \"function\"\n );\n}\n\nexport function isOpfsBlobStoreSupported(): boolean {\n return (\n typeof navigator === \"object\" && hasStorageDirectory(navigator.storage)\n );\n}\n\nexport function createOpfsBlobStore(namespace: string): BlobStore {\n return new OpfsBlobStore(namespace);\n}\n\n/**\n * Permanently remove the OPFS directory backing a namespace's blob store\n * (`tearleads/<namespace>`), discarding every stored blob for that namespace.\n * Used to forget local data on logout. No-op when OPFS is unavailable or the\n * directory was never created; never throws on a missing directory.\n */\nexport async function purgeOpfsBlobStore(namespace: string): Promise<void> {\n if (!isOpfsBlobStoreSupported()) {\n return;\n }\n\n const rootDirectory = await navigator.storage.getDirectory();\n let appDirectory: FileSystemDirectoryHandle;\n try {\n appDirectory = await rootDirectory.getDirectoryHandle(\"tearleads\");\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n\n try {\n await appDirectory.removeEntry(namespace, { recursive: true });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n return;\n }\n throw error;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { createDocument, exportAllUpdates } from "../../internal/loro/index.js";
2
- import { getScopedPeerSeed } from "../crdtPeerSeed.js";
2
+ import { getScopedPeerSeed } from "../sync/crdtPeerSeed.js";
3
3
  export function getDefaultContainerName(parentId) {
4
4
  return parentId === null ? "/" : "Untitled";
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"containerMetadataDocument.js","sourceRoot":"","sources":["containerMetadataDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAWpD,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC7D,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,YAAoB;IAEpB,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,OAAO,cAAc,CAAC,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0CAA0C,CAC9D,WAAmB,EACnB,KAA6B;IAK7B,MAAM,GAAG,GAAG,MAAM,+BAA+B,CAAC,WAAW,CAAC,CAAC;IAC/D,2BAA2B,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAExC,OAAO;QACL,GAAG;QACH,aAAa,EAAE,gBAAgB,CAAC,GAAG,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,GAA8B,EAC9B,WAAmB;IAEnB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO;QACL,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YACrD,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,IAAI;QACV,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC5D,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,WAAW;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,GAA8B,EAC9B,KAA6B;IAE7B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["import { createDocument, exportAllUpdates } from \"@tearleads/loro\";\nimport { getScopedPeerSeed } from \"../crdtPeerSeed\";\n\ninterface ContainerMetadataValue {\n icon: string | null;\n name: string;\n}\n\nexport type ContainerMetadataDocument = Awaited<\n ReturnType<typeof createDocument>\n>;\n\nexport function getDefaultContainerName(parentId: string | null): string {\n return parentId === null ? \"/\" : \"Untitled\";\n}\n\nexport async function createContainerMetadataDocument(\n _containerId: string,\n): Promise<ContainerMetadataDocument> {\n // A single static scope for all container-metadata docs: they are separate\n // CRDTs, so they can share one device peer, and a per-container scope would\n // hold a distinct device-peer lock (and cache entry) per container for the\n // tab's lifetime, accumulating without bound as containers are browsed.\n return createDocument(await getScopedPeerSeed(\"container-metadata\"));\n}\n\nexport async function createInitializedContainerMetadataDocument(\n containerId: string,\n value: ContainerMetadataValue,\n): Promise<{\n doc: ContainerMetadataDocument;\n initialUpdate: Uint8Array;\n}> {\n const doc = await createContainerMetadataDocument(containerId);\n writeContainerMetadataValue(doc, value);\n\n return {\n doc,\n initialUpdate: exportAllUpdates(doc),\n };\n}\n\nexport function readContainerMetadataValue(\n doc: ContainerMetadataDocument,\n defaultName: string,\n): ContainerMetadataValue {\n const metadata = doc.getMap(\"container\");\n const storedName = metadata.get(\"name\");\n const storedIcon = metadata.get(\"icon\");\n\n return {\n icon:\n typeof storedIcon === \"string\" && storedIcon.length > 0\n ? storedIcon\n : null,\n name:\n typeof storedName === \"string\" && storedName.trim().length > 0\n ? storedName\n : defaultName,\n };\n}\n\nexport function writeContainerMetadataValue(\n doc: ContainerMetadataDocument,\n value: ContainerMetadataValue,\n): void {\n const metadata = doc.getMap(\"container\");\n\n metadata.set(\"name\", value.name);\n\n if (value.icon) {\n metadata.set(\"icon\", value.icon);\n return;\n }\n\n metadata.delete(\"icon\");\n}\n"]}
1
+ {"version":3,"file":"containerMetadataDocument.js","sourceRoot":"","sources":["containerMetadataDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAWzD,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC7D,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,YAAoB;IAEpB,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,OAAO,cAAc,CAAC,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0CAA0C,CAC9D,WAAmB,EACnB,KAA6B;IAK7B,MAAM,GAAG,GAAG,MAAM,+BAA+B,CAAC,WAAW,CAAC,CAAC;IAC/D,2BAA2B,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAExC,OAAO;QACL,GAAG;QACH,aAAa,EAAE,gBAAgB,CAAC,GAAG,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,GAA8B,EAC9B,WAAmB;IAEnB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO;QACL,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YACrD,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,IAAI;QACV,IAAI,EACF,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC5D,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,WAAW;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,GAA8B,EAC9B,KAA6B;IAE7B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["import { createDocument, exportAllUpdates } from \"@tearleads/loro\";\nimport { getScopedPeerSeed } from \"../sync/crdtPeerSeed\";\n\ninterface ContainerMetadataValue {\n icon: string | null;\n name: string;\n}\n\nexport type ContainerMetadataDocument = Awaited<\n ReturnType<typeof createDocument>\n>;\n\nexport function getDefaultContainerName(parentId: string | null): string {\n return parentId === null ? \"/\" : \"Untitled\";\n}\n\nexport async function createContainerMetadataDocument(\n _containerId: string,\n): Promise<ContainerMetadataDocument> {\n // A single static scope for all container-metadata docs: they are separate\n // CRDTs, so they can share one device peer, and a per-container scope would\n // hold a distinct device-peer lock (and cache entry) per container for the\n // tab's lifetime, accumulating without bound as containers are browsed.\n return createDocument(await getScopedPeerSeed(\"container-metadata\"));\n}\n\nexport async function createInitializedContainerMetadataDocument(\n containerId: string,\n value: ContainerMetadataValue,\n): Promise<{\n doc: ContainerMetadataDocument;\n initialUpdate: Uint8Array;\n}> {\n const doc = await createContainerMetadataDocument(containerId);\n writeContainerMetadataValue(doc, value);\n\n return {\n doc,\n initialUpdate: exportAllUpdates(doc),\n };\n}\n\nexport function readContainerMetadataValue(\n doc: ContainerMetadataDocument,\n defaultName: string,\n): ContainerMetadataValue {\n const metadata = doc.getMap(\"container\");\n const storedName = metadata.get(\"name\");\n const storedIcon = metadata.get(\"icon\");\n\n return {\n icon:\n typeof storedIcon === \"string\" && storedIcon.length > 0\n ? storedIcon\n : null,\n name:\n typeof storedName === \"string\" && storedName.trim().length > 0\n ? storedName\n : defaultName,\n };\n}\n\nexport function writeContainerMetadataValue(\n doc: ContainerMetadataDocument,\n value: ContainerMetadataValue,\n): void {\n const metadata = doc.getMap(\"container\");\n\n metadata.set(\"name\", value.name);\n\n if (value.icon) {\n metadata.set(\"icon\", value.icon);\n return;\n }\n\n metadata.delete(\"icon\");\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { computeAccessEventBodyHash, computeAccessEventHash, computeAccessManifestHash, computeContainerKekMaterialId, deriveContainerAccessManifest, signAccessEvent, } from "../../../internal/crypto/index.js";
2
- import { readCanonicalJson } from "../../keyingCanonicalJson.js";
2
+ import { readCanonicalJson } from "../../keying/canonicalJson.js";
3
3
  import { uniqueSortedManifestHashes } from "./projection.js";
4
4
  export function buildContainerCreateBody(input) {
5
5
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerAccessManifestState,\n type ContainerCreateAccessEventBody,\n type ContainerGrantAccessEventBody,\n type ContainerKekRecipientTarget,\n type ContainerKeyEpoch,\n type ContainerMoveAccessEventBody,\n type ContainerReciteAccessEventBody,\n type ContainerRekeyAccessEventBody,\n type ContainerRevokeAccessEventBody,\n computeAccessEventBodyHash,\n computeAccessEventHash,\n computeAccessManifestHash,\n computeContainerKekMaterialId,\n deriveContainerAccessManifest,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readCanonicalJson } from \"../../keyingCanonicalJson\";\nimport { uniqueSortedManifestHashes } from \"./projection\";\nimport type {\n ContainerCreatePlan,\n ContainerMovePlan,\n ContainerMutationAuthor,\n ContainerRevokePlan,\n ContainerSharePlan,\n} from \"./types\";\n\nexport function buildContainerCreateBody(input: {\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n}): ContainerCreateAccessEventBody {\n return {\n systemSlot: input.systemSlot ?? null,\n eventType: \"container.create\",\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: [],\n referencedPrincipalHeads: [],\n };\n}\n\nexport async function signContainerCreateEvent(input: {\n author: ContainerMutationAuthor;\n body: ContainerCreateAccessEventBody;\n containerId: string;\n eventId: string;\n // The organization the new container belongs to — always the parent\n // container's org, NOT the author's. A member writing under another org's\n // shared root creates a container owned by that org; only the signer identity\n // comes from the author. The server trusts this signed field, so it is the\n // load-bearing org for the create.\n organizationId: string;\n parentPath: ContainerWriterProjectionResponse[\"path\"];\n signedAt: string;\n}): Promise<Pick<ContainerCreatePlan, \"event\" | \"eventHash\">> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container create body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: \"container.create\",\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.organizationId,\n previousManifestHash: null,\n dependencyManifestHashes: uniqueSortedManifestHashes(input.parentPath),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function signContainerMutationEvent(input: {\n author: ContainerMutationAuthor;\n body:\n | ContainerGrantAccessEventBody\n | ContainerMoveAccessEventBody\n | ContainerRekeyAccessEventBody\n | ContainerReciteAccessEventBody\n | ContainerRevokeAccessEventBody;\n containerId: string;\n dependencyManifestHashes: readonly string[];\n eventId: string;\n previousManifestHash: string;\n signedAt: string;\n}): Promise<\n Pick<\n ContainerSharePlan | ContainerMovePlan | ContainerRevokePlan,\n \"event\" | \"eventHash\"\n >\n> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container mutation body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: input.body.eventType,\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.author.organizationId,\n previousManifestHash: input.previousManifestHash,\n dependencyManifestHashes: [\n ...new Set(input.dependencyManifestHashes),\n ].sort(),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function deriveContainerCreateManifest(input: {\n containerId: string;\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n // Grants baked into the create manifest. Defaults to none. A child container\n // born with a managed-principal (group/organization) grant — e.g. the org\n // public metadata container granted to the Members group — supplies both the\n // grant and its referenced principal head here so the manifest hash reconciles\n // with the signed event body and the server can derive the KEK recipient target.\n directGrants?: ContainerCreateAccessEventBody[\"directGrants\"] | undefined;\n eventHash: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n // The parent container's org (see signContainerCreateEvent). Must match the\n // signed event's org or the manifest hash will not reconcile server-side.\n organizationId: string;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n referencedPrincipalHeads?:\n | ContainerCreateAccessEventBody[\"referencedPrincipalHeads\"]\n | undefined;\n}): Promise<Pick<ContainerCreatePlan, \"manifest\" | \"manifestHash\" | \"state\">> {\n const state: ContainerAccessManifestState = {\n systemSlot: input.systemSlot ?? null,\n version: 1,\n containerId: input.containerId,\n organizationId: input.organizationId,\n epoch: 1,\n previousManifestHash: null,\n eventHash: input.eventHash,\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: input.directGrants ? [...input.directGrants] : [],\n referencedPrincipalHeads: input.referencedPrincipalHeads\n ? [...input.referencedPrincipalHeads]\n : [],\n };\n const manifest = await deriveContainerAccessManifest(state);\n\n return {\n manifest,\n manifestHash: await computeAccessManifestHash(manifest),\n state,\n };\n}\n\nexport function buildContainerCreateKeyEpoch(input: {\n containerId: string;\n containerKeyEpochId: string;\n eventHash: string;\n /** Defaults to the creation epoch; rotations pass their next epoch. */\n keyEpoch?: number | undefined;\n manifestHash: string;\n parentContainerKeyEpochId: string | null;\n}): ContainerKeyEpoch {\n return {\n id: input.containerKeyEpochId,\n containerId: input.containerId,\n keyEpoch: input.keyEpoch ?? 1,\n accessManifestHash: input.manifestHash,\n parentContainerKeyEpochId: input.parentContainerKeyEpochId,\n createdByEventHash: input.eventHash,\n createdByManifestHash: input.manifestHash,\n };\n}\n\nexport function buildParentRecipientTargets(\n parentKek: ContainerKekResponse,\n): ContainerKekRecipientTarget[] {\n return [\n {\n recipientKind: \"container\",\n recipientId: parentKek.containerId,\n recipientKeyEpochId: parentKek.containerKeyEpochId,\n recipientKeyFingerprint: parentKek.keyEpochHash,\n },\n ];\n}\n\nexport async function resolveContainerKekEpochId(input: {\n containerId: string;\n keyEpoch: number;\n keyMaterial: Uint8Array;\n override?: string | undefined;\n}): Promise<string> {\n const materialId = await computeContainerKekMaterialId({\n containerId: input.containerId,\n keyEpoch: input.keyEpoch,\n keyMaterial: input.keyMaterial,\n });\n if (input.override !== undefined && input.override !== materialId) {\n throw new Error(\n \"Container key epoch id does not match the committed KEK material\",\n );\n }\n\n return materialId;\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerAccessManifestState,\n type ContainerCreateAccessEventBody,\n type ContainerGrantAccessEventBody,\n type ContainerKekRecipientTarget,\n type ContainerKeyEpoch,\n type ContainerMoveAccessEventBody,\n type ContainerReciteAccessEventBody,\n type ContainerRekeyAccessEventBody,\n type ContainerRevokeAccessEventBody,\n computeAccessEventBodyHash,\n computeAccessEventHash,\n computeAccessManifestHash,\n computeContainerKekMaterialId,\n deriveContainerAccessManifest,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readCanonicalJson } from \"../../keying/canonicalJson\";\nimport { uniqueSortedManifestHashes } from \"./projection\";\nimport type {\n ContainerCreatePlan,\n ContainerMovePlan,\n ContainerMutationAuthor,\n ContainerRevokePlan,\n ContainerSharePlan,\n} from \"./types\";\n\nexport function buildContainerCreateBody(input: {\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n}): ContainerCreateAccessEventBody {\n return {\n systemSlot: input.systemSlot ?? null,\n eventType: \"container.create\",\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: [],\n referencedPrincipalHeads: [],\n };\n}\n\nexport async function signContainerCreateEvent(input: {\n author: ContainerMutationAuthor;\n body: ContainerCreateAccessEventBody;\n containerId: string;\n eventId: string;\n // The organization the new container belongs to — always the parent\n // container's org, NOT the author's. A member writing under another org's\n // shared root creates a container owned by that org; only the signer identity\n // comes from the author. The server trusts this signed field, so it is the\n // load-bearing org for the create.\n organizationId: string;\n parentPath: ContainerWriterProjectionResponse[\"path\"];\n signedAt: string;\n}): Promise<Pick<ContainerCreatePlan, \"event\" | \"eventHash\">> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container create body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: \"container.create\",\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.organizationId,\n previousManifestHash: null,\n dependencyManifestHashes: uniqueSortedManifestHashes(input.parentPath),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function signContainerMutationEvent(input: {\n author: ContainerMutationAuthor;\n body:\n | ContainerGrantAccessEventBody\n | ContainerMoveAccessEventBody\n | ContainerRekeyAccessEventBody\n | ContainerReciteAccessEventBody\n | ContainerRevokeAccessEventBody;\n containerId: string;\n dependencyManifestHashes: readonly string[];\n eventId: string;\n previousManifestHash: string;\n signedAt: string;\n}): Promise<\n Pick<\n ContainerSharePlan | ContainerMovePlan | ContainerRevokePlan,\n \"event\" | \"eventHash\"\n >\n> {\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(input.body, \"Container mutation body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType: input.body.eventType,\n objectKind: \"container\",\n objectId: input.containerId,\n organizationId: input.author.organizationId,\n previousManifestHash: input.previousManifestHash,\n dependencyManifestHashes: [\n ...new Set(input.dependencyManifestHashes),\n ].sort(),\n bodyHash,\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt,\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n event,\n eventHash: await computeAccessEventHash(event),\n };\n}\n\nexport async function deriveContainerCreateManifest(input: {\n containerId: string;\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n // Grants baked into the create manifest. Defaults to none. A child container\n // born with a managed-principal (group/organization) grant — e.g. the org\n // public metadata container granted to the Members group — supplies both the\n // grant and its referenced principal head here so the manifest hash reconciles\n // with the signed event body and the server can derive the KEK recipient target.\n directGrants?: ContainerCreateAccessEventBody[\"directGrants\"] | undefined;\n eventHash: string;\n metadataDocumentId: string;\n systemSlot?: string | null | undefined;\n // The parent container's org (see signContainerCreateEvent). Must match the\n // signed event's org or the manifest hash will not reconcile server-side.\n organizationId: string;\n parentContainerId: string | null;\n parentManifestHash: string | null;\n referencedPrincipalHeads?:\n | ContainerCreateAccessEventBody[\"referencedPrincipalHeads\"]\n | undefined;\n}): Promise<Pick<ContainerCreatePlan, \"manifest\" | \"manifestHash\" | \"state\">> {\n const state: ContainerAccessManifestState = {\n systemSlot: input.systemSlot ?? null,\n version: 1,\n containerId: input.containerId,\n organizationId: input.organizationId,\n epoch: 1,\n previousManifestHash: null,\n eventHash: input.eventHash,\n parentContainerId: input.parentContainerId,\n parentManifestHash: input.parentManifestHash,\n metadataDocumentId: input.metadataDocumentId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n directGrants: input.directGrants ? [...input.directGrants] : [],\n referencedPrincipalHeads: input.referencedPrincipalHeads\n ? [...input.referencedPrincipalHeads]\n : [],\n };\n const manifest = await deriveContainerAccessManifest(state);\n\n return {\n manifest,\n manifestHash: await computeAccessManifestHash(manifest),\n state,\n };\n}\n\nexport function buildContainerCreateKeyEpoch(input: {\n containerId: string;\n containerKeyEpochId: string;\n eventHash: string;\n /** Defaults to the creation epoch; rotations pass their next epoch. */\n keyEpoch?: number | undefined;\n manifestHash: string;\n parentContainerKeyEpochId: string | null;\n}): ContainerKeyEpoch {\n return {\n id: input.containerKeyEpochId,\n containerId: input.containerId,\n keyEpoch: input.keyEpoch ?? 1,\n accessManifestHash: input.manifestHash,\n parentContainerKeyEpochId: input.parentContainerKeyEpochId,\n createdByEventHash: input.eventHash,\n createdByManifestHash: input.manifestHash,\n };\n}\n\nexport function buildParentRecipientTargets(\n parentKek: ContainerKekResponse,\n): ContainerKekRecipientTarget[] {\n return [\n {\n recipientKind: \"container\",\n recipientId: parentKek.containerId,\n recipientKeyEpochId: parentKek.containerKeyEpochId,\n recipientKeyFingerprint: parentKek.keyEpochHash,\n },\n ];\n}\n\nexport async function resolveContainerKekEpochId(input: {\n containerId: string;\n keyEpoch: number;\n keyMaterial: Uint8Array;\n override?: string | undefined;\n}): Promise<string> {\n const materialId = await computeContainerKekMaterialId({\n containerId: input.containerId,\n keyEpoch: input.keyEpoch,\n keyMaterial: input.keyMaterial,\n });\n if (input.override !== undefined && input.override !== materialId) {\n throw new Error(\n \"Container key epoch id does not match the committed KEK material\",\n );\n }\n\n return materialId;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { MAX_CONTAINER_PATH_LENGTH } from "../../../internal/validators/util/index.js";
2
- import { readCanonicalRecord } from "../../keyingCanonicalJson.js";
2
+ import { readCanonicalRecord } from "../../keying/canonicalJson.js";
3
3
  import { resolveCanonicalExecSql } from "../../sqlite/sqlSchema.js";
4
4
  // Opportunistic, process-local evidence, not a persistent cache or freshness
5
5
  // oracle. No secret keys are retained. Eviction merely limits cascade coverage.
@@ -1 +1 @@
1
- {"version":3,"file":"heldContainerHeads.js","sourceRoot":"","sources":["heldContainerHeads.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerAccessManifestState,\n VerifiedContainerAccessManifest,\n} from \"@tearleads/crypto\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport { MAX_CONTAINER_PATH_LENGTH } from \"@tearleads/validators/util\";\nimport { readCanonicalRecord } from \"../../keyingCanonicalJson\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../../principals/principalPolicyEvidence\";\nimport { type ExecSql, resolveCanonicalExecSql } from \"../../sqlite/sqlSchema\";\nimport type { AuthoredContainerMutationHead } from \"./mutationAcknowledgement\";\n\nexport interface HeldContainerHead {\n readonly bundle: AccessManifestBundleWire;\n readonly state: ContainerAccessManifestState;\n}\n\ninterface HeldContainers {\n readonly heads: Map<string, HeldContainerHead>;\n readonly policies: Map<\n string,\n {\n readonly organizationId: string;\n readonly policy: PrincipalPolicyCheckpointEvidence;\n }\n >;\n}\n\n// Opportunistic, process-local evidence, not a persistent cache or freshness\n// oracle. No secret keys are retained. Eviction merely limits cascade coverage.\nconst heldByDatabase = new WeakMap<ExecSql, HeldContainers>();\n// Executor-wide limits: another organization's activity may evict evidence,\n// which only skips optional recitations and never changes durable checkpoints.\nconst MAX_HEADS = 256;\nconst MAX_POLICIES = 512;\n\nfunction heldContainers(execSql: ExecSql): HeldContainers {\n const canonical = resolveCanonicalExecSql(execSql);\n let held = heldByDatabase.get(canonical);\n if (!held) {\n held = { heads: new Map(), policies: new Map() };\n heldByDatabase.set(canonical, held);\n }\n return held;\n}\n\nfunction boundedSet<T>(\n map: Map<string, T>,\n key: string,\n value: T,\n max: number,\n) {\n map.delete(key);\n map.set(key, value);\n if (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest !== undefined) map.delete(oldest);\n }\n}\n\nfunction rememberHead(\n execSql: ExecSql,\n head: Pick<VerifiedContainerAccessManifest, \"state\" | \"manifestHash\">,\n build: () => HeldContainerHead,\n): void {\n const heads = heldContainers(execSql).heads;\n const previous = heads.get(head.state.containerId);\n if (previous && previous.state.epoch >= head.state.epoch) {\n if (previous.bundle.manifestHash === head.manifestHash) {\n boundedSet(heads, head.state.containerId, previous, MAX_HEADS);\n }\n return;\n }\n boundedSet(\n heads,\n head.state.containerId,\n structuredClone(build()),\n MAX_HEADS,\n );\n}\n\n/** Called only after the complete projection and its durable pins validate. */\nexport function rememberVerifiedContainerHeads(input: {\n readonly organizationId: string;\n readonly execSql: ExecSql;\n readonly heads: readonly VerifiedContainerAccessManifest[];\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n}): void {\n for (const policy of input.policies) {\n if (\n policy.principalType === \"organization\" &&\n policy.principalId !== input.organizationId\n ) {\n throw new Error(\"Held principal policy belongs to another organization\");\n }\n }\n // Group signed states contain no organization ID. Their scope is supplied\n // by the already-verified projection/policy caller, not inferred here.\n for (const head of input.heads) {\n if (head.state.organizationId !== input.organizationId) {\n throw new Error(\"Held container head belongs to another organization\");\n }\n }\n for (const head of input.heads) {\n rememberHead(input.execSql, head, () => ({\n state: head.state,\n bundle: {\n event: readCanonicalRecord(head.event, \"Verified container event\"),\n manifest: readCanonicalRecord(\n head.manifest,\n \"Verified container manifest\",\n ),\n manifestHash: head.manifestHash,\n state: readCanonicalRecord(head.state, \"Verified container state\"),\n },\n }));\n }\n const policies = heldContainers(input.execSql).policies;\n for (const policy of input.policies) {\n const key = `${input.organizationId}:${policy.principalType}:${policy.principalId}`;\n const previous = policies.get(key);\n if (previous && previous.policy.version > policy.version) continue;\n if (\n previous?.policy.version === policy.version &&\n previous.policy.stateHash !== policy.stateHash\n )\n continue;\n boundedSet(\n policies,\n key,\n { organizationId: input.organizationId, policy: structuredClone(policy) },\n MAX_POLICIES,\n );\n }\n}\n\n/** Caller must first correlate the exact response and durably acknowledge it. */\nexport function rememberAcknowledgedContainerHead(\n execSql: ExecSql,\n plan: Pick<\n AuthoredContainerMutationHead,\n \"body\" | \"event\" | \"eventHash\" | \"manifest\" | \"manifestHash\" | \"state\"\n >,\n): HeldContainerHead {\n const head: HeldContainerHead = {\n state: plan.state,\n bundle: {\n event: readCanonicalRecord(\n {\n event: plan.event,\n eventHash: plan.eventHash,\n body: plan.body,\n },\n \"Acknowledged container event\",\n ),\n manifest: readCanonicalRecord(\n plan.manifest,\n \"Acknowledged container manifest\",\n ),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Acknowledged container state\"),\n },\n };\n rememberHead(execSql, plan, () => head);\n return head;\n}\n\nexport function heldContainerSnapshot(\n execSql: ExecSql,\n organizationId: string,\n) {\n const held = heldContainers(execSql);\n return {\n heads: new Map(\n [...held.heads]\n .filter(([, head]) => head.state.organizationId === organizationId)\n .map(([id, head]) => [id, structuredClone(head)] as const),\n ),\n policies: [...held.policies.values()]\n .filter((entry) => entry.organizationId === organizationId)\n .map((entry) => structuredClone(entry.policy)),\n };\n}\n\n/** Resolve parent edges only; parentManifestHash is historical keying evidence. */\nexport function heldContainerPath(\n heads: ReadonlyMap<string, HeldContainerHead>,\n containerId: string,\n): HeldContainerHead[] | null {\n const path: HeldContainerHead[] = [];\n const seen = new Set<string>();\n let id: string | null = containerId;\n while (id !== null) {\n if (seen.has(id) || path.length >= MAX_CONTAINER_PATH_LENGTH) return null;\n seen.add(id);\n const head = heads.get(id);\n if (!head) return null;\n path.unshift(head);\n id = head.state.parentContainerId;\n }\n return path;\n}\n"]}
1
+ {"version":3,"file":"heldContainerHeads.js","sourceRoot":"","sources":["heldContainerHeads.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerAccessManifestState,\n VerifiedContainerAccessManifest,\n} from \"@tearleads/crypto\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport { MAX_CONTAINER_PATH_LENGTH } from \"@tearleads/validators/util\";\nimport { readCanonicalRecord } from \"../../keying/canonicalJson\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../../principals/principalPolicyEvidence\";\nimport { type ExecSql, resolveCanonicalExecSql } from \"../../sqlite/sqlSchema\";\nimport type { AuthoredContainerMutationHead } from \"./mutationAcknowledgement\";\n\nexport interface HeldContainerHead {\n readonly bundle: AccessManifestBundleWire;\n readonly state: ContainerAccessManifestState;\n}\n\ninterface HeldContainers {\n readonly heads: Map<string, HeldContainerHead>;\n readonly policies: Map<\n string,\n {\n readonly organizationId: string;\n readonly policy: PrincipalPolicyCheckpointEvidence;\n }\n >;\n}\n\n// Opportunistic, process-local evidence, not a persistent cache or freshness\n// oracle. No secret keys are retained. Eviction merely limits cascade coverage.\nconst heldByDatabase = new WeakMap<ExecSql, HeldContainers>();\n// Executor-wide limits: another organization's activity may evict evidence,\n// which only skips optional recitations and never changes durable checkpoints.\nconst MAX_HEADS = 256;\nconst MAX_POLICIES = 512;\n\nfunction heldContainers(execSql: ExecSql): HeldContainers {\n const canonical = resolveCanonicalExecSql(execSql);\n let held = heldByDatabase.get(canonical);\n if (!held) {\n held = { heads: new Map(), policies: new Map() };\n heldByDatabase.set(canonical, held);\n }\n return held;\n}\n\nfunction boundedSet<T>(\n map: Map<string, T>,\n key: string,\n value: T,\n max: number,\n) {\n map.delete(key);\n map.set(key, value);\n if (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest !== undefined) map.delete(oldest);\n }\n}\n\nfunction rememberHead(\n execSql: ExecSql,\n head: Pick<VerifiedContainerAccessManifest, \"state\" | \"manifestHash\">,\n build: () => HeldContainerHead,\n): void {\n const heads = heldContainers(execSql).heads;\n const previous = heads.get(head.state.containerId);\n if (previous && previous.state.epoch >= head.state.epoch) {\n if (previous.bundle.manifestHash === head.manifestHash) {\n boundedSet(heads, head.state.containerId, previous, MAX_HEADS);\n }\n return;\n }\n boundedSet(\n heads,\n head.state.containerId,\n structuredClone(build()),\n MAX_HEADS,\n );\n}\n\n/** Called only after the complete projection and its durable pins validate. */\nexport function rememberVerifiedContainerHeads(input: {\n readonly organizationId: string;\n readonly execSql: ExecSql;\n readonly heads: readonly VerifiedContainerAccessManifest[];\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n}): void {\n for (const policy of input.policies) {\n if (\n policy.principalType === \"organization\" &&\n policy.principalId !== input.organizationId\n ) {\n throw new Error(\"Held principal policy belongs to another organization\");\n }\n }\n // Group signed states contain no organization ID. Their scope is supplied\n // by the already-verified projection/policy caller, not inferred here.\n for (const head of input.heads) {\n if (head.state.organizationId !== input.organizationId) {\n throw new Error(\"Held container head belongs to another organization\");\n }\n }\n for (const head of input.heads) {\n rememberHead(input.execSql, head, () => ({\n state: head.state,\n bundle: {\n event: readCanonicalRecord(head.event, \"Verified container event\"),\n manifest: readCanonicalRecord(\n head.manifest,\n \"Verified container manifest\",\n ),\n manifestHash: head.manifestHash,\n state: readCanonicalRecord(head.state, \"Verified container state\"),\n },\n }));\n }\n const policies = heldContainers(input.execSql).policies;\n for (const policy of input.policies) {\n const key = `${input.organizationId}:${policy.principalType}:${policy.principalId}`;\n const previous = policies.get(key);\n if (previous && previous.policy.version > policy.version) continue;\n if (\n previous?.policy.version === policy.version &&\n previous.policy.stateHash !== policy.stateHash\n )\n continue;\n boundedSet(\n policies,\n key,\n { organizationId: input.organizationId, policy: structuredClone(policy) },\n MAX_POLICIES,\n );\n }\n}\n\n/** Caller must first correlate the exact response and durably acknowledge it. */\nexport function rememberAcknowledgedContainerHead(\n execSql: ExecSql,\n plan: Pick<\n AuthoredContainerMutationHead,\n \"body\" | \"event\" | \"eventHash\" | \"manifest\" | \"manifestHash\" | \"state\"\n >,\n): HeldContainerHead {\n const head: HeldContainerHead = {\n state: plan.state,\n bundle: {\n event: readCanonicalRecord(\n {\n event: plan.event,\n eventHash: plan.eventHash,\n body: plan.body,\n },\n \"Acknowledged container event\",\n ),\n manifest: readCanonicalRecord(\n plan.manifest,\n \"Acknowledged container manifest\",\n ),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Acknowledged container state\"),\n },\n };\n rememberHead(execSql, plan, () => head);\n return head;\n}\n\nexport function heldContainerSnapshot(\n execSql: ExecSql,\n organizationId: string,\n) {\n const held = heldContainers(execSql);\n return {\n heads: new Map(\n [...held.heads]\n .filter(([, head]) => head.state.organizationId === organizationId)\n .map(([id, head]) => [id, structuredClone(head)] as const),\n ),\n policies: [...held.policies.values()]\n .filter((entry) => entry.organizationId === organizationId)\n .map((entry) => structuredClone(entry.policy)),\n };\n}\n\n/** Resolve parent edges only; parentManifestHash is historical keying evidence. */\nexport function heldContainerPath(\n heads: ReadonlyMap<string, HeldContainerHead>,\n containerId: string,\n): HeldContainerHead[] | null {\n const path: HeldContainerHead[] = [];\n const seen = new Set<string>();\n let id: string | null = containerId;\n while (id !== null) {\n if (seen.has(id) || path.length >= MAX_CONTAINER_PATH_LENGTH) return null;\n seen.add(id);\n const head = heads.get(id);\n if (!head) return null;\n path.unshift(head);\n id = head.state.parentContainerId;\n }\n return path;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { accessManifestCheckpointFromManifest, compareCanonicalStrings, computeContainerKekKeyringHash, computeContainerKekRecipientTargetHash, computeContainerKeyEpochHash, } from "../../../internal/crypto/index.js";
2
- import { canonicalKeyingJsonString } from "../../keyingCanonicalJson.js";
2
+ import { canonicalKeyingJsonString } from "../../keying/canonicalJson.js";
3
3
  import { advanceLocallyAcknowledgedAccessManifestHeadsAtomically, } from "../../persistence/locallyAcknowledgedCheckpointPersistence.js";
4
4
  function assertCanonicalMatch(input) {
5
5
  if (canonicalKeyingJsonString(input.actual, `${input.label} response`) !==
@@ -1 +1 @@
1
- {"version":3,"file":"mutationAcknowledgement.js","sourceRoot":"","sources":["mutationAcknowledgement.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AccessEvent,\n type AccessManifest,\n accessManifestCheckpointFromManifest,\n type ContainerAccessManifestState,\n type ContainerKekRecipientTarget,\n type ContainerKeyEpoch,\n type ContainerKeyWrap,\n compareCanonicalStrings,\n computeContainerKekKeyringHash,\n computeContainerKekRecipientTargetHash,\n computeContainerKeyEpochHash,\n} from \"@tearleads/crypto\";\nimport type { ContainerMutationResponse } from \"@tearleads/validators/response\";\nimport { canonicalKeyingJsonString } from \"../../keyingCanonicalJson\";\nimport {\n advanceLocallyAcknowledgedAccessManifestHeadsAtomically,\n type LocallyAcknowledgedAccessManifestHead,\n} from \"../../persistence/locallyAcknowledgedCheckpointPersistence\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\n\nexport interface AuthoredContainerMutationHead {\n readonly body: object;\n readonly containerId: string;\n readonly event: AccessEvent;\n readonly eventHash: string;\n readonly keyEpoch: ContainerKeyEpoch;\n readonly manifest: AccessManifest;\n readonly manifestHash: string;\n /**\n * The keyring the epoch already had, for mutations that keep their epoch.\n * Its artifact is immutable, so the response must echo exactly this.\n */\n readonly previousKeyring?: Record<string, unknown> | null | undefined;\n readonly state: ContainerAccessManifestState;\n readonly wraps: readonly ContainerKeyWrap[];\n}\n\nfunction assertCanonicalMatch(input: {\n readonly actual: unknown;\n readonly expected: unknown;\n readonly label: string;\n}): void {\n if (\n canonicalKeyingJsonString(input.actual, `${input.label} response`) !==\n canonicalKeyingJsonString(input.expected, `${input.label} plan`)\n ) {\n throw new Error(`Container mutation response ${input.label} mismatch`);\n }\n}\n\nfunction sortedCanonicalValues<T>(values: readonly T[], label: string): T[] {\n return [...values].sort((left, right) =>\n compareCanonicalStrings(\n canonicalKeyingJsonString(left, label),\n canonicalKeyingJsonString(right, label),\n ),\n );\n}\n\nfunction expectedRecipientTargets(\n wraps: readonly ContainerKeyWrap[],\n): ContainerKekRecipientTarget[] {\n return sortedCanonicalValues(\n wraps.map((wrap) => ({\n recipientId: wrap.recipientId,\n recipientKeyEpochId: wrap.recipientKeyEpochId,\n recipientKeyFingerprint: wrap.recipientKeyFingerprint,\n recipientKind: wrap.recipientKind,\n })),\n \"recipient target\",\n );\n}\n\nfunction assertResponseIdentity(\n plan: AuthoredContainerMutationHead,\n response: ContainerMutationResponse,\n): void {\n if (\n response.containerId !== plan.containerId ||\n response.organizationId !== plan.state.organizationId ||\n response.parentId !== plan.state.parentContainerId\n ) {\n throw new Error(\"Container mutation response object identity mismatch\");\n }\n // The top-level slot column is what local system-container lookups key on,\n // so it must echo the slot this client signed into the manifest state; an\n // omitted slot is the server's spelling of null.\n if ((response.systemSlot ?? null) !== plan.state.systemSlot) {\n throw new Error(\"Container mutation response system slot mismatch\");\n }\n if (\n response.manifestHead.epoch !== plan.state.epoch ||\n response.manifestHead.manifestHash !== plan.manifestHash ||\n response.accessManifest.manifestHash !== plan.manifestHash\n ) {\n throw new Error(\"Container mutation response manifest head mismatch\");\n }\n if (\n response.containerKek.containerId !== plan.containerId ||\n response.containerKek.accessManifestHash !== plan.manifestHash ||\n response.containerKek.containerKeyEpochId !== plan.keyEpoch.id ||\n response.containerKek.containerKeyEpoch !== plan.keyEpoch.keyEpoch\n ) {\n throw new Error(\"Container mutation response KEK identity mismatch\");\n }\n}\n\n/** A rotation body commits a keyring hash; other bodies do not. */\nfunction readOptionalKeyringHash(body: object): string | null {\n const value = Reflect.get(body, \"keyringHash\");\n return typeof value === \"string\" ? value : null;\n}\n\n/**\n * The response's keyring must be the one this client's own signed event\n * committed to. Without this a server could echo a substituted snapshot and\n * have it acknowledged into durable local state — the acknowledgement is the\n * moment the response becomes trusted, so the commitment is checked here.\n */\nasync function assertAcknowledgedKeyring(\n plan: AuthoredContainerMutationHead,\n response: ContainerMutationResponse,\n): Promise<void> {\n const committedHash = readOptionalKeyringHash(plan.body);\n const keyring = response.containerKek.keyring;\n if (committedHash === null) {\n // A non-rotating mutation keeps its epoch, so the echoed keyring must be\n // the immutable artifact that epoch already had. Accepting anything else\n // would let a server null or substitute the snapshot in the response that\n // becomes the next writer projection.\n const expected = plan.previousKeyring ?? null;\n if (expected === null) {\n // The epoch had no keyring, so the response must not invent one: an\n // injected snapshot would become the next writer projection's history.\n if (keyring) {\n throw new Error(\n \"Container mutation response added a keyring to an unchanged epoch\",\n );\n }\n return;\n }\n if (!keyring) {\n throw new Error(\n \"Container mutation response dropped its unchanged keyring\",\n );\n }\n if (\n (await computeContainerKekKeyringHash(keyring)) !==\n (await computeContainerKekKeyringHash(expected))\n ) {\n throw new Error(\n \"Container mutation response replaced its unchanged keyring\",\n );\n }\n return;\n }\n if (!keyring) {\n throw new Error(\"Container mutation response is missing its keyring\");\n }\n if ((await computeContainerKekKeyringHash(keyring)) !== committedHash) {\n throw new Error(\n \"Container mutation response keyring does not match its signed event\",\n );\n }\n}\n\nasync function assertResponseContent(\n plan: AuthoredContainerMutationHead,\n response: ContainerMutationResponse,\n): Promise<void> {\n assertCanonicalMatch({\n actual: response.accessManifest.event.event,\n expected: plan.event,\n label: \"event\",\n });\n assertCanonicalMatch({\n actual: response.accessManifest.event.body,\n expected: plan.body,\n label: \"event body\",\n });\n if (response.accessManifest.event.eventHash !== plan.eventHash) {\n throw new Error(\"Container mutation response event hash mismatch\");\n }\n assertCanonicalMatch({\n actual: response.accessManifest.manifest,\n expected: plan.manifest,\n label: \"manifest\",\n });\n assertCanonicalMatch({\n actual: response.accessManifest.state,\n expected: plan.state,\n label: \"state\",\n });\n assertCanonicalMatch({\n actual: response.containerKek.keyEpoch,\n expected: plan.keyEpoch,\n label: \"key epoch\",\n });\n await assertAcknowledgedKeyring(plan, response);\n assertCanonicalMatch({\n actual: sortedCanonicalValues(response.containerKek.wraps, \"response wrap\"),\n expected: sortedCanonicalValues(plan.wraps, \"planned wrap\"),\n label: \"wraps\",\n });\n const recipientTargets = expectedRecipientTargets(plan.wraps);\n const responseTargets = sortedCanonicalValues(\n response.containerKek.recipientTargets,\n \"response recipient target\",\n );\n assertCanonicalMatch({\n actual: responseTargets,\n expected: recipientTargets,\n label: \"recipient targets\",\n });\n if (\n response.containerKek.keyEpochHash !==\n (await computeContainerKeyEpochHash(plan.keyEpoch)) ||\n response.containerKek.keyTargetHash !==\n (await computeContainerKekRecipientTargetHash(recipientTargets)) ||\n response.containerKek.parentContainerKeyEpochId !==\n plan.keyEpoch.parentContainerKeyEpochId\n ) {\n throw new Error(\"Container mutation response KEK commitment mismatch\");\n }\n assertCanonicalMatch({\n actual: response.referencedPrincipalHeads,\n expected: plan.manifest.referencedPrincipalHeads,\n label: \"referenced principal heads\",\n });\n}\n\nexport async function locallyAcknowledgedContainerMutationHead(input: {\n readonly plan: AuthoredContainerMutationHead;\n readonly response: ContainerMutationResponse;\n}): Promise<LocallyAcknowledgedAccessManifestHead> {\n assertResponseIdentity(input.plan, input.response);\n await assertResponseContent(input.plan, input.response);\n return {\n checkpoint: accessManifestCheckpointFromManifest({\n manifest: input.plan.manifest,\n manifestHash: input.plan.manifestHash,\n }),\n previousManifestHash: input.plan.manifest.previousManifestHash,\n };\n}\n\n/** Correlates an API acknowledgement to the locally signed plan before pinning. */\nexport async function acknowledgeContainerMutation(input: {\n readonly execSql: ExecSql;\n readonly plan: AuthoredContainerMutationHead;\n readonly response: ContainerMutationResponse;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean> {\n return advanceLocallyAcknowledgedAccessManifestHeadsAtomically({\n execSql: input.execSql,\n heads: [\n await locallyAcknowledgedContainerMutationHead({\n plan: input.plan,\n response: input.response,\n }),\n ],\n stillCurrent: input.stillCurrent,\n });\n}\n\n/** Correlates and advances a complete authored mutation batch atomically. */\nexport async function acknowledgeContainerMutationBatch(input: {\n readonly execSql: ExecSql;\n readonly plans: readonly AuthoredContainerMutationHead[];\n readonly responses: readonly ContainerMutationResponse[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean> {\n if (input.plans.length !== input.responses.length) {\n throw new Error(\"Container mutation acknowledgement batch is incomplete\");\n }\n const heads = await Promise.all(\n input.plans.map(async (plan, index) => {\n const response = input.responses[index];\n if (!response) {\n throw new Error(\n \"Container mutation acknowledgement batch is incomplete\",\n );\n }\n return locallyAcknowledgedContainerMutationHead({ plan, response });\n }),\n );\n return advanceLocallyAcknowledgedAccessManifestHeadsAtomically({\n execSql: input.execSql,\n heads,\n stillCurrent: input.stillCurrent,\n });\n}\n"]}
1
+ {"version":3,"file":"mutationAcknowledgement.js","sourceRoot":"","sources":["mutationAcknowledgement.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AccessEvent,\n type AccessManifest,\n accessManifestCheckpointFromManifest,\n type ContainerAccessManifestState,\n type ContainerKekRecipientTarget,\n type ContainerKeyEpoch,\n type ContainerKeyWrap,\n compareCanonicalStrings,\n computeContainerKekKeyringHash,\n computeContainerKekRecipientTargetHash,\n computeContainerKeyEpochHash,\n} from \"@tearleads/crypto\";\nimport type { ContainerMutationResponse } from \"@tearleads/validators/response\";\nimport { canonicalKeyingJsonString } from \"../../keying/canonicalJson\";\nimport {\n advanceLocallyAcknowledgedAccessManifestHeadsAtomically,\n type LocallyAcknowledgedAccessManifestHead,\n} from \"../../persistence/locallyAcknowledgedCheckpointPersistence\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\n\nexport interface AuthoredContainerMutationHead {\n readonly body: object;\n readonly containerId: string;\n readonly event: AccessEvent;\n readonly eventHash: string;\n readonly keyEpoch: ContainerKeyEpoch;\n readonly manifest: AccessManifest;\n readonly manifestHash: string;\n /**\n * The keyring the epoch already had, for mutations that keep their epoch.\n * Its artifact is immutable, so the response must echo exactly this.\n */\n readonly previousKeyring?: Record<string, unknown> | null | undefined;\n readonly state: ContainerAccessManifestState;\n readonly wraps: readonly ContainerKeyWrap[];\n}\n\nfunction assertCanonicalMatch(input: {\n readonly actual: unknown;\n readonly expected: unknown;\n readonly label: string;\n}): void {\n if (\n canonicalKeyingJsonString(input.actual, `${input.label} response`) !==\n canonicalKeyingJsonString(input.expected, `${input.label} plan`)\n ) {\n throw new Error(`Container mutation response ${input.label} mismatch`);\n }\n}\n\nfunction sortedCanonicalValues<T>(values: readonly T[], label: string): T[] {\n return [...values].sort((left, right) =>\n compareCanonicalStrings(\n canonicalKeyingJsonString(left, label),\n canonicalKeyingJsonString(right, label),\n ),\n );\n}\n\nfunction expectedRecipientTargets(\n wraps: readonly ContainerKeyWrap[],\n): ContainerKekRecipientTarget[] {\n return sortedCanonicalValues(\n wraps.map((wrap) => ({\n recipientId: wrap.recipientId,\n recipientKeyEpochId: wrap.recipientKeyEpochId,\n recipientKeyFingerprint: wrap.recipientKeyFingerprint,\n recipientKind: wrap.recipientKind,\n })),\n \"recipient target\",\n );\n}\n\nfunction assertResponseIdentity(\n plan: AuthoredContainerMutationHead,\n response: ContainerMutationResponse,\n): void {\n if (\n response.containerId !== plan.containerId ||\n response.organizationId !== plan.state.organizationId ||\n response.parentId !== plan.state.parentContainerId\n ) {\n throw new Error(\"Container mutation response object identity mismatch\");\n }\n // The top-level slot column is what local system-container lookups key on,\n // so it must echo the slot this client signed into the manifest state; an\n // omitted slot is the server's spelling of null.\n if ((response.systemSlot ?? null) !== plan.state.systemSlot) {\n throw new Error(\"Container mutation response system slot mismatch\");\n }\n if (\n response.manifestHead.epoch !== plan.state.epoch ||\n response.manifestHead.manifestHash !== plan.manifestHash ||\n response.accessManifest.manifestHash !== plan.manifestHash\n ) {\n throw new Error(\"Container mutation response manifest head mismatch\");\n }\n if (\n response.containerKek.containerId !== plan.containerId ||\n response.containerKek.accessManifestHash !== plan.manifestHash ||\n response.containerKek.containerKeyEpochId !== plan.keyEpoch.id ||\n response.containerKek.containerKeyEpoch !== plan.keyEpoch.keyEpoch\n ) {\n throw new Error(\"Container mutation response KEK identity mismatch\");\n }\n}\n\n/** A rotation body commits a keyring hash; other bodies do not. */\nfunction readOptionalKeyringHash(body: object): string | null {\n const value = Reflect.get(body, \"keyringHash\");\n return typeof value === \"string\" ? value : null;\n}\n\n/**\n * The response's keyring must be the one this client's own signed event\n * committed to. Without this a server could echo a substituted snapshot and\n * have it acknowledged into durable local state — the acknowledgement is the\n * moment the response becomes trusted, so the commitment is checked here.\n */\nasync function assertAcknowledgedKeyring(\n plan: AuthoredContainerMutationHead,\n response: ContainerMutationResponse,\n): Promise<void> {\n const committedHash = readOptionalKeyringHash(plan.body);\n const keyring = response.containerKek.keyring;\n if (committedHash === null) {\n // A non-rotating mutation keeps its epoch, so the echoed keyring must be\n // the immutable artifact that epoch already had. Accepting anything else\n // would let a server null or substitute the snapshot in the response that\n // becomes the next writer projection.\n const expected = plan.previousKeyring ?? null;\n if (expected === null) {\n // The epoch had no keyring, so the response must not invent one: an\n // injected snapshot would become the next writer projection's history.\n if (keyring) {\n throw new Error(\n \"Container mutation response added a keyring to an unchanged epoch\",\n );\n }\n return;\n }\n if (!keyring) {\n throw new Error(\n \"Container mutation response dropped its unchanged keyring\",\n );\n }\n if (\n (await computeContainerKekKeyringHash(keyring)) !==\n (await computeContainerKekKeyringHash(expected))\n ) {\n throw new Error(\n \"Container mutation response replaced its unchanged keyring\",\n );\n }\n return;\n }\n if (!keyring) {\n throw new Error(\"Container mutation response is missing its keyring\");\n }\n if ((await computeContainerKekKeyringHash(keyring)) !== committedHash) {\n throw new Error(\n \"Container mutation response keyring does not match its signed event\",\n );\n }\n}\n\nasync function assertResponseContent(\n plan: AuthoredContainerMutationHead,\n response: ContainerMutationResponse,\n): Promise<void> {\n assertCanonicalMatch({\n actual: response.accessManifest.event.event,\n expected: plan.event,\n label: \"event\",\n });\n assertCanonicalMatch({\n actual: response.accessManifest.event.body,\n expected: plan.body,\n label: \"event body\",\n });\n if (response.accessManifest.event.eventHash !== plan.eventHash) {\n throw new Error(\"Container mutation response event hash mismatch\");\n }\n assertCanonicalMatch({\n actual: response.accessManifest.manifest,\n expected: plan.manifest,\n label: \"manifest\",\n });\n assertCanonicalMatch({\n actual: response.accessManifest.state,\n expected: plan.state,\n label: \"state\",\n });\n assertCanonicalMatch({\n actual: response.containerKek.keyEpoch,\n expected: plan.keyEpoch,\n label: \"key epoch\",\n });\n await assertAcknowledgedKeyring(plan, response);\n assertCanonicalMatch({\n actual: sortedCanonicalValues(response.containerKek.wraps, \"response wrap\"),\n expected: sortedCanonicalValues(plan.wraps, \"planned wrap\"),\n label: \"wraps\",\n });\n const recipientTargets = expectedRecipientTargets(plan.wraps);\n const responseTargets = sortedCanonicalValues(\n response.containerKek.recipientTargets,\n \"response recipient target\",\n );\n assertCanonicalMatch({\n actual: responseTargets,\n expected: recipientTargets,\n label: \"recipient targets\",\n });\n if (\n response.containerKek.keyEpochHash !==\n (await computeContainerKeyEpochHash(plan.keyEpoch)) ||\n response.containerKek.keyTargetHash !==\n (await computeContainerKekRecipientTargetHash(recipientTargets)) ||\n response.containerKek.parentContainerKeyEpochId !==\n plan.keyEpoch.parentContainerKeyEpochId\n ) {\n throw new Error(\"Container mutation response KEK commitment mismatch\");\n }\n assertCanonicalMatch({\n actual: response.referencedPrincipalHeads,\n expected: plan.manifest.referencedPrincipalHeads,\n label: \"referenced principal heads\",\n });\n}\n\nexport async function locallyAcknowledgedContainerMutationHead(input: {\n readonly plan: AuthoredContainerMutationHead;\n readonly response: ContainerMutationResponse;\n}): Promise<LocallyAcknowledgedAccessManifestHead> {\n assertResponseIdentity(input.plan, input.response);\n await assertResponseContent(input.plan, input.response);\n return {\n checkpoint: accessManifestCheckpointFromManifest({\n manifest: input.plan.manifest,\n manifestHash: input.plan.manifestHash,\n }),\n previousManifestHash: input.plan.manifest.previousManifestHash,\n };\n}\n\n/** Correlates an API acknowledgement to the locally signed plan before pinning. */\nexport async function acknowledgeContainerMutation(input: {\n readonly execSql: ExecSql;\n readonly plan: AuthoredContainerMutationHead;\n readonly response: ContainerMutationResponse;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean> {\n return advanceLocallyAcknowledgedAccessManifestHeadsAtomically({\n execSql: input.execSql,\n heads: [\n await locallyAcknowledgedContainerMutationHead({\n plan: input.plan,\n response: input.response,\n }),\n ],\n stillCurrent: input.stillCurrent,\n });\n}\n\n/** Correlates and advances a complete authored mutation batch atomically. */\nexport async function acknowledgeContainerMutationBatch(input: {\n readonly execSql: ExecSql;\n readonly plans: readonly AuthoredContainerMutationHead[];\n readonly responses: readonly ContainerMutationResponse[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean> {\n if (input.plans.length !== input.responses.length) {\n throw new Error(\"Container mutation acknowledgement batch is incomplete\");\n }\n const heads = await Promise.all(\n input.plans.map(async (plan, index) => {\n const response = input.responses[index];\n if (!response) {\n throw new Error(\n \"Container mutation acknowledgement batch is incomplete\",\n );\n }\n return locallyAcknowledgedContainerMutationHead({ plan, response });\n }),\n );\n return advanceLocallyAcknowledgedAccessManifestHeadsAtomically({\n execSql: input.execSql,\n heads,\n stillCurrent: input.stillCurrent,\n });\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { readCanonicalRecord } from "../../keyingCanonicalJson.js";
1
+ import { readCanonicalRecord } from "../../keying/canonicalJson.js";
2
2
  export function principalPolicyRequestRecord(policy, label = "Container principal policy") {
3
3
  return readCanonicalRecord({
4
4
  principalType: policy.principalType,
@@ -1 +1 @@
1
- {"version":3,"file":"principalPolicies.js","sourceRoot":"","sources":["principalPolicies.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAMhE,MAAM,UAAU,4BAA4B,CAC1C,MAAyC,EACzC,KAAK,GAAG,4BAA4B;IAEpC,OAAO,mBAAmB,CACxB;QACE,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK;YACf,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B;QACD,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,EACD,KAAK,CACN,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CACzB,MAGC;IAED,OAAO;QACL,MAAM,CAAC,aAAa;QACpB,MAAM,CAAC,WAAW;QAClB,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,SAAS;KACjB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,uBAAuB,CAErC,QAAsB;IACtB,MAAM,aAAa,GAAG,IAAI,GAAG,EAAa,CAAC;IAE3C,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;AACrC,CAAC","sourcesContent":["import type { VerifiedPrincipalPolicy } from \"@tearleads/crypto\";\nimport { readCanonicalRecord } from \"../../keyingCanonicalJson\";\nimport type {\n PrincipalPolicyCheckpointEvidence,\n PrincipalPolicyCurrentEvidence,\n} from \"../../principals/principalPolicyEvidence\";\n\nexport function principalPolicyRequestRecord(\n policy: PrincipalPolicyCheckpointEvidence,\n label = \"Container principal policy\",\n): Record<string, unknown> {\n return readCanonicalRecord(\n {\n principalType: policy.principalType,\n principalId: policy.principalId,\n version: policy.version,\n keyEpoch: policy.keyEpoch,\n stateHash: policy.stateHash,\n state: {\n ...policy.state,\n stateHash: policy.stateHash,\n },\n projection: policy.projection,\n grants: policy.grants,\n checkpoint: policy.checkpoint,\n },\n label,\n );\n}\n\nfunction principalPolicyKey(\n policy: Pick<\n VerifiedPrincipalPolicy,\n \"keyEpoch\" | \"principalId\" | \"principalType\" | \"stateHash\" | \"version\"\n >,\n): string {\n return [\n policy.principalType,\n policy.principalId,\n policy.version,\n policy.keyEpoch,\n policy.stateHash,\n ].join(\":\");\n}\n\nexport function uniquePrincipalPolicies<\n T extends PrincipalPolicyCurrentEvidence,\n>(policies: readonly T[]): T[] {\n const policiesByKey = new Map<string, T>();\n\n for (const policy of policies) {\n policiesByKey.set(principalPolicyKey(policy), policy);\n }\n\n return [...policiesByKey.values()];\n}\n"]}
1
+ {"version":3,"file":"principalPolicies.js","sourceRoot":"","sources":["principalPolicies.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAMjE,MAAM,UAAU,4BAA4B,CAC1C,MAAyC,EACzC,KAAK,GAAG,4BAA4B;IAEpC,OAAO,mBAAmB,CACxB;QACE,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK;YACf,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B;QACD,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,EACD,KAAK,CACN,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CACzB,MAGC;IAED,OAAO;QACL,MAAM,CAAC,aAAa;QACpB,MAAM,CAAC,WAAW;QAClB,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,SAAS;KACjB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,uBAAuB,CAErC,QAAsB;IACtB,MAAM,aAAa,GAAG,IAAI,GAAG,EAAa,CAAC;IAE3C,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;AACrC,CAAC","sourcesContent":["import type { VerifiedPrincipalPolicy } from \"@tearleads/crypto\";\nimport { readCanonicalRecord } from \"../../keying/canonicalJson\";\nimport type {\n PrincipalPolicyCheckpointEvidence,\n PrincipalPolicyCurrentEvidence,\n} from \"../../principals/principalPolicyEvidence\";\n\nexport function principalPolicyRequestRecord(\n policy: PrincipalPolicyCheckpointEvidence,\n label = \"Container principal policy\",\n): Record<string, unknown> {\n return readCanonicalRecord(\n {\n principalType: policy.principalType,\n principalId: policy.principalId,\n version: policy.version,\n keyEpoch: policy.keyEpoch,\n stateHash: policy.stateHash,\n state: {\n ...policy.state,\n stateHash: policy.stateHash,\n },\n projection: policy.projection,\n grants: policy.grants,\n checkpoint: policy.checkpoint,\n },\n label,\n );\n}\n\nfunction principalPolicyKey(\n policy: Pick<\n VerifiedPrincipalPolicy,\n \"keyEpoch\" | \"principalId\" | \"principalType\" | \"stateHash\" | \"version\"\n >,\n): string {\n return [\n policy.principalType,\n policy.principalId,\n policy.version,\n policy.keyEpoch,\n policy.stateHash,\n ].join(\":\");\n}\n\nexport function uniquePrincipalPolicies<\n T extends PrincipalPolicyCurrentEvidence,\n>(policies: readonly T[]): T[] {\n const policiesByKey = new Map<string, T>();\n\n for (const policy of policies) {\n policiesByKey.set(principalPolicyKey(policy), policy);\n }\n\n return [...policiesByKey.values()];\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  export { readContainerKeyEpoch } from "../../keyingProjectionVerification/readers.js";
2
- import { readCanonicalRecord } from "../../keyingCanonicalJson.js";
2
+ import { readCanonicalRecord } from "../../keying/canonicalJson.js";
3
3
  import { readContainerKekRecipientTarget, readContainerKeyWrap, } from "../../keyingProjectionVerification/readers.js";
4
- import { readRecordNullableString, readRecordPositiveInteger, readRecordString, readRecordValue, } from "../../recordReaders.js";
4
+ import { readRecordNullableString, readRecordPositiveInteger, readRecordString, readRecordValue, } from "../../shared/recordReaders.js";
5
5
  function readRecordVersion(record, label) {
6
6
  if (readRecordPositiveInteger(record, "version", label) !== 1) {
7
7
  throw new Error(`${label}.version must be 1`);
@@ -1 +1 @@
1
- {"version":3,"file":"readers.js","sourceRoot":"","sources":["readers.ts"],"names":[],"mappings":"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","sourcesContent":["export { readContainerKeyEpoch } from \"../../keyingProjectionVerification/readers\";\n\nimport type {\n ContainerAccessManifestState,\n ContainerDirectGrant,\n ContainerKekRecipientTarget,\n ContainerKeyWrap,\n} from \"@tearleads/crypto\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport { readCanonicalRecord } from \"../../keyingCanonicalJson\";\nimport {\n readContainerKekRecipientTarget,\n readContainerKeyWrap,\n} from \"../../keyingProjectionVerification/readers\";\nimport {\n readRecordNullableString,\n readRecordPositiveInteger,\n readRecordString,\n readRecordValue,\n} from \"../../recordReaders\";\n\nfunction readRecordVersion(\n record: Record<string, unknown>,\n label: string,\n): void {\n if (readRecordPositiveInteger(record, \"version\", label) !== 1) {\n throw new Error(`${label}.version must be 1`);\n }\n}\n\nexport function readCanonicalManifestBundle(\n value: unknown,\n label: string,\n): AccessManifestBundleWire {\n const record = readCanonicalRecord(value, label);\n return {\n event: readCanonicalRecord(\n readRecordValue(record, \"event\"),\n `${label}.event`,\n ),\n manifest: readCanonicalRecord(\n readRecordValue(record, \"manifest\"),\n `${label}.manifest`,\n ),\n manifestHash: readRecordString(record, \"manifestHash\", label),\n state: readCanonicalRecord(\n readRecordValue(record, \"state\"),\n `${label}.state`,\n ),\n };\n}\n\nfunction isContainerAccessLevel(\n value: unknown,\n): value is ContainerDirectGrant[\"accessLevel\"] {\n return value === \"admin\" || value === \"read\" || value === \"write\";\n}\n\nfunction isContainerGrantSubjectType(\n value: unknown,\n): value is ContainerDirectGrant[\"subjectType\"] {\n return value === \"group\" || value === \"user\";\n}\n\nfunction isContainerGrantPrincipalType(\n value: unknown,\n): value is ContainerAccessManifestState[\"referencedPrincipalHeads\"][number][\"principalType\"] {\n return value === \"group\";\n}\n\nfunction readContainerDirectGrant(\n value: unknown,\n label: string,\n): ContainerDirectGrant {\n const record = readCanonicalRecord(value, label);\n const accessLevel = readRecordValue(record, \"accessLevel\");\n const subjectType = readRecordValue(record, \"subjectType\");\n if (!isContainerAccessLevel(accessLevel)) {\n throw new Error(`${label}.accessLevel is invalid`);\n }\n if (!isContainerGrantSubjectType(subjectType)) {\n throw new Error(`${label}.subjectType is invalid`);\n }\n\n return {\n accessLevel,\n subjectId: readRecordString(record, \"subjectId\", label),\n subjectType,\n };\n}\n\nfunction readContainerDirectGrants(\n value: unknown,\n label: string,\n): ContainerDirectGrant[] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((grant, index) =>\n readContainerDirectGrant(grant, `${label}[${index}]`),\n );\n}\n\nfunction readReferencedPrincipalHead(\n value: unknown,\n label: string,\n): ContainerAccessManifestState[\"referencedPrincipalHeads\"][number] {\n const record = readCanonicalRecord(value, label);\n const principalType = readRecordValue(record, \"principalType\");\n if (!isContainerGrantPrincipalType(principalType)) {\n throw new Error(`${label}.principalType is invalid`);\n }\n\n return {\n principalType,\n principalId: readRecordString(record, \"principalId\", label),\n version: readRecordPositiveInteger(record, \"version\", label),\n keyEpoch: readRecordPositiveInteger(record, \"keyEpoch\", label),\n stateHash: readRecordString(record, \"stateHash\", label),\n keyFingerprint: readRecordString(record, \"keyFingerprint\", label),\n };\n}\n\nfunction readReferencedPrincipalHeads(\n value: unknown,\n label: string,\n): ContainerAccessManifestState[\"referencedPrincipalHeads\"] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((head, index) =>\n readReferencedPrincipalHead(head, `${label}[${index}]`),\n );\n}\n\nexport function readContainerAccessManifestState(\n value: unknown,\n label: string,\n): ContainerAccessManifestState {\n const record = readCanonicalRecord(value, label);\n readRecordVersion(record, label);\n\n return {\n systemSlot: readRecordNullableString(record, \"systemSlot\", label),\n version: 1,\n containerId: readRecordString(record, \"containerId\", label),\n organizationId: readRecordString(record, \"organizationId\", label),\n epoch: readRecordPositiveInteger(record, \"epoch\", label),\n previousManifestHash: readRecordNullableString(\n record,\n \"previousManifestHash\",\n label,\n ),\n eventHash: readRecordString(record, \"eventHash\", label),\n parentContainerId: readRecordNullableString(\n record,\n \"parentContainerId\",\n label,\n ),\n parentManifestHash: readRecordNullableString(\n record,\n \"parentManifestHash\",\n label,\n ),\n metadataDocumentId: readRecordString(record, \"metadataDocumentId\", label),\n containerKeyEpochId: readRecordNullableString(\n record,\n \"containerKeyEpochId\",\n label,\n ),\n containerKeyPublicKey: readRecordNullableString(\n record,\n \"containerKeyPublicKey\",\n label,\n ),\n directGrants: readContainerDirectGrants(\n readRecordValue(record, \"directGrants\"),\n `${label}.directGrants`,\n ),\n referencedPrincipalHeads: readReferencedPrincipalHeads(\n readRecordValue(record, \"referencedPrincipalHeads\"),\n `${label}.referencedPrincipalHeads`,\n ),\n };\n}\n\nexport function readContainerKeyWraps(\n value: unknown,\n label: string,\n): ContainerKeyWrap[] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((wrap, index) =>\n readContainerKeyWrap(wrap, `${label}[${index}]`),\n );\n}\n\nexport function readContainerKekRecipientTargets(\n value: unknown,\n label: string,\n): ContainerKekRecipientTarget[] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((target, index) =>\n readContainerKekRecipientTarget(target, `${label}[${index}]`),\n );\n}\n"]}
1
+ {"version":3,"file":"readers.js","sourceRoot":"","sources":["readers.ts"],"names":[],"mappings":"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","sourcesContent":["export { readContainerKeyEpoch } from \"../../keyingProjectionVerification/readers\";\n\nimport type {\n ContainerAccessManifestState,\n ContainerDirectGrant,\n ContainerKekRecipientTarget,\n ContainerKeyWrap,\n} from \"@tearleads/crypto\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport { readCanonicalRecord } from \"../../keying/canonicalJson\";\nimport {\n readContainerKekRecipientTarget,\n readContainerKeyWrap,\n} from \"../../keyingProjectionVerification/readers\";\nimport {\n readRecordNullableString,\n readRecordPositiveInteger,\n readRecordString,\n readRecordValue,\n} from \"../../shared/recordReaders\";\n\nfunction readRecordVersion(\n record: Record<string, unknown>,\n label: string,\n): void {\n if (readRecordPositiveInteger(record, \"version\", label) !== 1) {\n throw new Error(`${label}.version must be 1`);\n }\n}\n\nexport function readCanonicalManifestBundle(\n value: unknown,\n label: string,\n): AccessManifestBundleWire {\n const record = readCanonicalRecord(value, label);\n return {\n event: readCanonicalRecord(\n readRecordValue(record, \"event\"),\n `${label}.event`,\n ),\n manifest: readCanonicalRecord(\n readRecordValue(record, \"manifest\"),\n `${label}.manifest`,\n ),\n manifestHash: readRecordString(record, \"manifestHash\", label),\n state: readCanonicalRecord(\n readRecordValue(record, \"state\"),\n `${label}.state`,\n ),\n };\n}\n\nfunction isContainerAccessLevel(\n value: unknown,\n): value is ContainerDirectGrant[\"accessLevel\"] {\n return value === \"admin\" || value === \"read\" || value === \"write\";\n}\n\nfunction isContainerGrantSubjectType(\n value: unknown,\n): value is ContainerDirectGrant[\"subjectType\"] {\n return value === \"group\" || value === \"user\";\n}\n\nfunction isContainerGrantPrincipalType(\n value: unknown,\n): value is ContainerAccessManifestState[\"referencedPrincipalHeads\"][number][\"principalType\"] {\n return value === \"group\";\n}\n\nfunction readContainerDirectGrant(\n value: unknown,\n label: string,\n): ContainerDirectGrant {\n const record = readCanonicalRecord(value, label);\n const accessLevel = readRecordValue(record, \"accessLevel\");\n const subjectType = readRecordValue(record, \"subjectType\");\n if (!isContainerAccessLevel(accessLevel)) {\n throw new Error(`${label}.accessLevel is invalid`);\n }\n if (!isContainerGrantSubjectType(subjectType)) {\n throw new Error(`${label}.subjectType is invalid`);\n }\n\n return {\n accessLevel,\n subjectId: readRecordString(record, \"subjectId\", label),\n subjectType,\n };\n}\n\nfunction readContainerDirectGrants(\n value: unknown,\n label: string,\n): ContainerDirectGrant[] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((grant, index) =>\n readContainerDirectGrant(grant, `${label}[${index}]`),\n );\n}\n\nfunction readReferencedPrincipalHead(\n value: unknown,\n label: string,\n): ContainerAccessManifestState[\"referencedPrincipalHeads\"][number] {\n const record = readCanonicalRecord(value, label);\n const principalType = readRecordValue(record, \"principalType\");\n if (!isContainerGrantPrincipalType(principalType)) {\n throw new Error(`${label}.principalType is invalid`);\n }\n\n return {\n principalType,\n principalId: readRecordString(record, \"principalId\", label),\n version: readRecordPositiveInteger(record, \"version\", label),\n keyEpoch: readRecordPositiveInteger(record, \"keyEpoch\", label),\n stateHash: readRecordString(record, \"stateHash\", label),\n keyFingerprint: readRecordString(record, \"keyFingerprint\", label),\n };\n}\n\nfunction readReferencedPrincipalHeads(\n value: unknown,\n label: string,\n): ContainerAccessManifestState[\"referencedPrincipalHeads\"] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((head, index) =>\n readReferencedPrincipalHead(head, `${label}[${index}]`),\n );\n}\n\nexport function readContainerAccessManifestState(\n value: unknown,\n label: string,\n): ContainerAccessManifestState {\n const record = readCanonicalRecord(value, label);\n readRecordVersion(record, label);\n\n return {\n systemSlot: readRecordNullableString(record, \"systemSlot\", label),\n version: 1,\n containerId: readRecordString(record, \"containerId\", label),\n organizationId: readRecordString(record, \"organizationId\", label),\n epoch: readRecordPositiveInteger(record, \"epoch\", label),\n previousManifestHash: readRecordNullableString(\n record,\n \"previousManifestHash\",\n label,\n ),\n eventHash: readRecordString(record, \"eventHash\", label),\n parentContainerId: readRecordNullableString(\n record,\n \"parentContainerId\",\n label,\n ),\n parentManifestHash: readRecordNullableString(\n record,\n \"parentManifestHash\",\n label,\n ),\n metadataDocumentId: readRecordString(record, \"metadataDocumentId\", label),\n containerKeyEpochId: readRecordNullableString(\n record,\n \"containerKeyEpochId\",\n label,\n ),\n containerKeyPublicKey: readRecordNullableString(\n record,\n \"containerKeyPublicKey\",\n label,\n ),\n directGrants: readContainerDirectGrants(\n readRecordValue(record, \"directGrants\"),\n `${label}.directGrants`,\n ),\n referencedPrincipalHeads: readReferencedPrincipalHeads(\n readRecordValue(record, \"referencedPrincipalHeads\"),\n `${label}.referencedPrincipalHeads`,\n ),\n };\n}\n\nexport function readContainerKeyWraps(\n value: unknown,\n label: string,\n): ContainerKeyWrap[] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((wrap, index) =>\n readContainerKeyWrap(wrap, `${label}[${index}]`),\n );\n}\n\nexport function readContainerKekRecipientTargets(\n value: unknown,\n label: string,\n): ContainerKekRecipientTarget[] {\n if (!Array.isArray(value)) {\n throw new Error(`${label} must be an array`);\n }\n return value.map((target, index) =>\n readContainerKekRecipientTarget(target, `${label}[${index}]`),\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { bytesToHex, createIncrementalSha256 } from "../../internal/crypto/index.js";
2
- import { createBlobByteSource, } from "../blobContracts.js";
2
+ import { createBlobByteSource, } from "../blobs/blobContracts.js";
3
3
  /** Kept inside encrypted document content; independent of upload encryption/retries. */
4
4
  export async function attachmentContentSha256(input) {
5
5
  const source = createBlobByteSource(input);
@@ -1 +1 @@
1
- {"version":3,"file":"attachmentContentIdentity.js","sourceRoot":"","sources":["attachmentContentIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAEL,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAA0B;IAE1B,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,uBAAuB,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAClC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,IAAI,SAAS,EAAE,CAAC;QACrE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM;YAC7B,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import { bytesToHex, createIncrementalSha256 } from \"@tearleads/crypto\";\nimport {\n type BlobByteSourceInput,\n createBlobByteSource,\n} from \"../blobContracts\";\n\n/** Kept inside encrypted document content; independent of upload encryption/retries. */\nexport async function attachmentContentSha256(\n input: BlobByteSourceInput,\n): Promise<string> {\n const source = createBlobByteSource(input);\n const hash = createIncrementalSha256();\n const chunkSize = 5 * 1024 * 1024;\n for (let offset = 0; offset < source.byteLength; offset += chunkSize) {\n const length = Math.min(chunkSize, source.byteLength - offset);\n const bytes = await source.read(offset, length);\n if (bytes.byteLength !== length)\n throw new Error(\"Attachment source returned an unexpected byte length\");\n hash.update(bytes);\n }\n return bytesToHex(hash.digest());\n}\n"]}
1
+ {"version":3,"file":"attachmentContentIdentity.js","sourceRoot":"","sources":["attachmentContentIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAEL,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAEhC,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAA0B;IAE1B,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,uBAAuB,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAClC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,IAAI,SAAS,EAAE,CAAC;QACrE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM;YAC7B,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import { bytesToHex, createIncrementalSha256 } from \"@tearleads/crypto\";\nimport {\n type BlobByteSourceInput,\n createBlobByteSource,\n} from \"../blobs/blobContracts\";\n\n/** Kept inside encrypted document content; independent of upload encryption/retries. */\nexport async function attachmentContentSha256(\n input: BlobByteSourceInput,\n): Promise<string> {\n const source = createBlobByteSource(input);\n const hash = createIncrementalSha256();\n const chunkSize = 5 * 1024 * 1024;\n for (let offset = 0; offset < source.byteLength; offset += chunkSize) {\n const length = Math.min(chunkSize, source.byteLength - offset);\n const bytes = await source.read(offset, length);\n if (bytes.byteLength !== length)\n throw new Error(\"Attachment source returned an unexpected byte length\");\n hash.update(bytes);\n }\n return bytesToHex(hash.digest());\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"blobEnvelopeStream.js","sourceRoot":"","sources":["blobEnvelopeStream.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,GACjC,MAAM,mBAAmB,CAAC;AAG3B,gFAAgF;AAChF,MAAM,UAAU,wBAAwB,CAAC,MAAkC;IACzE,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,uBAAuB,EAAE,CAAC;IACvC,IAAI,OAAO,GAAe,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,KAAK,EAAE,MAAc,EAAsB,EAAE;QACxD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,OAAO,MAAM,GAAG,MAAM,EAAE,CAAC;YACvB,IAAI,OAAO,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI;oBACZ,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAChE,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,OAAO;QACL,IAAI;QACJ,KAAK,CAAC,UAAU;YACd,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACtD,MAAM,gBAAgB,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;YAClE,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAC/C,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAClB,KAAK,CAAC,GAAG,CACP,MAAM,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,EAChD,MAAM,CAAC,UAAU,CAClB,CAAC;YACF,OAAO,yBAAyB,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,MAAM;YACV,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC5D,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI;oBAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;gBACrC,IAAI,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC;oBAC5B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QACD,KAAK,CAAC,KAAK;YACT,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;YACvD,CAAC;YACD,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import {\n BLOB_ENVELOPE_PREFIX_BYTES,\n createIncrementalSha256,\n parseBlobEnvelopeV2Header,\n readBlobEnvelopeHeaderByteLength,\n} from \"@tearleads/crypto\";\nimport type { BlobBytes } from \"../../../blobContracts\";\n\n/** Reads exactly one bounded envelope part without retaining previous parts. */\nexport function createBlobEnvelopeStream(stream: ReadableStream<Uint8Array>) {\n const reader = stream.getReader();\n const hash = createIncrementalSha256();\n let pending: Uint8Array = new Uint8Array(0);\n const read = async (length: number): Promise<BlobBytes> => {\n const bytes = new Uint8Array(length);\n let offset = 0;\n while (offset < length) {\n if (pending.byteLength === 0) {\n const chunk = await reader.read();\n if (chunk.done)\n throw new Error(\"Blob encrypted bytes envelope is truncated\");\n pending = chunk.value;\n continue;\n }\n const count = Math.min(length - offset, pending.byteLength);\n bytes.set(pending.subarray(0, count), offset);\n pending = pending.subarray(count);\n offset += count;\n }\n hash.update(bytes);\n return bytes;\n };\n return {\n read,\n async readHeader() {\n const prefix = await read(BLOB_ENVELOPE_PREFIX_BYTES);\n const headerByteLength = readBlobEnvelopeHeaderByteLength(prefix);\n const bytes = new Uint8Array(headerByteLength);\n bytes.set(prefix);\n bytes.set(\n await read(headerByteLength - prefix.byteLength),\n prefix.byteLength,\n );\n return parseBlobEnvelopeV2Header(bytes);\n },\n async finish() {\n if (pending.byteLength > 0)\n throw new Error(\"Blob encrypted bytes length is invalid\");\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) return hash.digest();\n if (chunk.value.byteLength > 0)\n throw new Error(\"Blob encrypted bytes length is invalid\");\n }\n },\n async close() {\n try {\n await reader.cancel();\n } catch {\n /* Preserve the verification or transport failure. */\n }\n reader.releaseLock();\n },\n };\n}\n"]}
1
+ {"version":3,"file":"blobEnvelopeStream.js","sourceRoot":"","sources":["blobEnvelopeStream.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,GACjC,MAAM,mBAAmB,CAAC;AAG3B,gFAAgF;AAChF,MAAM,UAAU,wBAAwB,CAAC,MAAkC;IACzE,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,uBAAuB,EAAE,CAAC;IACvC,IAAI,OAAO,GAAe,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,KAAK,EAAE,MAAc,EAAsB,EAAE;QACxD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,OAAO,MAAM,GAAG,MAAM,EAAE,CAAC;YACvB,IAAI,OAAO,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI;oBACZ,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAChE,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,OAAO;QACL,IAAI;QACJ,KAAK,CAAC,UAAU;YACd,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACtD,MAAM,gBAAgB,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;YAClE,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAC/C,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAClB,KAAK,CAAC,GAAG,CACP,MAAM,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,EAChD,MAAM,CAAC,UAAU,CAClB,CAAC;YACF,OAAO,yBAAyB,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,MAAM;YACV,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC5D,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI;oBAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;gBACrC,IAAI,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC;oBAC5B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QACD,KAAK,CAAC,KAAK;YACT,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;YACvD,CAAC;YACD,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import {\n BLOB_ENVELOPE_PREFIX_BYTES,\n createIncrementalSha256,\n parseBlobEnvelopeV2Header,\n readBlobEnvelopeHeaderByteLength,\n} from \"@tearleads/crypto\";\nimport type { BlobBytes } from \"../../../blobs/blobContracts\";\n\n/** Reads exactly one bounded envelope part without retaining previous parts. */\nexport function createBlobEnvelopeStream(stream: ReadableStream<Uint8Array>) {\n const reader = stream.getReader();\n const hash = createIncrementalSha256();\n let pending: Uint8Array = new Uint8Array(0);\n const read = async (length: number): Promise<BlobBytes> => {\n const bytes = new Uint8Array(length);\n let offset = 0;\n while (offset < length) {\n if (pending.byteLength === 0) {\n const chunk = await reader.read();\n if (chunk.done)\n throw new Error(\"Blob encrypted bytes envelope is truncated\");\n pending = chunk.value;\n continue;\n }\n const count = Math.min(length - offset, pending.byteLength);\n bytes.set(pending.subarray(0, count), offset);\n pending = pending.subarray(count);\n offset += count;\n }\n hash.update(bytes);\n return bytes;\n };\n return {\n read,\n async readHeader() {\n const prefix = await read(BLOB_ENVELOPE_PREFIX_BYTES);\n const headerByteLength = readBlobEnvelopeHeaderByteLength(prefix);\n const bytes = new Uint8Array(headerByteLength);\n bytes.set(prefix);\n bytes.set(\n await read(headerByteLength - prefix.byteLength),\n prefix.byteLength,\n );\n return parseBlobEnvelopeV2Header(bytes);\n },\n async finish() {\n if (pending.byteLength > 0)\n throw new Error(\"Blob encrypted bytes length is invalid\");\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) return hash.digest();\n if (chunk.value.byteLength > 0)\n throw new Error(\"Blob encrypted bytes length is invalid\");\n }\n },\n async close() {\n try {\n await reader.cancel();\n } catch {\n /* Preserve the verification or transport failure. */\n }\n reader.releaseLock();\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { BlobByteSource, BlobBytes } from "../../../blobContracts.js";
1
+ import type { BlobByteSource, BlobBytes } from "../../../blobs/blobContracts.js";
2
2
  import type { BlobSourceSnapshot } from "./types.js";
3
3
  export type { BlobSourceSnapshot } from "./types.js";
4
4
  export declare function inspectBlobSource(source: BlobByteSource, chunkSize: number): Promise<BlobSourceSnapshot>;
@@ -1 +1 @@
1
- {"version":3,"file":"blobSourceSnapshot.js","sourceRoot":"","sources":["blobSourceSnapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n blobChunkPlaintextByteLength,\n bytesToHex,\n computeBlobChunkCount,\n createIncrementalSha256,\n normalizeBlobChunkSize,\n} from \"@tearleads/crypto\";\nimport type { BlobByteSource, BlobBytes } from \"../../../blobContracts\";\nimport { asWebCryptoBytes } from \"../../shared/readers\";\nimport type { BlobSourceSnapshot } from \"./types\";\n\nexport type { BlobSourceSnapshot } from \"./types\";\n\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n return bytesToHex(\n new Uint8Array(\n await crypto.subtle.digest(\"SHA-256\", asWebCryptoBytes(bytes)),\n ),\n );\n}\n\nfunction assertSourceByteLength(byteLength: number): void {\n if (!Number.isSafeInteger(byteLength) || byteLength < 0) {\n throw new Error(\n \"Blob source byte length must be a non-negative safe integer\",\n );\n }\n}\n\nasync function readExactSourceBytes(input: {\n readonly byteLength: number;\n readonly offset: number;\n readonly source: BlobByteSource;\n}): Promise<BlobBytes> {\n const bytes = await input.source.read(input.offset, input.byteLength);\n if (bytes.byteLength !== input.byteLength) {\n throw new Error(\"Blob source returned an unexpected byte length\");\n }\n const copy = new Uint8Array(bytes.byteLength);\n copy.set(bytes);\n return copy;\n}\n\nexport async function inspectBlobSource(\n source: BlobByteSource,\n chunkSize: number,\n): Promise<BlobSourceSnapshot> {\n assertSourceByteLength(source.byteLength);\n normalizeBlobChunkSize(chunkSize);\n const chunkCount = computeBlobChunkCount(source.byteLength, chunkSize);\n const chunkSha256: string[] = [];\n const objectHash = createIncrementalSha256();\n\n for (let chunkIndex = 0; chunkIndex < chunkCount; chunkIndex += 1) {\n const byteLength = blobChunkPlaintextByteLength({\n chunkCount,\n chunkIndex,\n chunkSize,\n plaintextByteLength: source.byteLength,\n });\n const bytes = await readExactSourceBytes({\n byteLength,\n offset: chunkIndex * chunkSize,\n source,\n });\n objectHash.update(bytes);\n chunkSha256.push(await sha256Hex(bytes));\n }\n\n return {\n byteLength: source.byteLength,\n chunkSha256,\n chunkSize,\n sha256: bytesToHex(objectHash.digest()),\n };\n}\n\nexport async function readVerifiedBlobSourceChunk(input: {\n readonly chunkIndex: number;\n readonly snapshot: BlobSourceSnapshot;\n readonly source: BlobByteSource;\n}): Promise<BlobBytes> {\n const { chunkIndex, snapshot, source } = input;\n if (source.byteLength !== snapshot.byteLength) {\n throw new Error(\"Blob source byte length changed after inspection\");\n }\n const chunkCount = computeBlobChunkCount(\n snapshot.byteLength,\n snapshot.chunkSize,\n );\n const byteLength = blobChunkPlaintextByteLength({\n chunkCount,\n chunkIndex,\n chunkSize: snapshot.chunkSize,\n plaintextByteLength: snapshot.byteLength,\n });\n const bytes = await readExactSourceBytes({\n byteLength,\n offset: chunkIndex * snapshot.chunkSize,\n source,\n });\n if ((await sha256Hex(bytes)) !== snapshot.chunkSha256[chunkIndex]) {\n throw new Error(\n `Blob plaintext chunk ${chunkIndex} changed after source inspection`,\n );\n }\n return bytes;\n}\n"]}
1
+ {"version":3,"file":"blobSourceSnapshot.js","sourceRoot":"","sources":["blobSourceSnapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n blobChunkPlaintextByteLength,\n bytesToHex,\n computeBlobChunkCount,\n createIncrementalSha256,\n normalizeBlobChunkSize,\n} from \"@tearleads/crypto\";\nimport type { BlobByteSource, BlobBytes } from \"../../../blobs/blobContracts\";\nimport { asWebCryptoBytes } from \"../../shared/readers\";\nimport type { BlobSourceSnapshot } from \"./types\";\n\nexport type { BlobSourceSnapshot } from \"./types\";\n\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n return bytesToHex(\n new Uint8Array(\n await crypto.subtle.digest(\"SHA-256\", asWebCryptoBytes(bytes)),\n ),\n );\n}\n\nfunction assertSourceByteLength(byteLength: number): void {\n if (!Number.isSafeInteger(byteLength) || byteLength < 0) {\n throw new Error(\n \"Blob source byte length must be a non-negative safe integer\",\n );\n }\n}\n\nasync function readExactSourceBytes(input: {\n readonly byteLength: number;\n readonly offset: number;\n readonly source: BlobByteSource;\n}): Promise<BlobBytes> {\n const bytes = await input.source.read(input.offset, input.byteLength);\n if (bytes.byteLength !== input.byteLength) {\n throw new Error(\"Blob source returned an unexpected byte length\");\n }\n const copy = new Uint8Array(bytes.byteLength);\n copy.set(bytes);\n return copy;\n}\n\nexport async function inspectBlobSource(\n source: BlobByteSource,\n chunkSize: number,\n): Promise<BlobSourceSnapshot> {\n assertSourceByteLength(source.byteLength);\n normalizeBlobChunkSize(chunkSize);\n const chunkCount = computeBlobChunkCount(source.byteLength, chunkSize);\n const chunkSha256: string[] = [];\n const objectHash = createIncrementalSha256();\n\n for (let chunkIndex = 0; chunkIndex < chunkCount; chunkIndex += 1) {\n const byteLength = blobChunkPlaintextByteLength({\n chunkCount,\n chunkIndex,\n chunkSize,\n plaintextByteLength: source.byteLength,\n });\n const bytes = await readExactSourceBytes({\n byteLength,\n offset: chunkIndex * chunkSize,\n source,\n });\n objectHash.update(bytes);\n chunkSha256.push(await sha256Hex(bytes));\n }\n\n return {\n byteLength: source.byteLength,\n chunkSha256,\n chunkSize,\n sha256: bytesToHex(objectHash.digest()),\n };\n}\n\nexport async function readVerifiedBlobSourceChunk(input: {\n readonly chunkIndex: number;\n readonly snapshot: BlobSourceSnapshot;\n readonly source: BlobByteSource;\n}): Promise<BlobBytes> {\n const { chunkIndex, snapshot, source } = input;\n if (source.byteLength !== snapshot.byteLength) {\n throw new Error(\"Blob source byte length changed after inspection\");\n }\n const chunkCount = computeBlobChunkCount(\n snapshot.byteLength,\n snapshot.chunkSize,\n );\n const byteLength = blobChunkPlaintextByteLength({\n chunkCount,\n chunkIndex,\n chunkSize: snapshot.chunkSize,\n plaintextByteLength: snapshot.byteLength,\n });\n const bytes = await readExactSourceBytes({\n byteLength,\n offset: chunkIndex * snapshot.chunkSize,\n source,\n });\n if ((await sha256Hex(bytes)) !== snapshot.chunkSha256[chunkIndex]) {\n throw new Error(\n `Blob plaintext chunk ${chunkIndex} changed after source inspection`,\n );\n }\n return bytes;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chunkedBlobCrypto.js","sourceRoot":"","sources":["chunkedBlobCrypto.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AES_256_KEY_BYTES,\n AES_GCM_TAG_BYTES,\n assertAesGcmIv,\n BLOB_CHUNK_SIZE_BYTES,\n BLOB_ENCRYPTED_BYTES_FORMAT,\n BLOB_ENCRYPTED_BYTES_VERSION,\n blobContentMetadataHash,\n bytesToHex,\n CONTENT_RECORD_ENCRYPTION_SUITE,\n computeBlobChunkCount,\n computeBlobEncryptedByteLength,\n computeContentRecordNonceDomainHash,\n createAesGcmIv,\n createIncrementalSha256,\n deriveBlobChunkIv,\n encodeBlobEnvelopeV2Header,\n normalizeBlobChunkSize,\n} from \"@tearleads/crypto\";\nimport { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { BlobContentKeyBundleRequest } from \"@tearleads/validators/request\";\nimport type { BlobByteSource, BlobBytes } from \"../../../blobContracts\";\nimport { importContentKeyMaterial } from \"../../shared/contentRecordKeys\";\nimport {\n contentRecordAdditionalDataBytes,\n deriveBlobBaseIv,\n deriveBlobContentRecordKey,\n} from \"./blobRecordCrypto\";\nimport {\n type BlobSourceSnapshot,\n inspectBlobSource,\n readVerifiedBlobSourceChunk,\n} from \"./blobSourceSnapshot\";\nimport { createEncryptedUploadParts } from \"./encryptedUploadParts\";\nimport type { BlobEncryptionPlan } from \"./types\";\n\nexport const DEFAULT_BLOB_CHUNK_SIZE_BYTES = BLOB_CHUNK_SIZE_BYTES;\n\ninterface PrepareBlobEncryptionInput {\n readonly blobId: string;\n readonly chunkSize?: number | undefined;\n readonly contentKey: Uint8Array;\n readonly contentKeyBundle: BlobContentKeyBundleRequest;\n readonly nonceSeed?: Uint8Array | undefined;\n readonly organizationId: string;\n readonly source: BlobByteSource;\n readonly sourceSnapshot?: BlobSourceSnapshot | undefined;\n}\n\ninterface BlobEncryptionContext {\n readonly baseIv: BlobBytes;\n readonly blobId: string;\n readonly chunkSize: number;\n readonly contentKeyEpoch: number;\n readonly contentRecordId: string;\n readonly headerBytes: BlobBytes;\n readonly metadataHash: string;\n readonly nonceDomainHash: string;\n readonly organizationId: string;\n readonly partCount: number;\n readonly plaintextByteLength: number;\n readonly recordKey: CryptoKey;\n}\n\nasync function createBlobEncryptionContext(\n input: PrepareBlobEncryptionInput,\n snapshot: BlobSourceSnapshot,\n): Promise<BlobEncryptionContext> {\n const chunkSize = normalizeBlobChunkSize(\n input.chunkSize ?? DEFAULT_BLOB_CHUNK_SIZE_BYTES,\n );\n const plaintextByteLength = input.source.byteLength;\n const partCount = computeBlobChunkCount(plaintextByteLength, chunkSize);\n const contentRecordId = input.blobId;\n const { contentKeyEpoch } = input.contentKeyBundle;\n const nonceSeed = new Uint8Array(input.nonceSeed ?? createAesGcmIv());\n const baseIv = await deriveBlobBaseIv({\n chunkSize,\n nonceSeed,\n plaintextSha256: snapshot.sha256,\n });\n\n const [nonceDomainHash, metadataHash] = await Promise.all([\n computeContentRecordNonceDomainHash({\n version: 1,\n organizationId: input.organizationId,\n objectKind: \"blob\",\n objectId: input.blobId,\n contentKeyEpoch,\n encryptionSuite: CONTENT_RECORD_ENCRYPTION_SUITE,\n contentRecordId,\n }),\n blobContentMetadataHash({\n blobId: input.blobId,\n byteLength: plaintextByteLength,\n chunkCount: partCount,\n chunkSize,\n contentKeyEpoch,\n }),\n ]);\n const contentKeyMaterial = await importContentKeyMaterial(input.contentKey);\n const recordKey = await deriveBlobContentRecordKey({\n blobId: input.blobId,\n contentKeyEpoch,\n contentKeyMaterial,\n contentRecordId,\n organizationId: input.organizationId,\n usage: \"encrypt\",\n });\n return {\n baseIv,\n blobId: input.blobId,\n chunkSize,\n contentKeyEpoch,\n contentRecordId,\n headerBytes: encodeBlobEnvelopeV2Header({\n blobId: input.blobId,\n byteLength: plaintextByteLength,\n chunkCount: partCount,\n chunkSize,\n contentKeyEpoch,\n contentRecordId,\n encryptionSuite: CONTENT_RECORD_ENCRYPTION_SUITE,\n format: BLOB_ENCRYPTED_BYTES_FORMAT,\n iv: bytesToBase64(baseIv),\n metadataHash,\n nonceDomainHash,\n version: BLOB_ENCRYPTED_BYTES_VERSION,\n }),\n metadataHash,\n nonceDomainHash,\n organizationId: input.organizationId,\n partCount,\n plaintextByteLength,\n recordKey,\n };\n}\n\nasync function encryptBlobChunk(\n context: BlobEncryptionContext,\n chunkIndex: number,\n plaintext: BlobBytes,\n): Promise<BlobBytes> {\n return new Uint8Array(\n await crypto.subtle.encrypt(\n {\n name: \"AES-GCM\",\n iv: deriveBlobChunkIv(context.baseIv, chunkIndex),\n additionalData: contentRecordAdditionalDataBytes({\n blobId: context.blobId,\n chunkCount: context.partCount,\n chunkIndex,\n chunkPlaintextByteLength: plaintext.byteLength,\n chunkSize: context.chunkSize,\n contentKeyEpoch: context.contentKeyEpoch,\n contentRecordId: context.contentRecordId,\n metadataHash: context.metadataHash,\n nonceDomainHash: context.nonceDomainHash,\n organizationId: context.organizationId,\n plaintextByteLength: context.plaintextByteLength,\n }),\n },\n context.recordKey,\n plaintext,\n ),\n );\n}\n\nasync function runEncryptionHashPass(\n source: BlobByteSource,\n snapshot: BlobSourceSnapshot,\n context: BlobEncryptionContext,\n): Promise<string> {\n const objectHash = createIncrementalSha256();\n objectHash.update(context.headerBytes);\n for (let chunkIndex = 0; chunkIndex < context.partCount; chunkIndex += 1) {\n const plaintext = await readVerifiedBlobSourceChunk({\n chunkIndex,\n snapshot,\n source,\n });\n objectHash.update(await encryptBlobChunk(context, chunkIndex, plaintext));\n }\n return bytesToHex(objectHash.digest());\n}\n\nfunction createBlobEncryptionPlan(input: {\n readonly context: BlobEncryptionContext;\n readonly sha256: string;\n readonly snapshot: BlobSourceSnapshot;\n readonly source: BlobByteSource;\n}): BlobEncryptionPlan {\n const { context, sha256, snapshot, source } = input;\n const byteLength = computeBlobEncryptedByteLength({\n chunkCount: context.partCount,\n headerByteLength: context.headerBytes.byteLength,\n plaintextByteLength: context.plaintextByteLength,\n });\n return {\n byteLength,\n chunkSize: context.chunkSize,\n metadataHash: context.metadataHash,\n plaintextByteLength: context.plaintextByteLength,\n plaintextSha256: snapshot.sha256,\n sha256,\n ...createEncryptedUploadParts({\n byteLength,\n chunkSize: context.chunkSize + AES_GCM_TAG_BYTES,\n header: context.headerBytes,\n async encryptChunk(chunkIndex) {\n const plaintext = await readVerifiedBlobSourceChunk({\n chunkIndex,\n snapshot,\n source,\n });\n return encryptBlobChunk(context, chunkIndex, plaintext);\n },\n }),\n };\n}\n\nexport async function prepareBlobEncryption(\n input: PrepareBlobEncryptionInput,\n): Promise<BlobEncryptionPlan> {\n if (input.contentKey.byteLength !== AES_256_KEY_BYTES) {\n throw new Error(\"Blob content key must be 32 bytes\");\n }\n if (input.nonceSeed) {\n assertAesGcmIv(input.nonceSeed, \"Blob nonce seed is invalid\");\n }\n const chunkSize = normalizeBlobChunkSize(\n input.chunkSize ?? DEFAULT_BLOB_CHUNK_SIZE_BYTES,\n );\n const snapshot =\n input.sourceSnapshot ?? (await inspectBlobSource(input.source, chunkSize));\n const context = await createBlobEncryptionContext(input, snapshot);\n if (\n snapshot.byteLength !== context.plaintextByteLength ||\n snapshot.chunkSize !== context.chunkSize\n ) {\n throw new Error(\"Blob source snapshot does not match encryption layout\");\n }\n const sha256 = await runEncryptionHashPass(input.source, snapshot, context);\n return createBlobEncryptionPlan({\n context,\n sha256,\n snapshot,\n source: input.source,\n });\n}\n"]}
1
+ {"version":3,"file":"chunkedBlobCrypto.js","sourceRoot":"","sources":["chunkedBlobCrypto.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AES_256_KEY_BYTES,\n AES_GCM_TAG_BYTES,\n assertAesGcmIv,\n BLOB_CHUNK_SIZE_BYTES,\n BLOB_ENCRYPTED_BYTES_FORMAT,\n BLOB_ENCRYPTED_BYTES_VERSION,\n blobContentMetadataHash,\n bytesToHex,\n CONTENT_RECORD_ENCRYPTION_SUITE,\n computeBlobChunkCount,\n computeBlobEncryptedByteLength,\n computeContentRecordNonceDomainHash,\n createAesGcmIv,\n createIncrementalSha256,\n deriveBlobChunkIv,\n encodeBlobEnvelopeV2Header,\n normalizeBlobChunkSize,\n} from \"@tearleads/crypto\";\nimport { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { BlobContentKeyBundleRequest } from \"@tearleads/validators/request\";\nimport type { BlobByteSource, BlobBytes } from \"../../../blobs/blobContracts\";\nimport { importContentKeyMaterial } from \"../../shared/contentRecordKeys\";\nimport {\n contentRecordAdditionalDataBytes,\n deriveBlobBaseIv,\n deriveBlobContentRecordKey,\n} from \"./blobRecordCrypto\";\nimport {\n type BlobSourceSnapshot,\n inspectBlobSource,\n readVerifiedBlobSourceChunk,\n} from \"./blobSourceSnapshot\";\nimport { createEncryptedUploadParts } from \"./encryptedUploadParts\";\nimport type { BlobEncryptionPlan } from \"./types\";\n\nexport const DEFAULT_BLOB_CHUNK_SIZE_BYTES = BLOB_CHUNK_SIZE_BYTES;\n\ninterface PrepareBlobEncryptionInput {\n readonly blobId: string;\n readonly chunkSize?: number | undefined;\n readonly contentKey: Uint8Array;\n readonly contentKeyBundle: BlobContentKeyBundleRequest;\n readonly nonceSeed?: Uint8Array | undefined;\n readonly organizationId: string;\n readonly source: BlobByteSource;\n readonly sourceSnapshot?: BlobSourceSnapshot | undefined;\n}\n\ninterface BlobEncryptionContext {\n readonly baseIv: BlobBytes;\n readonly blobId: string;\n readonly chunkSize: number;\n readonly contentKeyEpoch: number;\n readonly contentRecordId: string;\n readonly headerBytes: BlobBytes;\n readonly metadataHash: string;\n readonly nonceDomainHash: string;\n readonly organizationId: string;\n readonly partCount: number;\n readonly plaintextByteLength: number;\n readonly recordKey: CryptoKey;\n}\n\nasync function createBlobEncryptionContext(\n input: PrepareBlobEncryptionInput,\n snapshot: BlobSourceSnapshot,\n): Promise<BlobEncryptionContext> {\n const chunkSize = normalizeBlobChunkSize(\n input.chunkSize ?? DEFAULT_BLOB_CHUNK_SIZE_BYTES,\n );\n const plaintextByteLength = input.source.byteLength;\n const partCount = computeBlobChunkCount(plaintextByteLength, chunkSize);\n const contentRecordId = input.blobId;\n const { contentKeyEpoch } = input.contentKeyBundle;\n const nonceSeed = new Uint8Array(input.nonceSeed ?? createAesGcmIv());\n const baseIv = await deriveBlobBaseIv({\n chunkSize,\n nonceSeed,\n plaintextSha256: snapshot.sha256,\n });\n\n const [nonceDomainHash, metadataHash] = await Promise.all([\n computeContentRecordNonceDomainHash({\n version: 1,\n organizationId: input.organizationId,\n objectKind: \"blob\",\n objectId: input.blobId,\n contentKeyEpoch,\n encryptionSuite: CONTENT_RECORD_ENCRYPTION_SUITE,\n contentRecordId,\n }),\n blobContentMetadataHash({\n blobId: input.blobId,\n byteLength: plaintextByteLength,\n chunkCount: partCount,\n chunkSize,\n contentKeyEpoch,\n }),\n ]);\n const contentKeyMaterial = await importContentKeyMaterial(input.contentKey);\n const recordKey = await deriveBlobContentRecordKey({\n blobId: input.blobId,\n contentKeyEpoch,\n contentKeyMaterial,\n contentRecordId,\n organizationId: input.organizationId,\n usage: \"encrypt\",\n });\n return {\n baseIv,\n blobId: input.blobId,\n chunkSize,\n contentKeyEpoch,\n contentRecordId,\n headerBytes: encodeBlobEnvelopeV2Header({\n blobId: input.blobId,\n byteLength: plaintextByteLength,\n chunkCount: partCount,\n chunkSize,\n contentKeyEpoch,\n contentRecordId,\n encryptionSuite: CONTENT_RECORD_ENCRYPTION_SUITE,\n format: BLOB_ENCRYPTED_BYTES_FORMAT,\n iv: bytesToBase64(baseIv),\n metadataHash,\n nonceDomainHash,\n version: BLOB_ENCRYPTED_BYTES_VERSION,\n }),\n metadataHash,\n nonceDomainHash,\n organizationId: input.organizationId,\n partCount,\n plaintextByteLength,\n recordKey,\n };\n}\n\nasync function encryptBlobChunk(\n context: BlobEncryptionContext,\n chunkIndex: number,\n plaintext: BlobBytes,\n): Promise<BlobBytes> {\n return new Uint8Array(\n await crypto.subtle.encrypt(\n {\n name: \"AES-GCM\",\n iv: deriveBlobChunkIv(context.baseIv, chunkIndex),\n additionalData: contentRecordAdditionalDataBytes({\n blobId: context.blobId,\n chunkCount: context.partCount,\n chunkIndex,\n chunkPlaintextByteLength: plaintext.byteLength,\n chunkSize: context.chunkSize,\n contentKeyEpoch: context.contentKeyEpoch,\n contentRecordId: context.contentRecordId,\n metadataHash: context.metadataHash,\n nonceDomainHash: context.nonceDomainHash,\n organizationId: context.organizationId,\n plaintextByteLength: context.plaintextByteLength,\n }),\n },\n context.recordKey,\n plaintext,\n ),\n );\n}\n\nasync function runEncryptionHashPass(\n source: BlobByteSource,\n snapshot: BlobSourceSnapshot,\n context: BlobEncryptionContext,\n): Promise<string> {\n const objectHash = createIncrementalSha256();\n objectHash.update(context.headerBytes);\n for (let chunkIndex = 0; chunkIndex < context.partCount; chunkIndex += 1) {\n const plaintext = await readVerifiedBlobSourceChunk({\n chunkIndex,\n snapshot,\n source,\n });\n objectHash.update(await encryptBlobChunk(context, chunkIndex, plaintext));\n }\n return bytesToHex(objectHash.digest());\n}\n\nfunction createBlobEncryptionPlan(input: {\n readonly context: BlobEncryptionContext;\n readonly sha256: string;\n readonly snapshot: BlobSourceSnapshot;\n readonly source: BlobByteSource;\n}): BlobEncryptionPlan {\n const { context, sha256, snapshot, source } = input;\n const byteLength = computeBlobEncryptedByteLength({\n chunkCount: context.partCount,\n headerByteLength: context.headerBytes.byteLength,\n plaintextByteLength: context.plaintextByteLength,\n });\n return {\n byteLength,\n chunkSize: context.chunkSize,\n metadataHash: context.metadataHash,\n plaintextByteLength: context.plaintextByteLength,\n plaintextSha256: snapshot.sha256,\n sha256,\n ...createEncryptedUploadParts({\n byteLength,\n chunkSize: context.chunkSize + AES_GCM_TAG_BYTES,\n header: context.headerBytes,\n async encryptChunk(chunkIndex) {\n const plaintext = await readVerifiedBlobSourceChunk({\n chunkIndex,\n snapshot,\n source,\n });\n return encryptBlobChunk(context, chunkIndex, plaintext);\n },\n }),\n };\n}\n\nexport async function prepareBlobEncryption(\n input: PrepareBlobEncryptionInput,\n): Promise<BlobEncryptionPlan> {\n if (input.contentKey.byteLength !== AES_256_KEY_BYTES) {\n throw new Error(\"Blob content key must be 32 bytes\");\n }\n if (input.nonceSeed) {\n assertAesGcmIv(input.nonceSeed, \"Blob nonce seed is invalid\");\n }\n const chunkSize = normalizeBlobChunkSize(\n input.chunkSize ?? DEFAULT_BLOB_CHUNK_SIZE_BYTES,\n );\n const snapshot =\n input.sourceSnapshot ?? (await inspectBlobSource(input.source, chunkSize));\n const context = await createBlobEncryptionContext(input, snapshot);\n if (\n snapshot.byteLength !== context.plaintextByteLength ||\n snapshot.chunkSize !== context.chunkSize\n ) {\n throw new Error(\"Blob source snapshot does not match encryption layout\");\n }\n const sha256 = await runEncryptionHashPass(input.source, snapshot, context);\n return createBlobEncryptionPlan({\n context,\n sha256,\n snapshot,\n source: input.source,\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"encryptedUploadParts.js","sourceRoot":"","sources":["encryptedUploadParts.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,MAAM,UAAU,0BAA0B,CAAC,KAK1C;IACC,6EAA6E;IAC7E,gFAAgF;IAChF,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;IACzD,SAAS,iBAAiB,CAAC,KAAa;QACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC;IACjE,CAAC;IACD,OAAO;QACL,SAAS;QACT,iBAAiB;QACjB,KAAK,CAAC,WAAW,CAAC,KAAa;YAC7B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;YAC/B,MAAM,GAAG,GAAG,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;YACtC,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpC,MAAM,CAAC,GAAG,CACR,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CACrE,CAAC;YACJ,CAAC;YACD,IAAI,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACxD,OAAO,QAAQ,GAAG,GAAG,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAC3B,CAAC,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,SAAS,CACvD,CAAC;gBACF,MAAM,UAAU,GACd,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC;gBACzD,sEAAsE;gBACtE,yEAAyE;gBACzE,uEAAuE;gBACvE,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;gBACnD,MAAM,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;gBACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,MAAM,EAAE,GAAG,GAAG,QAAQ,CAAC,CAAC;gBACnE,IAAI,MAAM,IAAI,CAAC;oBACb,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;gBACrE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;gBACtE,QAAQ,IAAI,MAAM,CAAC;YACrB,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { BlobBytes } from \"../../../blobContracts\";\n\n/** Repartition the envelope without changing its encryption or buffering the file. */\nexport function createEncryptedUploadParts(input: {\n readonly byteLength: number;\n readonly chunkSize: number;\n readonly header: BlobBytes;\n readonly encryptChunk: (index: number) => Promise<BlobBytes>;\n}) {\n // Including the header in the fixed transport size keeps even a maximum-size\n // envelope within 10,000 parts. R2 requires equal sizes for all nonfinal parts.\n const partSize = input.chunkSize + input.header.byteLength;\n const partCount = Math.ceil(input.byteLength / partSize);\n function getPartByteLength(index: number): number {\n if (!Number.isInteger(index) || index < 0 || index >= partCount) {\n throw new Error(\"Blob encryption part index is out of range\");\n }\n return Math.min(partSize, input.byteLength - index * partSize);\n }\n return {\n partCount,\n getPartByteLength,\n async encryptPart(index: number): Promise<BlobBytes> {\n const output = new Uint8Array(getPartByteLength(index));\n const start = index * partSize;\n const end = start + output.byteLength;\n if (start < input.header.byteLength) {\n output.set(\n input.header.subarray(start, Math.min(end, input.header.byteLength)),\n );\n }\n let position = Math.max(start, input.header.byteLength);\n while (position < end) {\n const chunkIndex = Math.floor(\n (position - input.header.byteLength) / input.chunkSize,\n );\n const chunkStart =\n input.header.byteLength + chunkIndex * input.chunkSize;\n // Adjacent transport parts can re-read and re-encrypt a shared chunk.\n // Independent calls keep memory bounded during concurrent upload/resume;\n // the tradeoff is up to two encryptions per chunk in this upload pass.\n const chunk = await input.encryptChunk(chunkIndex);\n const offset = position - chunkStart;\n const length = Math.min(chunk.byteLength - offset, end - position);\n if (length <= 0)\n throw new Error(\"Encrypted blob chunk is shorter than its layout\");\n output.set(chunk.subarray(offset, offset + length), position - start);\n position += length;\n }\n return output;\n },\n };\n}\n"]}
1
+ {"version":3,"file":"encryptedUploadParts.js","sourceRoot":"","sources":["encryptedUploadParts.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,MAAM,UAAU,0BAA0B,CAAC,KAK1C;IACC,6EAA6E;IAC7E,gFAAgF;IAChF,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;IACzD,SAAS,iBAAiB,CAAC,KAAa;QACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC;IACjE,CAAC;IACD,OAAO;QACL,SAAS;QACT,iBAAiB;QACjB,KAAK,CAAC,WAAW,CAAC,KAAa;YAC7B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;YAC/B,MAAM,GAAG,GAAG,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;YACtC,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpC,MAAM,CAAC,GAAG,CACR,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CACrE,CAAC;YACJ,CAAC;YACD,IAAI,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACxD,OAAO,QAAQ,GAAG,GAAG,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAC3B,CAAC,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,SAAS,CACvD,CAAC;gBACF,MAAM,UAAU,GACd,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC;gBACzD,sEAAsE;gBACtE,yEAAyE;gBACzE,uEAAuE;gBACvE,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;gBACnD,MAAM,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;gBACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,MAAM,EAAE,GAAG,GAAG,QAAQ,CAAC,CAAC;gBACnE,IAAI,MAAM,IAAI,CAAC;oBACb,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;gBACrE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;gBACtE,QAAQ,IAAI,MAAM,CAAC;YACrB,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { BlobBytes } from \"../../../blobs/blobContracts\";\n\n/** Repartition the envelope without changing its encryption or buffering the file. */\nexport function createEncryptedUploadParts(input: {\n readonly byteLength: number;\n readonly chunkSize: number;\n readonly header: BlobBytes;\n readonly encryptChunk: (index: number) => Promise<BlobBytes>;\n}) {\n // Including the header in the fixed transport size keeps even a maximum-size\n // envelope within 10,000 parts. R2 requires equal sizes for all nonfinal parts.\n const partSize = input.chunkSize + input.header.byteLength;\n const partCount = Math.ceil(input.byteLength / partSize);\n function getPartByteLength(index: number): number {\n if (!Number.isInteger(index) || index < 0 || index >= partCount) {\n throw new Error(\"Blob encryption part index is out of range\");\n }\n return Math.min(partSize, input.byteLength - index * partSize);\n }\n return {\n partCount,\n getPartByteLength,\n async encryptPart(index: number): Promise<BlobBytes> {\n const output = new Uint8Array(getPartByteLength(index));\n const start = index * partSize;\n const end = start + output.byteLength;\n if (start < input.header.byteLength) {\n output.set(\n input.header.subarray(start, Math.min(end, input.header.byteLength)),\n );\n }\n let position = Math.max(start, input.header.byteLength);\n while (position < end) {\n const chunkIndex = Math.floor(\n (position - input.header.byteLength) / input.chunkSize,\n );\n const chunkStart =\n input.header.byteLength + chunkIndex * input.chunkSize;\n // Adjacent transport parts can re-read and re-encrypt a shared chunk.\n // Independent calls keep memory bounded during concurrent upload/resume;\n // the tradeoff is up to two encryptions per chunk in this upload pass.\n const chunk = await input.encryptChunk(chunkIndex);\n const offset = position - chunkStart;\n const length = Math.min(chunk.byteLength - offset, end - position);\n if (length <= 0)\n throw new Error(\"Encrypted blob chunk is shorter than its layout\");\n output.set(chunk.subarray(offset, offset + length), position - start);\n position += length;\n }\n return output;\n },\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { CONTENT_RECORD_ENCRYPTION_SUITE, computeAccessEventBodyHash, computeContentRecordNonceDomainHash, computeWriteHeaderHash, signAccessEvent, signWriteHeader, } from "../../../../internal/crypto/index.js";
2
- import { readCanonicalJson } from "../../../keyingCanonicalJson.js";
2
+ import { readCanonicalJson } from "../../../keying/canonicalJson.js";
3
3
  import { uniqueSortedStrings } from "../../shared/readers.js";
4
4
  async function signBlobAttachmentBodyEvent(body, input) {
5
5
  const bodyLabel = body.eventType === "attachment.bind"