@tearleads/client-sdk 0.1.41 → 0.1.43

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 (235) hide show
  1. package/client/Tearleads.js +3 -0
  2. package/client/Tearleads.js.map +1 -1
  3. package/data/blobs/transferPool.js +35 -8
  4. package/data/blobs/transferPool.js.map +1 -1
  5. package/data/containers/shared/projection.js +12 -0
  6. package/data/containers/shared/projection.js.map +1 -1
  7. package/data/documents/blob/shared/types.d.ts +2 -3
  8. package/data/documents/blob/shared/types.js.map +1 -1
  9. package/data/documents/shared/events.js +0 -1
  10. package/data/documents/shared/events.js.map +1 -1
  11. package/data/keyingProjectionVerification/accessManifestCheckpointEnforcement.js +2 -0
  12. package/data/keyingProjectionVerification/accessManifestCheckpointEnforcement.js.map +1 -1
  13. package/data/keyingProjectionVerification/checkpointContext.d.ts +12 -0
  14. package/data/keyingProjectionVerification/checkpointContext.js +16 -0
  15. package/data/keyingProjectionVerification/checkpointContext.js.map +1 -1
  16. package/data/keyingProjectionVerification/containerDestinationVerification.js +3 -1
  17. package/data/keyingProjectionVerification/containerDestinationVerification.js.map +1 -1
  18. package/data/keyingProjectionVerification/containerProjectionVerification.js +12 -6
  19. package/data/keyingProjectionVerification/containerProjectionVerification.js.map +1 -1
  20. package/data/keyingProjectionVerification/documentProjectionVerification.js +10 -4
  21. package/data/keyingProjectionVerification/documentProjectionVerification.js.map +1 -1
  22. package/data/persistence/container-contents/containerContentsPersistence.js +6 -22
  23. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  24. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +5 -15
  25. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  26. package/data/persistence/container-contents/containerPendingUpdatePersistence.js +6 -15
  27. package/data/persistence/container-contents/containerPendingUpdatePersistence.js.map +1 -1
  28. package/data/persistence/container-contents/containerRecoveryPersistence.js +3 -4
  29. package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
  30. package/data/persistence/container-contents/containerRemovalWork.js +3 -5
  31. package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
  32. package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
  33. package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
  34. package/data/persistence/documents/documentsPersistence.js +4 -9
  35. package/data/persistence/documents/documentsPersistence.js.map +1 -1
  36. package/data/persistence/documents/internal/discardDocument.js +1 -2
  37. package/data/persistence/documents/internal/discardDocument.js.map +1 -1
  38. package/data/persistence/documents/internal/documentDeletionPersistence.js +1 -2
  39. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  40. package/data/persistence/documents/internal/documentMutationPersistence.js +17 -25
  41. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  42. package/data/persistence/documents/internal/orphanSideRows.js +2 -14
  43. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  44. package/data/persistence/documents/internal/syncQueuePersistence.js +3 -3
  45. package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
  46. package/data/persistence/keyingCheckpointAdvancePersistence.js +27 -8
  47. package/data/persistence/keyingCheckpointAdvancePersistence.js.map +1 -1
  48. package/data/persistence/verifiedManifestBundlePersistence.d.ts +45 -0
  49. package/data/persistence/verifiedManifestBundlePersistence.js +282 -0
  50. package/data/persistence/verifiedManifestBundlePersistence.js.map +1 -0
  51. package/data/sqlite/documentHistoryPersistence.d.ts +9 -3
  52. package/data/sqlite/documentHistoryPersistence.js +31 -8
  53. package/data/sqlite/documentHistoryPersistence.js.map +1 -1
  54. package/data/sqlite/documentPendingUpdatePersistence.d.ts +58 -11
  55. package/data/sqlite/documentPendingUpdatePersistence.js +137 -63
  56. package/data/sqlite/documentPendingUpdatePersistence.js.map +1 -1
  57. package/data/sqlite/documentPersistence.d.ts +1 -1
  58. package/data/sqlite/documentPersistence.js +1 -1
  59. package/data/sqlite/documentPersistence.js.map +1 -1
  60. package/data/sqlite/documentPersistenceTypes.d.ts +2 -2
  61. package/data/sqlite/documentPersistenceTypes.js.map +1 -1
  62. package/data/sqlite/documentRecordPersistence.js +5 -4
  63. package/data/sqlite/documentRecordPersistence.js.map +1 -1
  64. package/data/sqlite/schema.d.ts +350 -443
  65. package/data/sqlite/schema.js +49 -47
  66. package/data/sqlite/schema.js.map +1 -1
  67. package/data/sqlite/verifiedManifestBundleSchema.d.ts +174 -0
  68. package/data/sqlite/verifiedManifestBundleSchema.js +36 -0
  69. package/data/sqlite/verifiedManifestBundleSchema.js.map +1 -0
  70. package/internal/api-client/ApiClient.d.ts +17 -19
  71. package/internal/api-client/ApiClient.js +10 -11
  72. package/internal/api-client/ApiClient.js.map +1 -1
  73. package/internal/api-client/binaryRequestOperationTransport.d.ts +18 -0
  74. package/internal/api-client/index.d.ts +2 -1
  75. package/internal/api-client/index.js +1 -1
  76. package/internal/api-client/index.js.map +1 -1
  77. package/internal/api-client/operationTransportFactory.d.ts +6 -0
  78. package/internal/api-client/principalHistoryRequest.js +8 -2
  79. package/internal/api-client/principalHistoryRequest.js.map +1 -1
  80. package/internal/api-client/principalHistoryRequestContext.js +15 -5
  81. package/internal/api-client/principalHistoryRequestContext.js.map +1 -1
  82. package/internal/api-client/routes/blobs/get.d.ts +7 -0
  83. package/internal/api-client/routes/blobs/get.js.map +1 -1
  84. package/internal/api-client/routes/blobs/multipart.js +1 -11
  85. package/internal/api-client/routes/blobs/multipart.js.map +1 -1
  86. package/internal/api-client/routes/blobs/multipartUpload.d.ts +14 -0
  87. package/internal/api-client/routes/blobs/multipartUpload.js +94 -43
  88. package/internal/api-client/routes/blobs/multipartUpload.js.map +1 -1
  89. package/internal/api-client/routes/writerProjections.js +6 -3
  90. package/internal/api-client/routes/writerProjections.js.map +1 -1
  91. package/internal/api-client/verifiedManifestCitations.d.ts +23 -0
  92. package/internal/api-client/verifiedManifestCitations.js +60 -0
  93. package/internal/api-client/verifiedManifestCitations.js.map +1 -0
  94. package/internal/api-client/writerProjectionRequests.js +75 -14
  95. package/internal/api-client/writerProjectionRequests.js.map +1 -1
  96. package/internal/crypto/index.d.ts +0 -1
  97. package/internal/crypto/index.js +0 -1
  98. package/internal/crypto/index.js.map +1 -1
  99. package/internal/validators/knownManifestsRefinements.js +5 -0
  100. package/internal/validators/knownManifestsRefinements.js.map +1 -0
  101. package/internal/validators/operation/attachments.d.ts +80 -160
  102. package/internal/validators/operation/auth.d.ts +760 -1664
  103. package/internal/validators/operation/blobDownloads.js +1 -1
  104. package/internal/validators/operation/blobDownloads.js.map +1 -1
  105. package/internal/validators/operation/containerMutations.d.ts +416 -856
  106. package/internal/validators/operation/documentMutations.d.ts +120 -264
  107. package/internal/validators/operation/documentSync.d.ts +40 -80
  108. package/internal/validators/operation/index.d.ts +1 -1
  109. package/internal/validators/operation/index.js +1 -1
  110. package/internal/validators/operation/index.js.map +1 -1
  111. package/internal/validators/operation/multipartBlobs.d.ts +70 -190
  112. package/internal/validators/operation/multipartBlobs.js +2 -24
  113. package/internal/validators/operation/multipartBlobs.js.map +1 -1
  114. package/internal/validators/operation/multipartPartUploads.d.ts +5 -5
  115. package/internal/validators/operation/multipartPartUploads.js +6 -20
  116. package/internal/validators/operation/multipartPartUploads.js.map +1 -1
  117. package/internal/validators/operation/organizations.d.ts +882 -1906
  118. package/internal/validators/operation/principals.d.ts +120 -240
  119. package/internal/validators/operation/registry.d.ts +1 -2
  120. package/internal/validators/operation/registry.js +1 -2
  121. package/internal/validators/operation/registry.js.map +1 -1
  122. package/internal/validators/operation/writerProjections.d.ts +85 -319
  123. package/internal/validators/operation/writerProjections.js +11 -11
  124. package/internal/validators/operation/writerProjections.js.map +1 -1
  125. package/internal/validators/request/blob.d.ts +100 -201
  126. package/internal/validators/request/blob.js +6 -13
  127. package/internal/validators/request/blob.js.map +1 -1
  128. package/internal/validators/request/container.d.ts +136 -272
  129. package/internal/validators/request/container.js +16 -10
  130. package/internal/validators/request/container.js.map +1 -1
  131. package/internal/validators/request/containerManifestRef.d.ts +54 -0
  132. package/internal/validators/request/containerManifestRef.js +28 -0
  133. package/internal/validators/request/containerManifestRef.js.map +1 -0
  134. package/internal/validators/request/containerMetadata.d.ts +160 -368
  135. package/internal/validators/request/document.d.ts +100 -245
  136. package/internal/validators/request/document.js +1 -2
  137. package/internal/validators/request/document.js.map +1 -1
  138. package/internal/validators/request/documentSyncSchema.d.ts +42 -109
  139. package/internal/validators/request/documentSyncSchema.js +8 -25
  140. package/internal/validators/request/documentSyncSchema.js.map +1 -1
  141. package/internal/validators/request/index.d.ts +1 -1
  142. package/internal/validators/request/index.js +1 -1
  143. package/internal/validators/request/index.js.map +1 -1
  144. package/internal/validators/request/organization.d.ts +160 -320
  145. package/internal/validators/request/organizationProvisioning.d.ts +2424 -5312
  146. package/internal/validators/request/principal.d.ts +160 -320
  147. package/internal/validators/request/registration.d.ts +760 -1664
  148. package/internal/validators/response/blob.d.ts +48 -27
  149. package/internal/validators/response/blob.js +3 -10
  150. package/internal/validators/response/blob.js.map +1 -1
  151. package/internal/validators/response/container.d.ts +429 -20
  152. package/internal/validators/response/container.js +40 -5
  153. package/internal/validators/response/container.js.map +1 -1
  154. package/internal/validators/response/documentMutation.d.ts +440 -20
  155. package/internal/validators/response/documentMutation.js +33 -3
  156. package/internal/validators/response/documentMutation.js.map +1 -1
  157. package/internal/validators/response/index.d.ts +4 -3
  158. package/internal/validators/response/index.js +4 -3
  159. package/internal/validators/response/index.js.map +1 -1
  160. package/internal/validators/response/manifestBundleReferences.js +79 -0
  161. package/internal/validators/response/manifestBundleReferences.js.map +1 -0
  162. package/internal/validators/response/writerProjectionWire.d.ts +19 -0
  163. package/internal/validators/response/writerProjectionWire.js +132 -0
  164. package/internal/validators/response/writerProjectionWire.js.map +1 -0
  165. package/internal/validators/schema.js +20 -0
  166. package/internal/validators/schema.js.map +1 -1
  167. package/internal/validators/util/blob.d.ts +7 -0
  168. package/internal/validators/util/blob.js +7 -0
  169. package/internal/validators/util/blob.js.map +1 -1
  170. package/internal/validators/util/blobTransferSchemas.d.ts +41 -0
  171. package/internal/validators/util/blobTransferSchemas.js +39 -0
  172. package/internal/validators/util/blobTransferSchemas.js.map +1 -0
  173. package/internal/validators/util/containerLimits.d.ts +7 -0
  174. package/internal/validators/util/containerLimits.js +7 -0
  175. package/internal/validators/util/containerLimits.js.map +1 -1
  176. package/internal/validators/util/index.d.ts +3 -2
  177. package/internal/validators/util/index.js +3 -2
  178. package/internal/validators/util/index.js.map +1 -1
  179. package/internal/validators/util/knownManifestWire.d.ts +11 -0
  180. package/internal/validators/util/knownManifestWire.js +28 -0
  181. package/internal/validators/util/knownManifestWire.js.map +1 -0
  182. package/internal/validators/writerProjectionRefinements.js +5 -0
  183. package/internal/validators/writerProjectionRefinements.js.map +1 -1
  184. package/package.json +1 -1
  185. package/workflows/blobs/multipartFirstParts.js +82 -0
  186. package/workflows/blobs/multipartFirstParts.js.map +1 -0
  187. package/workflows/blobs/multipartStageResolution.js +83 -0
  188. package/workflows/blobs/multipartStageResolution.js.map +1 -0
  189. package/workflows/blobs/multipartUpload.js +45 -89
  190. package/workflows/blobs/multipartUpload.js.map +1 -1
  191. package/workflows/container-contents/documentPriming.js +2 -1
  192. package/workflows/container-contents/documentPriming.js.map +1 -1
  193. package/workflows/container-contents/documentQueries/sql.js +4 -4
  194. package/workflows/container-contents/documentQueries/sql.js.map +1 -1
  195. package/workflows/container-contents/pendingWrites/deferredTails.js +6 -3
  196. package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
  197. package/workflows/container-contents/pendingWrites/sources.js +2 -1
  198. package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
  199. package/workflows/container-contents/pendingWrites.js +2 -1
  200. package/workflows/container-contents/pendingWrites.js.map +1 -1
  201. package/workflows/containers/child/create.js +3 -3
  202. package/workflows/containers/child/create.js.map +1 -1
  203. package/workflows/containers/child/move.js +2 -2
  204. package/workflows/containers/child/move.js.map +1 -1
  205. package/workflows/containers/child/mutationRequestCore.js +5 -4
  206. package/workflows/containers/child/mutationRequestCore.js.map +1 -1
  207. package/workflows/containers/child/recitePlan.js +3 -2
  208. package/workflows/containers/child/recitePlan.js.map +1 -1
  209. package/workflows/containers/child/sharePlanCore.js +2 -2
  210. package/workflows/containers/child/sharePlanCore.js.map +1 -1
  211. package/workflows/containers/root/create.js +2 -2
  212. package/workflows/containers/root/create.js.map +1 -1
  213. package/workflows/registration/provisioningBootstrapBuilders.d.ts +20 -51
  214. package/workflows/sync/remoteReset.js +11 -9
  215. package/workflows/sync/remoteReset.js.map +1 -1
  216. package/workflows/sync/remoteResetPlans.js +6 -3
  217. package/workflows/sync/remoteResetPlans.js.map +1 -1
  218. package/internal/api-client/projectionHistoryTransport.js +0 -107
  219. package/internal/api-client/projectionHistoryTransport.js.map +0 -1
  220. package/internal/api-client/verifiedProjectionHistory.d.ts +0 -4
  221. package/internal/api-client/verifiedProjectionHistory.js +0 -12
  222. package/internal/api-client/verifiedProjectionHistory.js.map +0 -1
  223. package/internal/crypto/projectionHistory.d.ts +0 -14
  224. package/internal/crypto/projectionHistory.js +0 -90
  225. package/internal/crypto/projectionHistory.js.map +0 -1
  226. package/internal/crypto/projectionHistorySlots.d.ts +0 -13
  227. package/internal/crypto/projectionHistorySlots.js +0 -81
  228. package/internal/crypto/projectionHistorySlots.js.map +0 -1
  229. package/internal/validators/operation/blobTransferSchemas.js +0 -11
  230. package/internal/validators/operation/blobTransferSchemas.js.map +0 -1
  231. package/internal/validators/projectionHistoryRefinements.js +0 -5
  232. package/internal/validators/projectionHistoryRefinements.js.map +0 -1
  233. package/internal/validators/util/projectionHistoryWire.d.ts +0 -23
  234. package/internal/validators/util/projectionHistoryWire.js +0 -33
  235. package/internal/validators/util/projectionHistoryWire.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import { ApiClient, ApiRequestMetrics } from "../internal/api-client/index.js";
