@tearleads/client-sdk 0.1.38 → 0.1.39

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 (39) hide show
  1. package/client/Tearleads.d.ts +3 -0
  2. package/client/Tearleads.js +20 -12
  3. package/client/Tearleads.js.map +1 -1
  4. package/client/session/index.js +2 -2
  5. package/client/session/index.js.map +1 -1
  6. package/client/session/sessionOrganizationCreation.js +1 -0
  7. package/client/session/sessionOrganizationCreation.js.map +1 -1
  8. package/client/session/sessionTypes.d.ts +3 -0
  9. package/client/session/sessionTypes.js.map +1 -1
  10. package/client/workflowRuntime.d.ts +2 -0
  11. package/client/workflowRuntime.js +34 -16
  12. package/client/workflowRuntime.js.map +1 -1
  13. package/data/persistence/documents/documentDiscoveryEvidencePersistence.d.ts +16 -0
  14. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +23 -0
  15. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  16. package/data/trustedUserIdentity/index.d.ts +1 -1
  17. package/data/trustedUserIdentity/index.js +1 -1
  18. package/data/trustedUserIdentity/index.js.map +1 -1
  19. package/data/trustedUserIdentity/service.d.ts +12 -1
  20. package/data/trustedUserIdentity/service.js +27 -3
  21. package/data/trustedUserIdentity/service.js.map +1 -1
  22. package/package.json +1 -1
  23. package/workflows/organizations/createOrganization.d.ts +3 -0
  24. package/workflows/organizations/createOrganization.js +1 -0
  25. package/workflows/organizations/createOrganization.js.map +1 -1
  26. package/workflows/registration/organizationProvisioningPersistence.d.ts +3 -0
  27. package/workflows/registration/organizationProvisioningPersistence.js +27 -1
  28. package/workflows/registration/organizationProvisioningPersistence.js.map +1 -1
  29. package/workflows/registration/persistRegistrationBootstrap.d.ts +3 -0
  30. package/workflows/registration/persistRegistrationBootstrap.js +7 -1
  31. package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
  32. package/workflows/registration/provisionedPrincipalHistory.d.ts +45 -0
  33. package/workflows/registration/provisionedPrincipalHistory.js +104 -0
  34. package/workflows/registration/provisionedPrincipalHistory.js.map +1 -0
  35. package/workflows/registration/provisioningAcknowledgement.js +18 -0
  36. package/workflows/registration/provisioningAcknowledgement.js.map +1 -1
  37. package/workflows/registration/registerIdentity.d.ts +3 -0
  38. package/workflows/registration/registerIdentity.js +1 -0
  39. package/workflows/registration/registerIdentity.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"workflowRuntime.js","sourceRoot":"","sources":["workflowRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { DocumentProjectorRegistry } from \"../data/documents/documentKinds\";\nimport type { DomainScope } from \"../data/domainScope\";\nimport { runWithSecurityIncidentReporting } from \"../data/keyingProjectionVerification/error\";\nimport type { PrincipalHistoryProtectionLease } from \"../data/principals/principalHistoryProtection\";\nimport type { SecurityIncidentReporter } from \"../data/securityIncidents\";\nimport { unavailableExecSql } from \"../data/sqlite/sqlSchema\";\nimport {\n createApiUserIdentitySource,\n createTrustedUserIdentityService,\n type LocalUserIdentityCandidate,\n type TrustedUserIdentityResolver,\n} from \"../data/trustedUserIdentity\";\nimport type { ContainerContentsRootAdopter } from \"../workflows/container-contents/runtime\";\nimport type {\n WorkflowRuntimeAuthInput,\n WorkflowRuntimeCryptoInput,\n WorkflowRuntimeGroups,\n WorkflowRuntimeInfraInput,\n WorkflowRuntimeStateInput,\n WorkflowRuntimeUtilInput,\n} from \"../workflows/runtimeInput\";\nimport type { Blobs } from \"./blobs\";\nimport type { Database } from \"./database\";\nimport type { Events } from \"./events\";\nimport type { Identity } from \"./identity\";\nimport { createListenerSet } from \"./listenerSet\";\nimport type { Network } from \"./network\";\nimport {\n createPrincipalHistoryProtectionCustody,\n type PrincipalHistoryKeyProvider,\n} from \"./principalHistoryProtection\";\nimport {\n createPrincipalMutationApiCustody,\n type PrincipalMutationApi,\n} from \"./principalMutationApi\";\nimport { adoptSessionRootContainer } from \"./rootContainerAdoption\";\nimport { acknowledgedSessionRoot } from \"./session/sessionRootAuthority\";\nimport type { Session, SessionSnapshot } from \"./session/sessionTypes\";\nimport type { SyncBillingGate } from \"./syncBillingGate\";\n\ntype HostWorkflowRuntimeUtilInput = Omit<\n WorkflowRuntimeUtilInput,\n \"reportSecurityIncident\"\n>;\n\nexport interface WorkflowRuntimeInput\n extends Omit<WorkflowRuntimeGroups, \"util\"> {\n readonly util: HostWorkflowRuntimeUtilInput;\n}\n\nexport type RuntimeListener = () => void;\n\nexport interface Runtime {\n readonly version: number;\n input(containerId?: string | null | undefined): WorkflowRuntimeInput;\n subscribe(listener: RuntimeListener): () => void;\n}\n\nexport interface InternalWorkflowRuntimeInput extends WorkflowRuntimeGroups {\n readonly apiClient: PrincipalMutationApi;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly withPrincipalHistoryProtection?:\n | PrincipalHistoryProtectionLease\n | undefined;\n}\n\nexport interface InternalRuntime {\n retirePrincipalHistoryProtection(): void;\n readonly sessionGeneration: number;\n readonly adoptRootContainer: ContainerContentsRootAdopter;\n readonly publicRuntime: Runtime;\n boundUserId(signingKeyFingerprint: string): Promise<string | null>;\n pinLocalUserIdentity(\n userId: string,\n candidate: LocalUserIdentityCandidate,\n ): Promise<void>;\n workflowInput(\n containerId?: string | null | undefined,\n ): InternalWorkflowRuntimeInput;\n}\n\ninterface WorkflowRuntimeDependencies {\n api: ApiClient;\n blobs: Blobs;\n database: Database;\n documentProjectors: DocumentProjectorRegistry;\n events: Events;\n getDomainScope: () => DomainScope;\n identity: Identity;\n identityTrustDomain: string | null;\n log: (message: string) => void;\n logError: (message: string | Error, cause?: unknown) => void;\n network: Network;\n peerScope?: string | null;\n principalHistoryKeyProvider?: PrincipalHistoryKeyProvider | undefined;\n principalMutationTimeoutMs?: number | undefined;\n reportSecurityIncident: SecurityIncidentReporter;\n session: Session;\n syncBillingGate?: SyncBillingGate | undefined;\n}\n\nfunction createRuntimeMutationApi(\n dependencies: WorkflowRuntimeDependencies,\n readGeneration: () => number,\n) {\n return createPrincipalMutationApiCustody({\n api: dependencies.api,\n principalMutationTimeoutMs: dependencies.principalMutationTimeoutMs,\n readScope: () => {\n const { signingKeyPair, signingFingerprint } = dependencies.identity;\n const { userId, isAuthenticated } = dependencies.session;\n const identityTrustDomain = dependencies.identityTrustDomain;\n if (\n !isAuthenticated ||\n !userId ||\n !signingKeyPair ||\n !signingFingerprint ||\n !identityTrustDomain ||\n dependencies.database.status !== \"ready\"\n )\n return null;\n return {\n database: dependencies.getDomainScope(),\n execSql: dependencies.database.requireExecSql(\"principal mutation\"),\n generation: readGeneration(),\n identityTrustDomain,\n signingFingerprint,\n signingKeyPair,\n userId,\n };\n },\n });\n}\n\nexport function createRuntime(\n dependencies: WorkflowRuntimeDependencies,\n): InternalRuntime {\n const trustedUserIdentityService = createTrustedUserIdentityService({\n getExecSql: () =>\n dependencies.database.status === \"ready\"\n ? dependencies.database.requireExecSql(\"trusted user identity\")\n : null,\n getLocalIdentity: () => {\n const encapsulationKeyPair = dependencies.identity.encapsulationKeyPair;\n const signingKeyPair = dependencies.identity.signingKeyPair;\n if (!encapsulationKeyPair || !signingKeyPair) {\n return null;\n }\n return {\n encapsulationPublicKey: encapsulationKeyPair.publicKey,\n signingKeyFingerprint: dependencies.identity.signingFingerprint,\n signingPublicKey: signingKeyPair.signingPublicKey,\n };\n },\n getLocalUserId: () => dependencies.session.userId,\n identityTrustDomain: dependencies.identityTrustDomain,\n remoteSource: createApiUserIdentitySource(dependencies.api),\n });\n const resolveTrustedUserIdentity: TrustedUserIdentityResolver = (userId) =>\n runWithSecurityIncidentReporting(\n dependencies.reportSecurityIncident,\n {\n objectId: userId,\n objectKind: \"user\",\n operation: \"user.identity.resolve\",\n organizationId: dependencies.session.organizationId,\n },\n () => trustedUserIdentityService.resolve(userId),\n );\n const runtimeSubscription = createRuntimeSubscription(dependencies);\n const historyProtection = createPrincipalHistoryProtectionCustody({\n keyProvider: dependencies.principalHistoryKeyProvider,\n readScope: () => {\n const signingFingerprint = dependencies.identity.signingFingerprint;\n const identityTrustDomain = dependencies.identityTrustDomain;\n if (\n !signingFingerprint ||\n !identityTrustDomain ||\n dependencies.database.status !== \"ready\"\n )\n return null;\n return {\n signingFingerprint,\n identityTrustDomain,\n database: dependencies.getDomainScope(),\n generation: runtimeSubscription.recoveryGeneration,\n };\n },\n });\n const runtimeInput = createRuntimeInputFactory(\n dependencies,\n resolveTrustedUserIdentity,\n historyProtection.bind,\n createRuntimeMutationApi(\n dependencies,\n () => runtimeSubscription.mutationGeneration,\n ).bind,\n );\n\n return {\n retirePrincipalHistoryProtection: historyProtection.retire,\n get sessionGeneration() {\n return runtimeSubscription.sessionGeneration;\n },\n adoptRootContainer: (input) =>\n adoptSessionRootContainer(dependencies, input),\n boundUserId: (signingKeyFingerprint) =>\n trustedUserIdentityService.boundUserId(signingKeyFingerprint),\n async pinLocalUserIdentity(userId, candidate) {\n await runWithSecurityIncidentReporting(\n dependencies.reportSecurityIncident,\n {\n objectId: userId,\n objectKind: \"user\",\n operation: \"user.identity.pin_local\",\n organizationId: dependencies.session.organizationId,\n },\n () => trustedUserIdentityService.pinLocal(userId, candidate),\n );\n },\n publicRuntime: {\n get version() {\n return runtimeSubscription.version;\n },\n input: runtimeInput.hostInput,\n subscribe: runtimeSubscription.subscribe,\n },\n workflowInput: runtimeInput.workflowInput,\n };\n}\n\nfunction createRuntimeSubscription(dependencies: WorkflowRuntimeDependencies) {\n const listeners = createListenerSet();\n let version = 0;\n let sessionGeneration = 0;\n let recoveryGeneration = 0;\n let mutationGeneration = 0;\n let sessionSnapshot = dependencies.session.snapshot;\n const notifyListeners = () => {\n version += 1;\n listeners.notify();\n };\n\n const notifyAuthority = () => {\n recoveryGeneration += 1;\n mutationGeneration += 1;\n notifyListeners();\n };\n dependencies.database.subscribe(notifyAuthority);\n dependencies.events.subscribe(notifyListeners);\n dependencies.identity.subscribe(notifyAuthority);\n dependencies.network.subscribe(() => notifyListeners());\n dependencies.session.subscribe(() => {\n const next = dependencies.session.snapshot;\n if (sessionAuthorityChanged(sessionSnapshot, next)) {\n sessionGeneration += 1;\n recoveryGeneration += 1;\n }\n if (sessionScopeChanged(sessionSnapshot, next)) mutationGeneration += 1;\n sessionSnapshot = next;\n notifyListeners();\n });\n dependencies.syncBillingGate?.subscribe(notifyListeners);\n\n return {\n get mutationGeneration() {\n return mutationGeneration;\n },\n get recoveryGeneration() {\n return recoveryGeneration;\n },\n get sessionGeneration() {\n return sessionGeneration;\n },\n get version() {\n return version;\n },\n subscribe(listener: RuntimeListener): () => void {\n return listeners.subscribe(listener);\n },\n };\n}\n\ninterface RuntimeInputFactory {\n hostInput(containerId?: string | null | undefined): WorkflowRuntimeInput;\n workflowInput(\n containerId?: string | null | undefined,\n ): InternalWorkflowRuntimeInput;\n}\n\nfunction sessionAuthInput({\n session,\n identity,\n}: WorkflowRuntimeDependencies): WorkflowRuntimeAuthInput {\n const signingFingerprint = identity.snapshot.signingFingerprint;\n return {\n defaultOrganizationId: session.defaultOrganizationId,\n rootContainerId: acknowledgedSessionRoot(session, signingFingerprint),\n isAuthenticated: session.isAuthenticated,\n isRoot: session.isRoot,\n organizationId: session.organizationId,\n userId: session.userId,\n };\n}\n\n/** Fields whose change invalidates work keyed on the session's authority. */\nfunction sessionAuthorityChanged(\n previous: SessionSnapshot,\n next: SessionSnapshot,\n): boolean {\n return (\n next.authToken !== previous.authToken || sessionScopeChanged(previous, next)\n );\n}\n\n// A transport token renewal cannot turn a definite write refusal into saved work.\n// Journal custody still expires on every change to its identity or storage scope.\nfunction sessionScopeChanged(\n previous: SessionSnapshot,\n next: SessionSnapshot,\n): boolean {\n return (\n next.isAuthenticated !== previous.isAuthenticated ||\n next.isRoot !== previous.isRoot ||\n next.organizationId !== previous.organizationId ||\n next.userId !== previous.userId\n );\n}\n\nfunction createRuntimeInputFactory(\n dependencies: WorkflowRuntimeDependencies,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n bindHistoryProtection: () => PrincipalHistoryProtectionLease | undefined,\n bindMutationApi: () => PrincipalMutationApi,\n): RuntimeInputFactory {\n let auth: WorkflowRuntimeAuthInput | undefined;\n let crypto: WorkflowRuntimeCryptoInput | undefined;\n let infra: WorkflowRuntimeInfraInput | undefined;\n let state: WorkflowRuntimeStateInput | undefined;\n let util: WorkflowRuntimeUtilInput | undefined;\n let hostUtil: HostWorkflowRuntimeUtilInput | undefined;\n\n const workflowInput = (\n containerId?: string | null | undefined,\n ): InternalWorkflowRuntimeInput => {\n const dbStatus = dependencies.database.status;\n const execSql =\n dbStatus === \"ready\"\n ? dependencies.database.requireExecSql(\"tearleads.runtime.input\")\n : unavailableExecSql;\n const nextContainerId =\n (containerId === undefined\n ? dependencies.session.containerId\n : containerId) ?? null;\n\n auth = reuseIfShallowEqual(auth, sessionAuthInput(dependencies));\n crypto = reuseIfShallowEqual(crypto, {\n encapsulationKeyPair: dependencies.identity.encapsulationKeyPair,\n signingFingerprint: dependencies.identity.signingFingerprint,\n signingKeyPair: dependencies.identity.signingKeyPair,\n });\n infra = reuseIfShallowEqual(infra, {\n blobStore: dependencies.blobs.store,\n dbStatus,\n documentProjectors: dependencies.documentProjectors,\n // Runtime consumers branch on dbStatus before touching SQLite. The\n // fallback preserves the runtime shape and catches lifecycle bugs.\n execSql,\n });\n state = reuseIfShallowEqual(state, {\n containerId: nextContainerId,\n domainScope: dependencies.getDomainScope(),\n events: dependencies.events.events,\n // Resolved sync-online: workflows treat local-only mode exactly like being\n // offline (no server I/O), while `tearleads.network` stays the truthful\n // connectivity signal for host/UI. See Session.syncEnabled.\n online: dependencies.network.online && dependencies.session.syncEnabled,\n peerScope: dependencies.peerScope ?? null,\n serverEventsConnectionGeneration:\n dependencies.events.connectionGeneration,\n });\n if (\n !util ||\n util.log !== dependencies.log ||\n util.logError !== dependencies.logError ||\n util.reportSecurityIncident !== dependencies.reportSecurityIncident\n ) {\n util = {\n isRemoteSyncBlocked: (organizationId) =>\n dependencies.syncBillingGate?.isBlockedForOrganization(\n organizationId,\n ) ?? false,\n log: dependencies.log,\n logError: dependencies.logError,\n reportSecurityIncident: dependencies.reportSecurityIncident,\n };\n }\n\n return {\n apiClient: bindMutationApi(),\n auth,\n crypto,\n infra,\n state,\n util,\n resolveTrustedUserIdentity,\n withPrincipalHistoryProtection: bindHistoryProtection(),\n };\n };\n\n return {\n hostInput(containerId) {\n const {\n apiClient: _apiClient,\n resolveTrustedUserIdentity: _resolveTrustedUserIdentity,\n withPrincipalHistoryProtection: _withPrincipalHistoryProtection,\n util: workflowUtil,\n ...input\n } = workflowInput(containerId);\n hostUtil = reuseIfShallowEqual(hostUtil, {\n isRemoteSyncBlocked: workflowUtil.isRemoteSyncBlocked,\n log: workflowUtil.log,\n logError: workflowUtil.logError,\n });\n return { ...input, util: hostUtil };\n },\n workflowInput,\n };\n}\n\n/**\n * Reuses the current runtime-input group when every field of the freshly\n * constructed `next` literal is reference-equal, so unchanged groups keep a\n * stable identity across runtime reads.\n */\nfunction reuseIfShallowEqual<T extends object>(\n current: T | undefined,\n next: T,\n): T {\n if (!current) {\n return next;\n }\n for (const key of Object.keys(next)) {\n if (Reflect.get(current, key) !== Reflect.get(next, key)) {\n return next;\n }\n }\n return current;\n}\n"]}
1
+ {"version":3,"file":"workflowRuntime.js","sourceRoot":"","sources":["workflowRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { DocumentProjectorRegistry } from \"../data/documents/documentKinds\";\nimport type { DomainScope } from \"../data/domainScope\";\nimport { runWithSecurityIncidentReporting } from \"../data/keyingProjectionVerification/error\";\nimport type { PrincipalHistoryProtectionLease } from \"../data/principals/principalHistoryProtection\";\nimport type { SecurityIncidentReporter } from \"../data/securityIncidents\";\nimport { type ExecSql, unavailableExecSql } from \"../data/sqlite/sqlSchema\";\nimport {\n createApiUserIdentitySource,\n createTrustedUserIdentityService,\n type LocalUserIdentityCandidate,\n loadPinnedUserIdentity,\n type TrustedUserIdentityResolver,\n} from \"../data/trustedUserIdentity\";\nimport type { ContainerContentsRootAdopter } from \"../workflows/container-contents/runtime\";\nimport {\n createProvisionedPrincipalHistoryPrimer,\n type ProvisionedPrincipalHistoryPrimer,\n} from \"../workflows/registration/provisionedPrincipalHistory\";\nimport type {\n WorkflowRuntimeAuthInput,\n WorkflowRuntimeCryptoInput,\n WorkflowRuntimeGroups,\n WorkflowRuntimeInfraInput,\n WorkflowRuntimeStateInput,\n WorkflowRuntimeUtilInput,\n} from \"../workflows/runtimeInput\";\nimport type { Blobs } from \"./blobs\";\nimport type { Database } from \"./database\";\nimport type { Events } from \"./events\";\nimport type { Identity } from \"./identity\";\nimport { createListenerSet } from \"./listenerSet\";\nimport type { Network } from \"./network\";\nimport {\n createPrincipalHistoryProtectionCustody,\n type PrincipalHistoryKeyProvider,\n} from \"./principalHistoryProtection\";\nimport {\n createPrincipalMutationApiCustody,\n type PrincipalMutationApi,\n} from \"./principalMutationApi\";\nimport { adoptSessionRootContainer } from \"./rootContainerAdoption\";\nimport { acknowledgedSessionRoot } from \"./session/sessionRootAuthority\";\nimport type { Session, SessionSnapshot } from \"./session/sessionTypes\";\nimport type { SyncBillingGate } from \"./syncBillingGate\";\n\ntype HostWorkflowRuntimeUtilInput = Omit<\n WorkflowRuntimeUtilInput,\n \"reportSecurityIncident\"\n>;\n\nexport interface WorkflowRuntimeInput\n extends Omit<WorkflowRuntimeGroups, \"util\"> {\n readonly util: HostWorkflowRuntimeUtilInput;\n}\n\nexport type RuntimeListener = () => void;\n\nexport interface Runtime {\n readonly version: number;\n input(containerId?: string | null | undefined): WorkflowRuntimeInput;\n subscribe(listener: RuntimeListener): () => void;\n}\n\nexport interface InternalWorkflowRuntimeInput extends WorkflowRuntimeGroups {\n readonly apiClient: PrincipalMutationApi;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly withPrincipalHistoryProtection?:\n | PrincipalHistoryProtectionLease\n | undefined;\n}\n\nexport interface InternalRuntime {\n retirePrincipalHistoryProtection(): void;\n readonly sessionGeneration: number;\n readonly adoptRootContainer: ContainerContentsRootAdopter;\n readonly publicRuntime: Runtime;\n boundUserId(signingKeyFingerprint: string): Promise<string | null>;\n pinLocalUserIdentity(\n userId: string,\n candidate: LocalUserIdentityCandidate,\n ): Promise<void>;\n readonly primeProvisionedPrincipalHistory: ProvisionedPrincipalHistoryPrimer;\n workflowInput(\n containerId?: string | null | undefined,\n ): InternalWorkflowRuntimeInput;\n}\n\ninterface WorkflowRuntimeDependencies {\n api: ApiClient;\n blobs: Blobs;\n database: Database;\n documentProjectors: DocumentProjectorRegistry;\n events: Events;\n getDomainScope: () => DomainScope;\n identity: Identity;\n identityTrustDomain: string | null;\n log: (message: string) => void;\n logError: (message: string | Error, cause?: unknown) => void;\n network: Network;\n peerScope?: string | null;\n principalHistoryKeyProvider?: PrincipalHistoryKeyProvider | undefined;\n principalMutationTimeoutMs?: number | undefined;\n reportSecurityIncident: SecurityIncidentReporter;\n session: Session;\n syncBillingGate?: SyncBillingGate | undefined;\n}\n\nfunction createRuntimeMutationApi(\n dependencies: WorkflowRuntimeDependencies,\n readGeneration: () => number,\n) {\n return createPrincipalMutationApiCustody({\n api: dependencies.api,\n principalMutationTimeoutMs: dependencies.principalMutationTimeoutMs,\n readScope: () => {\n const { signingKeyPair, signingFingerprint } = dependencies.identity;\n const { userId, isAuthenticated } = dependencies.session;\n const identityTrustDomain = dependencies.identityTrustDomain;\n if (\n !isAuthenticated ||\n !userId ||\n !signingKeyPair ||\n !signingFingerprint ||\n !identityTrustDomain ||\n dependencies.database.status !== \"ready\"\n )\n return null;\n return {\n database: dependencies.getDomainScope(),\n execSql: dependencies.database.requireExecSql(\"principal mutation\"),\n generation: readGeneration(),\n identityTrustDomain,\n signingFingerprint,\n signingKeyPair,\n userId,\n };\n },\n });\n}\n\nfunction localIdentityCandidate(\n identity: Identity,\n): LocalUserIdentityCandidate | null {\n const { encapsulationKeyPair, signingKeyPair } = identity;\n if (!encapsulationKeyPair || !signingKeyPair) return null;\n return {\n encapsulationPublicKey: encapsulationKeyPair.publicKey,\n signingKeyFingerprint: identity.signingFingerprint,\n signingPublicKey: signingKeyPair.signingPublicKey,\n };\n}\n\n/** Priming reads the runtime's database, identity and trust pins; it pins nothing. */\nfunction createRuntimeProvisioningPrimer(\n dependencies: WorkflowRuntimeDependencies,\n bindLease: () => PrincipalHistoryProtectionLease | undefined,\n readyExecSql: () => ExecSql | null,\n): ProvisionedPrincipalHistoryPrimer {\n return createProvisionedPrincipalHistoryPrimer({\n bindLease,\n execSqlFor: (database) =>\n dependencies.database.client === database ? readyExecSql() : null,\n loadPinnedIdentity: async (execSql, userId) =>\n dependencies.identityTrustDomain\n ? loadPinnedUserIdentity({\n execSql,\n identityTrustDomain: dependencies.identityTrustDomain,\n userId,\n })\n : null,\n logError: dependencies.logError,\n signingFingerprint: () => dependencies.identity.signingFingerprint,\n });\n}\n\nexport function createRuntime(\n dependencies: WorkflowRuntimeDependencies,\n): InternalRuntime {\n const readyExecSql = () =>\n dependencies.database.status === \"ready\"\n ? dependencies.database.requireExecSql(\"trusted user identity\")\n : null;\n const trustedUserIdentityService = createTrustedUserIdentityService({\n getExecSql: readyExecSql,\n getLocalIdentity: () => localIdentityCandidate(dependencies.identity),\n getLocalUserId: () => dependencies.session.userId,\n identityTrustDomain: dependencies.identityTrustDomain,\n remoteSource: createApiUserIdentitySource(dependencies.api),\n });\n const resolveTrustedUserIdentity: TrustedUserIdentityResolver = (userId) =>\n runWithSecurityIncidentReporting(\n dependencies.reportSecurityIncident,\n {\n objectId: userId,\n objectKind: \"user\",\n operation: \"user.identity.resolve\",\n organizationId: dependencies.session.organizationId,\n },\n () => trustedUserIdentityService.resolve(userId),\n );\n const runtimeSubscription = createRuntimeSubscription(dependencies);\n const historyProtection = createPrincipalHistoryProtectionCustody({\n keyProvider: dependencies.principalHistoryKeyProvider,\n readScope: () => {\n const signingFingerprint = dependencies.identity.signingFingerprint;\n const identityTrustDomain = dependencies.identityTrustDomain;\n if (\n !signingFingerprint ||\n !identityTrustDomain ||\n dependencies.database.status !== \"ready\"\n )\n return null;\n return {\n signingFingerprint,\n identityTrustDomain,\n database: dependencies.getDomainScope(),\n generation: runtimeSubscription.recoveryGeneration,\n };\n },\n });\n const runtimeInput = createRuntimeInputFactory(\n dependencies,\n resolveTrustedUserIdentity,\n historyProtection.bind,\n createRuntimeMutationApi(\n dependencies,\n () => runtimeSubscription.mutationGeneration,\n ).bind,\n );\n\n return {\n retirePrincipalHistoryProtection: historyProtection.retire,\n get sessionGeneration() {\n return runtimeSubscription.sessionGeneration;\n },\n adoptRootContainer: (input) =>\n adoptSessionRootContainer(dependencies, input),\n boundUserId: (signingKeyFingerprint) =>\n trustedUserIdentityService.boundUserId(signingKeyFingerprint),\n async pinLocalUserIdentity(userId, candidate) {\n await runWithSecurityIncidentReporting(\n dependencies.reportSecurityIncident,\n {\n objectId: userId,\n objectKind: \"user\",\n operation: \"user.identity.pin_local\",\n organizationId: dependencies.session.organizationId,\n },\n () => trustedUserIdentityService.pinLocal(userId, candidate),\n );\n },\n primeProvisionedPrincipalHistory: createRuntimeProvisioningPrimer(\n dependencies,\n historyProtection.bind,\n readyExecSql,\n ),\n publicRuntime: {\n get version() {\n return runtimeSubscription.version;\n },\n input: runtimeInput.hostInput,\n subscribe: runtimeSubscription.subscribe,\n },\n workflowInput: runtimeInput.workflowInput,\n };\n}\n\nfunction createRuntimeSubscription(dependencies: WorkflowRuntimeDependencies) {\n const listeners = createListenerSet();\n let version = 0;\n let sessionGeneration = 0;\n let recoveryGeneration = 0;\n let mutationGeneration = 0;\n let sessionSnapshot = dependencies.session.snapshot;\n const notifyListeners = () => {\n version += 1;\n listeners.notify();\n };\n\n const notifyAuthority = () => {\n recoveryGeneration += 1;\n mutationGeneration += 1;\n notifyListeners();\n };\n dependencies.database.subscribe(notifyAuthority);\n dependencies.events.subscribe(notifyListeners);\n dependencies.identity.subscribe(notifyAuthority);\n dependencies.network.subscribe(() => notifyListeners());\n dependencies.session.subscribe(() => {\n const next = dependencies.session.snapshot;\n if (sessionAuthorityChanged(sessionSnapshot, next)) {\n sessionGeneration += 1;\n recoveryGeneration += 1;\n }\n if (sessionScopeChanged(sessionSnapshot, next)) mutationGeneration += 1;\n sessionSnapshot = next;\n notifyListeners();\n });\n dependencies.syncBillingGate?.subscribe(notifyListeners);\n\n return {\n get mutationGeneration() {\n return mutationGeneration;\n },\n get recoveryGeneration() {\n return recoveryGeneration;\n },\n get sessionGeneration() {\n return sessionGeneration;\n },\n get version() {\n return version;\n },\n subscribe(listener: RuntimeListener): () => void {\n return listeners.subscribe(listener);\n },\n };\n}\n\ninterface RuntimeInputFactory {\n hostInput(containerId?: string | null | undefined): WorkflowRuntimeInput;\n workflowInput(\n containerId?: string | null | undefined,\n ): InternalWorkflowRuntimeInput;\n}\n\nfunction sessionAuthInput({\n session,\n identity,\n}: WorkflowRuntimeDependencies): WorkflowRuntimeAuthInput {\n const signingFingerprint = identity.snapshot.signingFingerprint;\n return {\n defaultOrganizationId: session.defaultOrganizationId,\n rootContainerId: acknowledgedSessionRoot(session, signingFingerprint),\n isAuthenticated: session.isAuthenticated,\n isRoot: session.isRoot,\n organizationId: session.organizationId,\n userId: session.userId,\n };\n}\n\n/** Fields whose change invalidates work keyed on the session's authority. */\nfunction sessionAuthorityChanged(\n previous: SessionSnapshot,\n next: SessionSnapshot,\n): boolean {\n return (\n next.authToken !== previous.authToken || sessionScopeChanged(previous, next)\n );\n}\n\n// A transport token renewal cannot turn a definite write refusal into saved work.\n// Journal custody still expires on every change to its identity or storage scope.\nfunction sessionScopeChanged(\n previous: SessionSnapshot,\n next: SessionSnapshot,\n): boolean {\n return (\n next.isAuthenticated !== previous.isAuthenticated ||\n next.isRoot !== previous.isRoot ||\n next.organizationId !== previous.organizationId ||\n next.userId !== previous.userId\n );\n}\n\nfunction createRuntimeInputFactory(\n dependencies: WorkflowRuntimeDependencies,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n bindHistoryProtection: () => PrincipalHistoryProtectionLease | undefined,\n bindMutationApi: () => PrincipalMutationApi,\n): RuntimeInputFactory {\n let auth: WorkflowRuntimeAuthInput | undefined;\n let crypto: WorkflowRuntimeCryptoInput | undefined;\n let infra: WorkflowRuntimeInfraInput | undefined;\n let state: WorkflowRuntimeStateInput | undefined;\n let util: WorkflowRuntimeUtilInput | undefined;\n let hostUtil: HostWorkflowRuntimeUtilInput | undefined;\n\n const workflowInput = (\n containerId?: string | null | undefined,\n ): InternalWorkflowRuntimeInput => {\n const dbStatus = dependencies.database.status;\n const execSql =\n dbStatus === \"ready\"\n ? dependencies.database.requireExecSql(\"tearleads.runtime.input\")\n : unavailableExecSql;\n const nextContainerId =\n (containerId === undefined\n ? dependencies.session.containerId\n : containerId) ?? null;\n\n auth = reuseIfShallowEqual(auth, sessionAuthInput(dependencies));\n crypto = reuseIfShallowEqual(crypto, {\n encapsulationKeyPair: dependencies.identity.encapsulationKeyPair,\n signingFingerprint: dependencies.identity.signingFingerprint,\n signingKeyPair: dependencies.identity.signingKeyPair,\n });\n infra = reuseIfShallowEqual(infra, {\n blobStore: dependencies.blobs.store,\n dbStatus,\n documentProjectors: dependencies.documentProjectors,\n // Runtime consumers branch on dbStatus before touching SQLite. The\n // fallback preserves the runtime shape and catches lifecycle bugs.\n execSql,\n });\n state = reuseIfShallowEqual(state, {\n containerId: nextContainerId,\n domainScope: dependencies.getDomainScope(),\n events: dependencies.events.events,\n // Resolved sync-online: workflows treat local-only mode exactly like being\n // offline (no server I/O), while `tearleads.network` stays the truthful\n // connectivity signal for host/UI. See Session.syncEnabled.\n online: dependencies.network.online && dependencies.session.syncEnabled,\n peerScope: dependencies.peerScope ?? null,\n serverEventsConnectionGeneration:\n dependencies.events.connectionGeneration,\n });\n if (\n !util ||\n util.log !== dependencies.log ||\n util.logError !== dependencies.logError ||\n util.reportSecurityIncident !== dependencies.reportSecurityIncident\n ) {\n util = {\n isRemoteSyncBlocked: (organizationId) =>\n dependencies.syncBillingGate?.isBlockedForOrganization(\n organizationId,\n ) ?? false,\n log: dependencies.log,\n logError: dependencies.logError,\n reportSecurityIncident: dependencies.reportSecurityIncident,\n };\n }\n\n return {\n apiClient: bindMutationApi(),\n auth,\n crypto,\n infra,\n state,\n util,\n resolveTrustedUserIdentity,\n withPrincipalHistoryProtection: bindHistoryProtection(),\n };\n };\n\n return {\n hostInput(containerId) {\n const {\n apiClient: _apiClient,\n resolveTrustedUserIdentity: _resolveTrustedUserIdentity,\n withPrincipalHistoryProtection: _withPrincipalHistoryProtection,\n util: workflowUtil,\n ...input\n } = workflowInput(containerId);\n hostUtil = reuseIfShallowEqual(hostUtil, {\n isRemoteSyncBlocked: workflowUtil.isRemoteSyncBlocked,\n log: workflowUtil.log,\n logError: workflowUtil.logError,\n });\n return { ...input, util: hostUtil };\n },\n workflowInput,\n };\n}\n\n/**\n * Reuses the current runtime-input group when every field of the freshly\n * constructed `next` literal is reference-equal, so unchanged groups keep a\n * stable identity across runtime reads.\n */\nfunction reuseIfShallowEqual<T extends object>(\n current: T | undefined,\n next: T,\n): T {\n if (!current) {\n return next;\n }\n for (const key of Object.keys(next)) {\n if (Reflect.get(current, key) !== Reflect.get(next, key)) {\n return next;\n }\n }\n return current;\n}\n"]}
@@ -23,4 +23,20 @@ export interface DocumentDiscoveryEvidenceStore {
23
23
  loadHead(documentId: string, manifestHash: string | null | undefined): Promise<CachedDiscoveryHead | null>;
24
24
  saveHead(documentId: string, head: CachedDiscoveryHead, generation: number): Promise<boolean>;
25
25
  }