2
2
  import { resolveDocumentProjectorRegistry, } from "../data/documents/documentKinds.js";
3
3
  import { createDomainScope } from "../data/domainScope.js";
4
+ import { createVerifiedManifestCitations } from "../data/persistence/verifiedManifestBundlePersistence.js";
4
5
  import { disposeDomainSyncCoordinator } from "../data/sync/syncCoordinator.js";
5
6
  import { resolveIdentityTrustDomain } from "../data/trustedUserIdentity/index.js";
6
7
  import { ApiVersion } from "./apiVersion.js";
@@ -161,6 +162,8 @@ export class Tearleads {
161
162
  this.boundUserId = (signingKeyFingerprint) => runtime.boundUserId(signingKeyFingerprint);
162
163
  }
163
164
  configureApiClientCallbacks() {
165
+ // Projection reads cite bundles this identity's database already verified.
166
+ this.apiClient.setVerifiedManifestCitations(createVerifiedManifestCitations(() => this.database.execSql));
164
167
  this.apiClient.setOnError((message) => this.logError(message));
165
168
  // An authoritative host source owns connectivity. Without one, request
166
169
  // outcomes remain reachability hints. Browser and native app bindings both
@@ -1 +1 @@
1
- {"version":3,"file":"Tearleads.js","sourceRoot":"","sources":["Tearleads.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiClient, ApiRequestMetrics } from \"@tearleads/api-client\";\nimport type { BlobStore } from \"../data/blobContracts\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n resolveDocumentProjectorRegistry,\n} from \"../data/documents/documentKinds\";\nimport { createDomainScope, type DomainScope } from \"../data/domainScope\";\nimport type { SecurityIncidentReporter } from \"../data/securityIncidents\";\nimport { disposeDomainSyncCoordinator } from \"../data/sync/syncCoordinator\";\nimport { resolveIdentityTrustDomain } from \"../data/trustedUserIdentity\";\nimport type { ProvisionedSystemContainerSpec } from \"../workflows/registration\";\nimport { ApiVersion } from \"./apiVersion\";\nimport { type BlobStoreFactory, Blobs } from \"./blobs\";\nimport {\n type ContainerContents,\n createContainerContents,\n} from \"./containerContents\";\nimport { Database, type DatabaseOptions } from \"./database\";\nimport { createDeviceFirst, type DeviceFirst } from \"./deviceFirst\";\nimport { createDocuments, type Documents } from \"./documents\";\nimport { Events } from \"./events\";\nimport {\n createIdentity,\n type Identity,\n type IdentityOptions,\n} from \"./identity\";\nimport { type Logger, logErrorToConsole } from \"./logger\";\nimport { Network } from \"./network\";\nimport { createOrganizations, type Organizations } from \"./organizations\";\nimport type { PrincipalHistoryKeyProvider } from \"./principalHistoryProtection\";\nimport { createRoot, type Root, rootRuntimeOf } from \"./root\";\nimport {\n createSecurityIncidentService,\n type SecurityIncidentListener,\n type SecurityIncidents,\n} from \"./securityIncidents\";\nimport { createSession } from \"./session\";\nimport type { Session } from \"./session/sessionTypes\";\nimport { SyncBillingGate } from \"./syncBillingGate\";\nimport { createUserIdentities, type UserIdentities } from \"./userIdentities\";\nimport {\n createRuntime,\n type InternalRuntime,\n type Runtime,\n} from \"./workflowRuntime\";\n\nfunction createClientSecurityIncidentService(input: {\n readonly apiBaseUrl: string;\n readonly database: Database;\n readonly logError: (message: string | Error, cause?: unknown) => void;\n readonly options: ClientOptions;\n}) {\n const identityTrustDomain = resolveIdentityTrustDomain({\n apiBaseUrl: input.apiBaseUrl,\n identityTrustDomain: input.options.identityTrustDomain,\n });\n return {\n identityTrustDomain,\n service: createSecurityIncidentService({\n database: input.database,\n logError: input.logError,\n onIncident: input.options.onSecurityIncident,\n trustDomain: identityTrustDomain,\n }),\n };\n}\n\nexport type ClientDatabaseOptions = Omit<DatabaseOptions, \"status\">;\n\nexport interface ClientOptions {\n apiBaseUrl?: string | undefined;\n /** Reuse a memory-only request counter across client lifetimes. */\n apiRequestMetrics?: ApiRequestMetrics | undefined;\n blobStore?: BlobStore | undefined;\n blobStoreFactory?: BlobStoreFactory | undefined;\n database?: ClientDatabaseOptions | undefined;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n events?: ReadonlyArray<unknown> | undefined;\n identity?: IdentityOptions | undefined;\n /**\n * Absolute, host-controlled API namespace for durable user-identity pins.\n * Required only when apiBaseUrl is relative and no browser origin exists.\n */\n identityTrustDomain?: string | undefined;\n identityProvisioning?: \"auto\" | \"manual\" | undefined;\n logger?: Logger | undefined;\n online?: boolean | undefined;\n /** Called after a trust-boundary verification failure is durably recorded. */\n onSecurityIncident?: SecurityIncidentListener | undefined;\n /**\n * Per-pane discriminator so documents in distinct panes derive distinct Loro\n * peer ids (e.g. the pane's local identity namespace). Omit for single-pane.\n */\n peerScope?: string | undefined;\n /** Private host key for durable history progress; omitted uses disposable session keys. */\n principalHistoryKeyProvider?: PrincipalHistoryKeyProvider | undefined;\n /** Compound policy dispatch/recovery deadline in milliseconds; defaults to 60 seconds. */\n principalMutationTimeoutMs?: number | undefined;\n /**\n * App-owned system containers born with every new organization (both\n * registration and additional-org creation provision them atomically in the\n * same server call), e.g. a trash bin. The app owns these because their slot\n * namespaces are app concepts the SDK stays agnostic to.\n */\n provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n}\n\nexport class Tearleads {\n readonly apiVersion = new ApiVersion();\n readonly apiRequests: ApiRequestMetrics;\n readonly blobs: Blobs;\n readonly database: Database;\n readonly deviceFirst: DeviceFirst;\n readonly documents: Documents;\n readonly events: Events;\n readonly containerContents: ContainerContents;\n readonly identity: Identity;\n readonly network: Network;\n readonly organizations: Organizations;\n readonly root: Root;\n readonly runtime: Runtime;\n readonly securityIncidents: SecurityIncidents;\n readonly session: Session;\n readonly syncBillingGate: SyncBillingGate;\n readonly userIdentities: UserIdentities;\n\n private readonly apiClient: ApiClient;\n private readonly documentProjectors: DocumentProjectorRegistry;\n private readonly disposeSecurityIncidents: () => void;\n private retirePrincipalHistoryProtection = () => {};\n // Tracks the storage/identity pair that owns domain-scoped runtime state.\n private domainScopeKey: string | null = null;\n // Recreated when the storage database or signing identity changes.\n private domainScopeValue: DomainScope = createDomainScope();\n private readonly logErrorHandler: (\n message: string | Error,\n cause?: unknown,\n ) => void;\n private readonly logHandler: (message: string) => void;\n private autoIdentityProvisioned = false;\n private autoIdentityProvisioningPromise: Promise<void> | null = null;\n private expiredSessionLoginPromise: Promise<boolean> | null = null;\n // Rebound to the workflow runtime once it exists; the session is created first.\n private pinLocalUserIdentity: InternalRuntime[\"pinLocalUserIdentity\"] =\n async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n private primeProvisionedPrincipalHistory: InternalRuntime[\"primeProvisionedPrincipalHistory\"] =\n async () => undefined;\n private boundUserId: InternalRuntime[\"boundUserId\"] = async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n\n constructor(options: ClientOptions = {}) {\n const apiBaseUrl = options.apiBaseUrl ?? \"\";\n this.apiRequests = options.apiRequestMetrics ?? new ApiRequestMetrics();\n this.apiClient = this.createApiClient(apiBaseUrl);\n this.blobs = new Blobs(options.blobStore, options.blobStoreFactory);\n this.database = new Database(options.database);\n this.documentProjectors = resolveDocumentProjectorRegistry(\n options.documentProjectors,\n );\n this.events = new Events(options.events, () =>\n this.apiClient.clearWriterProjectionCaches(),\n );\n this.logHandler = options.logger?.log ?? (() => undefined);\n this.logErrorHandler = options.logger?.logError ?? logErrorToConsole;\n const security = createClientSecurityIncidentService({\n apiBaseUrl,\n database: this.database,\n logError: this.logError,\n options,\n });\n this.securityIncidents = security.service.incidents;\n this.disposeSecurityIncidents = security.service.dispose;\n this.network = new Network(options.online);\n this.syncBillingGate = new SyncBillingGate();\n let session: Session | null = null;\n this.identity = createIdentity(\n options.identity,\n (signingFingerprint) =>\n this.blobs.updateIdentityNamespace(signingFingerprint),\n this.log,\n {\n bootstrapLocalRootContainer: async () => {\n if (this.database.status !== \"ready\") {\n throw new Error(\n \"identity.generate requires a ready SQLite database.\",\n );\n }\n if (!session) {\n throw new Error(\n \"identity.generate requires an initialized session.\",\n );\n }\n\n return session.bootstrapLocalRootContainer();\n },\n getUserId: () => session?.userId ?? null,\n },\n );\n session = this.createClientSession(options, security.service.report);\n this.session = session;\n const runtime = this.createWorkflowRuntime(\n security.identityTrustDomain,\n options,\n security.service.report,\n );\n this.bindTrustedIdentityRuntime(runtime);\n this.runtime = runtime.publicRuntime;\n this.documents = createDocuments({\n getDefaultContainerId: () => this.session.containerId,\n runtime,\n });\n this.containerContents = createContainerContents(runtime);\n this.deviceFirst = createDeviceFirst(runtime, this.containerContents);\n this.organizations = createOrganizations(runtime, this.containerContents);\n this.root = createRoot(rootRuntimeOf(runtime, this.session));\n this.userIdentities = createUserIdentities({\n log: this.log,\n resolveTrustedUserIdentity: (userId) =>\n runtime.workflowInput().resolveTrustedUserIdentity(userId),\n });\n\n this.configureApiClientCallbacks();\n\n if (options.identityProvisioning === \"auto\") {\n this.startAutomaticIdentityProvisioning();\n }\n }\n\n /** Trust callbacks reach the workflow runtime, which is created later. */\n private createClientSession(\n options: ClientOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): Session {\n return createSession({\n api: this.apiClient,\n database: this.database,\n documentProjectors: this.documentProjectors,\n identity: this.identity,\n log: this.log,\n logError: this.logError,\n boundUserIdForSigningKey: (signingKeyFingerprint) =>\n this.boundUserId(signingKeyFingerprint),\n onUserIdentityAvailable: (userId, candidate) =>\n this.pinLocalUserIdentity(userId, candidate),\n primeProvisionedPrincipalHistory: (input) =>\n this.primeProvisionedPrincipalHistory(input),\n provisionedSystemContainers: options.provisionedSystemContainers,\n reportSecurityIncident,\n });\n }\n\n private createApiClient(apiBaseUrl: string): ApiClient {\n return new ApiClient(apiBaseUrl, {\n metrics: this.apiRequests,\n getIdentity: () => this.identity.signingFingerprint,\n });\n }\n\n /** Rebinds the session's trust callbacks once the runtime exists. */\n private bindTrustedIdentityRuntime(runtime: InternalRuntime): void {\n this.retirePrincipalHistoryProtection =\n runtime.retirePrincipalHistoryProtection;\n this.pinLocalUserIdentity = (userId, candidate) =>\n runtime.pinLocalUserIdentity(userId, candidate);\n this.primeProvisionedPrincipalHistory =\n runtime.primeProvisionedPrincipalHistory;\n this.boundUserId = (signingKeyFingerprint) =>\n runtime.boundUserId(signingKeyFingerprint);\n }\n\n private configureApiClientCallbacks(): void {\n this.apiClient.setOnError((message) => this.logError(message));\n // An authoritative host source owns connectivity. Without one, request\n // outcomes remain reachability hints. Browser and native app bindings both\n // install authoritative sources so a backend outage cannot stop retries.\n this.apiClient.setOnNetworkError(() =>\n this.network.reportReachability(false),\n );\n this.apiClient.setOnNetworkSuccess(() =>\n this.network.reportReachability(true),\n );\n this.apiClient.setOnApiVersion((version) =>\n this.apiVersion.observe(version),\n );\n this.apiClient.setOnSessionExpired(() => this.loginAfterSessionExpired());\n this.apiClient.setOnPaymentRequired((organizationId) =>\n this.syncBillingGate.notifyPaymentRequired(organizationId),\n );\n }\n\n private createWorkflowRuntime(\n identityTrustDomain: string | null,\n options: ClientOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): InternalRuntime {\n return createRuntime({\n api: this.apiClient,\n blobs: this.blobs,\n database: this.database,\n documentProjectors: this.documentProjectors,\n events: this.events,\n getDomainScope: () => this.domainScope,\n identity: this.identity,\n identityTrustDomain,\n log: this.log,\n logError: this.logError,\n network: this.network,\n peerScope: options.peerScope ?? null,\n principalHistoryKeyProvider: options.principalHistoryKeyProvider,\n principalMutationTimeoutMs: options.principalMutationTimeoutMs,\n reportSecurityIncident,\n session: this.session,\n syncBillingGate: this.syncBillingGate,\n });\n }\n\n log = (message: string): void => {\n this.logHandler(message);\n };\n\n // Preserve the host's return value so best-effort callers can also catch\n // rejected promises from async loggers accepted by the void callback type.\n logError = (message: string | Error, cause?: unknown): void =>\n this.logErrorHandler(message, cause);\n\n /**\n * A single-use ticket to authenticate the server-events websocket handshake\n * (which cannot carry the bearer header): the one login returned for the\n * first connect of that session, otherwise a freshly minted one. Returns\n * null when no session is active. The caller appends it to the websocket URL.\n */\n requestWebSocketTicket(): Promise<string | null> {\n return this.apiClient.requestWebSocketTicket();\n }\n\n get domainScope(): DomainScope {\n const nextScopeKey = JSON.stringify([\n this.database.id,\n this.identity.signingFingerprint,\n ]);\n if (this.domainScopeKey !== nextScopeKey) {\n this.domainScopeKey = nextScopeKey;\n this.domainScopeValue = createDomainScope();\n }\n\n return this.domainScopeValue;\n }\n\n /**\n * Tear down background work for the active domain scope: stop the reconciler\n * and force-stop the sync coordinator pump, then drop the coordinator from\n * its registry. Hosts call this from unmount/cleanup so a pump cannot outlive\n * the React tree that created it. A later access for the same scope rebuilds\n * fresh state.\n */\n dispose(): void {\n const domainScope = this.domainScope;\n this.disposeSecurityIncidents();\n this.retirePrincipalHistoryProtection();\n this.deviceFirst.dispose();\n disposeDomainSyncCoordinator(domainScope);\n }\n\n private loginAfterSessionExpired(): Promise<boolean> {\n if (!this.session.authToken || !this.identity.signingKeyPair) {\n this.session.logout();\n return Promise.resolve(false);\n }\n\n // The API client replays requests the expired session sent, so a login is\n // their renewal only when the loaded keys authenticate that known user.\n const expiredUserId = this.session.userId;\n this.expiredSessionLoginPromise ??= this.session\n .login()\n .then(\n (renewed) =>\n renewed &&\n expiredUserId !== null &&\n this.session.userId === expiredUserId,\n )\n .finally(() => {\n this.expiredSessionLoginPromise = null;\n });\n return this.expiredSessionLoginPromise;\n }\n\n private startAutomaticIdentityProvisioning(): void {\n let unsubscribe: (() => void) | null = null;\n const stopProvisioningListener = () => {\n unsubscribe?.();\n unsubscribe = null;\n };\n const maybeProvisionIdentity = () => {\n if (this.autoIdentityProvisioned || this.identity.signingKeyPair) {\n stopProvisioningListener();\n return;\n }\n\n if (\n this.autoIdentityProvisioningPromise ||\n this.database.status !== \"ready\"\n ) {\n return;\n }\n\n this.autoIdentityProvisioningPromise = this.identity\n .generate()\n .then(() => {\n this.autoIdentityProvisioned = true;\n stopProvisioningListener();\n })\n .catch((error: unknown) => {\n try {\n this.logError(\"Automatic identity provisioning failed\", error);\n } catch {\n // Keep background provisioning failures from surfacing as unhandled rejections.\n }\n })\n .finally(() => {\n this.autoIdentityProvisioningPromise = null;\n });\n };\n\n unsubscribe = this.database.subscribe(maybeProvisionIdentity);\n void Promise.resolve().then(maybeProvisionIdentity);\n }\n}\n"]}
1
+ {"version":3,"file":"Tearleads.js","sourceRoot":"","sources":["Tearleads.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiClient, ApiRequestMetrics } from \"@tearleads/api-client\";\nimport type { BlobStore } from \"../data/blobContracts\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n resolveDocumentProjectorRegistry,\n} from \"../data/documents/documentKinds\";\nimport { createDomainScope, type DomainScope } from \"../data/domainScope\";\nimport { createVerifiedManifestCitations } from \"../data/persistence/verifiedManifestBundlePersistence\";\nimport type { SecurityIncidentReporter } from \"../data/securityIncidents\";\nimport { disposeDomainSyncCoordinator } from \"../data/sync/syncCoordinator\";\nimport { resolveIdentityTrustDomain } from \"../data/trustedUserIdentity\";\nimport type { ProvisionedSystemContainerSpec } from \"../workflows/registration\";\nimport { ApiVersion } from \"./apiVersion\";\nimport { type BlobStoreFactory, Blobs } from \"./blobs\";\nimport {\n type ContainerContents,\n createContainerContents,\n} from \"./containerContents\";\nimport { Database, type DatabaseOptions } from \"./database\";\nimport { createDeviceFirst, type DeviceFirst } from \"./deviceFirst\";\nimport { createDocuments, type Documents } from \"./documents\";\nimport { Events } from \"./events\";\nimport {\n createIdentity,\n type Identity,\n type IdentityOptions,\n} from \"./identity\";\nimport { type Logger, logErrorToConsole } from \"./logger\";\nimport { Network } from \"./network\";\nimport { createOrganizations, type Organizations } from \"./organizations\";\nimport type { PrincipalHistoryKeyProvider } from \"./principalHistoryProtection\";\nimport { createRoot, type Root, rootRuntimeOf } from \"./root\";\nimport {\n createSecurityIncidentService,\n type SecurityIncidentListener,\n type SecurityIncidents,\n} from \"./securityIncidents\";\nimport { createSession } from \"./session\";\nimport type { Session } from \"./session/sessionTypes\";\nimport { SyncBillingGate } from \"./syncBillingGate\";\nimport { createUserIdentities, type UserIdentities } from \"./userIdentities\";\nimport {\n createRuntime,\n type InternalRuntime,\n type Runtime,\n} from \"./workflowRuntime\";\n\nfunction createClientSecurityIncidentService(input: {\n readonly apiBaseUrl: string;\n readonly database: Database;\n readonly logError: (message: string | Error, cause?: unknown) => void;\n readonly options: ClientOptions;\n}) {\n const identityTrustDomain = resolveIdentityTrustDomain({\n apiBaseUrl: input.apiBaseUrl,\n identityTrustDomain: input.options.identityTrustDomain,\n });\n return {\n identityTrustDomain,\n service: createSecurityIncidentService({\n database: input.database,\n logError: input.logError,\n onIncident: input.options.onSecurityIncident,\n trustDomain: identityTrustDomain,\n }),\n };\n}\n\nexport type ClientDatabaseOptions = Omit<DatabaseOptions, \"status\">;\n\nexport interface ClientOptions {\n apiBaseUrl?: string | undefined;\n /** Reuse a memory-only request counter across client lifetimes. */\n apiRequestMetrics?: ApiRequestMetrics | undefined;\n blobStore?: BlobStore | undefined;\n blobStoreFactory?: BlobStoreFactory | undefined;\n database?: ClientDatabaseOptions | undefined;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n events?: ReadonlyArray<unknown> | undefined;\n identity?: IdentityOptions | undefined;\n /**\n * Absolute, host-controlled API namespace for durable user-identity pins.\n * Required only when apiBaseUrl is relative and no browser origin exists.\n */\n identityTrustDomain?: string | undefined;\n identityProvisioning?: \"auto\" | \"manual\" | undefined;\n logger?: Logger | undefined;\n online?: boolean | undefined;\n /** Called after a trust-boundary verification failure is durably recorded. */\n onSecurityIncident?: SecurityIncidentListener | undefined;\n /**\n * Per-pane discriminator so documents in distinct panes derive distinct Loro\n * peer ids (e.g. the pane's local identity namespace). Omit for single-pane.\n */\n peerScope?: string | undefined;\n /** Private host key for durable history progress; omitted uses disposable session keys. */\n principalHistoryKeyProvider?: PrincipalHistoryKeyProvider | undefined;\n /** Compound policy dispatch/recovery deadline in milliseconds; defaults to 60 seconds. */\n principalMutationTimeoutMs?: number | undefined;\n /**\n * App-owned system containers born with every new organization (both\n * registration and additional-org creation provision them atomically in the\n * same server call), e.g. a trash bin. The app owns these because their slot\n * namespaces are app concepts the SDK stays agnostic to.\n */\n provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n}\n\nexport class Tearleads {\n readonly apiVersion = new ApiVersion();\n readonly apiRequests: ApiRequestMetrics;\n readonly blobs: Blobs;\n readonly database: Database;\n readonly deviceFirst: DeviceFirst;\n readonly documents: Documents;\n readonly events: Events;\n readonly containerContents: ContainerContents;\n readonly identity: Identity;\n readonly network: Network;\n readonly organizations: Organizations;\n readonly root: Root;\n readonly runtime: Runtime;\n readonly securityIncidents: SecurityIncidents;\n readonly session: Session;\n readonly syncBillingGate: SyncBillingGate;\n readonly userIdentities: UserIdentities;\n\n private readonly apiClient: ApiClient;\n private readonly documentProjectors: DocumentProjectorRegistry;\n private readonly disposeSecurityIncidents: () => void;\n private retirePrincipalHistoryProtection = () => {};\n // Tracks the storage/identity pair that owns domain-scoped runtime state.\n private domainScopeKey: string | null = null;\n // Recreated when the storage database or signing identity changes.\n private domainScopeValue: DomainScope = createDomainScope();\n private readonly logErrorHandler: (\n message: string | Error,\n cause?: unknown,\n ) => void;\n private readonly logHandler: (message: string) => void;\n private autoIdentityProvisioned = false;\n private autoIdentityProvisioningPromise: Promise<void> | null = null;\n private expiredSessionLoginPromise: Promise<boolean> | null = null;\n // Rebound to the workflow runtime once it exists; the session is created first.\n private pinLocalUserIdentity: InternalRuntime[\"pinLocalUserIdentity\"] =\n async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n private primeProvisionedPrincipalHistory: InternalRuntime[\"primeProvisionedPrincipalHistory\"] =\n async () => undefined;\n private boundUserId: InternalRuntime[\"boundUserId\"] = async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n\n constructor(options: ClientOptions = {}) {\n const apiBaseUrl = options.apiBaseUrl ?? \"\";\n this.apiRequests = options.apiRequestMetrics ?? new ApiRequestMetrics();\n this.apiClient = this.createApiClient(apiBaseUrl);\n this.blobs = new Blobs(options.blobStore, options.blobStoreFactory);\n this.database = new Database(options.database);\n this.documentProjectors = resolveDocumentProjectorRegistry(\n options.documentProjectors,\n );\n this.events = new Events(options.events, () =>\n this.apiClient.clearWriterProjectionCaches(),\n );\n this.logHandler = options.logger?.log ?? (() => undefined);\n this.logErrorHandler = options.logger?.logError ?? logErrorToConsole;\n const security = createClientSecurityIncidentService({\n apiBaseUrl,\n database: this.database,\n logError: this.logError,\n options,\n });\n this.securityIncidents = security.service.incidents;\n this.disposeSecurityIncidents = security.service.dispose;\n this.network = new Network(options.online);\n this.syncBillingGate = new SyncBillingGate();\n let session: Session | null = null;\n this.identity = createIdentity(\n options.identity,\n (signingFingerprint) =>\n this.blobs.updateIdentityNamespace(signingFingerprint),\n this.log,\n {\n bootstrapLocalRootContainer: async () => {\n if (this.database.status !== \"ready\") {\n throw new Error(\n \"identity.generate requires a ready SQLite database.\",\n );\n }\n if (!session) {\n throw new Error(\n \"identity.generate requires an initialized session.\",\n );\n }\n\n return session.bootstrapLocalRootContainer();\n },\n getUserId: () => session?.userId ?? null,\n },\n );\n session = this.createClientSession(options, security.service.report);\n this.session = session;\n const runtime = this.createWorkflowRuntime(\n security.identityTrustDomain,\n options,\n security.service.report,\n );\n this.bindTrustedIdentityRuntime(runtime);\n this.runtime = runtime.publicRuntime;\n this.documents = createDocuments({\n getDefaultContainerId: () => this.session.containerId,\n runtime,\n });\n this.containerContents = createContainerContents(runtime);\n this.deviceFirst = createDeviceFirst(runtime, this.containerContents);\n this.organizations = createOrganizations(runtime, this.containerContents);\n this.root = createRoot(rootRuntimeOf(runtime, this.session));\n this.userIdentities = createUserIdentities({\n log: this.log,\n resolveTrustedUserIdentity: (userId) =>\n runtime.workflowInput().resolveTrustedUserIdentity(userId),\n });\n\n this.configureApiClientCallbacks();\n\n if (options.identityProvisioning === \"auto\") {\n this.startAutomaticIdentityProvisioning();\n }\n }\n\n /** Trust callbacks reach the workflow runtime, which is created later. */\n private createClientSession(\n options: ClientOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): Session {\n return createSession({\n api: this.apiClient,\n database: this.database,\n documentProjectors: this.documentProjectors,\n identity: this.identity,\n log: this.log,\n logError: this.logError,\n boundUserIdForSigningKey: (signingKeyFingerprint) =>\n this.boundUserId(signingKeyFingerprint),\n onUserIdentityAvailable: (userId, candidate) =>\n this.pinLocalUserIdentity(userId, candidate),\n primeProvisionedPrincipalHistory: (input) =>\n this.primeProvisionedPrincipalHistory(input),\n provisionedSystemContainers: options.provisionedSystemContainers,\n reportSecurityIncident,\n });\n }\n\n private createApiClient(apiBaseUrl: string): ApiClient {\n return new ApiClient(apiBaseUrl, {\n metrics: this.apiRequests,\n getIdentity: () => this.identity.signingFingerprint,\n });\n }\n\n /** Rebinds the session's trust callbacks once the runtime exists. */\n private bindTrustedIdentityRuntime(runtime: InternalRuntime): void {\n this.retirePrincipalHistoryProtection =\n runtime.retirePrincipalHistoryProtection;\n this.pinLocalUserIdentity = (userId, candidate) =>\n runtime.pinLocalUserIdentity(userId, candidate);\n this.primeProvisionedPrincipalHistory =\n runtime.primeProvisionedPrincipalHistory;\n this.boundUserId = (signingKeyFingerprint) =>\n runtime.boundUserId(signingKeyFingerprint);\n }\n\n private configureApiClientCallbacks(): void {\n // Projection reads cite bundles this identity's database already verified.\n this.apiClient.setVerifiedManifestCitations(\n createVerifiedManifestCitations(() => this.database.execSql),\n );\n this.apiClient.setOnError((message) => this.logError(message));\n // An authoritative host source owns connectivity. Without one, request\n // outcomes remain reachability hints. Browser and native app bindings both\n // install authoritative sources so a backend outage cannot stop retries.\n this.apiClient.setOnNetworkError(() =>\n this.network.reportReachability(false),\n );\n this.apiClient.setOnNetworkSuccess(() =>\n this.network.reportReachability(true),\n );\n this.apiClient.setOnApiVersion((version) =>\n this.apiVersion.observe(version),\n );\n this.apiClient.setOnSessionExpired(() => this.loginAfterSessionExpired());\n this.apiClient.setOnPaymentRequired((organizationId) =>\n this.syncBillingGate.notifyPaymentRequired(organizationId),\n );\n }\n\n private createWorkflowRuntime(\n identityTrustDomain: string | null,\n options: ClientOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): InternalRuntime {\n return createRuntime({\n api: this.apiClient,\n blobs: this.blobs,\n database: this.database,\n documentProjectors: this.documentProjectors,\n events: this.events,\n getDomainScope: () => this.domainScope,\n identity: this.identity,\n identityTrustDomain,\n log: this.log,\n logError: this.logError,\n network: this.network,\n peerScope: options.peerScope ?? null,\n principalHistoryKeyProvider: options.principalHistoryKeyProvider,\n principalMutationTimeoutMs: options.principalMutationTimeoutMs,\n reportSecurityIncident,\n session: this.session,\n syncBillingGate: this.syncBillingGate,\n });\n }\n\n log = (message: string): void => {\n this.logHandler(message);\n };\n\n // Preserve the host's return value so best-effort callers can also catch\n // rejected promises from async loggers accepted by the void callback type.\n logError = (message: string | Error, cause?: unknown): void =>\n this.logErrorHandler(message, cause);\n\n /**\n * A single-use ticket to authenticate the server-events websocket handshake\n * (which cannot carry the bearer header): the one login returned for the\n * first connect of that session, otherwise a freshly minted one. Returns\n * null when no session is active. The caller appends it to the websocket URL.\n */\n requestWebSocketTicket(): Promise<string | null> {\n return this.apiClient.requestWebSocketTicket();\n }\n\n get domainScope(): DomainScope {\n const nextScopeKey = JSON.stringify([\n this.database.id,\n this.identity.signingFingerprint,\n ]);\n if (this.domainScopeKey !== nextScopeKey) {\n this.domainScopeKey = nextScopeKey;\n this.domainScopeValue = createDomainScope();\n }\n\n return this.domainScopeValue;\n }\n\n /**\n * Tear down background work for the active domain scope: stop the reconciler\n * and force-stop the sync coordinator pump, then drop the coordinator from\n * its registry. Hosts call this from unmount/cleanup so a pump cannot outlive\n * the React tree that created it. A later access for the same scope rebuilds\n * fresh state.\n */\n dispose(): void {\n const domainScope = this.domainScope;\n this.disposeSecurityIncidents();\n this.retirePrincipalHistoryProtection();\n this.deviceFirst.dispose();\n disposeDomainSyncCoordinator(domainScope);\n }\n\n private loginAfterSessionExpired(): Promise<boolean> {\n if (!this.session.authToken || !this.identity.signingKeyPair) {\n this.session.logout();\n return Promise.resolve(false);\n }\n\n // The API client replays requests the expired session sent, so a login is\n // their renewal only when the loaded keys authenticate that known user.\n const expiredUserId = this.session.userId;\n this.expiredSessionLoginPromise ??= this.session\n .login()\n .then(\n (renewed) =>\n renewed &&\n expiredUserId !== null &&\n this.session.userId === expiredUserId,\n )\n .finally(() => {\n this.expiredSessionLoginPromise = null;\n });\n return this.expiredSessionLoginPromise;\n }\n\n private startAutomaticIdentityProvisioning(): void {\n let unsubscribe: (() => void) | null = null;\n const stopProvisioningListener = () => {\n unsubscribe?.();\n unsubscribe = null;\n };\n const maybeProvisionIdentity = () => {\n if (this.autoIdentityProvisioned || this.identity.signingKeyPair) {\n stopProvisioningListener();\n return;\n }\n\n if (\n this.autoIdentityProvisioningPromise ||\n this.database.status !== \"ready\"\n ) {\n return;\n }\n\n this.autoIdentityProvisioningPromise = this.identity\n .generate()\n .then(() => {\n this.autoIdentityProvisioned = true;\n stopProvisioningListener();\n })\n .catch((error: unknown) => {\n try {\n this.logError(\"Automatic identity provisioning failed\", error);\n } catch {\n // Keep background provisioning failures from surfacing as unhandled rejections.\n }\n })\n .finally(() => {\n this.autoIdentityProvisioningPromise = null;\n });\n };\n\n unsubscribe = this.database.subscribe(maybeProvisionIdentity);\n void Promise.resolve().then(maybeProvisionIdentity);\n }\n}\n"]}
@@ -2,20 +2,51 @@
2
2
  export const BLOB_TRANSFER_CONCURRENCY = 4;
3
3
  const TRANSFER_IDLE_TIMEOUT_MS = 120_000;
4
4
  const pools = new WeakMap();
5
- export async function runBlobTransfer(client, transfer, timeoutMs = TRANSFER_IDLE_TIMEOUT_MS) {
6
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
7
- throw new RangeError("Blob transfer timeout must be positive and finite");
5
+ function poolFor(client) {
8
6
  let pool = pools.get(client);
9
7
  if (!pool) {
10
8
  pool = { active: 0, waiting: [] };
11
9
  pools.set(client, pool);
12
10
  }
11
+ return pool;
12
+ }
13
+ function permitFrom(pool) {
14
+ let held = true;
15
+ return {
16
+ release() {
17
+ if (!held)
18
+ return;
19
+ held = false;
20
+ const next = pool.waiting.shift();
21
+ if (next)
22
+ next();
23
+ else
24
+ pool.active -= 1;
25
+ },
26
+ };
27
+ }
28
+ export async function acquireBlobTransferPermit(client) {
29
+ const pool = poolFor(client);
13
30
  if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {
14
31
  await new Promise((resolve) => pool.waiting.push(resolve));
15
32
  }
16
33
  else {
17
34
  pool.active += 1;
18
35
  }
36
+ return permitFrom(pool);
37
+ }
38
+ /** A permit only if one is free now; never queues behind other transfers. */
39
+ export function tryAcquireBlobTransferPermit(client) {
40
+ const pool = poolFor(client);
41
+ if (pool.active >= BLOB_TRANSFER_CONCURRENCY)
42
+ return null;
43
+ pool.active += 1;
44
+ return permitFrom(pool);
45
+ }
46
+ export async function runBlobTransfer(client, transfer, timeoutMs = TRANSFER_IDLE_TIMEOUT_MS, heldPermit) {
47
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
48
+ throw new RangeError("Blob transfer timeout must be positive and finite");
49
+ const permit = heldPermit ?? (await acquireBlobTransferPermit(client));
19
50
  const controller = new AbortController();
20
51
  let timer;
21
52
  const progress = () => {
@@ -43,11 +74,7 @@ export async function runBlobTransfer(client, transfer, timeoutMs = TRANSFER_IDL
43
74
  }
44
75
  finally {
45
76
  clearTimeout(timer);
46
- const next = pool.waiting.shift();
47
- if (next)
48
- next();
49
- else
50
- pool.active -= 1;
77
+ permit.release();
51
78
  }
52
79
  }
53
80
  //# sourceMappingURL=transferPool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transferPool.js","sourceRoot":"","sources":["transferPool.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAKzC,MAAM,KAAK,GAAG,IAAI,OAAO,EAAwB,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,QAAmE,EACnE,SAAS,GAAG,wBAAwB;IAEpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC;QAC/C,MAAM,IAAI,UAAU,CAAC,mDAAmD,CAAC,CAAC;IAC5E,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAClC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC7C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACnE,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,KAAgD,CAAC;IACrD,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACnC,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,KAAK,GAAG,UAAU,CAChB,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAC5D,SAAS,CACV,CAAC;IACJ,CAAC,CAAC;IACF,QAAQ,EAAE,CAAC;IACX,IAAI,CAAC;QACH,0EAA0E;QAC1E,4EAA4E;QAC5E,OAAO,MAAM,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvD,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,KAAK,OAAO,CAAC,OAAO,EAAE;iBACnB,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;iBACjD,IAAI,CACH,CAAC,KAAK,EAAE,EAAE;gBACR,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACxD,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;gBACjB,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACxD,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CACF,CAAC;QACN,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI;YAAE,IAAI,EAAE,CAAC;;YACZ,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IACxB,CAAC;AACH,CAAC","sourcesContent":["/** Bound byte I/O across documents sharing a client, including multipart parts. */\nexport const BLOB_TRANSFER_CONCURRENCY = 4;\nconst TRANSFER_IDLE_TIMEOUT_MS = 120_000;\ninterface TransferPool {\n active: number;\n waiting: Array<() => void>;\n}\nconst pools = new WeakMap<object, TransferPool>();\n\nexport async function runBlobTransfer<T>(\n client: object,\n transfer: (signal: AbortSignal, progress: () => void) => Promise<T>,\n timeoutMs = TRANSFER_IDLE_TIMEOUT_MS,\n): Promise<T> {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)\n throw new RangeError(\"Blob transfer timeout must be positive and finite\");\n let pool = pools.get(client);\n if (!pool) {\n pool = { active: 0, waiting: [] };\n pools.set(client, pool);\n }\n if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {\n await new Promise<void>((resolve) => pool.waiting.push(resolve));\n } else {\n pool.active += 1;\n }\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const progress = () => {\n controller.signal.throwIfAborted();\n clearTimeout(timer);\n timer = setTimeout(\n () => controller.abort(new Error(\"Blob transfer timed out\")),\n timeoutMs,\n );\n };\n progress();\n try {\n // A native bridge or custom transport may ignore abort. Bound its logical\n // ownership anyway; callers must check the signal before accepting results.\n return await new Promise<T>((resolve, reject) => {\n const aborted = () => reject(controller.signal.reason);\n controller.signal.addEventListener(\"abort\", aborted, { once: true });\n void Promise.resolve()\n .then(() => transfer(controller.signal, progress))\n .then(\n (value) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n resolve(value);\n },\n (error: unknown) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n reject(error);\n },\n );\n });\n } finally {\n clearTimeout(timer);\n const next = pool.waiting.shift();\n if (next) next();\n else pool.active -= 1;\n }\n}\n"]}
1
+ {"version":3,"file":"transferPool.js","sourceRoot":"","sources":["transferPool.ts"],"names":[],"mappings":"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","sourcesContent":["/** Bound byte I/O across documents sharing a client, including multipart parts. */\nexport const BLOB_TRANSFER_CONCURRENCY = 4;\nconst TRANSFER_IDLE_TIMEOUT_MS = 120_000;\ninterface TransferPool {\n active: number;\n waiting: Array<() => void>;\n}\nconst pools = new WeakMap<object, TransferPool>();\n\n/**\n * One slot of a client's transfer pool, held ahead of its transfer by bytes\n * that must exist before the transfer can start (a multipart stage's first\n * parts are encrypted to describe them). Releasing is idempotent.\n */\nexport interface BlobTransferPermit {\n release(): void;\n}\n\nfunction poolFor(client: object): TransferPool {\n let pool = pools.get(client);\n if (!pool) {\n pool = { active: 0, waiting: [] };\n pools.set(client, pool);\n }\n return pool;\n}\n\nfunction permitFrom(pool: TransferPool): BlobTransferPermit {\n let held = true;\n return {\n release() {\n if (!held) return;\n held = false;\n const next = pool.waiting.shift();\n if (next) next();\n else pool.active -= 1;\n },\n };\n}\n\nexport async function acquireBlobTransferPermit(\n client: object,\n): Promise<BlobTransferPermit> {\n const pool = poolFor(client);\n if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {\n await new Promise<void>((resolve) => pool.waiting.push(resolve));\n } else {\n pool.active += 1;\n }\n return permitFrom(pool);\n}\n\n/** A permit only if one is free now; never queues behind other transfers. */\nexport function tryAcquireBlobTransferPermit(\n client: object,\n): BlobTransferPermit | null {\n const pool = poolFor(client);\n if (pool.active >= BLOB_TRANSFER_CONCURRENCY) return null;\n pool.active += 1;\n return permitFrom(pool);\n}\n\nexport async function runBlobTransfer<T>(\n client: object,\n transfer: (signal: AbortSignal, progress: () => void) => Promise<T>,\n timeoutMs = TRANSFER_IDLE_TIMEOUT_MS,\n heldPermit?: BlobTransferPermit,\n): Promise<T> {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)\n throw new RangeError(\"Blob transfer timeout must be positive and finite\");\n const permit = heldPermit ?? (await acquireBlobTransferPermit(client));\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const progress = () => {\n controller.signal.throwIfAborted();\n clearTimeout(timer);\n timer = setTimeout(\n () => controller.abort(new Error(\"Blob transfer timed out\")),\n timeoutMs,\n );\n };\n progress();\n try {\n // A native bridge or custom transport may ignore abort. Bound its logical\n // ownership anyway; callers must check the signal before accepting results.\n return await new Promise<T>((resolve, reject) => {\n const aborted = () => reject(controller.signal.reason);\n controller.signal.addEventListener(\"abort\", aborted, { once: true });\n void Promise.resolve()\n .then(() => transfer(controller.signal, progress))\n .then(\n (value) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n resolve(value);\n },\n (error: unknown) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n reject(error);\n },\n );\n });\n } finally {\n clearTimeout(timer);\n permit.release();\n }\n}\n"]}
@@ -37,6 +37,18 @@ export function getParentCreateContext(parentProjection) {
37
37
  export function asContainerManifestBundle(bundle) {
38
38
  return readCanonicalManifestBundle(bundle, "Container manifest bundle");
39
39
  }
40
+ /**
41
+ * Cite a manifest the server already stores. Mutation requests carry these
42
+ * references instead of echoing the bundles a writer projection served; the
43
+ * server resolves each from its own verified store.
44
+ */
45
+ export function containerManifestRef(bundle) {
46
+ const containerId = Reflect.get(bundle.state, "containerId");
47
+ if (typeof containerId !== "string" || containerId.length === 0) {
48
+ throw new Error("Container manifest is missing a container id");
49
+ }
50
+ return { containerId, manifestHash: bundle.manifestHash };
51
+ }
40
52
  export function readContainerState(bundle) {
41
53
  return readContainerAccessManifestState(bundle.state, "Container manifest state");
42
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"projection.js","sourceRoot":"","sources":["projection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerGrantPrincipalHead,\n type ContainerKekRecipientTarget,\n type ContainerKeyWrap,\n type ContainerUserRecipientKey,\n derivePrincipalRecipientKeyEpochId,\n wrapDekForRecipients,\n} from \"@tearleads/crypto\";\nimport { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport type { AccessManifestBundleWire } from \"@tearleads/validators/request\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readManifestContainerId } from \"../../documents/shared/readers\";\nimport {\n readCanonicalManifestBundle,\n readContainerAccessManifestState,\n} from \"./readers\";\nimport type { ParentContainerCreateContext } from \"./types\";\n\nexport function uniqueSortedManifestHashes(\n path: readonly ContainerWriterProjectionResponse[\"path\"][number][],\n): string[] {\n return [...new Set(path.map((bundle) => bundle.manifestHash))].sort();\n}\n\ninterface LeafContainerContextErrors {\n readonly emptyProjection: string;\n readonly inconsistentKek: string;\n readonly inconsistentPath: string;\n readonly inconsistentTarget: string;\n readonly staleKek: string;\n}\n\nfunction getLeafContainerContext(\n projection: ContainerWriterProjectionResponse,\n errors: LeafContainerContextErrors,\n): ParentContainerCreateContext {\n if (projection.path.length !== projection.containerKeks.length) {\n throw new Error(errors.inconsistentPath);\n }\n\n const manifest = projection.path.at(-1);\n const kek = projection.containerKeks.at(-1);\n if (!manifest || !kek) {\n throw new Error(errors.emptyProjection);\n }\n if (readManifestContainerId(manifest) !== projection.containerId) {\n throw new Error(errors.inconsistentTarget);\n }\n if (kek.containerId !== projection.containerId) {\n throw new Error(errors.inconsistentKek);\n }\n if (kek.accessManifestHash !== manifest.manifestHash) {\n throw new Error(errors.staleKek);\n }\n\n return { manifest, kek };\n}\n\nexport function getParentCreateContext(\n parentProjection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(parentProjection, {\n emptyProjection: \"Container parent projection is empty\",\n inconsistentKek: \"Container parent KEK target is inconsistent\",\n inconsistentPath:\n \"Container parent projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container parent projection target is inconsistent\",\n staleKek: \"Container parent KEK is stale\",\n });\n}\n\nexport function asContainerManifestBundle(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): AccessManifestBundleWire {\n return readCanonicalManifestBundle(bundle, \"Container manifest bundle\");\n}\n\nexport function readContainerState(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): ReturnType<typeof readContainerAccessManifestState> {\n return readContainerAccessManifestState(\n bundle.state,\n \"Container manifest state\",\n );\n}\n\nexport function getTargetContainerContext(\n projection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(projection, {\n emptyProjection: \"Container projection is empty\",\n inconsistentKek: \"Container target KEK is inconsistent\",\n inconsistentPath: \"Container projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container projection target is inconsistent\",\n staleKek: \"Container target KEK is stale\",\n });\n}\n\nexport function getParentKekForTarget(\n projection: ContainerWriterProjectionResponse,\n): ContainerKekResponse | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parentKek = projection.containerKeks.at(-2);\n if (!parentKek || parentKek.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent KEK is unavailable\");\n }\n\n return parentKek;\n}\n\nexport async function wrapContainerKeyToParent(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n parentKek: ContainerKekResponse;\n parentPublicKey: string;\n}): Promise<ContainerKeyWrap> {\n const [wrapped] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.parentPublicKey),\n ]);\n if (!wrapped) throw new Error(\"Container parent wrap is unavailable\");\n\n return {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"container\",\n recipientId: input.parentKek.containerId,\n recipientKeyEpochId: input.parentKek.containerKeyEpochId,\n recipientKeyFingerprint: input.parentKek.keyEpochHash,\n kemCipherText: bytesToBase64(wrapped.kemCipherText),\n wrappedKey: bytesToBase64(wrapped.wrappedKey),\n wrapManifestHash: input.manifestHash,\n };\n}\n\nexport async function wrapContainerKeyToRootUser(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n recipientEncapsulationPublicKey: Uint8Array;\n userId: string;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n userRecipientKey: ContainerUserRecipientKey;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n input.recipientEncapsulationPublicKey,\n ]);\n if (!recipient) {\n throw new Error(\"Container root recipient wrap is unavailable\");\n }\n\n const userRecipientKey: ContainerUserRecipientKey = {\n userId: input.userId,\n recipientKeyEpochId: `user:${input.userId}:encapsulation:${recipient.keyFingerprint}`,\n recipientKeyFingerprint: recipient.keyFingerprint,\n };\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n };\n\n return {\n recipientTarget,\n userRecipientKey,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport async function wrapContainerKeyToManagedPrincipal(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n principalEncapsulationPublicKey: string;\n principalHead: ContainerGrantPrincipalHead;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.principalEncapsulationPublicKey),\n ]);\n if (!recipient) {\n throw new Error(\n \"Container managed principal recipient wrap is unavailable\",\n );\n }\n\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: input.principalHead.principalType,\n recipientId: input.principalHead.principalId,\n recipientKeyEpochId: derivePrincipalRecipientKeyEpochId(\n input.principalHead,\n ),\n recipientKeyFingerprint: input.principalHead.keyFingerprint,\n };\n\n return {\n recipientTarget,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: recipientTarget.recipientKind,\n recipientId: recipientTarget.recipientId,\n recipientKeyEpochId: recipientTarget.recipientKeyEpochId,\n recipientKeyFingerprint: recipientTarget.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport function getParentWrappingPublicKey(\n projection: ContainerWriterProjectionResponse,\n): string | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parent = projection.path.at(-2);\n if (!parent) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const parentState = readContainerState(parent);\n if (parentState.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const publicKey = parentState.containerKeyPublicKey;\n if (!publicKey)\n throw new Error(\"Container parent wrapping public key is missing\");\n return publicKey;\n}\n"]}
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["projection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerGrantPrincipalHead,\n type ContainerKekRecipientTarget,\n type ContainerKeyWrap,\n type ContainerUserRecipientKey,\n derivePrincipalRecipientKeyEpochId,\n wrapDekForRecipients,\n} from \"@tearleads/crypto\";\nimport { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport type {\n AccessManifestBundleWire,\n ContainerManifestRef,\n} from \"@tearleads/validators/request\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { readManifestContainerId } from \"../../documents/shared/readers\";\nimport {\n readCanonicalManifestBundle,\n readContainerAccessManifestState,\n} from \"./readers\";\nimport type { ParentContainerCreateContext } from \"./types\";\n\nexport function uniqueSortedManifestHashes(\n path: readonly ContainerWriterProjectionResponse[\"path\"][number][],\n): string[] {\n return [...new Set(path.map((bundle) => bundle.manifestHash))].sort();\n}\n\ninterface LeafContainerContextErrors {\n readonly emptyProjection: string;\n readonly inconsistentKek: string;\n readonly inconsistentPath: string;\n readonly inconsistentTarget: string;\n readonly staleKek: string;\n}\n\nfunction getLeafContainerContext(\n projection: ContainerWriterProjectionResponse,\n errors: LeafContainerContextErrors,\n): ParentContainerCreateContext {\n if (projection.path.length !== projection.containerKeks.length) {\n throw new Error(errors.inconsistentPath);\n }\n\n const manifest = projection.path.at(-1);\n const kek = projection.containerKeks.at(-1);\n if (!manifest || !kek) {\n throw new Error(errors.emptyProjection);\n }\n if (readManifestContainerId(manifest) !== projection.containerId) {\n throw new Error(errors.inconsistentTarget);\n }\n if (kek.containerId !== projection.containerId) {\n throw new Error(errors.inconsistentKek);\n }\n if (kek.accessManifestHash !== manifest.manifestHash) {\n throw new Error(errors.staleKek);\n }\n\n return { manifest, kek };\n}\n\nexport function getParentCreateContext(\n parentProjection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(parentProjection, {\n emptyProjection: \"Container parent projection is empty\",\n inconsistentKek: \"Container parent KEK target is inconsistent\",\n inconsistentPath:\n \"Container parent projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container parent projection target is inconsistent\",\n staleKek: \"Container parent KEK is stale\",\n });\n}\n\nexport function asContainerManifestBundle(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): AccessManifestBundleWire {\n return readCanonicalManifestBundle(bundle, \"Container manifest bundle\");\n}\n\n/**\n * Cite a manifest the server already stores. Mutation requests carry these\n * references instead of echoing the bundles a writer projection served; the\n * server resolves each from its own verified store.\n */\nexport function containerManifestRef(bundle: {\n readonly manifestHash: string;\n readonly state: Record<string, unknown>;\n}): ContainerManifestRef {\n const containerId = Reflect.get(bundle.state, \"containerId\");\n if (typeof containerId !== \"string\" || containerId.length === 0) {\n throw new Error(\"Container manifest is missing a container id\");\n }\n return { containerId, manifestHash: bundle.manifestHash };\n}\n\nexport function readContainerState(\n bundle: ContainerWriterProjectionResponse[\"path\"][number],\n): ReturnType<typeof readContainerAccessManifestState> {\n return readContainerAccessManifestState(\n bundle.state,\n \"Container manifest state\",\n );\n}\n\nexport function getTargetContainerContext(\n projection: ContainerWriterProjectionResponse,\n): ParentContainerCreateContext {\n return getLeafContainerContext(projection, {\n emptyProjection: \"Container projection is empty\",\n inconsistentKek: \"Container target KEK is inconsistent\",\n inconsistentPath: \"Container projection path and KEKs are inconsistent\",\n inconsistentTarget: \"Container projection target is inconsistent\",\n staleKek: \"Container target KEK is stale\",\n });\n}\n\nexport function getParentKekForTarget(\n projection: ContainerWriterProjectionResponse,\n): ContainerKekResponse | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parentKek = projection.containerKeks.at(-2);\n if (!parentKek || parentKek.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent KEK is unavailable\");\n }\n\n return parentKek;\n}\n\nexport async function wrapContainerKeyToParent(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n parentKek: ContainerKekResponse;\n parentPublicKey: string;\n}): Promise<ContainerKeyWrap> {\n const [wrapped] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.parentPublicKey),\n ]);\n if (!wrapped) throw new Error(\"Container parent wrap is unavailable\");\n\n return {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"container\",\n recipientId: input.parentKek.containerId,\n recipientKeyEpochId: input.parentKek.containerKeyEpochId,\n recipientKeyFingerprint: input.parentKek.keyEpochHash,\n kemCipherText: bytesToBase64(wrapped.kemCipherText),\n wrappedKey: bytesToBase64(wrapped.wrappedKey),\n wrapManifestHash: input.manifestHash,\n };\n}\n\nexport async function wrapContainerKeyToRootUser(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n recipientEncapsulationPublicKey: Uint8Array;\n userId: string;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n userRecipientKey: ContainerUserRecipientKey;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n input.recipientEncapsulationPublicKey,\n ]);\n if (!recipient) {\n throw new Error(\"Container root recipient wrap is unavailable\");\n }\n\n const userRecipientKey: ContainerUserRecipientKey = {\n userId: input.userId,\n recipientKeyEpochId: `user:${input.userId}:encapsulation:${recipient.keyFingerprint}`,\n recipientKeyFingerprint: recipient.keyFingerprint,\n };\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n };\n\n return {\n recipientTarget,\n userRecipientKey,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: \"user\",\n recipientId: input.userId,\n recipientKeyEpochId: userRecipientKey.recipientKeyEpochId,\n recipientKeyFingerprint: userRecipientKey.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport async function wrapContainerKeyToManagedPrincipal(input: {\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n principalEncapsulationPublicKey: string;\n principalHead: ContainerGrantPrincipalHead;\n}): Promise<{\n recipientTarget: ContainerKekRecipientTarget;\n wrap: ContainerKeyWrap;\n}> {\n const [recipient] = await wrapDekForRecipients(input.containerKey, [\n base64ToBytes(input.principalEncapsulationPublicKey),\n ]);\n if (!recipient) {\n throw new Error(\n \"Container managed principal recipient wrap is unavailable\",\n );\n }\n\n const recipientTarget: ContainerKekRecipientTarget = {\n recipientKind: input.principalHead.principalType,\n recipientId: input.principalHead.principalId,\n recipientKeyEpochId: derivePrincipalRecipientKeyEpochId(\n input.principalHead,\n ),\n recipientKeyFingerprint: input.principalHead.keyFingerprint,\n };\n\n return {\n recipientTarget,\n wrap: {\n containerKeyEpochId: input.containerKeyEpochId,\n recipientKind: recipientTarget.recipientKind,\n recipientId: recipientTarget.recipientId,\n recipientKeyEpochId: recipientTarget.recipientKeyEpochId,\n recipientKeyFingerprint: recipientTarget.recipientKeyFingerprint,\n kemCipherText: bytesToBase64(recipient.kemCipherText),\n wrappedKey: bytesToBase64(recipient.wrappedKey),\n wrapManifestHash: input.manifestHash,\n },\n };\n}\n\nexport function getParentWrappingPublicKey(\n projection: ContainerWriterProjectionResponse,\n): string | null {\n const targetState = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n if (!targetState.parentContainerId) {\n return null;\n }\n\n const parent = projection.path.at(-2);\n if (!parent) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const parentState = readContainerState(parent);\n if (parentState.containerId !== targetState.parentContainerId) {\n throw new Error(\"Container parent wrapping public key is unavailable\");\n }\n const publicKey = parentState.containerKeyPublicKey;\n if (!publicKey)\n throw new Error(\"Container parent wrapping public key is missing\");\n return publicKey;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import type { RequestFailureKind, RequestResultOptions, UploadMultipartBlobPartBytesRequest } from "../../../../internal/api-client/index.js";
2
2
  import type { BlobContentKeyTarget, BlobEnvelopeHeaderRecord, BlobEnvelopeRecord, WriteHeader } from "../../../../internal/crypto/index.js";
3
- import type { BlobAttachmentBindRequest, BlobAttachmentDetachRequest, BlobContentKeyBundleRequest, CompleteMultipartBlobStageRequest, InitiateMultipartBlobStageRequest } from "../../../../internal/validators/request/index.js";
4
- import type { BlobAttachmentBindResponse, BlobAttachmentDetachResponse, BlobAttachmentSummary, CompleteMultipartBlobStageResponse, DocumentWriterProjectionResponse, InitiateMultipartBlobStageResponse, MultipartBlobStageStatusResponse, UploadMultipartBlobPartResponse } from "../../../../internal/validators/response/index.js";
3
+ import type { BlobAttachmentBindRequest, BlobAttachmentDetachRequest, BlobContentKeyBundleRequest, InitiateMultipartBlobStageRequest } from "../../../../internal/validators/request/index.js";
4
+ import type { BlobAttachmentBindResponse, BlobAttachmentDetachResponse, BlobAttachmentSummary, DocumentWriterProjectionResponse, InitiateMultipartBlobStageResponse, MultipartBlobStageStatusResponse, UploadMultipartBlobPartResponse } from "../../../../internal/validators/response/index.js";
5
5
  import type { BlobByteSourceInput, BlobBytes } from "../../../blobContracts.js";
6
6
  import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../../keyingProjectionVerification.js";
7
7
  import type { ExecSql } from "../../../sqlite/sqlSchema.js";
@@ -27,7 +27,6 @@ export interface BlobAttachmentApi {
27
27
  readonly message: string;
28
28
  readonly status: number | null;
29
29
  } | null;
30
- completeMultipartBlobStage(stageId: string, input: CompleteMultipartBlobStageRequest): Promise<CompleteMultipartBlobStageResponse | null>;
31
30
  getDocumentWriterProjection(documentId: string): Promise<DocumentWriterProjectionResponse | null>;
32
31
  getMultipartBlobStage(stageId: string): Promise<MultipartBlobStageStatusResponse | null>;
33
32
  initiateMultipartBlobStage(input: InitiateMultipartBlobStageRequest): Promise<InitiateMultipartBlobStageResponse | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAoCA,MAAM,CAAC,MAAM,mCAAmC,GAC9C,wCAAwC,CAAC;AAC3C,MAAM,CAAC,MAAM,8BAA8B,GACzC,mCAAmC,CAAC;AACtC,MAAM,CAAC,MAAM,gCAAgC,GAC3C,qCAAqC,CAAC;AACxC,MAAM,CAAC,MAAM,6BAA6B,GACxC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,yCAAyC,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC","sourcesContent":["import type {\n RequestFailureKind,\n RequestResultOptions,\n UploadMultipartBlobPartBytesRequest,\n} from \"@tearleads/api-client\";\nimport type {\n BlobContentKeyTarget,\n BlobEnvelopeHeaderRecord,\n BlobEnvelopeRecord,\n WriteHeader,\n} from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentBindRequest,\n BlobAttachmentDetachRequest,\n BlobContentKeyBundleRequest,\n CompleteMultipartBlobStageRequest,\n InitiateMultipartBlobStageRequest,\n} from \"@tearleads/validators/request\";\nimport type {\n BlobAttachmentBindResponse,\n BlobAttachmentDetachResponse,\n BlobAttachmentSummary,\n CompleteMultipartBlobStageResponse,\n DocumentWriterProjectionResponse,\n InitiateMultipartBlobStageResponse,\n MultipartBlobStageStatusResponse,\n UploadMultipartBlobPartResponse,\n} from \"@tearleads/validators/response\";\nimport type { BlobByteSourceInput, BlobBytes } from \"../../../blobContracts\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentCreateAuthor } from \"../../shared/types\";\n\nexport const BLOB_CONTENT_RECORD_KEY_INFO_DOMAIN =\n \"tearleads.blob.content-record-key-info\";\nexport const BLOB_CONTENT_RECORD_AAD_DOMAIN =\n \"tearleads.blob.content-record-aad\";\nexport const BLOB_CONTENT_RECORD_NONCE_DOMAIN =\n \"tearleads.blob.content-record-nonce\";\nexport const BLOB_CONTENT_RECORD_HKDF_SALT: Uint8Array<ArrayBuffer> =\n new TextEncoder().encode(\"tearleads.blob.content-record-hkdf-salt\");\nexport const TEXT_ENCODER = new TextEncoder();\n\nexport interface BlobAttachmentRequestOptions {\n readonly expectedPaymentRequiredOrganizationId?: string | undefined;\n}\n\nexport interface BlobAttachmentApi {\n bindBlobAttachment(\n blobId: string,\n input: BlobAttachmentBindRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentBindResponse | null>;\n clearWriterProjectionCaches?(): void;\n evictDocumentWriterProjection?(documentId: string): void;\n getRequestFailure?(input: {\n method: \"DELETE\" | \"GET\" | \"POST\" | \"PUT\";\n path: string;\n }): {\n readonly code?: string | undefined;\n readonly kind: RequestFailureKind;\n readonly message: string;\n readonly status: number | null;\n } | null;\n completeMultipartBlobStage(\n stageId: string,\n input: CompleteMultipartBlobStageRequest,\n ): Promise<CompleteMultipartBlobStageResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n getMultipartBlobStage(\n stageId: string,\n ): Promise<MultipartBlobStageStatusResponse | null>;\n initiateMultipartBlobStage(\n input: InitiateMultipartBlobStageRequest,\n ): Promise<InitiateMultipartBlobStageResponse | null>;\n uploadMultipartBlobPartBytes(\n stageId: string,\n partNumber: number,\n input: UploadMultipartBlobPartBytesRequest,\n options?: RequestResultOptions,\n ): Promise<UploadMultipartBlobPartResponse | null>;\n}\n\nexport interface BlobAttachmentDetachApi {\n detachBlobAttachment(\n blobId: string,\n bindingId: string,\n input: BlobAttachmentDetachRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentDetachResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n}\n\nexport type { BlobContentKeyTarget };\n\n/**\n * Aliases of the crypto parser's own types. The parser is shared with the API,\n * so restating these shapes here would let the two drift apart silently.\n */\nexport type BlobEncryptedBytesRecord = BlobEnvelopeRecord;\n\n/**\n * The envelope as the header establishes it. Streaming readers hold this\n * before any ciphertext is read, so it has no `chunks`: an empty array there\n * would read as an empty object rather than an unread one.\n */\nexport type BlobEncryptedBytesHeader = BlobEnvelopeHeaderRecord;\n\nexport type BlobEncryptedChunk = BlobEnvelopeRecord[\"chunks\"][number];\n\nexport interface BlobSourceSnapshot {\n readonly byteLength: number;\n readonly chunkSha256: readonly string[];\n readonly chunkSize: number;\n readonly sha256: string;\n}\n\nexport interface BlobEncryptionPlan {\n readonly byteLength: number;\n readonly chunkSize: number;\n readonly metadataHash: string;\n readonly partCount: number;\n readonly plaintextByteLength: number;\n readonly plaintextSha256: string;\n readonly sha256: string;\n encryptPart(index: number): Promise<BlobBytes>;\n getPartByteLength(index: number): number;\n}\n\nexport interface DocumentManifestIdentity {\n documentId: string;\n manifestHash: string;\n organizationId: string;\n}\n\nexport interface BlobAttachmentMaterial {\n blobAccessManifestHash: string;\n contentKeyBundle: BlobContentKeyBundleRequest;\n encrypted: BlobEncryptionPlan;\n manifestIdentity: DocumentManifestIdentity;\n targetHash: string;\n targets: BlobContentKeyTarget[];\n writerProjection: DocumentWriterProjectionResponse;\n}\n\n/**\n * Progress for an in-flight multipart blob upload.\n */\nexport interface MultipartUploadProgress {\n readonly bytesTotal: number;\n readonly bytesUploaded: number;\n readonly partsCompleted: number;\n readonly partsTotal: number;\n}\n\nexport type MultipartUploadProgressListener = (\n progress: MultipartUploadProgress,\n) => void;\n\n/**\n * Fires once a multipart stage has been opened (or resumed), with its id and\n * plaintext chunk size. Callers persist both so a later attempt can reproduce\n * the same encrypted parts and resume instead of orphaning the partial upload.\n */\nexport type MultipartStageResolvedListener = (input: {\n readonly partSize: number;\n readonly stageId: string;\n}) => void | Promise<void>;\n\nexport interface UploadDocumentAttachmentInput {\n apiClient: BlobAttachmentApi;\n author: DocumentCreateAuthor;\n blobId?: string | undefined;\n bindingId?: string | undefined;\n bytes: BlobByteSourceInput;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedBindingId: string | null;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n // A persisted nonce seed. The plaintext digest derives the envelope IV from\n // it, then each chunk derives a unique IV. Same-source retries reproduce the\n // encrypted parts; changed bytes cannot reuse their AES-GCM nonces.\n nonceSeed?: Uint8Array | undefined;\n multipart?: MultipartBlobUploadOptions | undefined;\n onMultipartProgress?: MultipartUploadProgressListener | undefined;\n onStageResolved?: MultipartStageResolvedListener | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface MultipartBlobUploadOptions {\n /** Exactly 5 MiB per plaintext encryption chunk; transport parts include envelope overhead. */\n readonly partSize: number;\n // The id of a previously opened stage to resume. When set, the upload refetches\n // that stage and skips parts the server already has instead of opening a new\n // one; if the stage is gone (expired), it falls back to a fresh stage.\n readonly resumeStageId?: string | undefined;\n readonly uploadConcurrency?: number | undefined;\n}\n\nexport interface UploadDocumentAttachmentResult {\n blobId: string;\n bindingId: string;\n request: BlobAttachmentBindRequest;\n response: BlobAttachmentBindResponse;\n sha256: string;\n byteLength: number;\n writeHeader: WriteHeader;\n writeHeaderHash: string;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DetachDocumentAttachmentInput {\n apiClient: BlobAttachmentDetachApi;\n author: DocumentCreateAuthor;\n bindingId: string;\n blobId: string;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface DetachDocumentAttachmentResult {\n request: BlobAttachmentDetachRequest;\n response: BlobAttachmentDetachResponse;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DecryptDocumentAttachmentBlobInput {\n binding: BlobAttachmentSummary;\n encryptedBytes: BlobBytes;\n expectedDocumentId: string;\n expectedSlotId: string;\n execSql: ExecSql;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n targetSecretKey: Uint8Array;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAkCA,MAAM,CAAC,MAAM,mCAAmC,GAC9C,wCAAwC,CAAC;AAC3C,MAAM,CAAC,MAAM,8BAA8B,GACzC,mCAAmC,CAAC;AACtC,MAAM,CAAC,MAAM,gCAAgC,GAC3C,qCAAqC,CAAC;AACxC,MAAM,CAAC,MAAM,6BAA6B,GACxC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,yCAAyC,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC","sourcesContent":["import type {\n RequestFailureKind,\n RequestResultOptions,\n UploadMultipartBlobPartBytesRequest,\n} from \"@tearleads/api-client\";\nimport type {\n BlobContentKeyTarget,\n BlobEnvelopeHeaderRecord,\n BlobEnvelopeRecord,\n WriteHeader,\n} from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentBindRequest,\n BlobAttachmentDetachRequest,\n BlobContentKeyBundleRequest,\n InitiateMultipartBlobStageRequest,\n} from \"@tearleads/validators/request\";\nimport type {\n BlobAttachmentBindResponse,\n BlobAttachmentDetachResponse,\n BlobAttachmentSummary,\n DocumentWriterProjectionResponse,\n InitiateMultipartBlobStageResponse,\n MultipartBlobStageStatusResponse,\n UploadMultipartBlobPartResponse,\n} from \"@tearleads/validators/response\";\nimport type { BlobByteSourceInput, BlobBytes } from \"../../../blobContracts\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentCreateAuthor } from \"../../shared/types\";\n\nexport const BLOB_CONTENT_RECORD_KEY_INFO_DOMAIN =\n \"tearleads.blob.content-record-key-info\";\nexport const BLOB_CONTENT_RECORD_AAD_DOMAIN =\n \"tearleads.blob.content-record-aad\";\nexport const BLOB_CONTENT_RECORD_NONCE_DOMAIN =\n \"tearleads.blob.content-record-nonce\";\nexport const BLOB_CONTENT_RECORD_HKDF_SALT: Uint8Array<ArrayBuffer> =\n new TextEncoder().encode(\"tearleads.blob.content-record-hkdf-salt\");\nexport const TEXT_ENCODER = new TextEncoder();\n\nexport interface BlobAttachmentRequestOptions {\n readonly expectedPaymentRequiredOrganizationId?: string | undefined;\n}\n\nexport interface BlobAttachmentApi {\n bindBlobAttachment(\n blobId: string,\n input: BlobAttachmentBindRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentBindResponse | null>;\n clearWriterProjectionCaches?(): void;\n evictDocumentWriterProjection?(documentId: string): void;\n getRequestFailure?(input: {\n method: \"DELETE\" | \"GET\" | \"POST\" | \"PUT\";\n path: string;\n }): {\n readonly code?: string | undefined;\n readonly kind: RequestFailureKind;\n readonly message: string;\n readonly status: number | null;\n } | null;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n getMultipartBlobStage(\n stageId: string,\n ): Promise<MultipartBlobStageStatusResponse | null>;\n initiateMultipartBlobStage(\n input: InitiateMultipartBlobStageRequest,\n ): Promise<InitiateMultipartBlobStageResponse | null>;\n uploadMultipartBlobPartBytes(\n stageId: string,\n partNumber: number,\n input: UploadMultipartBlobPartBytesRequest,\n options?: RequestResultOptions,\n ): Promise<UploadMultipartBlobPartResponse | null>;\n}\n\nexport interface BlobAttachmentDetachApi {\n detachBlobAttachment(\n blobId: string,\n bindingId: string,\n input: BlobAttachmentDetachRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentDetachResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n}\n\nexport type { BlobContentKeyTarget };\n\n/**\n * Aliases of the crypto parser's own types. The parser is shared with the API,\n * so restating these shapes here would let the two drift apart silently.\n */\nexport type BlobEncryptedBytesRecord = BlobEnvelopeRecord;\n\n/**\n * The envelope as the header establishes it. Streaming readers hold this\n * before any ciphertext is read, so it has no `chunks`: an empty array there\n * would read as an empty object rather than an unread one.\n */\nexport type BlobEncryptedBytesHeader = BlobEnvelopeHeaderRecord;\n\nexport type BlobEncryptedChunk = BlobEnvelopeRecord[\"chunks\"][number];\n\nexport interface BlobSourceSnapshot {\n readonly byteLength: number;\n readonly chunkSha256: readonly string[];\n readonly chunkSize: number;\n readonly sha256: string;\n}\n\nexport interface BlobEncryptionPlan {\n readonly byteLength: number;\n readonly chunkSize: number;\n readonly metadataHash: string;\n readonly partCount: number;\n readonly plaintextByteLength: number;\n readonly plaintextSha256: string;\n readonly sha256: string;\n encryptPart(index: number): Promise<BlobBytes>;\n getPartByteLength(index: number): number;\n}\n\nexport interface DocumentManifestIdentity {\n documentId: string;\n manifestHash: string;\n organizationId: string;\n}\n\nexport interface BlobAttachmentMaterial {\n blobAccessManifestHash: string;\n contentKeyBundle: BlobContentKeyBundleRequest;\n encrypted: BlobEncryptionPlan;\n manifestIdentity: DocumentManifestIdentity;\n targetHash: string;\n targets: BlobContentKeyTarget[];\n writerProjection: DocumentWriterProjectionResponse;\n}\n\n/**\n * Progress for an in-flight multipart blob upload.\n */\nexport interface MultipartUploadProgress {\n readonly bytesTotal: number;\n readonly bytesUploaded: number;\n readonly partsCompleted: number;\n readonly partsTotal: number;\n}\n\nexport type MultipartUploadProgressListener = (\n progress: MultipartUploadProgress,\n) => void;\n\n/**\n * Fires once a multipart stage has been opened (or resumed), with its id and\n * plaintext chunk size. Callers persist both so a later attempt can reproduce\n * the same encrypted parts and resume instead of orphaning the partial upload.\n */\nexport type MultipartStageResolvedListener = (input: {\n readonly partSize: number;\n readonly stageId: string;\n}) => void | Promise<void>;\n\nexport interface UploadDocumentAttachmentInput {\n apiClient: BlobAttachmentApi;\n author: DocumentCreateAuthor;\n blobId?: string | undefined;\n bindingId?: string | undefined;\n bytes: BlobByteSourceInput;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedBindingId: string | null;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n // A persisted nonce seed. The plaintext digest derives the envelope IV from\n // it, then each chunk derives a unique IV. Same-source retries reproduce the\n // encrypted parts; changed bytes cannot reuse their AES-GCM nonces.\n nonceSeed?: Uint8Array | undefined;\n multipart?: MultipartBlobUploadOptions | undefined;\n onMultipartProgress?: MultipartUploadProgressListener | undefined;\n onStageResolved?: MultipartStageResolvedListener | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface MultipartBlobUploadOptions {\n /** Exactly 5 MiB per plaintext encryption chunk; transport parts include envelope overhead. */\n readonly partSize: number;\n // The id of a previously opened stage to resume. When set, the upload refetches\n // that stage and skips parts the server already has instead of opening a new\n // one; if the stage is gone (expired), it falls back to a fresh stage.\n readonly resumeStageId?: string | undefined;\n readonly uploadConcurrency?: number | undefined;\n}\n\nexport interface UploadDocumentAttachmentResult {\n blobId: string;\n bindingId: string;\n request: BlobAttachmentBindRequest;\n response: BlobAttachmentBindResponse;\n sha256: string;\n byteLength: number;\n writeHeader: WriteHeader;\n writeHeaderHash: string;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DetachDocumentAttachmentInput {\n apiClient: BlobAttachmentDetachApi;\n author: DocumentCreateAuthor;\n bindingId: string;\n blobId: string;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface DetachDocumentAttachmentResult {\n request: BlobAttachmentDetachRequest;\n response: BlobAttachmentDetachResponse;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DecryptDocumentAttachmentBlobInput {\n binding: BlobAttachmentSummary;\n encryptedBytes: BlobBytes;\n expectedDocumentId: string;\n expectedSlotId: string;\n execSql: ExecSql;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n targetSecretKey: Uint8Array;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}\n"]}
@@ -62,7 +62,6 @@ export async function buildDocumentCreatePlan({ author, containerProjection, con
62
62
  body: readCanonicalRecord(body, "Document create body"),
63
63
  expectedManifestHash: manifestHash,
64
64
  manifest: readCanonicalRecord(manifest, "Document create manifest"),
65
- previousManifest: null,
66
65
  targetContainerPathRefs: containerPathRefs(containerProjection.path),
67
66
  contentKeyBundle: {
68
67
  contentKeyEpoch,
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computeAccessEventBodyHash,\n computeAccessEventHash,\n computeAccessManifestHash,\n computeDocumentContentKeyTargetHash,\n type DocumentLinkAccessEventBody,\n type DocumentLinkSetManifestState,\n deriveDocumentLinkSetManifest,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type { ContainerManifestRef } from \"@tearleads/validators/request\";\nimport type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n} from \"../../keyingCanonicalJson\";\nimport {\n authorizingContainerPathRefsForLinkSet,\n containerPathRefs,\n deriveDocumentCreateTargets,\n mergeTargetEnvelopes,\n} from \"./projection\";\nimport { sortDocumentTargets, uniqueSortedStrings } from \"./readers\";\nimport type {\n BuildDocumentCreatePlanInput,\n DocumentCreateAuthor,\n DocumentCreatePlan,\n DocumentLinkSetEventPlan,\n DocumentLinkSetMutationBody,\n DocumentLinkSetMutationOperation,\n DocumentLinkSetTargetState,\n} from \"./types\";\n\nexport async function buildDocumentCreatePlan({\n author,\n containerProjection,\n contentKeyEpoch = 1,\n documentId = crypto.randomUUID(),\n eventId = crypto.randomUUID(),\n signedAt = new Date().toISOString(),\n targetEnvelopes,\n}: BuildDocumentCreatePlanInput): Promise<DocumentCreatePlan> {\n // The document belongs to its container's organization, not the author's. A\n // member authoring a document under another org's shared container creates a\n // document owned by that org; the author supplies only the signer identity.\n const organizationId = containerProjection.organizationId;\n\n const targets = deriveDocumentCreateTargets(containerProjection);\n const targetEnvelopesForRequest = mergeTargetEnvelopes(\n targets,\n targetEnvelopes,\n );\n const targetContainerManifestHash = targets[0]?.containerManifestHash;\n const targetContainerId = targets[0]?.containerId;\n if (!targetContainerManifestHash || !targetContainerId) {\n throw new Error(\"Document create target is unavailable\");\n }\n\n const body: DocumentLinkAccessEventBody = {\n blobRewraps: [],\n eventType: \"document.link\",\n containerId: targetContainerId,\n containerManifestHash: targetContainerManifestHash,\n };\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(body, \"Document create body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId,\n eventType: \"document.link\",\n objectKind: \"document\",\n objectId: documentId,\n organizationId,\n previousManifestHash: null,\n dependencyManifestHashes: uniqueSortedStrings(\n containerProjection.path.map((bundle) => bundle.manifestHash),\n ),\n bodyHash,\n signerUserId: author.signerUserId,\n signerDeviceId: author.signerDeviceId,\n signerKeyFingerprint: author.signerKeyFingerprint,\n signedAt,\n };\n const event = await signAccessEvent(unsignedEvent, author.signerPrivateKey);\n const eventHash = await computeAccessEventHash(event);\n const state: DocumentLinkSetManifestState = {\n version: 1,\n documentId,\n organizationId,\n epoch: 1,\n previousManifestHash: null,\n eventHash,\n linkedContainerIds: [targetContainerId],\n };\n const manifest = await deriveDocumentLinkSetManifest(state);\n const manifestHash = await computeAccessManifestHash(manifest);\n const targetHash = await computeDocumentContentKeyTargetHash(targets);\n\n return {\n body,\n documentId,\n event,\n eventHash,\n manifest,\n manifestHash,\n request: {\n event: readCanonicalRecord(event, \"Document create event\"),\n body: readCanonicalRecord(body, \"Document create body\"),\n expectedManifestHash: manifestHash,\n manifest: readCanonicalRecord(manifest, \"Document create manifest\"),\n previousManifest: null,\n targetContainerPathRefs: containerPathRefs(containerProjection.path),\n contentKeyBundle: {\n contentKeyEpoch,\n linkSetManifestHash: manifestHash,\n targetHash,\n targets: targetEnvelopesForRequest,\n },\n },\n state,\n targetHash,\n targets: sortDocumentTargets(targets),\n };\n}\n\nexport async function buildDocumentLinkSetEventPlan(input: {\n blobRewraps: DocumentLinkAccessEventBody[\"blobRewraps\"];\n author: DocumentCreateAuthor;\n eventId: string;\n operation: DocumentLinkSetMutationOperation;\n // The document's existing organization (from its manifest). Link/unlink does\n // not change ownership, so the event keeps the document's org, which is the\n // container's org — never the acting member's personal org.\n organizationId: string;\n signedAt: string;\n targetContainerPathRefs: readonly ContainerManifestRef[];\n targetState: DocumentLinkSetTargetState;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<DocumentLinkSetEventPlan> {\n const eventType =\n input.operation === \"link\" ? \"document.link\" : \"document.unlink\";\n const body: DocumentLinkSetMutationBody = {\n blobRewraps: input.blobRewraps,\n eventType,\n containerId: input.targetState.target.containerId,\n containerManifestHash: input.targetState.target.containerManifestHash,\n };\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(body, \"Document link-set body\"),\n );\n const authorizingContainerPathRefs = authorizingContainerPathRefsForLinkSet({\n operation: input.operation,\n targetContainerId: input.targetState.target.containerId,\n writerProjection: input.writerProjection,\n });\n const dependencyManifestHashes = uniqueSortedStrings(\n [\n ...input.targetContainerPathRefs,\n ...authorizingContainerPathRefs.flat(),\n ].map((ref) => ref.manifestHash),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType,\n objectKind: \"document\",\n objectId: input.writerProjection.documentId,\n organizationId: input.organizationId,\n previousManifestHash: input.writerProjection.documentManifest.manifestHash,\n dependencyManifestHashes,\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 const eventHash = await computeAccessEventHash(event);\n\n return {\n authorizingContainerPathRefs,\n body,\n event,\n eventHash,\n };\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computeAccessEventBodyHash,\n computeAccessEventHash,\n computeAccessManifestHash,\n computeDocumentContentKeyTargetHash,\n type DocumentLinkAccessEventBody,\n type DocumentLinkSetManifestState,\n deriveDocumentLinkSetManifest,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type { ContainerManifestRef } from \"@tearleads/validators/request\";\nimport type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n} from \"../../keyingCanonicalJson\";\nimport {\n authorizingContainerPathRefsForLinkSet,\n containerPathRefs,\n deriveDocumentCreateTargets,\n mergeTargetEnvelopes,\n} from \"./projection\";\nimport { sortDocumentTargets, uniqueSortedStrings } from \"./readers\";\nimport type {\n BuildDocumentCreatePlanInput,\n DocumentCreateAuthor,\n DocumentCreatePlan,\n DocumentLinkSetEventPlan,\n DocumentLinkSetMutationBody,\n DocumentLinkSetMutationOperation,\n DocumentLinkSetTargetState,\n} from \"./types\";\n\nexport async function buildDocumentCreatePlan({\n author,\n containerProjection,\n contentKeyEpoch = 1,\n documentId = crypto.randomUUID(),\n eventId = crypto.randomUUID(),\n signedAt = new Date().toISOString(),\n targetEnvelopes,\n}: BuildDocumentCreatePlanInput): Promise<DocumentCreatePlan> {\n // The document belongs to its container's organization, not the author's. A\n // member authoring a document under another org's shared container creates a\n // document owned by that org; the author supplies only the signer identity.\n const organizationId = containerProjection.organizationId;\n\n const targets = deriveDocumentCreateTargets(containerProjection);\n const targetEnvelopesForRequest = mergeTargetEnvelopes(\n targets,\n targetEnvelopes,\n );\n const targetContainerManifestHash = targets[0]?.containerManifestHash;\n const targetContainerId = targets[0]?.containerId;\n if (!targetContainerManifestHash || !targetContainerId) {\n throw new Error(\"Document create target is unavailable\");\n }\n\n const body: DocumentLinkAccessEventBody = {\n blobRewraps: [],\n eventType: \"document.link\",\n containerId: targetContainerId,\n containerManifestHash: targetContainerManifestHash,\n };\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(body, \"Document create body\"),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId,\n eventType: \"document.link\",\n objectKind: \"document\",\n objectId: documentId,\n organizationId,\n previousManifestHash: null,\n dependencyManifestHashes: uniqueSortedStrings(\n containerProjection.path.map((bundle) => bundle.manifestHash),\n ),\n bodyHash,\n signerUserId: author.signerUserId,\n signerDeviceId: author.signerDeviceId,\n signerKeyFingerprint: author.signerKeyFingerprint,\n signedAt,\n };\n const event = await signAccessEvent(unsignedEvent, author.signerPrivateKey);\n const eventHash = await computeAccessEventHash(event);\n const state: DocumentLinkSetManifestState = {\n version: 1,\n documentId,\n organizationId,\n epoch: 1,\n previousManifestHash: null,\n eventHash,\n linkedContainerIds: [targetContainerId],\n };\n const manifest = await deriveDocumentLinkSetManifest(state);\n const manifestHash = await computeAccessManifestHash(manifest);\n const targetHash = await computeDocumentContentKeyTargetHash(targets);\n\n return {\n body,\n documentId,\n event,\n eventHash,\n manifest,\n manifestHash,\n request: {\n event: readCanonicalRecord(event, \"Document create event\"),\n body: readCanonicalRecord(body, \"Document create body\"),\n expectedManifestHash: manifestHash,\n manifest: readCanonicalRecord(manifest, \"Document create manifest\"),\n targetContainerPathRefs: containerPathRefs(containerProjection.path),\n contentKeyBundle: {\n contentKeyEpoch,\n linkSetManifestHash: manifestHash,\n targetHash,\n targets: targetEnvelopesForRequest,\n },\n },\n state,\n targetHash,\n targets: sortDocumentTargets(targets),\n };\n}\n\nexport async function buildDocumentLinkSetEventPlan(input: {\n blobRewraps: DocumentLinkAccessEventBody[\"blobRewraps\"];\n author: DocumentCreateAuthor;\n eventId: string;\n operation: DocumentLinkSetMutationOperation;\n // The document's existing organization (from its manifest). Link/unlink does\n // not change ownership, so the event keeps the document's org, which is the\n // container's org — never the acting member's personal org.\n organizationId: string;\n signedAt: string;\n targetContainerPathRefs: readonly ContainerManifestRef[];\n targetState: DocumentLinkSetTargetState;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<DocumentLinkSetEventPlan> {\n const eventType =\n input.operation === \"link\" ? \"document.link\" : \"document.unlink\";\n const body: DocumentLinkSetMutationBody = {\n blobRewraps: input.blobRewraps,\n eventType,\n containerId: input.targetState.target.containerId,\n containerManifestHash: input.targetState.target.containerManifestHash,\n };\n const bodyHash = await computeAccessEventBodyHash(\n readCanonicalJson(body, \"Document link-set body\"),\n );\n const authorizingContainerPathRefs = authorizingContainerPathRefsForLinkSet({\n operation: input.operation,\n targetContainerId: input.targetState.target.containerId,\n writerProjection: input.writerProjection,\n });\n const dependencyManifestHashes = uniqueSortedStrings(\n [\n ...input.targetContainerPathRefs,\n ...authorizingContainerPathRefs.flat(),\n ].map((ref) => ref.manifestHash),\n );\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId,\n eventType,\n objectKind: \"document\",\n objectId: input.writerProjection.documentId,\n organizationId: input.organizationId,\n previousManifestHash: input.writerProjection.documentManifest.manifestHash,\n dependencyManifestHashes,\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 const eventHash = await computeAccessEventHash(event);\n\n return {\n authorizingContainerPathRefs,\n body,\n event,\n eventHash,\n };\n}\n"]}
@@ -43,6 +43,7 @@ export async function validateAccessManifestCheckpoints(input) {
43
43
  policies: input.policies,
44
44
  authorizationPolicies: input.authorizationPolicies,
45
45
  stillCurrent: input.stillCurrent,
46
+ verifiedBundles: input.verifiedBundles,
46
47
  });
47
48
  }
48
49
  export async function enforceAccessManifestCheckpoints(input) {
@@ -54,6 +55,7 @@ export async function enforceAccessManifestCheckpoints(input) {
54
55
  policies: input.policies,
55
56
  authorizationPolicies: input.authorizationPolicies,
56
57
  stillCurrent: input.stillCurrent,
58
+ verifiedBundles: input.verifiedBundles,
57
59
  });
58
60
  }
59
61
  //# sourceMappingURL=accessManifestCheckpointEnforcement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"accessManifestCheckpointEnforcement.js","sourceRoot":"","sources":["accessManifestCheckpointEnforcement.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedAccessManifestCheckpointEvidence,\n type VerifiedPrincipalPolicySelection,\n} from \"@tearleads/crypto\";\nimport type { DocumentPurgeCheckpoint } from \"../persistence/documentPurgeCheckpointPersistence\";\nimport {\n type AccessManifestCheckpointAdvance,\n advanceKeyingCheckpointsAtomically,\n validateKeyingCheckpointsAtomically,\n} from \"../persistence/keyingCheckpointAdvancePersistence\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../principals/principalPolicyEvidence\";\nimport type { ExecSql } from \"../sqlite/sqlSchema\";\n\nfunction objectKey(manifest: VerifiedAccessManifestCheckpointEvidence): string {\n const { objectKind, organizationId, objectId } = manifest.checkpoint;\n return JSON.stringify([objectKind, organizationId, objectId]);\n}\n\nfunction manifestsByObject(\n manifests: readonly VerifiedAccessManifestCheckpointEvidence[],\n): Map<string, Map<string, VerifiedAccessManifestCheckpointEvidence>> {\n const byObject = new Map<\n string,\n Map<string, VerifiedAccessManifestCheckpointEvidence>\n >();\n for (const manifest of manifests) {\n const key = objectKey(manifest);\n let byHash = byObject.get(key);\n if (!byHash) {\n byHash = new Map();\n byObject.set(key, byHash);\n }\n byHash.set(manifest.manifestHash, manifest);\n }\n return byObject;\n}\n\nfunction accessManifestCheckpointAdvances(input: {\n readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];\n readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];\n}): AccessManifestCheckpointAdvance[] {\n const evidenceByObject = manifestsByObject(input.verifiedManifests);\n const headsByObject = manifestsByObject(input.verifiedHeads);\n const advances: AccessManifestCheckpointAdvance[] = [];\n\n for (const [key, headsByHash] of headsByObject) {\n if (headsByHash.size !== 1) {\n throw new KeyingVerificationError(\n \"equivocation\",\n `projection declares conflicting access manifest heads for ${key}`,\n );\n }\n const head = headsByHash.values().next().value;\n if (!head) {\n continue;\n }\n const predecessors = [\n ...(evidenceByObject.get(key)?.values() ?? []),\n ].filter((manifest) => manifest.manifestHash !== head.manifestHash);\n advances.push({ head, predecessors });\n }\n\n return advances;\n}\n\nexport async function validateAccessManifestCheckpoints(input: {\n readonly execSql: ExecSql;\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n readonly authorizationPolicies?:\n | readonly VerifiedPrincipalPolicySelection[]\n | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];\n readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];\n}): Promise<void> {\n await validateKeyingCheckpointsAtomically({\n access: accessManifestCheckpointAdvances(input),\n execSql: input.execSql,\n policies: input.policies,\n authorizationPolicies: input.authorizationPolicies,\n stillCurrent: input.stillCurrent,\n });\n}\n\nexport async function enforceAccessManifestCheckpoints(input: {\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly documentPurgeCheckpoint?: DocumentPurgeCheckpoint | undefined;\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n readonly authorizationPolicies?:\n | readonly VerifiedPrincipalPolicySelection[]\n | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];\n readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];\n}): Promise<void> {\n await advanceKeyingCheckpointsAtomically({\n access: accessManifestCheckpointAdvances(input),\n documentPurgeCheckpoint: input.documentPurgeCheckpoint,\n execSql: input.execSql,\n organizationId: input.organizationId,\n policies: input.policies,\n authorizationPolicies: input.authorizationPolicies,\n stillCurrent: input.stillCurrent,\n });\n}\n"]}
1
+ {"version":3,"file":"accessManifestCheckpointEnforcement.js","sourceRoot":"","sources":["accessManifestCheckpointEnforcement.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedAccessManifestCheckpointEvidence,\n type VerifiedPrincipalPolicySelection,\n} from \"@tearleads/crypto\";\nimport type { DocumentPurgeCheckpoint } from \"../persistence/documentPurgeCheckpointPersistence\";\nimport {\n type AccessManifestCheckpointAdvance,\n advanceKeyingCheckpointsAtomically,\n validateKeyingCheckpointsAtomically,\n} from \"../persistence/keyingCheckpointAdvancePersistence\";\nimport type { VerifiedManifestBundle } from \"../persistence/verifiedManifestBundlePersistence\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../principals/principalPolicyEvidence\";\nimport type { ExecSql } from \"../sqlite/sqlSchema\";\n\nfunction objectKey(manifest: VerifiedAccessManifestCheckpointEvidence): string {\n const { objectKind, organizationId, objectId } = manifest.checkpoint;\n return JSON.stringify([objectKind, organizationId, objectId]);\n}\n\nfunction manifestsByObject(\n manifests: readonly VerifiedAccessManifestCheckpointEvidence[],\n): Map<string, Map<string, VerifiedAccessManifestCheckpointEvidence>> {\n const byObject = new Map<\n string,\n Map<string, VerifiedAccessManifestCheckpointEvidence>\n >();\n for (const manifest of manifests) {\n const key = objectKey(manifest);\n let byHash = byObject.get(key);\n if (!byHash) {\n byHash = new Map();\n byObject.set(key, byHash);\n }\n byHash.set(manifest.manifestHash, manifest);\n }\n return byObject;\n}\n\nfunction accessManifestCheckpointAdvances(input: {\n readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];\n readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];\n}): AccessManifestCheckpointAdvance[] {\n const evidenceByObject = manifestsByObject(input.verifiedManifests);\n const headsByObject = manifestsByObject(input.verifiedHeads);\n const advances: AccessManifestCheckpointAdvance[] = [];\n\n for (const [key, headsByHash] of headsByObject) {\n if (headsByHash.size !== 1) {\n throw new KeyingVerificationError(\n \"equivocation\",\n `projection declares conflicting access manifest heads for ${key}`,\n );\n }\n const head = headsByHash.values().next().value;\n if (!head) {\n continue;\n }\n const predecessors = [\n ...(evidenceByObject.get(key)?.values() ?? []),\n ].filter((manifest) => manifest.manifestHash !== head.manifestHash);\n advances.push({ head, predecessors });\n }\n\n return advances;\n}\n\nexport async function validateAccessManifestCheckpoints(input: {\n readonly execSql: ExecSql;\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n readonly authorizationPolicies?:\n | readonly VerifiedPrincipalPolicySelection[]\n | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly verifiedBundles?: readonly VerifiedManifestBundle[] | undefined;\n readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];\n readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];\n}): Promise<void> {\n await validateKeyingCheckpointsAtomically({\n access: accessManifestCheckpointAdvances(input),\n execSql: input.execSql,\n policies: input.policies,\n authorizationPolicies: input.authorizationPolicies,\n stillCurrent: input.stillCurrent,\n verifiedBundles: input.verifiedBundles,\n });\n}\n\nexport async function enforceAccessManifestCheckpoints(input: {\n readonly execSql: ExecSql;\n readonly organizationId?: string | undefined;\n readonly documentPurgeCheckpoint?: DocumentPurgeCheckpoint | undefined;\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n readonly authorizationPolicies?:\n | readonly VerifiedPrincipalPolicySelection[]\n | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly verifiedBundles?: readonly VerifiedManifestBundle[] | undefined;\n readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];\n readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];\n}): Promise<void> {\n await advanceKeyingCheckpointsAtomically({\n access: accessManifestCheckpointAdvances(input),\n documentPurgeCheckpoint: input.documentPurgeCheckpoint,\n execSql: input.execSql,\n organizationId: input.organizationId,\n policies: input.policies,\n authorizationPolicies: input.authorizationPolicies,\n stillCurrent: input.stillCurrent,\n verifiedBundles: input.verifiedBundles,\n });\n}\n"]}
@@ -1,5 +1,7 @@
1
1
  import { type AccessManifestCheckpoint, type VerifiedAccessManifestCheckpointEvidence, type VerifiedContainerAccessManifest, type VerifiedPrincipalPolicySelection } from "../../internal/crypto/index.js";
2
+ import type { AccessManifestBundleWireResponse } from "../../internal/validators/response/index.js";
2
3
  import type { DocumentPurgeCheckpoint } from "../persistence/documentPurgeCheckpointPersistence.js";
4
+ import type { VerifiedManifestBundle } from "../persistence/verifiedManifestBundlePersistence.js";
3
5
  import type { PrincipalPolicyCheckpointEvidence } from "../principals/principalPolicyEvidence.js";
4
6
  import type { ExecSql } from "../sqlite/sqlSchema.js";
5
7
  export interface ProjectionCheckpointContext {
@@ -9,6 +11,7 @@ export interface ProjectionCheckpointContext {
9
11
  organizationId?: string | undefined;
10
12
  readonly policies: PrincipalPolicyCheckpointEvidence[];
11
13
  readonly authorizationPolicies: VerifiedPrincipalPolicySelection[];
14
+ readonly verifiedBundles: VerifiedManifestBundle[];
12
15
  readonly verifiedHeads: VerifiedAccessManifestCheckpointEvidence[];
13
16
  readonly verifiedManifests: VerifiedAccessManifestCheckpointEvidence[];
14
17
  }
@@ -20,6 +23,15 @@ export declare function observeAccessManifestCheckpoints(context: ProjectionChec
20
23
  readonly verifiedHeads: readonly VerifiedAccessManifestCheckpointEvidence[];
21
24
  readonly verifiedManifests: readonly VerifiedAccessManifestCheckpointEvidence[];
22
25
  }): void;
26
+ /**
27
+ * Records each served bundle whose manifest this verification produced, so
28
+ * the transaction finalizing the checkpoints also stores it for later
29
+ * citation. A bundle the projection carried but verification never reached
30
+ * is skipped.
31
+ */
32
+ export declare function observeVerifiedProjectionBundles(context: ProjectionCheckpointContext, bundlesByHash: ReadonlyMap<string, AccessManifestBundleWireResponse>, verifiedByHash: ReadonlyMap<string, {
33
+ readonly checkpoint: AccessManifestCheckpoint;
34
+ }>): void;
23
35
  export declare function observePrincipalPolicy(context: ProjectionCheckpointContext, policy: PrincipalPolicyCheckpointEvidence, organizationId?: string | undefined): void;
24
36
  export declare function commitProjectionCheckpoints(context: ProjectionCheckpointContext, input?: {
25
37
  readonly documentPurgeCheckpoint?: DocumentPurgeCheckpoint | undefined;
@@ -16,6 +16,7 @@ export function createProjectionCheckpointContext(input) {
16
16
  organizationId: input.organizationId,
17
17
  policies: [],
18
18
  authorizationPolicies: [],
19
+ verifiedBundles: [],
19
20
  verifiedHeads: [],
20
21
  verifiedManifests: [],
21
22
  };
@@ -24,6 +25,19 @@ export function observeAccessManifestCheckpoints(context, input) {
24
25
  context.verifiedHeads.push(...input.verifiedHeads);
25
26
  context.verifiedManifests.push(...input.verifiedManifests);
26
27
  }
28
+ /**
29
+ * Records each served bundle whose manifest this verification produced, so
30
+ * the transaction finalizing the checkpoints also stores it for later
31
+ * citation. A bundle the projection carried but verification never reached
32
+ * is skipped.
33
+ */
34
+ export function observeVerifiedProjectionBundles(context, bundlesByHash, verifiedByHash) {
35
+ for (const [manifestHash, bundle] of bundlesByHash) {
36
+ const verified = verifiedByHash.get(manifestHash);
37
+ if (verified)
38
+ context.verifiedBundles.push({ bundle, checkpoint: verified.checkpoint });
39
+ }
40
+ }
27
41
  export function observePrincipalPolicy(context, policy, organizationId) {
28
42
  if (organizationId !== undefined &&
29
43
  context.organizationId !== undefined &&
@@ -46,6 +60,7 @@ export async function commitProjectionCheckpoints(context, input) {
46
60
  policies: context.policies,
47
61
  authorizationPolicies: context.authorizationPolicies,
48
62
  stillCurrent: input?.stillCurrent,
63
+ verifiedBundles: context.verifiedBundles,
49
64
  verifiedHeads: context.verifiedHeads,
50
65
  verifiedManifests: context.verifiedManifests,
51
66
  }).catch((error) => {
@@ -67,6 +82,7 @@ async function validateProjectionCheckpoints(context, input) {
67
82
  policies: context.policies,
68
83
  authorizationPolicies: context.authorizationPolicies,
69
84
  stillCurrent: input?.stillCurrent,
85
+ verifiedBundles: context.verifiedBundles,
70
86
  verifiedHeads: context.verifiedHeads,
71
87
  verifiedManifests: context.verifiedManifests,
72
88
  }).catch((error) => {