26
+ /**
27
+ * A document head this client signed, already checked against the server's
28
+ * create acknowledgement and pinned as its access-manifest checkpoint in the
29
+ * same transaction. It is the same signed head a discovery projection would
30
+ * verify, so it seeds the exact-head cache; `loadHead` still reuses it only
31
+ * while that checkpoint matches.
32
+ */
33
+ export interface AuthoredDiscoveryHead {
34
+ readonly documentId: string;
35
+ readonly organizationId: string;
36
+ readonly accessEpoch: number;
37
+ readonly accessStateHash: string;
38
+ readonly linkedContainerIds: readonly string[];
39
+ }
40
+ /** Writes authored heads inside the caller's serialized write transaction. */
41
+ export declare function primeAuthoredDocumentDiscoveryHeads(execSql: ExecSql, authored: readonly AuthoredDiscoveryHead[]): Promise<void>;
26
42
  export declare function createDocumentDiscoveryEvidenceStore(execSql: ExecSql, now?: () => number): DocumentDiscoveryEvidenceStore;
@@ -1,4 +1,5 @@
1
1
  import { and, asc, eq, inArray, lte, min, sql } from "drizzle-orm";
2
+ import { uniqueSortedStrings } from "../../documents/shared/readers.js";
2
3
  import { readStringArray } from "../../recordReaders.js";
3
4
  import { documentDiscoveryHeads, documentDiscoverySequence, pendingDocumentDiscoveries, } from "../../sqlite/documentDiscoveryEvidenceSchema.js";
4
5
  import { accessManifestCheckpoints, documentContainerProjectionTables, } from "../../sqlite/schema.js";
@@ -231,6 +232,28 @@ class SqlDocumentDiscoveryEvidenceStore {
231
232
  return true;
232
233
  });
233
234
  }
235
+ /** Writes authored heads inside the caller's serialized write transaction. */
236
+ export async function primeAuthoredDocumentDiscoveryHeads(execSql, authored) {
237
+ const db = getClientSQLitePersistenceRuntime(execSql).db;
238
+ for (const head of authored) {
239
+ const row = {
240
+ documentId: head.documentId,
241
+ organizationId: head.organizationId,
242
+ manifestHash: head.accessStateHash,
243
+ accessEpoch: head.accessEpoch,
244
+ linksJson: JSON.stringify(uniqueSortedStrings(head.linkedContainerIds)),
245
+ };
246
+ await db
247
+ .insert(heads)
248
+ .values(row)
249
+ .onConflictDoUpdate({
250
+ target: [heads.documentId, heads.organizationId],
251
+ set: row,
252
+ setWhere: lte(heads.accessEpoch, head.accessEpoch),
253
+ })
254
+ .run();
255
+ }
256
+ }
234
257
  export function createDocumentDiscoveryEvidenceStore(execSql, now = Date.now) {
235
258
  return new SqlDocumentDiscoveryEvidenceStore(execSql, now);
236
259
  }
@@ -1 +1 @@
1
- {"version":3,"file":"documentDiscoveryEvidencePersistence.js","sourceRoot":"","sources":["documentDiscoveryEvidencePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray, lte, min, sql } from \"drizzle-orm\";\nimport { readStringArray } from \"../../recordReaders\";\nimport {\n documentDiscoveryHeads,\n documentDiscoverySequence,\n pendingDocumentDiscoveries,\n} from \"../../sqlite/documentDiscoveryEvidenceSchema\";\nimport {\n accessManifestCheckpoints,\n documentContainerProjectionTables,\n} from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport { loadDocumentPurgeCheckpoint } from \"../documentPurgeCheckpointPersistence\";\nimport { heldTombstoneRetryDelayMs } from \"./containerDocumentTombstoneHoldsPersistence\";\n\nimport {\n type DiscoveredDocumentCandidate,\n isDiscoveredDocumentCandidate,\n readStoredDiscoveryCandidate,\n} from \"./documentDiscoveryCandidate\";\n\nimport { isDocumentDiscoveryGenerationCurrent } from \"./documentDiscoveryReset\";\n\nexport type { DiscoveredDocumentCandidate } from \"./documentDiscoveryCandidate\";\nexport interface CachedDiscoveryHead {\n readonly organizationId: string | null;\n readonly accessEpoch: number;\n readonly accessStateHash?: string;\n readonly linkedContainerIds: readonly string[];\n}\ninterface RemovedDiscoveryPlacement {\n readonly containerId: string;\n readonly documentId: string;\n}\nexport interface DocumentDiscoveryEvidenceStore {\n begin(): Promise<number>;\n isCurrent(generation: number): Promise<boolean>;\n stage(\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n removed?: readonly RemovedDiscoveryPlacement[],\n ): Promise<boolean>;\n pending(\n containerIds: readonly string[],\n limit: number,\n ): Promise<readonly DiscoveredDocumentCandidate[]>;\n defer(input: DiscoveredDocumentCandidate, generation: number): Promise<void>;\n acknowledge(\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n ): Promise<void>;\n hasPending(containerIds: readonly string[]): Promise<boolean>;\n retryDelay(containerIds: readonly string[]): Promise<number | null>;\n loadHead(\n documentId: string,\n manifestHash: string | null | undefined,\n ): Promise<CachedDiscoveryHead | null>;\n saveHead(\n documentId: string,\n head: CachedDiscoveryHead,\n generation: number,\n ): Promise<boolean>;\n}\n\nconst pending = pendingDocumentDiscoveries;\nconst heads = documentDiscoveryHeads;\nconst ID_BATCH_SIZE = 400;\nconst batches = (ids: readonly string[]) =>\n Array.from({ length: Math.ceil(ids.length / ID_BATCH_SIZE) }, (_, i) =>\n ids.slice(i * ID_BATCH_SIZE, (i + 1) * ID_BATCH_SIZE),\n );\nconst identity = (input: DiscoveredDocumentCandidate) =>\n and(\n eq(pending.containerId, input.containerId),\n eq(pending.documentId, input.documentId),\n eq(pending.inputJson, JSON.stringify(input)),\n );\n\nclass SqlDocumentDiscoveryEvidenceStore\n implements DocumentDiscoveryEvidenceStore\n{\n constructor(\n private readonly execSql: ExecSql,\n private readonly now: () => number,\n ) {}\n\n private read = async () => {\n await ensureSqlTables(this.execSql, documentContainerProjectionTables);\n return getClientSQLitePersistenceRuntime(this.execSql).db;\n };\n private write = async <T>(\n operation: (\n db: ReturnType<typeof getClientSQLitePersistenceRuntime>[\"db\"],\n ) => Promise<T>,\n ) =>\n runSerializedSqlMutation(this.execSql, async (locked) => {\n await ensureSqlTables(locked, documentContainerProjectionTables);\n return operation(getClientSQLitePersistenceRuntime(locked).db);\n });\n begin = async () => {\n let generation = 0;\n await this.write(async (db) => {\n const [row] = await db\n .insert(documentDiscoverySequence)\n .values({ id: \"requests\", generation: 1 })\n .onConflictDoUpdate({\n target: documentDiscoverySequence.id,\n set: {\n generation: sql`${documentDiscoverySequence.generation} + 1`,\n },\n })\n .returning({ generation: documentDiscoverySequence.generation });\n if (!row || !Number.isSafeInteger(row.generation))\n throw new Error(\"Document discovery generation is exhausted\");\n generation = row.generation;\n });\n return generation;\n };\n isCurrent = async (generation: number) =>\n isDocumentDiscoveryGenerationCurrent(await this.read(), generation);\n stage = (\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n removed: readonly RemovedDiscoveryPlacement[] = [],\n ) => {\n return this.write(async (db) => {\n if (!(await isDocumentDiscoveryGenerationCurrent(db, generation)))\n return false;\n if (inputs.length === 0 && removed.length === 0) return true;\n await db.transaction(async (tx) => {\n for (const input of inputs) {\n if (!isDiscoveredDocumentCandidate(input)) continue;\n for (const containerId of input.listedContainerIds) {\n const rowInput = {\n ...input,\n containerId,\n listedContainerIds: [containerId],\n };\n const inputJson = JSON.stringify(rowInput);\n await tx\n .insert(pending)\n .values({\n containerId,\n documentId: input.documentId,\n accessEpoch: input.accessEpoch,\n generation,\n inputJson,\n retryAt: 0,\n })\n .onConflictDoUpdate({\n target: [pending.containerId, pending.documentId],\n set: {\n accessEpoch: input.accessEpoch,\n generation,\n inputJson,\n retryAt: sql`case when ${pending.inputJson} = ${inputJson} then ${pending.retryAt} else 0 end`,\n attempts: sql`case when ${pending.inputJson} = ${inputJson} then ${pending.attempts} else 0 end`,\n },\n setWhere: lte(pending.generation, generation),\n })\n .run();\n }\n }\n // These are untrusted, unapplied hints only. Removing an existing local\n // placement still requires the separate signed tombstone evidence gate.\n for (const row of removed) {\n await tx\n .delete(pending)\n .where(\n and(\n eq(pending.containerId, row.containerId),\n eq(pending.documentId, row.documentId),\n lte(pending.generation, generation),\n ),\n )\n .run();\n }\n });\n return true;\n });\n };\n pending = async (containerIds: readonly string[], limit: number) => {\n const db = await this.read();\n const result: DiscoveredDocumentCandidate[] = [];\n for (const batch of batches(containerIds)) {\n if (result.length >= limit) break;\n const rows = await db\n .select({ inputJson: pending.inputJson })\n .from(pending)\n .where(\n and(\n inArray(pending.containerId, [...batch]),\n lte(pending.retryAt, this.now()),\n ),\n )\n .orderBy(asc(pending.retryAt), asc(pending.documentId))\n .limit(limit - result.length);\n result.push(\n ...rows.map((row) => readStoredDiscoveryCandidate(row.inputJson)),\n );\n }\n return result;\n };\n defer = (input: DiscoveredDocumentCandidate, generation: number) =>\n this.write(async (db) => {\n if (!(await isDocumentDiscoveryGenerationCurrent(db, generation))) return;\n const [row] = await db\n .select({ attempts: pending.attempts })\n .from(pending)\n .where(identity(input))\n .limit(1);\n if (!row) return;\n const attempts = Math.min(row.attempts + 1, 8);\n await db\n .update(pending)\n .set({\n attempts,\n retryAt: this.now() + heldTombstoneRetryDelayMs(attempts),\n })\n .where(identity(input))\n .run();\n });\n acknowledge = (\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n ) =>\n this.write(async (db) => {\n if (!(await isDocumentDiscoveryGenerationCurrent(db, generation))) return;\n await db.transaction(async (tx) => {\n for (const input of inputs)\n await tx.delete(pending).where(identity(input)).run();\n });\n });\n hasPending = async (containerIds: readonly string[]) => {\n const db = await this.read();\n for (const batch of batches(containerIds)) {\n if (\n (\n await db\n .select({ documentId: pending.documentId })\n .from(pending)\n .where(inArray(pending.containerId, [...batch]))\n .limit(1)\n ).length\n )\n return true;\n }\n return false;\n };\n retryDelay = async (containerIds: readonly string[]) => {\n const db = await this.read();\n let due: number | null = null;\n for (const batch of batches(containerIds)) {\n const [row] = await db\n .select({ due: min(pending.retryAt) })\n .from(pending)\n .where(inArray(pending.containerId, [...batch]));\n if (row?.due !== null && row?.due !== undefined)\n due = Math.min(due ?? row.due, row.due);\n }\n return due === null ? null : Math.max(0, due - this.now());\n };\n loadHead = async (\n documentId: string,\n manifestHash: string | null | undefined,\n ) => {\n if (await loadDocumentPurgeCheckpoint(this.execSql, documentId))\n return {\n organizationId: null,\n accessEpoch: Number.MAX_SAFE_INTEGER,\n linkedContainerIds: [],\n };\n if (!manifestHash) return null;\n const db = await this.read();\n const [row] = await db\n .select()\n .from(heads)\n .where(\n and(\n eq(heads.documentId, documentId),\n eq(heads.manifestHash, manifestHash),\n ),\n )\n .limit(1);\n if (!row) return null;\n // A different verifier (for example tombstone removal) can advance the\n // signed checkpoint without updating documents.accessEpoch or this cache.\n // Old-organization pins survive recovery; only the cached signed head's\n // organization can authorize reuse. Missing pins require full verification.\n const checkpoints = await db\n .select()\n .from(accessManifestCheckpoints)\n .where(\n and(\n eq(accessManifestCheckpoints.objectKind, \"document\"),\n eq(accessManifestCheckpoints.objectId, documentId),\n eq(accessManifestCheckpoints.organizationId, row.organizationId),\n ),\n )\n .limit(1);\n if (\n checkpoints.length !== 1 ||\n checkpoints[0]?.manifestHash !== row.manifestHash ||\n checkpoints[0]?.epoch !== row.accessEpoch\n )\n return null;\n return {\n organizationId: row.organizationId,\n accessEpoch: row.accessEpoch,\n accessStateHash: row.manifestHash,\n linkedContainerIds: readStringArray(\n JSON.parse(row.linksJson),\n \"stored discovery links\",\n ),\n };\n };\n saveHead = (\n documentId: string,\n head: CachedDiscoveryHead,\n generation: number,\n ) =>\n this.write(async (db) => {\n if (\n !head.accessStateHash ||\n !head.organizationId ||\n !(await isDocumentDiscoveryGenerationCurrent(db, generation))\n )\n return false;\n const row = {\n documentId,\n organizationId: head.organizationId,\n manifestHash: head.accessStateHash,\n accessEpoch: head.accessEpoch,\n linksJson: JSON.stringify(head.linkedContainerIds),\n };\n await db\n .insert(heads)\n .values(row)\n .onConflictDoUpdate({\n target: [heads.documentId, heads.organizationId],\n set: row,\n setWhere: lte(heads.accessEpoch, head.accessEpoch),\n })\n .run();\n return true;\n });\n}\n\nexport function createDocumentDiscoveryEvidenceStore(\n execSql: ExecSql,\n now = Date.now,\n): DocumentDiscoveryEvidenceStore {\n return new SqlDocumentDiscoveryEvidenceStore(execSql, now);\n}\n"]}
1
+ {"version":3,"file":"documentDiscoveryEvidencePersistence.js","sourceRoot":"","sources":["documentDiscoveryEvidencePersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,EAEL,eAAe,EACf,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AAEzF,OAAO,EAEL,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,oCAAoC,EAAE,MAAM,0BAA0B,CAAC;AA2ChF,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAC3C,MAAM,KAAK,GAAG,sBAAsB,CAAC;AACrC,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,OAAO,GAAG,CAAC,GAAsB,EAAE,EAAE,CACzC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACrE,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,CACtD,CAAC;AACJ,MAAM,QAAQ,GAAG,CAAC,KAAkC,EAAE,EAAE,CACtD,GAAG,CACD,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,EAC1C,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,EACxC,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAC7C,CAAC;AAEJ,MAAM,iCAAiC;IAIlB;IACA;IAFnB,YACmB,OAAgB,EAChB,GAAiB;QADjB,YAAO,GAAP,OAAO,CAAS;QAChB,QAAG,GAAH,GAAG,CAAc;IACjC,CAAC;IAEI,IAAI,GAAG,KAAK,IAAI,EAAE;QACxB,MAAM,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,iCAAiC,CAAC,CAAC;QACvE,OAAO,iCAAiC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;IAC5D,CAAC,CAAC;IACM,KAAK,GAAG,KAAK,EACnB,SAEe,EACf,EAAE,CACF,wBAAwB,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACtD,MAAM,eAAe,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;QACjE,OAAO,SAAS,CAAC,iCAAiC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IACL,KAAK,GAAG,KAAK,IAAI,EAAE;QACjB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;iBACnB,MAAM,CAAC,yBAAyB,CAAC;iBACjC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;iBACzC,kBAAkB,CAAC;gBAClB,MAAM,EAAE,yBAAyB,CAAC,EAAE;gBACpC,GAAG,EAAE;oBACH,UAAU,EAAE,GAAG,CAAA,GAAG,yBAAyB,CAAC,UAAU,MAAM;iBAC7D;aACF,CAAC;iBACD,SAAS,CAAC,EAAE,UAAU,EAAE,yBAAyB,CAAC,UAAU,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;IACF,SAAS,GAAG,KAAK,EAAE,UAAkB,EAAE,EAAE,CACvC,oCAAoC,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,UAAU,CAAC,CAAC;IACtE,KAAK,GAAG,CACN,MAA8C,EAC9C,UAAkB,EAClB,UAAgD,EAAE,EAClD,EAAE;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC7B,IAAI,CAAC,CAAC,MAAM,oCAAoC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBAC/D,OAAO,KAAK,CAAC;YACf,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC7D,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;gBAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC;wBAAE,SAAS;oBACpD,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;wBACnD,MAAM,QAAQ,GAAG;4BACf,GAAG,KAAK;4BACR,WAAW;4BACX,kBAAkB,EAAE,CAAC,WAAW,CAAC;yBAClC,CAAC;wBACF,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;wBAC3C,MAAM,EAAE;6BACL,MAAM,CAAC,OAAO,CAAC;6BACf,MAAM,CAAC;4BACN,WAAW;4BACX,UAAU,EAAE,KAAK,CAAC,UAAU;4BAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;4BAC9B,UAAU;4BACV,SAAS;4BACT,OAAO,EAAE,CAAC;yBACX,CAAC;6BACD,kBAAkB,CAAC;4BAClB,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC;4BACjD,GAAG,EAAE;gCACH,WAAW,EAAE,KAAK,CAAC,WAAW;gCAC9B,UAAU;gCACV,SAAS;gCACT,OAAO,EAAE,GAAG,CAAA,aAAa,OAAO,CAAC,SAAS,MAAM,SAAS,SAAS,OAAO,CAAC,OAAO,aAAa;gCAC9F,QAAQ,EAAE,GAAG,CAAA,aAAa,OAAO,CAAC,SAAS,MAAM,SAAS,SAAS,OAAO,CAAC,QAAQ,aAAa;6BACjG;4BACD,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC;yBAC9C,CAAC;6BACD,GAAG,EAAE,CAAC;oBACX,CAAC;gBACH,CAAC;gBACD,wEAAwE;gBACxE,wEAAwE;gBACxE,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;oBAC1B,MAAM,EAAE;yBACL,MAAM,CAAC,OAAO,CAAC;yBACf,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,EACxC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,EACtC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CACpC,CACF;yBACA,GAAG,EAAE,CAAC;gBACX,CAAC;YACH,CAAC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,OAAO,GAAG,KAAK,EAAE,YAA+B,EAAE,KAAa,EAAE,EAAE;QACjE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAkC,EAAE,CAAC;QACjD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1C,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK;gBAAE,MAAM;YAClC,MAAM,IAAI,GAAG,MAAM,EAAE;iBAClB,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;iBACxC,IAAI,CAAC,OAAO,CAAC;iBACb,KAAK,CACJ,GAAG,CACD,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,EACxC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CACjC,CACF;iBACA,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;iBACtD,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAChC,MAAM,CAAC,IAAI,CACT,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,4BAA4B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAClE,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,KAAK,GAAG,CAAC,KAAkC,EAAE,UAAkB,EAAE,EAAE,CACjE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC,CAAC,MAAM,oCAAoC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAAE,OAAO;QAC1E,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;aACnB,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;aACtC,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aACtB,KAAK,CAAC,CAAC,CAAC,CAAC;QACZ,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,EAAE;aACL,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC;YACH,QAAQ;YACR,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,yBAAyB,CAAC,QAAQ,CAAC;SAC1D,CAAC;aACD,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aACtB,GAAG,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;IACL,WAAW,GAAG,CACZ,MAA8C,EAC9C,UAAkB,EAClB,EAAE,CACF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC,CAAC,MAAM,oCAAoC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAAE,OAAO;QAC1E,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAChC,KAAK,MAAM,KAAK,IAAI,MAAM;gBACxB,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACL,UAAU,GAAG,KAAK,EAAE,YAA+B,EAAE,EAAE;QACrD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1C,IACE,CACE,MAAM,EAAE;iBACL,MAAM,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;iBAC1C,IAAI,CAAC,OAAO,CAAC;iBACb,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;iBAC/C,KAAK,CAAC,CAAC,CAAC,CACZ,CAAC,MAAM;gBAER,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,UAAU,GAAG,KAAK,EAAE,YAA+B,EAAE,EAAE;QACrD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,GAAG,GAAkB,IAAI,CAAC;QAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;iBACnB,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;iBACrC,IAAI,CAAC,OAAO,CAAC;iBACb,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACnD,IAAI,GAAG,EAAE,GAAG,KAAK,IAAI,IAAI,GAAG,EAAE,GAAG,KAAK,SAAS;gBAC7C,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC;IACF,QAAQ,GAAG,KAAK,EACd,UAAkB,EAClB,YAAuC,EACvC,EAAE;QACF,IAAI,MAAM,2BAA2B,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC;YAC7D,OAAO;gBACL,cAAc,EAAE,IAAI;gBACpB,WAAW,EAAE,MAAM,CAAC,gBAAgB;gBACpC,kBAAkB,EAAE,EAAE;aACvB,CAAC;QACJ,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;aACnB,MAAM,EAAE;aACR,IAAI,CAAC,KAAK,CAAC;aACX,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,EAChC,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,YAAY,CAAC,CACrC,CACF;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QACZ,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,4EAA4E;QAC5E,MAAM,WAAW,GAAG,MAAM,EAAE;aACzB,MAAM,EAAE;aACR,IAAI,CAAC,yBAAyB,CAAC;aAC/B,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,yBAAyB,CAAC,UAAU,EAAE,UAAU,CAAC,EACpD,EAAE,CAAC,yBAAyB,CAAC,QAAQ,EAAE,UAAU,CAAC,EAClD,EAAE,CAAC,yBAAyB,CAAC,cAAc,EAAE,GAAG,CAAC,cAAc,CAAC,CACjE,CACF;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QACZ,IACE,WAAW,CAAC,MAAM,KAAK,CAAC;YACxB,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,KAAK,GAAG,CAAC,YAAY;YACjD,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,GAAG,CAAC,WAAW;YAEzC,OAAO,IAAI,CAAC;QACd,OAAO;YACL,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,eAAe,EAAE,GAAG,CAAC,YAAY;YACjC,kBAAkB,EAAE,eAAe,CACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EACzB,wBAAwB,CACzB;SACF,CAAC;IACJ,CAAC,CAAC;IACF,QAAQ,GAAG,CACT,UAAkB,EAClB,IAAyB,EACzB,UAAkB,EAClB,EAAE,CACF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACtB,IACE,CAAC,IAAI,CAAC,eAAe;YACrB,CAAC,IAAI,CAAC,cAAc;YACpB,CAAC,CAAC,MAAM,oCAAoC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAE7D,OAAO,KAAK,CAAC;QACf,MAAM,GAAG,GAAG;YACV,UAAU;YACV,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,YAAY,EAAE,IAAI,CAAC,eAAe;YAClC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC;SACnD,CAAC;QACF,MAAM,EAAE;aACL,MAAM,CAAC,KAAK,CAAC;aACb,MAAM,CAAC,GAAG,CAAC;aACX,kBAAkB,CAAC;YAClB,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC;YAChD,GAAG,EAAE,GAAG;YACR,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC;SACnD,CAAC;aACD,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;CACN;AAiBD,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,OAAgB,EAChB,QAA0C;IAE1C,MAAM,EAAE,GAAG,iCAAiC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;IACzD,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG;YACV,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,YAAY,EAAE,IAAI,CAAC,eAAe;YAClC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;SACxE,CAAC;QACF,MAAM,EAAE;aACL,MAAM,CAAC,KAAK,CAAC;aACb,MAAM,CAAC,GAAG,CAAC;aACX,kBAAkB,CAAC;YAClB,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC;YAChD,GAAG,EAAE,GAAG;YACR,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC;SACnD,CAAC;aACD,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oCAAoC,CAClD,OAAgB,EAChB,GAAG,GAAG,IAAI,CAAC,GAAG;IAEd,OAAO,IAAI,iCAAiC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAC7D,CAAC","sourcesContent":["import { and, asc, eq, inArray, lte, min, sql } from \"drizzle-orm\";\nimport { uniqueSortedStrings } from \"../../documents/shared/readers\";\nimport { readStringArray } from \"../../recordReaders\";\nimport {\n documentDiscoveryHeads,\n documentDiscoverySequence,\n pendingDocumentDiscoveries,\n} from \"../../sqlite/documentDiscoveryEvidenceSchema\";\nimport {\n accessManifestCheckpoints,\n documentContainerProjectionTables,\n} from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport { loadDocumentPurgeCheckpoint } from \"../documentPurgeCheckpointPersistence\";\nimport { heldTombstoneRetryDelayMs } from \"./containerDocumentTombstoneHoldsPersistence\";\n\nimport {\n type DiscoveredDocumentCandidate,\n isDiscoveredDocumentCandidate,\n readStoredDiscoveryCandidate,\n} from \"./documentDiscoveryCandidate\";\n\nimport { isDocumentDiscoveryGenerationCurrent } from \"./documentDiscoveryReset\";\n\nexport type { DiscoveredDocumentCandidate } from \"./documentDiscoveryCandidate\";\nexport interface CachedDiscoveryHead {\n readonly organizationId: string | null;\n readonly accessEpoch: number;\n readonly accessStateHash?: string;\n readonly linkedContainerIds: readonly string[];\n}\ninterface RemovedDiscoveryPlacement {\n readonly containerId: string;\n readonly documentId: string;\n}\nexport interface DocumentDiscoveryEvidenceStore {\n begin(): Promise<number>;\n isCurrent(generation: number): Promise<boolean>;\n stage(\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n removed?: readonly RemovedDiscoveryPlacement[],\n ): Promise<boolean>;\n pending(\n containerIds: readonly string[],\n limit: number,\n ): Promise<readonly DiscoveredDocumentCandidate[]>;\n defer(input: DiscoveredDocumentCandidate, generation: number): Promise<void>;\n acknowledge(\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n ): Promise<void>;\n hasPending(containerIds: readonly string[]): Promise<boolean>;\n retryDelay(containerIds: readonly string[]): Promise<number | null>;\n loadHead(\n documentId: string,\n manifestHash: string | null | undefined,\n ): Promise<CachedDiscoveryHead | null>;\n saveHead(\n documentId: string,\n head: CachedDiscoveryHead,\n generation: number,\n ): Promise<boolean>;\n}\n\nconst pending = pendingDocumentDiscoveries;\nconst heads = documentDiscoveryHeads;\nconst ID_BATCH_SIZE = 400;\nconst batches = (ids: readonly string[]) =>\n Array.from({ length: Math.ceil(ids.length / ID_BATCH_SIZE) }, (_, i) =>\n ids.slice(i * ID_BATCH_SIZE, (i + 1) * ID_BATCH_SIZE),\n );\nconst identity = (input: DiscoveredDocumentCandidate) =>\n and(\n eq(pending.containerId, input.containerId),\n eq(pending.documentId, input.documentId),\n eq(pending.inputJson, JSON.stringify(input)),\n );\n\nclass SqlDocumentDiscoveryEvidenceStore\n implements DocumentDiscoveryEvidenceStore\n{\n constructor(\n private readonly execSql: ExecSql,\n private readonly now: () => number,\n ) {}\n\n private read = async () => {\n await ensureSqlTables(this.execSql, documentContainerProjectionTables);\n return getClientSQLitePersistenceRuntime(this.execSql).db;\n };\n private write = async <T>(\n operation: (\n db: ReturnType<typeof getClientSQLitePersistenceRuntime>[\"db\"],\n ) => Promise<T>,\n ) =>\n runSerializedSqlMutation(this.execSql, async (locked) => {\n await ensureSqlTables(locked, documentContainerProjectionTables);\n return operation(getClientSQLitePersistenceRuntime(locked).db);\n });\n begin = async () => {\n let generation = 0;\n await this.write(async (db) => {\n const [row] = await db\n .insert(documentDiscoverySequence)\n .values({ id: \"requests\", generation: 1 })\n .onConflictDoUpdate({\n target: documentDiscoverySequence.id,\n set: {\n generation: sql`${documentDiscoverySequence.generation} + 1`,\n },\n })\n .returning({ generation: documentDiscoverySequence.generation });\n if (!row || !Number.isSafeInteger(row.generation))\n throw new Error(\"Document discovery generation is exhausted\");\n generation = row.generation;\n });\n return generation;\n };\n isCurrent = async (generation: number) =>\n isDocumentDiscoveryGenerationCurrent(await this.read(), generation);\n stage = (\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n removed: readonly RemovedDiscoveryPlacement[] = [],\n ) => {\n return this.write(async (db) => {\n if (!(await isDocumentDiscoveryGenerationCurrent(db, generation)))\n return false;\n if (inputs.length === 0 && removed.length === 0) return true;\n await db.transaction(async (tx) => {\n for (const input of inputs) {\n if (!isDiscoveredDocumentCandidate(input)) continue;\n for (const containerId of input.listedContainerIds) {\n const rowInput = {\n ...input,\n containerId,\n listedContainerIds: [containerId],\n };\n const inputJson = JSON.stringify(rowInput);\n await tx\n .insert(pending)\n .values({\n containerId,\n documentId: input.documentId,\n accessEpoch: input.accessEpoch,\n generation,\n inputJson,\n retryAt: 0,\n })\n .onConflictDoUpdate({\n target: [pending.containerId, pending.documentId],\n set: {\n accessEpoch: input.accessEpoch,\n generation,\n inputJson,\n retryAt: sql`case when ${pending.inputJson} = ${inputJson} then ${pending.retryAt} else 0 end`,\n attempts: sql`case when ${pending.inputJson} = ${inputJson} then ${pending.attempts} else 0 end`,\n },\n setWhere: lte(pending.generation, generation),\n })\n .run();\n }\n }\n // These are untrusted, unapplied hints only. Removing an existing local\n // placement still requires the separate signed tombstone evidence gate.\n for (const row of removed) {\n await tx\n .delete(pending)\n .where(\n and(\n eq(pending.containerId, row.containerId),\n eq(pending.documentId, row.documentId),\n lte(pending.generation, generation),\n ),\n )\n .run();\n }\n });\n return true;\n });\n };\n pending = async (containerIds: readonly string[], limit: number) => {\n const db = await this.read();\n const result: DiscoveredDocumentCandidate[] = [];\n for (const batch of batches(containerIds)) {\n if (result.length >= limit) break;\n const rows = await db\n .select({ inputJson: pending.inputJson })\n .from(pending)\n .where(\n and(\n inArray(pending.containerId, [...batch]),\n lte(pending.retryAt, this.now()),\n ),\n )\n .orderBy(asc(pending.retryAt), asc(pending.documentId))\n .limit(limit - result.length);\n result.push(\n ...rows.map((row) => readStoredDiscoveryCandidate(row.inputJson)),\n );\n }\n return result;\n };\n defer = (input: DiscoveredDocumentCandidate, generation: number) =>\n this.write(async (db) => {\n if (!(await isDocumentDiscoveryGenerationCurrent(db, generation))) return;\n const [row] = await db\n .select({ attempts: pending.attempts })\n .from(pending)\n .where(identity(input))\n .limit(1);\n if (!row) return;\n const attempts = Math.min(row.attempts + 1, 8);\n await db\n .update(pending)\n .set({\n attempts,\n retryAt: this.now() + heldTombstoneRetryDelayMs(attempts),\n })\n .where(identity(input))\n .run();\n });\n acknowledge = (\n inputs: readonly DiscoveredDocumentCandidate[],\n generation: number,\n ) =>\n this.write(async (db) => {\n if (!(await isDocumentDiscoveryGenerationCurrent(db, generation))) return;\n await db.transaction(async (tx) => {\n for (const input of inputs)\n await tx.delete(pending).where(identity(input)).run();\n });\n });\n hasPending = async (containerIds: readonly string[]) => {\n const db = await this.read();\n for (const batch of batches(containerIds)) {\n if (\n (\n await db\n .select({ documentId: pending.documentId })\n .from(pending)\n .where(inArray(pending.containerId, [...batch]))\n .limit(1)\n ).length\n )\n return true;\n }\n return false;\n };\n retryDelay = async (containerIds: readonly string[]) => {\n const db = await this.read();\n let due: number | null = null;\n for (const batch of batches(containerIds)) {\n const [row] = await db\n .select({ due: min(pending.retryAt) })\n .from(pending)\n .where(inArray(pending.containerId, [...batch]));\n if (row?.due !== null && row?.due !== undefined)\n due = Math.min(due ?? row.due, row.due);\n }\n return due === null ? null : Math.max(0, due - this.now());\n };\n loadHead = async (\n documentId: string,\n manifestHash: string | null | undefined,\n ) => {\n if (await loadDocumentPurgeCheckpoint(this.execSql, documentId))\n return {\n organizationId: null,\n accessEpoch: Number.MAX_SAFE_INTEGER,\n linkedContainerIds: [],\n };\n if (!manifestHash) return null;\n const db = await this.read();\n const [row] = await db\n .select()\n .from(heads)\n .where(\n and(\n eq(heads.documentId, documentId),\n eq(heads.manifestHash, manifestHash),\n ),\n )\n .limit(1);\n if (!row) return null;\n // A different verifier (for example tombstone removal) can advance the\n // signed checkpoint without updating documents.accessEpoch or this cache.\n // Old-organization pins survive recovery; only the cached signed head's\n // organization can authorize reuse. Missing pins require full verification.\n const checkpoints = await db\n .select()\n .from(accessManifestCheckpoints)\n .where(\n and(\n eq(accessManifestCheckpoints.objectKind, \"document\"),\n eq(accessManifestCheckpoints.objectId, documentId),\n eq(accessManifestCheckpoints.organizationId, row.organizationId),\n ),\n )\n .limit(1);\n if (\n checkpoints.length !== 1 ||\n checkpoints[0]?.manifestHash !== row.manifestHash ||\n checkpoints[0]?.epoch !== row.accessEpoch\n )\n return null;\n return {\n organizationId: row.organizationId,\n accessEpoch: row.accessEpoch,\n accessStateHash: row.manifestHash,\n linkedContainerIds: readStringArray(\n JSON.parse(row.linksJson),\n \"stored discovery links\",\n ),\n };\n };\n saveHead = (\n documentId: string,\n head: CachedDiscoveryHead,\n generation: number,\n ) =>\n this.write(async (db) => {\n if (\n !head.accessStateHash ||\n !head.organizationId ||\n !(await isDocumentDiscoveryGenerationCurrent(db, generation))\n )\n return false;\n const row = {\n documentId,\n organizationId: head.organizationId,\n manifestHash: head.accessStateHash,\n accessEpoch: head.accessEpoch,\n linksJson: JSON.stringify(head.linkedContainerIds),\n };\n await db\n .insert(heads)\n .values(row)\n .onConflictDoUpdate({\n target: [heads.documentId, heads.organizationId],\n set: row,\n setWhere: lte(heads.accessEpoch, head.accessEpoch),\n })\n .run();\n return true;\n });\n}\n\n/**\n * A document head this client signed, already checked against the server's\n * create acknowledgement and pinned as its access-manifest checkpoint in the\n * same transaction. It is the same signed head a discovery projection would\n * verify, so it seeds the exact-head cache; `loadHead` still reuses it only\n * while that checkpoint matches.\n */\nexport interface AuthoredDiscoveryHead {\n readonly documentId: string;\n readonly organizationId: string;\n readonly accessEpoch: number;\n readonly accessStateHash: string;\n readonly linkedContainerIds: readonly string[];\n}\n\n/** Writes authored heads inside the caller's serialized write transaction. */\nexport async function primeAuthoredDocumentDiscoveryHeads(\n execSql: ExecSql,\n authored: readonly AuthoredDiscoveryHead[],\n): Promise<void> {\n const db = getClientSQLitePersistenceRuntime(execSql).db;\n for (const head of authored) {\n const row = {\n documentId: head.documentId,\n organizationId: head.organizationId,\n manifestHash: head.accessStateHash,\n accessEpoch: head.accessEpoch,\n linksJson: JSON.stringify(uniqueSortedStrings(head.linkedContainerIds)),\n };\n await db\n .insert(heads)\n .values(row)\n .onConflictDoUpdate({\n target: [heads.documentId, heads.organizationId],\n set: row,\n setWhere: lte(heads.accessEpoch, head.accessEpoch),\n })\n .run();\n }\n}\n\nexport function createDocumentDiscoveryEvidenceStore(\n execSql: ExecSql,\n now = Date.now,\n): DocumentDiscoveryEvidenceStore {\n return new SqlDocumentDiscoveryEvidenceStore(execSql, now);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  export { createApiUserIdentitySource } from "./apiAdapter.js";
2
2
  export { requireTrustedUserIdentityResolver } from "./requiredResolver.js";
3
- export { createTrustedUserIdentityService } from "./service.js";
3
+ export { createTrustedUserIdentityService, loadPinnedUserIdentity, } from "./service.js";
4
4
  export { resolveIdentityTrustDomain } from "./trustDomain.js";
5
5
  export type { LocalUserIdentityCandidate, TrustedUserIdentity, TrustedUserIdentityResolver, } from "./types.js";
6
6
  export { validateUserIdentityKeys } from "./validation.js";
@@ -1,6 +1,6 @@
1
1
  export { createApiUserIdentitySource } from "./apiAdapter.js";
2
2
  export { requireTrustedUserIdentityResolver } from "./requiredResolver.js";
3
- export { createTrustedUserIdentityService } from "./service.js";
3
+ export { createTrustedUserIdentityService, loadPinnedUserIdentity, } from "./service.js";
4
4
  export { resolveIdentityTrustDomain } from "./trustDomain.js";
5
5
  export { validateUserIdentityKeys } from "./validation.js";
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,kCAAkC,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,gCAAgC,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAM3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { createApiUserIdentitySource } from \"./apiAdapter\";\nexport { requireTrustedUserIdentityResolver } from \"./requiredResolver\";\nexport { createTrustedUserIdentityService } from \"./service\";\nexport { resolveIdentityTrustDomain } from \"./trustDomain\";\nexport type {\n LocalUserIdentityCandidate,\n TrustedUserIdentity,\n TrustedUserIdentityResolver,\n} from \"./types\";\nexport { validateUserIdentityKeys } from \"./validation\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,kCAAkC,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EACL,gCAAgC,EAChC,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAM3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { createApiUserIdentitySource } from \"./apiAdapter\";\nexport { requireTrustedUserIdentityResolver } from \"./requiredResolver\";\nexport {\n createTrustedUserIdentityService,\n loadPinnedUserIdentity,\n} from \"./service\";\nexport { resolveIdentityTrustDomain } from \"./trustDomain\";\nexport type {\n LocalUserIdentityCandidate,\n TrustedUserIdentity,\n TrustedUserIdentityResolver,\n} from \"./types\";\nexport { validateUserIdentityKeys } from \"./validation\";\n"]}
@@ -1,2 +1,13 @@
1
- import { type TrustedUserIdentityService, type TrustedUserIdentityServiceDependencies } from "./types.js";
1
+ import type { ExecSql } from "../sqlite/sqlSchema.js";
2
+ import { type TrustedUserIdentity, type TrustedUserIdentityService, type TrustedUserIdentityServiceDependencies } from "./types.js";
3
+ /**
4
+ * Read-only: the identity this trust store already pins for `userId`, or null.
5
+ * The stored keys must still match their stored fingerprints. Never inserts,
6
+ * compares against or replaces a pin.
7
+ */
8
+ export declare function loadPinnedUserIdentity(input: {
9
+ readonly execSql: ExecSql;
10
+ readonly identityTrustDomain: string;
11
+ readonly userId: string;
12
+ }): Promise<TrustedUserIdentity | null>;
2
13
  export declare function createTrustedUserIdentityService(dependencies: TrustedUserIdentityServiceDependencies): TrustedUserIdentityService;
@@ -1,10 +1,10 @@
1
1
  import { KeyingVerificationError } from "../../internal/crypto/index.js";
2
- import { bytesToBase64 } from "../../internal/encoding/index.js";
3
- import { compareOrInsertTrustedUserIdentityPin, loadTrustedUserIdForSigningKey, TrustedUserIdentityPinCorruptError, TrustedUserIdentityPinMismatchError, } from "../persistence/trustedUserIdentityPinPersistence.js";
2
+ import { base64ToBytes, bytesToBase64 } from "../../internal/encoding/index.js";
3
+ import { compareOrInsertTrustedUserIdentityPin, loadTrustedUserIdentityPin, loadTrustedUserIdForSigningKey, TrustedUserIdentityPinCorruptError, TrustedUserIdentityPinMismatchError, } from "../persistence/trustedUserIdentityPinPersistence.js";
4
4
  import { TrustedUserIdentityPinContentionError } from "../persistence/trustedUserIdentityPinTransaction.js";
5
5
  import { DatabaseUnavailableError } from "../sync/databaseUnavailable.js";
6
6
  import { brandTrustedUserIdentity, TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE, TRUSTED_USER_IDENTITY_FORMAT_VERSION, TRUSTED_USER_IDENTITY_SIGNING_SUITE, } from "./types.js";
7
- import { assertTrustedUserIdentityUserId, validateLocalUserIdentity, validateRemoteUserIdentity, } from "./validation.js";
7
+ import { assertTrustedUserIdentityUserId, validateLocalUserIdentity, validateRemoteUserIdentity, validateUserIdentityKeys, } from "./validation.js";
8
8
  function requireTrustStore(dependencies) {
9
9
  // A missing trust domain is a static misconfiguration and must stay loud.
10
10
  if (!dependencies.identityTrustDomain) {
@@ -85,6 +85,30 @@ async function pinIdentity(input) {
85
85
  });
86
86
  return brandTrustedUserIdentity(input.identity);
87
87
  }
88
+ /**
89
+ * Read-only: the identity this trust store already pins for `userId`, or null.
90
+ * The stored keys must still match their stored fingerprints. Never inserts,
91
+ * compares against or replaces a pin.
92
+ */
93
+ export async function loadPinnedUserIdentity(input) {
94
+ assertTrustedUserIdentityUserId(input.userId);
95
+ const pin = await loadTrustedUserIdentityPin(input);
96
+ if (!pin)
97
+ return null;
98
+ const keys = await validateUserIdentityKeys({
99
+ candidate: {
100
+ encapsulationPublicKey: base64ToBytes(pin.encapsulationPublicKey),
101
+ signingKeyFingerprint: pin.signingKeyFingerprint,
102
+ signingPublicKey: base64ToBytes(pin.signingPublicKey),
103
+ },
104
+ encapsulationKeyFingerprint: pin.encapsulationKeyFingerprint,
105
+ });
106
+ return brandTrustedUserIdentity({
107
+ ...keys,
108
+ identityTrustDomain: input.identityTrustDomain,
109
+ userId: input.userId,
110
+ });
111
+ }
88
112
  export function createTrustedUserIdentityService(dependencies) {
89
113
  return {
90
114
  async boundUserId(signingKeyFingerprint) {
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,qCAAqC,EACrC,8BAA8B,EAC9B,kCAAkC,EAClC,mCAAmC,GACpC,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,qCAAqC,EAAE,MAAM,kDAAkD,CAAC;AACzG,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EACL,wBAAwB,EACxB,yCAAyC,EACzC,oCAAoC,EACpC,mCAAmC,GAKpC,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAEtB,SAAS,iBAAiB,CACxB,YAAoD;IAOpD,0EAA0E;IAC1E,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;QACtC,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,EACpB,qEAAqE,CACtE,CAAC;IACJ,CAAC;IACD,4EAA4E;IAC5E,6EAA6E;IAC7E,wEAAwE;IACxE,yEAAyE;IACzE,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,wBAAwB,CAChC,sEAAsE,CACvE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,YAAY,CAAC,mBAAmB,EAAE,CAAC;AAC5E,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,KAMpC;IACC,IAAI,CAAC;QACH,MAAM,qCAAqC,CAAC;YAC1C,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,EAAE;gBACH,2BAA2B,EAAE,KAAK,CAAC,QAAQ,CAAC,2BAA2B;gBACvE,sBAAsB,EAAE,aAAa,CACnC,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CACtC;gBACD,kBAAkB,EAAE,yCAAyC;gBAC7D,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,aAAa,EAAE,oCAAoC;gBACnD,mBAAmB,EAAE,KAAK,CAAC,QAAQ,CAAC,mBAAmB;gBACvD,qBAAqB,EAAE,KAAK,CAAC,QAAQ,CAAC,qBAAqB;gBAC3D,gBAAgB,EAAE,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAChE,YAAY,EAAE,mCAAmC;gBACjD,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;aAC9B;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,mCAAmC,EAAE,CAAC;YACzD,MAAM,IAAI,uBAAuB,CAC/B,cAAc,EACd,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC,MAAM;gBAC9C,CAAC,CAAC,mBAAmB,KAAK,CAAC,QAAQ,CAAC,MAAM,wBAAwB,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE;gBACzF,CAAC,CAAC,qCAAqC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CACjE,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,YAAY,kCAAkC,EAAE,CAAC;YACxD,MAAM,IAAI,uBAAuB,CAC/B,eAAe,EACf,4CAA4C,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CACpE,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,YAAY,qCAAqC,EAAE,CAAC;YAC3D,sEAAsE;YACtE,yEAAyE;YACzE,MAAM,IAAI,wBAAwB,CAChC,+CAA+C,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CACvE,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,YAAoD,EACpD,MAAc,EACd,mBAA2B;IAE3B,MAAM,WAAW,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC;IAClD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3B,MAAM,aAAa,GAAG,YAAY,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,EACpB,mDAAmD,CACpD,CAAC;QACJ,CAAC;QACD,OAAO,yBAAyB,CAAC;YAC/B,SAAS,EAAE,aAAa;YACxB,mBAAmB;YACnB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpE,OAAO,cAAc;QACnB,CAAC,CAAC,0BAA0B,CAAC;YACzB,SAAS,EAAE,cAAc;YACzB,mBAAmB;YACnB,eAAe,EAAE,MAAM;SACxB,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAM1B;IACC,MAAM,qBAAqB,CAAC;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,WAAW,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE;QACrE,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC;IACH,OAAO,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,gCAAgC,CAC9C,YAAoD;IAEpD,OAAO;QACL,KAAK,CAAC,WAAW,CAAC,qBAAqB;YACrC,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;YACzE,OAAO,8BAA8B,CAAC;gBACpC,OAAO;gBACP,mBAAmB;gBACnB,qBAAqB;aACtB,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS;YAC9B,+BAA+B,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;YACzE,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAAC;gBAC/C,SAAS;gBACT,mBAAmB;gBACnB,MAAM;aACP,CAAC,CAAC;YACH,OAAO,WAAW,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,MAAM;YAClB,+BAA+B,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;YACzE,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,YAAY,EACZ,MAAM,EACN,mBAAmB,CACpB,CAAC;gBACF,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,OAAO,MAAM,WAAW,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YAChE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBAC7C,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n compareOrInsertTrustedUserIdentityPin,\n loadTrustedUserIdForSigningKey,\n TrustedUserIdentityPinCorruptError,\n TrustedUserIdentityPinMismatchError,\n} from \"../persistence/trustedUserIdentityPinPersistence\";\nimport { TrustedUserIdentityPinContentionError } from \"../persistence/trustedUserIdentityPinTransaction\";\nimport { DatabaseUnavailableError } from \"../sync/databaseUnavailable\";\nimport {\n brandTrustedUserIdentity,\n TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n type TrustedUserIdentity,\n type TrustedUserIdentityService,\n type TrustedUserIdentityServiceDependencies,\n type ValidatedUserIdentityCandidate,\n} from \"./types\";\nimport {\n assertTrustedUserIdentityUserId,\n validateLocalUserIdentity,\n validateRemoteUserIdentity,\n} from \"./validation\";\n\nfunction requireTrustStore(\n dependencies: TrustedUserIdentityServiceDependencies,\n): {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identityTrustDomain: string;\n} {\n // A missing trust domain is a static misconfiguration and must stay loud.\n if (!dependencies.identityTrustDomain) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Trusted user identity resolution requires a stable API trust domain\",\n );\n }\n // An absent trust store is not: getExecSql() returns null exactly while the\n // database is not ready, which happens routinely when the runtime is swapped\n // under in-flight sync work. Callers that tolerate a vanishing database\n // discriminate on the error type, so this must not share the code above.\n const execSql = dependencies.getExecSql();\n if (!execSql) {\n throw new DatabaseUnavailableError(\n \"Trusted user identity resolution requires a ready SQLite trust store\",\n );\n }\n return { execSql, identityTrustDomain: dependencies.identityTrustDomain };\n}\n\nasync function compareWithDurablePin(input: {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly firstSeenAt: string;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<void> {\n try {\n await compareOrInsertTrustedUserIdentityPin({\n execSql: input.execSql,\n pin: {\n encapsulationKeyFingerprint: input.identity.encapsulationKeyFingerprint,\n encapsulationPublicKey: bytesToBase64(\n input.identity.encapsulationPublicKey,\n ),\n encapsulationSuite: TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n firstSeenAt: input.firstSeenAt,\n formatVersion: TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n identityTrustDomain: input.identity.identityTrustDomain,\n signingKeyFingerprint: input.identity.signingKeyFingerprint,\n signingPublicKey: bytesToBase64(input.identity.signingPublicKey),\n signingSuite: TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n userId: input.identity.userId,\n },\n });\n } catch (error) {\n if (error instanceof TrustedUserIdentityPinMismatchError) {\n throw new KeyingVerificationError(\n \"equivocation\",\n error.existing.userId !== error.candidate.userId\n ? `Signing key for ${input.identity.userId} is already bound to ${error.existing.userId}`\n : `Trusted user identity changed for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinCorruptError) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n `Trusted user identity pin is corrupt for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinContentionError) {\n // Lock contention says nothing about the identity; the caller retries\n // once the trust store is free, so this must not be recordable evidence.\n throw new DatabaseUnavailableError(\n `Trusted user identity pin store is busy for ${input.identity.userId}`,\n );\n }\n throw error;\n }\n}\n\nasync function resolveCandidate(\n dependencies: TrustedUserIdentityServiceDependencies,\n userId: string,\n identityTrustDomain: string,\n): Promise<ValidatedUserIdentityCandidate | null> {\n const localUserId = dependencies.getLocalUserId();\n if (userId === localUserId) {\n const localIdentity = dependencies.getLocalIdentity(userId);\n if (!localIdentity) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Authoritative local identity keys are unavailable\",\n );\n }\n return validateLocalUserIdentity({\n candidate: localIdentity,\n identityTrustDomain,\n userId,\n });\n }\n\n const remoteIdentity = await dependencies.remoteSource.load(userId);\n return remoteIdentity\n ? validateRemoteUserIdentity({\n candidate: remoteIdentity,\n identityTrustDomain,\n requestedUserId: userId,\n })\n : null;\n}\n\nasync function pinIdentity(input: {\n readonly dependencies: TrustedUserIdentityServiceDependencies;\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<TrustedUserIdentity> {\n await compareWithDurablePin({\n execSql: input.execSql,\n firstSeenAt: (input.dependencies.now?.() ?? new Date()).toISOString(),\n identity: input.identity,\n });\n return brandTrustedUserIdentity(input.identity);\n}\n\nexport function createTrustedUserIdentityService(\n dependencies: TrustedUserIdentityServiceDependencies,\n): TrustedUserIdentityService {\n return {\n async boundUserId(signingKeyFingerprint) {\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n return loadTrustedUserIdForSigningKey({\n execSql,\n identityTrustDomain,\n signingKeyFingerprint,\n });\n },\n async pinLocal(userId, candidate) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n const identity = await validateLocalUserIdentity({\n candidate,\n identityTrustDomain,\n userId,\n });\n return pinIdentity({ dependencies, execSql, identity });\n },\n async resolve(userId) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n try {\n const identity = await resolveCandidate(\n dependencies,\n userId,\n identityTrustDomain,\n );\n if (!identity) {\n return null;\n }\n return await pinIdentity({ dependencies, execSql, identity });\n } catch (error) {\n dependencies.remoteSource.invalidate(userId);\n throw error;\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["service.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n compareOrInsertTrustedUserIdentityPin,\n loadTrustedUserIdentityPin,\n loadTrustedUserIdForSigningKey,\n TrustedUserIdentityPinCorruptError,\n TrustedUserIdentityPinMismatchError,\n} from \"../persistence/trustedUserIdentityPinPersistence\";\nimport { TrustedUserIdentityPinContentionError } from \"../persistence/trustedUserIdentityPinTransaction\";\nimport type { ExecSql } from \"../sqlite/sqlSchema\";\nimport { DatabaseUnavailableError } from \"../sync/databaseUnavailable\";\nimport {\n brandTrustedUserIdentity,\n TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n type TrustedUserIdentity,\n type TrustedUserIdentityService,\n type TrustedUserIdentityServiceDependencies,\n type ValidatedUserIdentityCandidate,\n} from \"./types\";\nimport {\n assertTrustedUserIdentityUserId,\n validateLocalUserIdentity,\n validateRemoteUserIdentity,\n validateUserIdentityKeys,\n} from \"./validation\";\n\nfunction requireTrustStore(\n dependencies: TrustedUserIdentityServiceDependencies,\n): {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identityTrustDomain: string;\n} {\n // A missing trust domain is a static misconfiguration and must stay loud.\n if (!dependencies.identityTrustDomain) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Trusted user identity resolution requires a stable API trust domain\",\n );\n }\n // An absent trust store is not: getExecSql() returns null exactly while the\n // database is not ready, which happens routinely when the runtime is swapped\n // under in-flight sync work. Callers that tolerate a vanishing database\n // discriminate on the error type, so this must not share the code above.\n const execSql = dependencies.getExecSql();\n if (!execSql) {\n throw new DatabaseUnavailableError(\n \"Trusted user identity resolution requires a ready SQLite trust store\",\n );\n }\n return { execSql, identityTrustDomain: dependencies.identityTrustDomain };\n}\n\nasync function compareWithDurablePin(input: {\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly firstSeenAt: string;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<void> {\n try {\n await compareOrInsertTrustedUserIdentityPin({\n execSql: input.execSql,\n pin: {\n encapsulationKeyFingerprint: input.identity.encapsulationKeyFingerprint,\n encapsulationPublicKey: bytesToBase64(\n input.identity.encapsulationPublicKey,\n ),\n encapsulationSuite: TRUSTED_USER_IDENTITY_ENCAPSULATION_SUITE,\n firstSeenAt: input.firstSeenAt,\n formatVersion: TRUSTED_USER_IDENTITY_FORMAT_VERSION,\n identityTrustDomain: input.identity.identityTrustDomain,\n signingKeyFingerprint: input.identity.signingKeyFingerprint,\n signingPublicKey: bytesToBase64(input.identity.signingPublicKey),\n signingSuite: TRUSTED_USER_IDENTITY_SIGNING_SUITE,\n userId: input.identity.userId,\n },\n });\n } catch (error) {\n if (error instanceof TrustedUserIdentityPinMismatchError) {\n throw new KeyingVerificationError(\n \"equivocation\",\n error.existing.userId !== error.candidate.userId\n ? `Signing key for ${input.identity.userId} is already bound to ${error.existing.userId}`\n : `Trusted user identity changed for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinCorruptError) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n `Trusted user identity pin is corrupt for ${input.identity.userId}`,\n );\n }\n if (error instanceof TrustedUserIdentityPinContentionError) {\n // Lock contention says nothing about the identity; the caller retries\n // once the trust store is free, so this must not be recordable evidence.\n throw new DatabaseUnavailableError(\n `Trusted user identity pin store is busy for ${input.identity.userId}`,\n );\n }\n throw error;\n }\n}\n\nasync function resolveCandidate(\n dependencies: TrustedUserIdentityServiceDependencies,\n userId: string,\n identityTrustDomain: string,\n): Promise<ValidatedUserIdentityCandidate | null> {\n const localUserId = dependencies.getLocalUserId();\n if (userId === localUserId) {\n const localIdentity = dependencies.getLocalIdentity(userId);\n if (!localIdentity) {\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Authoritative local identity keys are unavailable\",\n );\n }\n return validateLocalUserIdentity({\n candidate: localIdentity,\n identityTrustDomain,\n userId,\n });\n }\n\n const remoteIdentity = await dependencies.remoteSource.load(userId);\n return remoteIdentity\n ? validateRemoteUserIdentity({\n candidate: remoteIdentity,\n identityTrustDomain,\n requestedUserId: userId,\n })\n : null;\n}\n\nasync function pinIdentity(input: {\n readonly dependencies: TrustedUserIdentityServiceDependencies;\n readonly execSql: NonNullable<\n ReturnType<TrustedUserIdentityServiceDependencies[\"getExecSql\"]>\n >;\n readonly identity: ValidatedUserIdentityCandidate;\n}): Promise<TrustedUserIdentity> {\n await compareWithDurablePin({\n execSql: input.execSql,\n firstSeenAt: (input.dependencies.now?.() ?? new Date()).toISOString(),\n identity: input.identity,\n });\n return brandTrustedUserIdentity(input.identity);\n}\n\n/**\n * Read-only: the identity this trust store already pins for `userId`, or null.\n * The stored keys must still match their stored fingerprints. Never inserts,\n * compares against or replaces a pin.\n */\nexport async function loadPinnedUserIdentity(input: {\n readonly execSql: ExecSql;\n readonly identityTrustDomain: string;\n readonly userId: string;\n}): Promise<TrustedUserIdentity | null> {\n assertTrustedUserIdentityUserId(input.userId);\n const pin = await loadTrustedUserIdentityPin(input);\n if (!pin) return null;\n const keys = await validateUserIdentityKeys({\n candidate: {\n encapsulationPublicKey: base64ToBytes(pin.encapsulationPublicKey),\n signingKeyFingerprint: pin.signingKeyFingerprint,\n signingPublicKey: base64ToBytes(pin.signingPublicKey),\n },\n encapsulationKeyFingerprint: pin.encapsulationKeyFingerprint,\n });\n return brandTrustedUserIdentity({\n ...keys,\n identityTrustDomain: input.identityTrustDomain,\n userId: input.userId,\n });\n}\n\nexport function createTrustedUserIdentityService(\n dependencies: TrustedUserIdentityServiceDependencies,\n): TrustedUserIdentityService {\n return {\n async boundUserId(signingKeyFingerprint) {\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n return loadTrustedUserIdForSigningKey({\n execSql,\n identityTrustDomain,\n signingKeyFingerprint,\n });\n },\n async pinLocal(userId, candidate) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n const identity = await validateLocalUserIdentity({\n candidate,\n identityTrustDomain,\n userId,\n });\n return pinIdentity({ dependencies, execSql, identity });\n },\n async resolve(userId) {\n assertTrustedUserIdentityUserId(userId);\n const { execSql, identityTrustDomain } = requireTrustStore(dependencies);\n try {\n const identity = await resolveCandidate(\n dependencies,\n userId,\n identityTrustDomain,\n );\n if (!identity) {\n return null;\n }\n return await pinIdentity({ dependencies, execSql, identity });\n } catch (error) {\n dependencies.remoteSource.invalidate(userId);\n throw error;\n }\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tearleads/client-sdk",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "description": "React-free Tearleads client runtime: local SQLite persistence, keys, sync, encrypted blobs, and domain workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -3,6 +3,7 @@ import type { CreateOrganizationRequest } from "../../internal/validators/reques
3
3
  import type { CreateOrganizationResponse } from "../../internal/validators/response/index.js";
4
4
  import type { DocumentProjectorRegistryInput } from "../../data/documents/documentKinds.js";
5
5
  import type { ExecSqlClientLike } from "../../data/sqlite/sqlSchema.js";
6
+ import type { ProvisionedPrincipalHistoryPrimer } from "../registration/provisionedPrincipalHistory.js";
6
7
  import { type ProvisionedSystemContainerSpec } from "../registration/registerIdentity.js";
7
8
  import { removeNativeSubscriptionRestoreProvisioningAttempt } from "./organizationProvisioningAttempt.js";
8
9
  export { removeNativeSubscriptionRestoreProvisioningAttempt };
@@ -29,6 +30,8 @@ export interface CreateOrganizationInput {
29
30
  logError?: ((message: string | Error, cause?: unknown) => void) | undefined;
30
31
  /** Overrides the seeded organization profile name; see registration. */
31
32
  organizationProfileName?: string | undefined;
33
+ /** Seeds verified recovery progress for the founding policy heads. */
34
+ primePrincipalHistory?: ProvisionedPrincipalHistoryPrimer | undefined;
32
35
  /**
33
36
  * App-owned system containers to provision atomically with the new
34
37
  * organization (e.g. a trash bin). See registration.
@@ -115,6 +115,7 @@ export async function createOrganization(input) {
115
115
  log: input.log,
116
116
  logError: input.logError,
117
117
  organizationMetadataBootstrap: artifacts.organizationMetadataBootstrap,
118
+ primePrincipalHistory: input.primePrincipalHistory,
118
119
  response,
119
120
  rootContainer: artifacts.rootContainer,
120
121
  rootMetadataDocument: artifacts.rootMetadataDocument,
@@ -1 +1 @@
1
- {"version":3,"file":"createOrganization.js","sourceRoot":"","sources":["createOrganization.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type EncapsulationKeyPair,\n type SigningKeyPair,\n signOrganizationReplacementAuthorization,\n} from \"@tearleads/crypto\";\nimport type { CreateOrganizationRequest } from \"@tearleads/validators/request\";\nimport type { CreateOrganizationResponse } from \"@tearleads/validators/response\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport type { ExecSqlClientLike } from \"../../data/sqlite/sqlSchema\";\nimport { createExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n buildOrganizationProvisioningArtifacts,\n type OrganizationProvisioningArtifacts,\n type OrganizationProvisioningArtifactsInput,\n type ProvisionedSystemContainerSpec,\n persistOrganizationProvisioningState,\n} from \"../registration/registerIdentity\";\nimport {\n makeOrganizationProvisioningAttemptDurable,\n removeNativeSubscriptionRestoreProvisioningAttempt,\n} from \"./organizationProvisioningAttempt\";\nimport { pinOrganizationReplacementResponse } from \"./organizationReplacementVerification\";\n\nexport { removeNativeSubscriptionRestoreProvisioningAttempt };\n\nexport interface CreateOrganizationApi {\n createOrganization(\n request: CreateOrganizationRequest,\n ): Promise<CreateOrganizationResponse | null>;\n}\n\nexport interface CreateOrganizationInput {\n apiClient: CreateOrganizationApi;\n dbClient: ExecSqlClientLike;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n encapsulationKeyPair: EncapsulationKeyPair;\n /**\n * Returns false once the identity that supplied the key pairs is no longer\n * active. Checked before the remote create (so a stale request is never\n * submitted) and again before local persistence: an identity switch closes\n * or renews the captured database client, so persisting would write another\n * identity's bootstrap — or throw — after the org already exists remotely.\n * The caller discards the result.\n */\n isIdentityCurrent?: (() => boolean) | undefined;\n /** @internal Forwarded to the bootstrap persist; test-only seam. */\n onPersistQueued?: (() => void) | undefined;\n log?: ((message: string) => void) | undefined;\n logError?: ((message: string | Error, cause?: unknown) => void) | undefined;\n /** Overrides the seeded organization profile name; see registration. */\n organizationProfileName?: string | undefined;\n /**\n * App-owned system containers to provision atomically with the new\n * organization (e.g. a trash bin). See registration.\n */\n provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n /** Purged organization whose personal-org generation this replaces. */\n replacesOrganizationId?: string | undefined;\n /** Marks and durably replays a fresh native-subscription restore target. */\n nativeSubscriptionRestore?: boolean | undefined;\n /** Overrides the seeded self roster-profile nickname; see registration. */\n rosterProfileNickname?: string | undefined;\n signingKeyPair: SigningKeyPair;\n /**\n * The already-registered user creating the organization; they become its\n * founding admin. The server independently requires this to match the\n * authenticated session.\n */\n userId: string;\n}\n\nfunction isAdoptedReplacementResponse(input: {\n creation: CreateOrganizationInput;\n request: CreateOrganizationRequest;\n response: CreateOrganizationResponse;\n}): boolean {\n if (\n input.response.organizationId === input.request.organizationId &&\n input.response.rootContainerId === input.request.rootContainerId\n ) {\n return false;\n }\n if (\n !input.creation.replacesOrganizationId ||\n input.response.userId !== input.creation.userId\n ) {\n throw new Error(\n \"Organization provisioning returned an unexpected organization\",\n );\n }\n input.creation.log?.(\n `Organization replacement adopted (${input.response.organizationId})`,\n );\n return true;\n}\n\nasync function buildOrganizationCandidate(\n input: CreateOrganizationInput,\n rootContainerId: string,\n): Promise<OrganizationProvisioningArtifacts | null> {\n const artifactsInput: OrganizationProvisioningArtifactsInput = {\n encapsulationKeyPair: input.encapsulationKeyPair,\n organizationProfileName: input.organizationProfileName,\n provisionedSystemContainers: input.provisionedSystemContainers,\n rootContainerId,\n rosterProfileNickname: input.rosterProfileNickname,\n signingKeyPair: input.signingKeyPair,\n userId: input.userId,\n };\n const artifacts: OrganizationProvisioningArtifacts =\n await buildOrganizationProvisioningArtifacts(artifactsInput);\n\n if (input.replacesOrganizationId) {\n artifacts.replacementAuthorization =\n await signOrganizationReplacementAuthorization(\n {\n ...artifacts,\n replacesOrganizationId: input.replacesOrganizationId,\n rootContainerId,\n userId: input.userId,\n },\n input.signingKeyPair,\n );\n }\n\n if (\n input.replacesOrganizationId &&\n input.isIdentityCurrent &&\n !input.isIdentityCurrent()\n ) {\n input.log?.(\n \"Organization creation aborted: identity changed while building artifacts\",\n );\n return null;\n }\n\n return artifacts;\n}\n\n/**\n * Provisions an additional organization for an already-registered user, reusing\n * the exact artifact-build and local-persistence path as registration\n * ({@link buildOrganizationProvisioningArtifacts} /\n * {@link persistOrganizationProvisioningState}). Unlike registration it mints a\n * fresh root container id, signs with the caller's existing identity, and needs\n * no auth challenge — the user is already authenticated.\n */\nexport async function createOrganization(\n input: CreateOrganizationInput,\n): Promise<CreateOrganizationResponse | null> {\n input.log?.(\"Creating organization...\");\n\n const rootContainerId = crypto.randomUUID();\n const candidateArtifacts = await buildOrganizationCandidate(\n input,\n rootContainerId,\n );\n\n if (!candidateArtifacts) return null;\n\n const durableAttempt = await makeOrganizationProvisioningAttemptDurable({\n artifacts: candidateArtifacts,\n canStartDurableMutation: input.isIdentityCurrent,\n dbClient: input.dbClient,\n nativeSubscriptionRestore: input.nativeSubscriptionRestore,\n replacesOrganizationId: input.replacesOrganizationId,\n rootContainerId,\n userId: input.userId,\n });\n if (!durableAttempt) {\n input.log?.(\n \"Organization creation aborted: identity changed before saving artifacts\",\n );\n return null;\n }\n const {\n artifacts,\n request,\n rootContainerId: durableRootContainerId,\n } = durableAttempt;\n\n if (input.isIdentityCurrent && !input.isIdentityCurrent()) {\n input.log?.(\n \"Organization creation aborted: identity changed before provisioning\",\n );\n return null;\n }\n\n const response = await input.apiClient.createOrganization(request);\n if (!response) {\n return null;\n }\n\n if (input.isIdentityCurrent && !input.isIdentityCurrent()) {\n input.log?.(\n \"Organization creation discarded: identity changed while provisioning\",\n );\n return null;\n }\n\n if (\n input.replacesOrganizationId &&\n !(await pinOrganizationReplacementResponse({\n replacesOrganizationId: input.replacesOrganizationId,\n response,\n signingPublicKey: input.signingKeyPair.signingPublicKey,\n userId: input.userId,\n execSql: createExecSql(input.dbClient),\n stillCurrent: input.isIdentityCurrent,\n }))\n )\n return null;\n\n if (isAdoptedReplacementResponse({ creation: input, request, response })) {\n // Another device authorized this winning genesis with the same identity.\n // Its encrypted bootstrap will hydrate normally; persisting\n // this device's losing candidate would instead create an unrelated local\n // root. The session reset rebinds retained local data to the winning ids.\n return response;\n }\n\n input.log?.(`Organization created (${response.organizationId})`);\n await persistOrganizationProvisioningState({\n bootstrap: artifacts.bootstrap,\n canStartDurableMutation: input.isIdentityCurrent,\n onPersistQueued: input.onPersistQueued,\n containerId: durableRootContainerId,\n dbClient: input.dbClient,\n documentProjectors: input.documentProjectors,\n initialAdminGroup: artifacts.initialAdminGroup,\n initialMemberGroup: artifacts.initialMemberGroup,\n initialOrganizationPolicy: artifacts.initialOrganizationPolicy,\n log: input.log,\n logError: input.logError,\n organizationMetadataBootstrap: artifacts.organizationMetadataBootstrap,\n response,\n rootContainer: artifacts.rootContainer,\n rootMetadataDocument: artifacts.rootMetadataDocument,\n rootMetadataDocumentRequest: artifacts.rootMetadataDocumentRequest,\n rosterProfileBootstrap: artifacts.rosterProfileBootstrap,\n systemContainerBootstraps: artifacts.systemContainerBootstraps,\n });\n\n return response;\n}\n"]}
1
+ {"version":3,"file":"createOrganization.js","sourceRoot":"","sources":["createOrganization.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type EncapsulationKeyPair,\n type SigningKeyPair,\n signOrganizationReplacementAuthorization,\n} from \"@tearleads/crypto\";\nimport type { CreateOrganizationRequest } from \"@tearleads/validators/request\";\nimport type { CreateOrganizationResponse } from \"@tearleads/validators/response\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport type { ExecSqlClientLike } from \"../../data/sqlite/sqlSchema\";\nimport { createExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { ProvisionedPrincipalHistoryPrimer } from \"../registration/provisionedPrincipalHistory\";\nimport {\n buildOrganizationProvisioningArtifacts,\n type OrganizationProvisioningArtifacts,\n type OrganizationProvisioningArtifactsInput,\n type ProvisionedSystemContainerSpec,\n persistOrganizationProvisioningState,\n} from \"../registration/registerIdentity\";\nimport {\n makeOrganizationProvisioningAttemptDurable,\n removeNativeSubscriptionRestoreProvisioningAttempt,\n} from \"./organizationProvisioningAttempt\";\nimport { pinOrganizationReplacementResponse } from \"./organizationReplacementVerification\";\n\nexport { removeNativeSubscriptionRestoreProvisioningAttempt };\n\nexport interface CreateOrganizationApi {\n createOrganization(\n request: CreateOrganizationRequest,\n ): Promise<CreateOrganizationResponse | null>;\n}\n\nexport interface CreateOrganizationInput {\n apiClient: CreateOrganizationApi;\n dbClient: ExecSqlClientLike;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n encapsulationKeyPair: EncapsulationKeyPair;\n /**\n * Returns false once the identity that supplied the key pairs is no longer\n * active. Checked before the remote create (so a stale request is never\n * submitted) and again before local persistence: an identity switch closes\n * or renews the captured database client, so persisting would write another\n * identity's bootstrap — or throw — after the org already exists remotely.\n * The caller discards the result.\n */\n isIdentityCurrent?: (() => boolean) | undefined;\n /** @internal Forwarded to the bootstrap persist; test-only seam. */\n onPersistQueued?: (() => void) | undefined;\n log?: ((message: string) => void) | undefined;\n logError?: ((message: string | Error, cause?: unknown) => void) | undefined;\n /** Overrides the seeded organization profile name; see registration. */\n organizationProfileName?: string | undefined;\n /** Seeds verified recovery progress for the founding policy heads. */\n primePrincipalHistory?: ProvisionedPrincipalHistoryPrimer | undefined;\n /**\n * App-owned system containers to provision atomically with the new\n * organization (e.g. a trash bin). See registration.\n */\n provisionedSystemContainers?:\n | ReadonlyArray<ProvisionedSystemContainerSpec>\n | undefined;\n /** Purged organization whose personal-org generation this replaces. */\n replacesOrganizationId?: string | undefined;\n /** Marks and durably replays a fresh native-subscription restore target. */\n nativeSubscriptionRestore?: boolean | undefined;\n /** Overrides the seeded self roster-profile nickname; see registration. */\n rosterProfileNickname?: string | undefined;\n signingKeyPair: SigningKeyPair;\n /**\n * The already-registered user creating the organization; they become its\n * founding admin. The server independently requires this to match the\n * authenticated session.\n */\n userId: string;\n}\n\nfunction isAdoptedReplacementResponse(input: {\n creation: CreateOrganizationInput;\n request: CreateOrganizationRequest;\n response: CreateOrganizationResponse;\n}): boolean {\n if (\n input.response.organizationId === input.request.organizationId &&\n input.response.rootContainerId === input.request.rootContainerId\n ) {\n return false;\n }\n if (\n !input.creation.replacesOrganizationId ||\n input.response.userId !== input.creation.userId\n ) {\n throw new Error(\n \"Organization provisioning returned an unexpected organization\",\n );\n }\n input.creation.log?.(\n `Organization replacement adopted (${input.response.organizationId})`,\n );\n return true;\n}\n\nasync function buildOrganizationCandidate(\n input: CreateOrganizationInput,\n rootContainerId: string,\n): Promise<OrganizationProvisioningArtifacts | null> {\n const artifactsInput: OrganizationProvisioningArtifactsInput = {\n encapsulationKeyPair: input.encapsulationKeyPair,\n organizationProfileName: input.organizationProfileName,\n provisionedSystemContainers: input.provisionedSystemContainers,\n rootContainerId,\n rosterProfileNickname: input.rosterProfileNickname,\n signingKeyPair: input.signingKeyPair,\n userId: input.userId,\n };\n const artifacts: OrganizationProvisioningArtifacts =\n await buildOrganizationProvisioningArtifacts(artifactsInput);\n\n if (input.replacesOrganizationId) {\n artifacts.replacementAuthorization =\n await signOrganizationReplacementAuthorization(\n {\n ...artifacts,\n replacesOrganizationId: input.replacesOrganizationId,\n rootContainerId,\n userId: input.userId,\n },\n input.signingKeyPair,\n );\n }\n\n if (\n input.replacesOrganizationId &&\n input.isIdentityCurrent &&\n !input.isIdentityCurrent()\n ) {\n input.log?.(\n \"Organization creation aborted: identity changed while building artifacts\",\n );\n return null;\n }\n\n return artifacts;\n}\n\n/**\n * Provisions an additional organization for an already-registered user, reusing\n * the exact artifact-build and local-persistence path as registration\n * ({@link buildOrganizationProvisioningArtifacts} /\n * {@link persistOrganizationProvisioningState}). Unlike registration it mints a\n * fresh root container id, signs with the caller's existing identity, and needs\n * no auth challenge — the user is already authenticated.\n */\nexport async function createOrganization(\n input: CreateOrganizationInput,\n): Promise<CreateOrganizationResponse | null> {\n input.log?.(\"Creating organization...\");\n\n const rootContainerId = crypto.randomUUID();\n const candidateArtifacts = await buildOrganizationCandidate(\n input,\n rootContainerId,\n );\n\n if (!candidateArtifacts) return null;\n\n const durableAttempt = await makeOrganizationProvisioningAttemptDurable({\n artifacts: candidateArtifacts,\n canStartDurableMutation: input.isIdentityCurrent,\n dbClient: input.dbClient,\n nativeSubscriptionRestore: input.nativeSubscriptionRestore,\n replacesOrganizationId: input.replacesOrganizationId,\n rootContainerId,\n userId: input.userId,\n });\n if (!durableAttempt) {\n input.log?.(\n \"Organization creation aborted: identity changed before saving artifacts\",\n );\n return null;\n }\n const {\n artifacts,\n request,\n rootContainerId: durableRootContainerId,\n } = durableAttempt;\n\n if (input.isIdentityCurrent && !input.isIdentityCurrent()) {\n input.log?.(\n \"Organization creation aborted: identity changed before provisioning\",\n );\n return null;\n }\n\n const response = await input.apiClient.createOrganization(request);\n if (!response) {\n return null;\n }\n\n if (input.isIdentityCurrent && !input.isIdentityCurrent()) {\n input.log?.(\n \"Organization creation discarded: identity changed while provisioning\",\n );\n return null;\n }\n\n if (\n input.replacesOrganizationId &&\n !(await pinOrganizationReplacementResponse({\n replacesOrganizationId: input.replacesOrganizationId,\n response,\n signingPublicKey: input.signingKeyPair.signingPublicKey,\n userId: input.userId,\n execSql: createExecSql(input.dbClient),\n stillCurrent: input.isIdentityCurrent,\n }))\n )\n return null;\n\n if (isAdoptedReplacementResponse({ creation: input, request, response })) {\n // Another device authorized this winning genesis with the same identity.\n // Its encrypted bootstrap will hydrate normally; persisting\n // this device's losing candidate would instead create an unrelated local\n // root. The session reset rebinds retained local data to the winning ids.\n return response;\n }\n\n input.log?.(`Organization created (${response.organizationId})`);\n await persistOrganizationProvisioningState({\n bootstrap: artifacts.bootstrap,\n canStartDurableMutation: input.isIdentityCurrent,\n onPersistQueued: input.onPersistQueued,\n containerId: durableRootContainerId,\n dbClient: input.dbClient,\n documentProjectors: input.documentProjectors,\n initialAdminGroup: artifacts.initialAdminGroup,\n initialMemberGroup: artifacts.initialMemberGroup,\n initialOrganizationPolicy: artifacts.initialOrganizationPolicy,\n log: input.log,\n logError: input.logError,\n organizationMetadataBootstrap: artifacts.organizationMetadataBootstrap,\n primePrincipalHistory: input.primePrincipalHistory,\n response,\n rootContainer: artifacts.rootContainer,\n rootMetadataDocument: artifacts.rootMetadataDocument,\n rootMetadataDocumentRequest: artifacts.rootMetadataDocumentRequest,\n rosterProfileBootstrap: artifacts.rosterProfileBootstrap,\n systemContainerBootstraps: artifacts.systemContainerBootstraps,\n });\n\n return response;\n}\n"]}
@@ -2,6 +2,7 @@ import type { OrganizationProvisioningResponse } from "../../internal/validators
2
2
  import type { DocumentProjectorRegistryInput } from "../../data/documents/documentKinds.js";
3
3
  import type { ExecSqlClientLike } from "../../data/sqlite/sqlSchema.js";
4
4
  import type { OrganizationProvisioningArtifacts } from "./organizationProvisioningArtifacts.js";
5
+ import type { ProvisionedPrincipalHistoryPrimer } from "./provisionedPrincipalHistory.js";
5
6
  type PersistOrganizationProvisioningStateInput = Pick<OrganizationProvisioningArtifacts, "bootstrap" | "initialAdminGroup" | "initialMemberGroup" | "initialOrganizationPolicy" | "organizationMetadataBootstrap" | "rootContainer" | "rootMetadataDocument" | "rootMetadataDocumentRequest" | "rosterProfileBootstrap" | "systemContainerBootstraps"> & {
6
7
  /** Forwarded to the bootstrap persist's in-mutex currency check. */
7
8
  readonly canStartDurableMutation?: (() => boolean) | undefined;
@@ -12,6 +13,8 @@ type PersistOrganizationProvisioningStateInput = Pick<OrganizationProvisioningAr
12
13
  readonly documentProjectors?: DocumentProjectorRegistryInput | undefined;
13
14
  readonly log?: ((message: string) => void) | undefined;
14
15
  readonly logError?: ((message: string | Error, cause?: unknown) => void) | undefined;
16
+ /** Seeds verified recovery progress once the bootstrap commits. */
17
+ readonly primePrincipalHistory?: ProvisionedPrincipalHistoryPrimer | undefined;
15
18
  readonly response: OrganizationProvisioningResponse;
16
19
  };
17
20
  export declare function persistOrganizationProvisioningState(input: PersistOrganizationProvisioningStateInput): Promise<void>;