@tearleads/client-sdk 0.1.38 → 0.1.40

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 (76) 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/organizations/organizationGroupPresentation.d.ts +1 -12
  5. package/client/session/index.js +2 -2
  6. package/client/session/index.js.map +1 -1
  7. package/client/session/sessionOrganizationCreation.js +1 -0
  8. package/client/session/sessionOrganizationCreation.js.map +1 -1
  9. package/client/session/sessionTypes.d.ts +3 -0
  10. package/client/session/sessionTypes.js.map +1 -1
  11. package/client/workflowRuntime.d.ts +2 -0
  12. package/client/workflowRuntime.js +34 -16
  13. package/client/workflowRuntime.js.map +1 -1
  14. package/data/persistence/documents/documentDiscoveryEvidencePersistence.d.ts +16 -0
  15. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +23 -0
  16. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  17. package/data/persistence/organizations/organizationReadModelGrantPersistence.js +2 -1
  18. package/data/persistence/organizations/organizationReadModelGrantPersistence.js.map +1 -1
  19. package/data/persistence/organizations/organizationReadModelMemberLoad.d.ts +9 -0
  20. package/data/persistence/organizations/organizationReadModelMemberLoad.js +29 -21
  21. package/data/persistence/organizations/organizationReadModelMemberLoad.js.map +1 -1
  22. package/data/persistence/organizations/organizationReadModelMembershipPersistence.js +91 -46
  23. package/data/persistence/organizations/organizationReadModelMembershipPersistence.js.map +1 -1
  24. package/data/persistence/organizations/organizationReadModelPersistence.js +95 -73
  25. package/data/persistence/organizations/organizationReadModelPersistence.js.map +1 -1
  26. package/data/persistence/organizations/organizationReadModelProjection.js +78 -89
  27. package/data/persistence/organizations/organizationReadModelProjection.js.map +1 -1
  28. package/data/persistence/organizations/organizationReadModelPurge.js +14 -15
  29. package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
  30. package/data/sqlite/organizationReadModelSchema.js +23 -28
  31. package/data/sqlite/organizationReadModelSchema.js.map +1 -1
  32. package/data/sqlite/organizationReadModelTableRegistry.d.ts +116 -263
  33. package/data/sqlite/organizationReadModelTableRegistry.js +10 -7
  34. package/data/sqlite/organizationReadModelTableRegistry.js.map +1 -1
  35. package/data/sqlite/schema.d.ts +116 -263
  36. package/data/sqlite/sqliteBindBudget.js +30 -0
  37. package/data/sqlite/sqliteBindBudget.js.map +1 -0
  38. package/data/trustedUserIdentity/index.d.ts +1 -1
  39. package/data/trustedUserIdentity/index.js +1 -1
  40. package/data/trustedUserIdentity/index.js.map +1 -1
  41. package/data/trustedUserIdentity/service.d.ts +12 -1
  42. package/data/trustedUserIdentity/service.js +27 -3
  43. package/data/trustedUserIdentity/service.js.map +1 -1
  44. package/internal/validators/operation/organizations.d.ts +0 -16
  45. package/internal/validators/response/index.d.ts +1 -1
  46. package/internal/validators/response/index.js.map +1 -1
  47. package/internal/validators/response/organizationReadModel.d.ts +10 -48
  48. package/internal/validators/response/organizationReadModel.js +9 -1
  49. package/internal/validators/response/organizationReadModel.js.map +1 -1
  50. package/package.json +1 -1
  51. package/workflows/organizations/createOrganization.d.ts +3 -0
  52. package/workflows/organizations/createOrganization.js +1 -0
  53. package/workflows/organizations/createOrganization.js.map +1 -1
  54. package/workflows/organizations/readModel.d.ts +8 -3
  55. package/workflows/organizations/readModel.js.map +1 -1
  56. package/workflows/organizations/readModelProjection.d.ts +2 -12
  57. package/workflows/organizations/readModelProjection.js +1 -1
  58. package/workflows/organizations/readModelProjection.js.map +1 -1
  59. package/workflows/registration/organizationProvisioningPersistence.d.ts +3 -0
  60. package/workflows/registration/organizationProvisioningPersistence.js +27 -1
  61. package/workflows/registration/organizationProvisioningPersistence.js.map +1 -1
  62. package/workflows/registration/persistRegistrationBootstrap.d.ts +3 -0
  63. package/workflows/registration/persistRegistrationBootstrap.js +7 -1
  64. package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
  65. package/workflows/registration/provisionedPrincipalHistory.d.ts +45 -0
  66. package/workflows/registration/provisionedPrincipalHistory.js +104 -0
  67. package/workflows/registration/provisionedPrincipalHistory.js.map +1 -0
  68. package/workflows/registration/provisioningAcknowledgement.js +18 -0
  69. package/workflows/registration/provisioningAcknowledgement.js.map +1 -1
  70. package/workflows/registration/registerIdentity.d.ts +3 -0
  71. package/workflows/registration/registerIdentity.js +1 -0
  72. package/workflows/registration/registerIdentity.js.map +1 -1
  73. package/workflows/sync/remoteReset.js +1 -3
  74. package/workflows/sync/remoteReset.js.map +1 -1
  75. package/data/persistence/organizations/organizationReadModelPolicyHeadPersistence.js +0 -64
  76. package/data/persistence/organizations/organizationReadModelPolicyHeadPersistence.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"readModelProjection.js","sourceRoot":"","sources":["readModelProjection.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RequestResult,\n RequestResultOptions,\n} from \"@tearleads/api-client\";\nimport {\n ORGANIZATION_READ_MODEL_ERROR_CODES,\n type OrganizationReadModelResponse,\n} from \"@tearleads/validators/response\";\nimport { purgeOrganizationAccessProjection } from \"../../data/persistence/organizations/organizationAccessRevocationPersistence\";\nimport { recordOrganizationPresentationDenials } from \"../../data/persistence/organizations/organizationPresentationDenialPersistence\";\nimport { loadOrganizationReadModelGroupMembers } from \"../../data/persistence/organizations/organizationReadModelMemberLoad\";\nimport { OrganizationReadModelBindingError } from \"../../data/persistence/organizations/organizationReadModelMembershipPersistence\";\nimport {\n applyOrganizationReadModelResponse,\n loadOrganizationReadModelProjection,\n type OrganizationReadModelProjection,\n purgeOrganizationReadModelProjection,\n} from \"../../data/persistence/organizations/organizationReadModelPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n captureOrganizationPresentationAccessAttempt,\n denyOrganizationPresentationAccess,\n isOrganizationPresentationAccessAttemptCurrent,\n isOrganizationPresentationAccessReadable,\n type OrganizationPresentationAccessAttempt,\n type OrganizationPresentationAccessInput,\n restoreOrganizationPresentationAccess,\n runOrganizationPresentationMutation,\n runOrganizationPresentationRead,\n} from \"./organizationPresentationAccessState\";\nimport { isOrganizationPresentationAccessDeniedFailure } from \"./organizationPresentationFailures\";\nimport type { OrganizationDirectoryAndGroups } from \"./readModel\";\n\nconst MAX_READ_MODEL_PAGES = 100;\nconst MAX_STALE_RETRIES = 1;\n\ninterface OrganizationReadModelApi {\n getOrganizationReadModelResult(\n organizationId: string,\n cursor?: string,\n options?: RequestResultOptions,\n ): Promise<RequestResult<OrganizationReadModelResponse>>;\n}\n\ninterface OrganizationReadModelProjectionInput {\n readonly currentUserId: string;\n readonly execSql: ExecSql;\n readonly organizationId: string;\n}\n\nexport interface ReconcileOrganizationDirectoryAndGroupsInput\n extends OrganizationReadModelProjectionInput {\n readonly apiClient: OrganizationReadModelApi;\n readonly logError?:\n | ((message: string | Error, cause?: unknown) => void)\n | undefined;\n}\n\nfunction toDirectoryAndGroups(\n projection: OrganizationReadModelProjection | null,\n): OrganizationDirectoryAndGroups | null {\n if (!projection?.requester) {\n return null;\n }\n\n return {\n directory: {\n ...projection.directory,\n currentUser: projection.requester,\n },\n // Hydration decides whether a name is unreadable; a stored blank name may\n // only mean the group has not been hydrated yet.\n groups: projection.groups.groups.map((group) => ({\n ...group,\n nameUnreadable: false,\n })),\n memberGroupId: projection.groups.memberGroupId,\n readModelCursor: projection.cursor,\n };\n}\n\nasync function loadProjection(\n input: OrganizationReadModelProjectionInput,\n): Promise<OrganizationReadModelProjection | null> {\n return runOrganizationPresentationRead(\n organizationPresentationAccessInput(input),\n \"readModel\",\n () => loadRawProjection(input),\n );\n}\n\nfunction loadRawProjection(\n input: OrganizationReadModelProjectionInput,\n): Promise<OrganizationReadModelProjection | null> {\n return loadOrganizationReadModelProjection(\n input.execSql,\n input.organizationId,\n input.currentUserId,\n );\n}\n\nfunction organizationPresentationAccessInput(\n input: OrganizationReadModelProjectionInput,\n): OrganizationPresentationAccessInput {\n return {\n execSql: input.execSql,\n organizationId: input.organizationId,\n requesterUserId: input.currentUserId,\n };\n}\n\ninterface ReconciliationState {\n readonly accessAttempt: OrganizationPresentationAccessAttempt;\n expectedLocalCursor: string | null;\n preparedDeniedProjection: boolean;\n projection: OrganizationReadModelProjection | null;\n requestCursor: string | undefined;\n retriedBindingFailure: boolean;\n retriedInvalidCursor: boolean;\n staleRetries: number;\n}\n\ntype ReconciliationStep =\n | { readonly kind: \"continue\" }\n | {\n readonly kind: \"done\";\n readonly value: OrganizationDirectoryAndGroups | null | undefined;\n };\n\ntype PageRequestStep =\n | ReconciliationStep\n | {\n readonly kind: \"response\";\n readonly response: OrganizationReadModelResponse;\n };\n\nfunction localResult(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n outcome: { readonly failed: boolean },\n): ReconciliationStep {\n const accessInput = organizationPresentationAccessInput(input);\n const readable =\n isOrganizationPresentationAccessAttemptCurrent(\n accessInput,\n state.accessAttempt,\n ) && isOrganizationPresentationAccessReadable(accessInput, \"readModel\");\n if (!readable) {\n return { kind: \"done\", value: null };\n }\n const value = toDirectoryAndGroups(state.projection);\n // A failed pass that retained nothing must not read as a completed (null)\n // pass: consumers mark a scope caught up only on completed passes, and this\n // scope still needs a fresh catch-up.\n if (value === null && outcome.failed) {\n return { kind: \"done\", value: undefined };\n }\n return { kind: \"done\", value };\n}\n\nfunction resetRequestCursor(state: ReconciliationState): void {\n state.expectedLocalCursor = state.projection?.cursor ?? null;\n state.requestCursor = state.projection?.cursor ?? undefined;\n}\n\nfunction isInvalidReadModelCursorFailure(\n result: RequestResult<OrganizationReadModelResponse>,\n): boolean {\n return (\n !result.ok &&\n result.kind === \"http\" &&\n result.status === 400 &&\n result.code === ORGANIZATION_READ_MODEL_ERROR_CODES.cursorInvalid\n );\n}\n\nasync function requestReadModelPage(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n): Promise<PageRequestStep> {\n const result = await input.apiClient.getOrganizationReadModelResult(\n input.organizationId,\n state.requestCursor,\n { reportErrors: false },\n );\n if (result.ok) {\n return { kind: \"response\", response: result.data };\n }\n if (isOrganizationPresentationAccessDeniedFailure(result)) {\n const accessInput = organizationPresentationAccessInput(input);\n denyOrganizationPresentationAccess(accessInput, [\"readModel\", \"usage\"]);\n // The durable marker lands before the purge attempt: if the purge fails,\n // an offline restart must still refuse to serve the revoked projection.\n try {\n await runOrganizationPresentationMutation(input.execSql, () =>\n recordOrganizationPresentationDenials(accessInput, [\n \"readModel\",\n \"usage\",\n ]),\n );\n } catch (error) {\n input.logError?.(\"Failed to record denied organization access\", error);\n }\n try {\n await runOrganizationPresentationMutation(input.execSql, () =>\n purgeOrganizationAccessProjection({\n execSql: input.execSql,\n organizationId: input.organizationId,\n requesterUserId: input.currentUserId,\n }),\n );\n } catch (error) {\n input.logError?.(\"Failed to purge denied organization access\", error);\n }\n return { kind: \"done\", value: null };\n }\n if (\n isInvalidReadModelCursorFailure(result) &&\n state.requestCursor !== undefined &&\n !state.retriedInvalidCursor\n ) {\n state.requestCursor = undefined;\n state.retriedInvalidCursor = true;\n return { kind: \"continue\" };\n }\n\n result.report();\n return localResult(input, state, { failed: true });\n}\n\nfunction responseMatchesRequest(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n response: OrganizationReadModelResponse,\n): boolean {\n if (response.organizationId !== input.organizationId) {\n input.logError?.(\n `Organization read-model response scope does not match ${input.organizationId}`,\n );\n return false;\n }\n if (response.hasMore && response.nextCursor === state.expectedLocalCursor) {\n input.logError?.(\"Organization read-model page did not advance its cursor\");\n return false;\n }\n return true;\n}\n\nfunction reconciliationIsCurrent(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n): boolean {\n return isOrganizationPresentationAccessAttemptCurrent(\n organizationPresentationAccessInput(input),\n state.accessAttempt,\n );\n}\n\ntype ApplyResponseStep =\n | ReconciliationStep\n | {\n readonly kind: \"applied\";\n readonly result: Awaited<\n ReturnType<typeof applyOrganizationReadModelResponse>\n >;\n };\n\nasync function applyResponse(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n response: OrganizationReadModelResponse,\n): Promise<ApplyResponseStep> {\n try {\n return {\n kind: \"applied\",\n result: await applyOrganizationReadModelResponse({\n currentUserId: input.currentUserId,\n execSql: input.execSql,\n requestedCursor: state.expectedLocalCursor,\n response,\n }),\n };\n } catch (error) {\n input.logError?.(\"Failed to apply organization read-model response\", error);\n if (\n !(error instanceof OrganizationReadModelBindingError) ||\n state.retriedBindingFailure\n ) {\n return localResult(input, state, { failed: true });\n }\n state.retriedBindingFailure = true;\n await purgeOrganizationReadModelProjection(\n input.execSql,\n input.organizationId,\n );\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n state.projection = null;\n resetRequestCursor(state);\n return { kind: \"continue\" };\n }\n}\n\nasync function prepareDeniedProjectionForApply(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n): Promise<ReconciliationStep | null> {\n if (state.preparedDeniedProjection) {\n return null;\n }\n try {\n // The apply that follows replaces the shared rows authoritatively, so\n // only this requester's row is dropped: another local identity sharing\n // the database keeps its access and reads the replacement.\n await purgeOrganizationReadModelProjection(\n input.execSql,\n input.organizationId,\n { onlyRequesterUserId: input.currentUserId },\n );\n } catch (error) {\n input.logError?.(\"Failed to replace denied organization read model\", error);\n return { kind: \"done\", value: null };\n }\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n state.expectedLocalCursor = null;\n state.preparedDeniedProjection = true;\n state.projection = null;\n return null;\n}\n\nasync function applyReadModelPage(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n response: OrganizationReadModelResponse,\n): Promise<ReconciliationStep> {\n if (!responseMatchesRequest(input, state, response)) {\n return localResult(input, state, { failed: true });\n }\n\n const accessInput = organizationPresentationAccessInput(input);\n return runOrganizationPresentationMutation(input.execSql, async () => {\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n const preparation = await prepareDeniedProjectionForApply(input, state);\n if (preparation) {\n return preparation;\n }\n\n const applied = await applyResponse(input, state, response);\n if (applied.kind !== \"applied\") {\n return applied;\n }\n\n state.projection = await loadRawProjection(input);\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n if (applied.result === \"stale\") {\n if (state.staleRetries >= MAX_STALE_RETRIES) {\n return localResult(input, state, { failed: true });\n }\n state.staleRetries += 1;\n resetRequestCursor(state);\n return { kind: \"continue\" };\n }\n\n state.expectedLocalCursor = state.projection?.cursor ?? response.nextCursor;\n if (!response.hasMore) {\n return restoreOrganizationPresentationAccess(\n accessInput,\n state.accessAttempt,\n )\n ? localResult(input, state, { failed: false })\n : { kind: \"done\", value: null };\n }\n state.requestCursor = response.nextCursor;\n return { kind: \"continue\" };\n });\n}\n\nexport async function loadLocalOrganizationDirectoryAndGroups(\n input: OrganizationReadModelProjectionInput,\n): Promise<OrganizationDirectoryAndGroups | null> {\n return toDirectoryAndGroups(await loadProjection(input));\n}\n\nexport async function loadLocalOrganizationGroupMembers(\n input: OrganizationReadModelProjectionInput & { readonly groupId: string },\n) {\n return runOrganizationPresentationRead(\n organizationPresentationAccessInput(input),\n \"readModel\",\n () =>\n loadOrganizationReadModelGroupMembers(\n input.execSql,\n input.organizationId,\n input.groupId,\n input.currentUserId,\n ),\n );\n}\n\n/**\n * Resolves the reconciled projection, `null` when the pass completed\n * authoritatively with nothing presentable (including a denial that purged\n * the projection), or `undefined` when the feed failed and no local\n * projection was retained — a pass that must not count as caught up.\n */\nexport async function reconcileOrganizationDirectoryAndGroups(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n): Promise<OrganizationDirectoryAndGroups | null | undefined> {\n const accessInput = organizationPresentationAccessInput(input);\n const accessAttempt = captureOrganizationPresentationAccessAttempt(\n accessInput,\n \"readModel\",\n );\n const state: ReconciliationState = {\n accessAttempt,\n expectedLocalCursor: null,\n preparedDeniedProjection: !accessAttempt.startedDenied,\n projection: await loadProjection(input),\n requestCursor: undefined,\n retriedBindingFailure: false,\n retriedInvalidCursor: false,\n staleRetries: 0,\n };\n resetRequestCursor(state);\n\n for (let page = 0; page < MAX_READ_MODEL_PAGES; page += 1) {\n const request = await requestReadModelPage(input, state);\n if (request.kind === \"done\") {\n return request.value;\n }\n if (request.kind === \"continue\") {\n continue;\n }\n const applied = await applyReadModelPage(input, state, request.response);\n if (applied.kind === \"done\") {\n return applied.value;\n }\n }\n\n input.logError?.(\n \"Organization read-model reconciliation exceeded page limit\",\n );\n const retained = localResult(input, state, { failed: true });\n return retained.kind === \"done\" ? retained.value : null;\n}\n"]}
1
+ {"version":3,"file":"readModelProjection.js","sourceRoot":"","sources":["readModelProjection.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RequestResult,\n RequestResultOptions,\n} from \"@tearleads/api-client\";\nimport {\n ORGANIZATION_READ_MODEL_ERROR_CODES,\n type OrganizationReadModelResponse,\n} from \"@tearleads/validators/response\";\nimport { purgeOrganizationAccessProjection } from \"../../data/persistence/organizations/organizationAccessRevocationPersistence\";\nimport { recordOrganizationPresentationDenials } from \"../../data/persistence/organizations/organizationPresentationDenialPersistence\";\nimport {\n loadOrganizationReadModelGroupMembers,\n type OrganizationReadModelGroupMembers,\n} from \"../../data/persistence/organizations/organizationReadModelMemberLoad\";\nimport { OrganizationReadModelBindingError } from \"../../data/persistence/organizations/organizationReadModelMembershipPersistence\";\nimport {\n applyOrganizationReadModelResponse,\n loadOrganizationReadModelProjection,\n type OrganizationReadModelProjection,\n purgeOrganizationReadModelProjection,\n} from \"../../data/persistence/organizations/organizationReadModelPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n captureOrganizationPresentationAccessAttempt,\n denyOrganizationPresentationAccess,\n isOrganizationPresentationAccessAttemptCurrent,\n isOrganizationPresentationAccessReadable,\n type OrganizationPresentationAccessAttempt,\n type OrganizationPresentationAccessInput,\n restoreOrganizationPresentationAccess,\n runOrganizationPresentationMutation,\n runOrganizationPresentationRead,\n} from \"./organizationPresentationAccessState\";\nimport { isOrganizationPresentationAccessDeniedFailure } from \"./organizationPresentationFailures\";\nimport type { OrganizationDirectoryAndGroups } from \"./readModel\";\n\nconst MAX_READ_MODEL_PAGES = 100;\nconst MAX_STALE_RETRIES = 1;\n\ninterface OrganizationReadModelApi {\n getOrganizationReadModelResult(\n organizationId: string,\n cursor?: string,\n options?: RequestResultOptions,\n ): Promise<RequestResult<OrganizationReadModelResponse>>;\n}\n\ninterface OrganizationReadModelProjectionInput {\n readonly currentUserId: string;\n readonly execSql: ExecSql;\n readonly organizationId: string;\n}\n\nexport interface ReconcileOrganizationDirectoryAndGroupsInput\n extends OrganizationReadModelProjectionInput {\n readonly apiClient: OrganizationReadModelApi;\n readonly logError?:\n | ((message: string | Error, cause?: unknown) => void)\n | undefined;\n}\n\nfunction toDirectoryAndGroups(\n projection: OrganizationReadModelProjection | null,\n): OrganizationDirectoryAndGroups | null {\n if (!projection?.requester) {\n return null;\n }\n\n return {\n directory: {\n ...projection.directory,\n currentUser: projection.requester,\n },\n // Hydration decides whether a name is unreadable; a stored blank name may\n // only mean the group has not been hydrated yet.\n groups: projection.groups.groups.map((group) => ({\n ...group,\n nameUnreadable: false,\n })),\n memberGroupId: projection.groups.memberGroupId,\n readModelCursor: projection.cursor,\n };\n}\n\nasync function loadProjection(\n input: OrganizationReadModelProjectionInput,\n): Promise<OrganizationReadModelProjection | null> {\n return runOrganizationPresentationRead(\n organizationPresentationAccessInput(input),\n \"readModel\",\n () => loadRawProjection(input),\n );\n}\n\nfunction loadRawProjection(\n input: OrganizationReadModelProjectionInput,\n): Promise<OrganizationReadModelProjection | null> {\n return loadOrganizationReadModelProjection(\n input.execSql,\n input.organizationId,\n input.currentUserId,\n );\n}\n\nfunction organizationPresentationAccessInput(\n input: OrganizationReadModelProjectionInput,\n): OrganizationPresentationAccessInput {\n return {\n execSql: input.execSql,\n organizationId: input.organizationId,\n requesterUserId: input.currentUserId,\n };\n}\n\ninterface ReconciliationState {\n readonly accessAttempt: OrganizationPresentationAccessAttempt;\n expectedLocalCursor: string | null;\n preparedDeniedProjection: boolean;\n projection: OrganizationReadModelProjection | null;\n requestCursor: string | undefined;\n retriedBindingFailure: boolean;\n retriedInvalidCursor: boolean;\n staleRetries: number;\n}\n\ntype ReconciliationStep =\n | { readonly kind: \"continue\" }\n | {\n readonly kind: \"done\";\n readonly value: OrganizationDirectoryAndGroups | null | undefined;\n };\n\ntype PageRequestStep =\n | ReconciliationStep\n | {\n readonly kind: \"response\";\n readonly response: OrganizationReadModelResponse;\n };\n\nfunction localResult(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n outcome: { readonly failed: boolean },\n): ReconciliationStep {\n const accessInput = organizationPresentationAccessInput(input);\n const readable =\n isOrganizationPresentationAccessAttemptCurrent(\n accessInput,\n state.accessAttempt,\n ) && isOrganizationPresentationAccessReadable(accessInput, \"readModel\");\n if (!readable) {\n return { kind: \"done\", value: null };\n }\n const value = toDirectoryAndGroups(state.projection);\n // A failed pass that retained nothing must not read as a completed (null)\n // pass: consumers mark a scope caught up only on completed passes, and this\n // scope still needs a fresh catch-up.\n if (value === null && outcome.failed) {\n return { kind: \"done\", value: undefined };\n }\n return { kind: \"done\", value };\n}\n\nfunction resetRequestCursor(state: ReconciliationState): void {\n state.expectedLocalCursor = state.projection?.cursor ?? null;\n state.requestCursor = state.projection?.cursor ?? undefined;\n}\n\nfunction isInvalidReadModelCursorFailure(\n result: RequestResult<OrganizationReadModelResponse>,\n): boolean {\n return (\n !result.ok &&\n result.kind === \"http\" &&\n result.status === 400 &&\n result.code === ORGANIZATION_READ_MODEL_ERROR_CODES.cursorInvalid\n );\n}\n\nasync function requestReadModelPage(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n): Promise<PageRequestStep> {\n const result = await input.apiClient.getOrganizationReadModelResult(\n input.organizationId,\n state.requestCursor,\n { reportErrors: false },\n );\n if (result.ok) {\n return { kind: \"response\", response: result.data };\n }\n if (isOrganizationPresentationAccessDeniedFailure(result)) {\n const accessInput = organizationPresentationAccessInput(input);\n denyOrganizationPresentationAccess(accessInput, [\"readModel\", \"usage\"]);\n // The durable marker lands before the purge attempt: if the purge fails,\n // an offline restart must still refuse to serve the revoked projection.\n try {\n await runOrganizationPresentationMutation(input.execSql, () =>\n recordOrganizationPresentationDenials(accessInput, [\n \"readModel\",\n \"usage\",\n ]),\n );\n } catch (error) {\n input.logError?.(\"Failed to record denied organization access\", error);\n }\n try {\n await runOrganizationPresentationMutation(input.execSql, () =>\n purgeOrganizationAccessProjection({\n execSql: input.execSql,\n organizationId: input.organizationId,\n requesterUserId: input.currentUserId,\n }),\n );\n } catch (error) {\n input.logError?.(\"Failed to purge denied organization access\", error);\n }\n return { kind: \"done\", value: null };\n }\n if (\n isInvalidReadModelCursorFailure(result) &&\n state.requestCursor !== undefined &&\n !state.retriedInvalidCursor\n ) {\n state.requestCursor = undefined;\n state.retriedInvalidCursor = true;\n return { kind: \"continue\" };\n }\n\n result.report();\n return localResult(input, state, { failed: true });\n}\n\nfunction responseMatchesRequest(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n response: OrganizationReadModelResponse,\n): boolean {\n if (response.organizationId !== input.organizationId) {\n input.logError?.(\n `Organization read-model response scope does not match ${input.organizationId}`,\n );\n return false;\n }\n if (response.hasMore && response.nextCursor === state.expectedLocalCursor) {\n input.logError?.(\"Organization read-model page did not advance its cursor\");\n return false;\n }\n return true;\n}\n\nfunction reconciliationIsCurrent(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n): boolean {\n return isOrganizationPresentationAccessAttemptCurrent(\n organizationPresentationAccessInput(input),\n state.accessAttempt,\n );\n}\n\ntype ApplyResponseStep =\n | ReconciliationStep\n | {\n readonly kind: \"applied\";\n readonly result: Awaited<\n ReturnType<typeof applyOrganizationReadModelResponse>\n >;\n };\n\nasync function applyResponse(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n response: OrganizationReadModelResponse,\n): Promise<ApplyResponseStep> {\n try {\n return {\n kind: \"applied\",\n result: await applyOrganizationReadModelResponse({\n currentUserId: input.currentUserId,\n execSql: input.execSql,\n requestedCursor: state.expectedLocalCursor,\n response,\n }),\n };\n } catch (error) {\n input.logError?.(\"Failed to apply organization read-model response\", error);\n if (\n !(error instanceof OrganizationReadModelBindingError) ||\n state.retriedBindingFailure\n ) {\n return localResult(input, state, { failed: true });\n }\n state.retriedBindingFailure = true;\n await purgeOrganizationReadModelProjection(\n input.execSql,\n input.organizationId,\n );\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n state.projection = null;\n resetRequestCursor(state);\n return { kind: \"continue\" };\n }\n}\n\nasync function prepareDeniedProjectionForApply(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n): Promise<ReconciliationStep | null> {\n if (state.preparedDeniedProjection) {\n return null;\n }\n try {\n // The apply that follows replaces the shared rows authoritatively, so\n // only this requester's row is dropped: another local identity sharing\n // the database keeps its access and reads the replacement.\n await purgeOrganizationReadModelProjection(\n input.execSql,\n input.organizationId,\n { onlyRequesterUserId: input.currentUserId },\n );\n } catch (error) {\n input.logError?.(\"Failed to replace denied organization read model\", error);\n return { kind: \"done\", value: null };\n }\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n state.expectedLocalCursor = null;\n state.preparedDeniedProjection = true;\n state.projection = null;\n return null;\n}\n\nasync function applyReadModelPage(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n state: ReconciliationState,\n response: OrganizationReadModelResponse,\n): Promise<ReconciliationStep> {\n if (!responseMatchesRequest(input, state, response)) {\n return localResult(input, state, { failed: true });\n }\n\n const accessInput = organizationPresentationAccessInput(input);\n return runOrganizationPresentationMutation(input.execSql, async () => {\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n const preparation = await prepareDeniedProjectionForApply(input, state);\n if (preparation) {\n return preparation;\n }\n\n const applied = await applyResponse(input, state, response);\n if (applied.kind !== \"applied\") {\n return applied;\n }\n\n state.projection = await loadRawProjection(input);\n if (!reconciliationIsCurrent(input, state)) {\n return { kind: \"done\", value: null };\n }\n if (applied.result === \"stale\") {\n if (state.staleRetries >= MAX_STALE_RETRIES) {\n return localResult(input, state, { failed: true });\n }\n state.staleRetries += 1;\n resetRequestCursor(state);\n return { kind: \"continue\" };\n }\n\n state.expectedLocalCursor = state.projection?.cursor ?? response.nextCursor;\n if (!response.hasMore) {\n return restoreOrganizationPresentationAccess(\n accessInput,\n state.accessAttempt,\n )\n ? localResult(input, state, { failed: false })\n : { kind: \"done\", value: null };\n }\n state.requestCursor = response.nextCursor;\n return { kind: \"continue\" };\n });\n}\n\nexport async function loadLocalOrganizationDirectoryAndGroups(\n input: OrganizationReadModelProjectionInput,\n): Promise<OrganizationDirectoryAndGroups | null> {\n return toDirectoryAndGroups(await loadProjection(input));\n}\n\nexport async function loadLocalOrganizationGroupMembers(\n input: OrganizationReadModelProjectionInput & { readonly groupId: string },\n): Promise<OrganizationReadModelGroupMembers | null> {\n return runOrganizationPresentationRead(\n organizationPresentationAccessInput(input),\n \"readModel\",\n () =>\n loadOrganizationReadModelGroupMembers(\n input.execSql,\n input.organizationId,\n input.groupId,\n input.currentUserId,\n ),\n );\n}\n\n/**\n * Resolves the reconciled projection, `null` when the pass completed\n * authoritatively with nothing presentable (including a denial that purged\n * the projection), or `undefined` when the feed failed and no local\n * projection was retained — a pass that must not count as caught up.\n */\nexport async function reconcileOrganizationDirectoryAndGroups(\n input: ReconcileOrganizationDirectoryAndGroupsInput,\n): Promise<OrganizationDirectoryAndGroups | null | undefined> {\n const accessInput = organizationPresentationAccessInput(input);\n const accessAttempt = captureOrganizationPresentationAccessAttempt(\n accessInput,\n \"readModel\",\n );\n const state: ReconciliationState = {\n accessAttempt,\n expectedLocalCursor: null,\n preparedDeniedProjection: !accessAttempt.startedDenied,\n projection: await loadProjection(input),\n requestCursor: undefined,\n retriedBindingFailure: false,\n retriedInvalidCursor: false,\n staleRetries: 0,\n };\n resetRequestCursor(state);\n\n for (let page = 0; page < MAX_READ_MODEL_PAGES; page += 1) {\n const request = await requestReadModelPage(input, state);\n if (request.kind === \"done\") {\n return request.value;\n }\n if (request.kind === \"continue\") {\n continue;\n }\n const applied = await applyReadModelPage(input, state, request.response);\n if (applied.kind === \"done\") {\n return applied.value;\n }\n }\n\n input.logError?.(\n \"Organization read-model reconciliation exceeded page limit\",\n );\n const retained = localResult(input, state, { failed: true });\n return retained.kind === \"done\" ? retained.value : null;\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>;
@@ -3,7 +3,7 @@ import { persistedDocumentCreateStateFromResponse } from "../../data/documents/s
3
3
  import { createExecSql } from "../../data/sqlite/sqlSchema.js";
4
4
  import { persistRegistrationBootstrapFromExecSql } from "./persistRegistrationBootstrap.js";
5
5
  import { buildOrganizationProfileBootstrapInput, buildRosterProfileBootstrapInput, } from "./profileBootstrapPersistence.js";
6
- import { provisioningAcknowledgedAccessHeads } from "./provisioningAcknowledgement.js";
6
+ import { provisioningAcknowledgedAccessHeads, provisioningDiscoveryHeads, } from "./provisioningAcknowledgement.js";
7
7
  import { principalPolicyBundleFromInitialGroupRequest, principalPolicyBundleFromInitialOrganizationRequest, } from "./registrationPrincipalPolicyPersistence.js";
8
8
  function coreMetadataInitialUpdateCommitted(response, updateId) {
9
9
  return (updateId !== undefined &&
@@ -81,6 +81,19 @@ async function buildProvisioningPersistenceArtifacts(input) {
81
81
  ]);
82
82
  return {
83
83
  acknowledgedAccessHeads,
84
+ // Discovery lists the seeded profile documents; their signed heads are the
85
+ // ones this client just authored and the server acknowledged.
86
+ authoredDiscoveryHeads: provisioningDiscoveryHeads([
87
+ {
88
+ plan: input.rosterProfileBootstrap.profileDocument.plan,
89
+ response: input.response.rosterProfileDocument,
90
+ },
91
+ {
92
+ plan: input.organizationMetadataBootstrap.organizationProfileDocument
93
+ .plan,
94
+ response: input.response.organizationProfileDocument,
95
+ },
96
+ ]),
84
97
  initialAdminGroupPolicy,
85
98
  initialMemberGroupPolicy,
86
99
  initialOrganizationPolicy,
@@ -110,6 +123,7 @@ export async function persistOrganizationProvisioningState(input) {
110
123
  const artifacts = await buildProvisioningPersistenceArtifacts(input);
111
124
  const persisted = await persistRegistrationBootstrapFromExecSql(createExecSql(input.dbClient), {
112
125
  acknowledgedAccessHeads: artifacts.acknowledgedAccessHeads,
126
+ authoredDiscoveryHeads: artifacts.authoredDiscoveryHeads,
113
127
  canStartDurableMutation: input.canStartDurableMutation,
114
128
  onPersistQueued: input.onPersistQueued,
115
129
  containerId: input.containerId,
@@ -150,6 +164,18 @@ export async function persistOrganizationProvisioningState(input) {
150
164
  input.log?.(persisted
151
165
  ? "Local organization bootstrap persisted"
152
166
  : "Local organization bootstrap skipped: identity replaced");
167
+ if (persisted)
168
+ await input.primePrincipalHistory?.({
169
+ database: input.dbClient,
170
+ isCurrent: input.canStartDurableMutation ?? (() => true),
171
+ organizationId: input.response.organizationId,
172
+ policies: {
173
+ adminGroup: artifacts.initialAdminGroupPolicy,
174
+ memberGroup: artifacts.initialMemberGroupPolicy,
175
+ organization: artifacts.initialOrganizationPolicy,
176
+ },
177
+ userId: input.response.userId,
178
+ });
153
179
  }
154
180
  catch (error) {
155
181
  if (input.logError) {
@@ -1 +1 @@
1
- {"version":3,"file":"organizationProvisioningPersistence.js","sourceRoot":"","sources":["organizationProvisioningPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { OrganizationProvisioningResponse } from \"@tearleads/validators/response\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport { persistedDocumentCreateStateFromResponse } from \"../../data/documents/shared/responses\";\nimport type { ExecSqlClientLike } from \"../../data/sqlite/sqlSchema\";\nimport { createExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { OrganizationProvisioningArtifacts } from \"./organizationProvisioningArtifacts\";\nimport { persistRegistrationBootstrapFromExecSql } from \"./persistRegistrationBootstrap\";\nimport {\n buildOrganizationProfileBootstrapInput,\n buildRosterProfileBootstrapInput,\n} from \"./profileBootstrapPersistence\";\nimport { provisioningAcknowledgedAccessHeads } from \"./provisioningAcknowledgement\";\nimport {\n principalPolicyBundleFromInitialGroupRequest,\n principalPolicyBundleFromInitialOrganizationRequest,\n} from \"./registrationPrincipalPolicyPersistence\";\n\ntype PersistOrganizationProvisioningStateInput = Pick<\n OrganizationProvisioningArtifacts,\n | \"bootstrap\"\n | \"initialAdminGroup\"\n | \"initialMemberGroup\"\n | \"initialOrganizationPolicy\"\n | \"organizationMetadataBootstrap\"\n | \"rootContainer\"\n | \"rootMetadataDocument\"\n | \"rootMetadataDocumentRequest\"\n | \"rosterProfileBootstrap\"\n | \"systemContainerBootstraps\"\n> & {\n /** Forwarded to the bootstrap persist's in-mutex currency check. */\n readonly canStartDurableMutation?: (() => boolean) | undefined;\n /** @internal Forwarded to the bootstrap persist; test-only seam. */\n readonly onPersistQueued?: (() => void) | undefined;\n readonly containerId: string;\n readonly dbClient: ExecSqlClientLike;\n readonly documentProjectors?: DocumentProjectorRegistryInput | undefined;\n readonly log?: ((message: string) => void) | undefined;\n readonly logError?:\n | ((message: string | Error, cause?: unknown) => void)\n | undefined;\n readonly response: OrganizationProvisioningResponse;\n};\n\ntype PersistBootstrapInput = Parameters<\n typeof persistRegistrationBootstrapFromExecSql\n>[1];\n\nfunction coreMetadataInitialUpdateCommitted(\n response: OrganizationProvisioningResponse,\n updateId?: string,\n): boolean {\n return (\n updateId !== undefined &&\n response.committedCoreMetadataUpdateIds.includes(updateId)\n );\n}\n\nfunction buildCoreContainerBootstrapInput(\n response: OrganizationProvisioningResponse,\n container: OrganizationProvisioningResponse[\"organizationMetadataContainer\"],\n bootstrap: Pick<\n OrganizationProvisioningArtifacts[\"rosterProfileBootstrap\"],\n | \"containerId\"\n | \"containerMetadataDocument\"\n | \"containerMetadataInitialUpdate\"\n | \"containerRequest\"\n | \"systemSlot\"\n >,\n): NonNullable<PersistBootstrapInput[\"organizationMetadataContainer\"]> {\n return {\n accessEpoch: container.container.manifestHead.epoch,\n accessStateHash: container.container.manifestHead.manifestHash,\n containerId: bootstrap.containerId,\n createdAt: container.container.createdAt,\n metadataDocumentId: container.metadataDocument.id,\n metadataInitialUpdate: bootstrap.containerMetadataInitialUpdate,\n metadataInitialUpdateCommitted: coreMetadataInitialUpdateCommitted(\n response,\n bootstrap.containerRequest.initialMetadataSync.outgoingUpdates[0]?.id,\n ),\n metadataSnapshot: bytesToBase64(bootstrap.containerMetadataInitialUpdate),\n metadataState: persistedDocumentCreateStateFromResponse(\n bootstrap.containerMetadataDocument.plan,\n container.metadataDocument,\n ),\n systemSlot: bootstrap.systemSlot,\n updatedAt: container.container.updatedAt,\n };\n}\n\nfunction buildSystemContainersBootstrapInput(\n input: PersistOrganizationProvisioningStateInput,\n): PersistBootstrapInput[\"systemContainers\"] {\n const responses = input.response.systemContainers;\n if (responses.length === 0) {\n return;\n }\n const responseByContainerId = new Map(\n responses.map((response) => [response.container.containerId, response]),\n );\n const entries: NonNullable<PersistBootstrapInput[\"systemContainers\"]> = [];\n for (const bootstrap of input.systemContainerBootstraps) {\n const response = responseByContainerId.get(bootstrap.containerId);\n if (!response) {\n continue;\n }\n entries.push({\n accessEpoch: response.container.manifestHead.epoch,\n accessStateHash: response.container.manifestHead.manifestHash,\n containerId: bootstrap.containerId,\n createdAt: response.container.createdAt,\n icon: bootstrap.icon,\n metadataDocumentId: response.metadataDocument.id,\n metadataSnapshot: bytesToBase64(bootstrap.containerMetadataInitialUpdate),\n metadataState: persistedDocumentCreateStateFromResponse(\n bootstrap.containerMetadataDocument.plan,\n response.metadataDocument,\n ),\n name: bootstrap.name,\n systemSlot: bootstrap.systemSlot,\n updatedAt: response.container.updatedAt,\n });\n }\n return entries.length > 0 ? entries : undefined;\n}\n\nasync function buildProvisioningPersistenceArtifacts(\n input: PersistOrganizationProvisioningStateInput,\n) {\n const acknowledgedAccessHeads = await provisioningAcknowledgedAccessHeads({\n expectedOrganizationId: input.rootContainer.plan.state.organizationId,\n expectedUserId: input.rootContainer.plan.event.signerUserId,\n organizationMetadata: {\n containerPlan: input.organizationMetadataBootstrap.containerPlan.plan,\n metadataDocumentPlan:\n input.organizationMetadataBootstrap.containerMetadataDocument.plan,\n },\n organizationProfileDocumentPlan:\n input.organizationMetadataBootstrap.organizationProfileDocument.plan,\n response: input.response,\n rootContainerPlan: input.rootContainer.plan,\n rootMetadataDocumentPlan: input.rootMetadataDocument.plan,\n rosterProfile: {\n containerPlan: input.rosterProfileBootstrap.containerPlan.plan,\n metadataDocumentPlan:\n input.rosterProfileBootstrap.containerMetadataDocument.plan,\n },\n rosterProfileDocumentPlan:\n input.rosterProfileBootstrap.profileDocument.plan,\n systemContainers: input.systemContainerBootstraps.map((bootstrap) => ({\n containerPlan: bootstrap.containerPlan.plan,\n metadataDocumentPlan: bootstrap.containerMetadataDocument.plan,\n })),\n });\n const [\n initialAdminGroupPolicy,\n initialMemberGroupPolicy,\n initialOrganizationPolicy,\n ] = await Promise.all([\n principalPolicyBundleFromInitialGroupRequest(input.initialAdminGroup),\n principalPolicyBundleFromInitialGroupRequest(input.initialMemberGroup),\n principalPolicyBundleFromInitialOrganizationRequest(\n input.initialOrganizationPolicy,\n ),\n ]);\n return {\n acknowledgedAccessHeads,\n initialAdminGroupPolicy,\n initialMemberGroupPolicy,\n initialOrganizationPolicy,\n organizationMetadataContainer: buildCoreContainerBootstrapInput(\n input.response,\n input.response.organizationMetadataContainer,\n input.organizationMetadataBootstrap,\n ),\n organizationProfileDocument: buildOrganizationProfileBootstrapInput({\n containerId: input.organizationMetadataBootstrap.containerId,\n materializedDocument:\n input.organizationMetadataBootstrap.organizationProfileDocument,\n request:\n input.organizationMetadataBootstrap.organizationProfileDocumentRequest,\n response: input.response,\n snapshot: input.organizationMetadataBootstrap.organizationProfileSnapshot,\n }),\n rosterProfileContainer: input.response.rosterProfileContainer\n ? buildCoreContainerBootstrapInput(\n input.response,\n input.response.rosterProfileContainer,\n input.rosterProfileBootstrap,\n )\n : undefined,\n rosterProfileDocument: buildRosterProfileBootstrapInput({\n containerId: input.rosterProfileBootstrap.containerId,\n initialUpdate: input.rosterProfileBootstrap.profileDocumentInitialUpdate,\n materializedDocument: input.rosterProfileBootstrap.profileDocument,\n request: input.rosterProfileBootstrap.profileDocumentRequest,\n response: input.response,\n }),\n systemContainers: buildSystemContainersBootstrapInput(input),\n };\n}\n\nexport async function persistOrganizationProvisioningState(\n input: PersistOrganizationProvisioningStateInput,\n): Promise<void> {\n try {\n const artifacts = await buildProvisioningPersistenceArtifacts(input);\n const persisted = await persistRegistrationBootstrapFromExecSql(\n createExecSql(input.dbClient),\n {\n acknowledgedAccessHeads: artifacts.acknowledgedAccessHeads,\n canStartDurableMutation: input.canStartDurableMutation,\n onPersistQueued: input.onPersistQueued,\n containerId: input.containerId,\n documentProjectors: input.documentProjectors,\n initialAdminGroupPolicy: artifacts.initialAdminGroupPolicy,\n initialMemberGroupPolicy: artifacts.initialMemberGroupPolicy,\n initialOrganizationPolicy: artifacts.initialOrganizationPolicy,\n organizationId: input.response.organizationId,\n // The provisioning response does not expose the root container's own\n // timestamps. Its metadata document is created in the same transaction,\n // so its server timestamp is the acknowledged remote anchor for the\n // locally persisted root row.\n rootContainerServerTimestamp:\n input.response.rootMetadataDocument.createdAt,\n rootMetadataAccessEpoch: input.response.rootMetadataAccessEpoch,\n rootMetadataAccessStateHash: input.response.rootMetadataAccessStateHash,\n rootMetadataDocumentId: input.response.rootMetadataDocumentId,\n rootMetadataInitialUpdate: input.bootstrap.initialUpdate,\n rootMetadataInitialUpdateCommitted: coreMetadataInitialUpdateCommitted(\n input.response,\n input.rootMetadataDocumentRequest.initialSync.outgoingUpdates[0]?.id,\n ),\n rootMetadataSnapshot: bytesToBase64(input.bootstrap.initialUpdate),\n rootMetadataState: persistedDocumentCreateStateFromResponse(\n input.rootMetadataDocument.plan,\n input.response.rootMetadataDocument,\n ),\n ...(artifacts.rosterProfileContainer\n ? { rosterProfileContainer: artifacts.rosterProfileContainer }\n : {}),\n organizationMetadataContainer: artifacts.organizationMetadataContainer,\n ...(artifacts.organizationProfileDocument\n ? {\n organizationProfileDocument:\n artifacts.organizationProfileDocument,\n }\n : {}),\n ...(artifacts.rosterProfileDocument\n ? { rosterProfileDocument: artifacts.rosterProfileDocument }\n : {}),\n ...(artifacts.systemContainers\n ? { systemContainers: artifacts.systemContainers }\n : {}),\n userId: input.response.userId,\n },\n );\n input.log?.(\n persisted\n ? \"Local organization bootstrap persisted\"\n : \"Local organization bootstrap skipped: identity replaced\",\n );\n } catch (error: unknown) {\n if (input.logError) {\n input.logError(\"Failed to persist registration data\", error);\n } else {\n console.error(\"Failed to persist registration data:\", error);\n }\n throw error;\n }\n}\n"]}
1
+ {"version":3,"file":"organizationProvisioningPersistence.js","sourceRoot":"","sources":["organizationProvisioningPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { OrganizationProvisioningResponse } from \"@tearleads/validators/response\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport { persistedDocumentCreateStateFromResponse } from \"../../data/documents/shared/responses\";\nimport type { ExecSqlClientLike } from \"../../data/sqlite/sqlSchema\";\nimport { createExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { OrganizationProvisioningArtifacts } from \"./organizationProvisioningArtifacts\";\nimport { persistRegistrationBootstrapFromExecSql } from \"./persistRegistrationBootstrap\";\nimport {\n buildOrganizationProfileBootstrapInput,\n buildRosterProfileBootstrapInput,\n} from \"./profileBootstrapPersistence\";\nimport type { ProvisionedPrincipalHistoryPrimer } from \"./provisionedPrincipalHistory\";\nimport {\n provisioningAcknowledgedAccessHeads,\n provisioningDiscoveryHeads,\n} from \"./provisioningAcknowledgement\";\nimport {\n principalPolicyBundleFromInitialGroupRequest,\n principalPolicyBundleFromInitialOrganizationRequest,\n} from \"./registrationPrincipalPolicyPersistence\";\n\ntype PersistOrganizationProvisioningStateInput = Pick<\n OrganizationProvisioningArtifacts,\n | \"bootstrap\"\n | \"initialAdminGroup\"\n | \"initialMemberGroup\"\n | \"initialOrganizationPolicy\"\n | \"organizationMetadataBootstrap\"\n | \"rootContainer\"\n | \"rootMetadataDocument\"\n | \"rootMetadataDocumentRequest\"\n | \"rosterProfileBootstrap\"\n | \"systemContainerBootstraps\"\n> & {\n /** Forwarded to the bootstrap persist's in-mutex currency check. */\n readonly canStartDurableMutation?: (() => boolean) | undefined;\n /** @internal Forwarded to the bootstrap persist; test-only seam. */\n readonly onPersistQueued?: (() => void) | undefined;\n readonly containerId: string;\n readonly dbClient: ExecSqlClientLike;\n readonly documentProjectors?: DocumentProjectorRegistryInput | undefined;\n readonly log?: ((message: string) => void) | undefined;\n readonly logError?:\n | ((message: string | Error, cause?: unknown) => void)\n | undefined;\n /** Seeds verified recovery progress once the bootstrap commits. */\n readonly primePrincipalHistory?:\n | ProvisionedPrincipalHistoryPrimer\n | undefined;\n readonly response: OrganizationProvisioningResponse;\n};\n\ntype PersistBootstrapInput = Parameters<\n typeof persistRegistrationBootstrapFromExecSql\n>[1];\n\nfunction coreMetadataInitialUpdateCommitted(\n response: OrganizationProvisioningResponse,\n updateId?: string,\n): boolean {\n return (\n updateId !== undefined &&\n response.committedCoreMetadataUpdateIds.includes(updateId)\n );\n}\n\nfunction buildCoreContainerBootstrapInput(\n response: OrganizationProvisioningResponse,\n container: OrganizationProvisioningResponse[\"organizationMetadataContainer\"],\n bootstrap: Pick<\n OrganizationProvisioningArtifacts[\"rosterProfileBootstrap\"],\n | \"containerId\"\n | \"containerMetadataDocument\"\n | \"containerMetadataInitialUpdate\"\n | \"containerRequest\"\n | \"systemSlot\"\n >,\n): NonNullable<PersistBootstrapInput[\"organizationMetadataContainer\"]> {\n return {\n accessEpoch: container.container.manifestHead.epoch,\n accessStateHash: container.container.manifestHead.manifestHash,\n containerId: bootstrap.containerId,\n createdAt: container.container.createdAt,\n metadataDocumentId: container.metadataDocument.id,\n metadataInitialUpdate: bootstrap.containerMetadataInitialUpdate,\n metadataInitialUpdateCommitted: coreMetadataInitialUpdateCommitted(\n response,\n bootstrap.containerRequest.initialMetadataSync.outgoingUpdates[0]?.id,\n ),\n metadataSnapshot: bytesToBase64(bootstrap.containerMetadataInitialUpdate),\n metadataState: persistedDocumentCreateStateFromResponse(\n bootstrap.containerMetadataDocument.plan,\n container.metadataDocument,\n ),\n systemSlot: bootstrap.systemSlot,\n updatedAt: container.container.updatedAt,\n };\n}\n\nfunction buildSystemContainersBootstrapInput(\n input: PersistOrganizationProvisioningStateInput,\n): PersistBootstrapInput[\"systemContainers\"] {\n const responses = input.response.systemContainers;\n if (responses.length === 0) {\n return;\n }\n const responseByContainerId = new Map(\n responses.map((response) => [response.container.containerId, response]),\n );\n const entries: NonNullable<PersistBootstrapInput[\"systemContainers\"]> = [];\n for (const bootstrap of input.systemContainerBootstraps) {\n const response = responseByContainerId.get(bootstrap.containerId);\n if (!response) {\n continue;\n }\n entries.push({\n accessEpoch: response.container.manifestHead.epoch,\n accessStateHash: response.container.manifestHead.manifestHash,\n containerId: bootstrap.containerId,\n createdAt: response.container.createdAt,\n icon: bootstrap.icon,\n metadataDocumentId: response.metadataDocument.id,\n metadataSnapshot: bytesToBase64(bootstrap.containerMetadataInitialUpdate),\n metadataState: persistedDocumentCreateStateFromResponse(\n bootstrap.containerMetadataDocument.plan,\n response.metadataDocument,\n ),\n name: bootstrap.name,\n systemSlot: bootstrap.systemSlot,\n updatedAt: response.container.updatedAt,\n });\n }\n return entries.length > 0 ? entries : undefined;\n}\n\nasync function buildProvisioningPersistenceArtifacts(\n input: PersistOrganizationProvisioningStateInput,\n) {\n const acknowledgedAccessHeads = await provisioningAcknowledgedAccessHeads({\n expectedOrganizationId: input.rootContainer.plan.state.organizationId,\n expectedUserId: input.rootContainer.plan.event.signerUserId,\n organizationMetadata: {\n containerPlan: input.organizationMetadataBootstrap.containerPlan.plan,\n metadataDocumentPlan:\n input.organizationMetadataBootstrap.containerMetadataDocument.plan,\n },\n organizationProfileDocumentPlan:\n input.organizationMetadataBootstrap.organizationProfileDocument.plan,\n response: input.response,\n rootContainerPlan: input.rootContainer.plan,\n rootMetadataDocumentPlan: input.rootMetadataDocument.plan,\n rosterProfile: {\n containerPlan: input.rosterProfileBootstrap.containerPlan.plan,\n metadataDocumentPlan:\n input.rosterProfileBootstrap.containerMetadataDocument.plan,\n },\n rosterProfileDocumentPlan:\n input.rosterProfileBootstrap.profileDocument.plan,\n systemContainers: input.systemContainerBootstraps.map((bootstrap) => ({\n containerPlan: bootstrap.containerPlan.plan,\n metadataDocumentPlan: bootstrap.containerMetadataDocument.plan,\n })),\n });\n const [\n initialAdminGroupPolicy,\n initialMemberGroupPolicy,\n initialOrganizationPolicy,\n ] = await Promise.all([\n principalPolicyBundleFromInitialGroupRequest(input.initialAdminGroup),\n principalPolicyBundleFromInitialGroupRequest(input.initialMemberGroup),\n principalPolicyBundleFromInitialOrganizationRequest(\n input.initialOrganizationPolicy,\n ),\n ]);\n return {\n acknowledgedAccessHeads,\n // Discovery lists the seeded profile documents; their signed heads are the\n // ones this client just authored and the server acknowledged.\n authoredDiscoveryHeads: provisioningDiscoveryHeads([\n {\n plan: input.rosterProfileBootstrap.profileDocument.plan,\n response: input.response.rosterProfileDocument,\n },\n {\n plan: input.organizationMetadataBootstrap.organizationProfileDocument\n .plan,\n response: input.response.organizationProfileDocument,\n },\n ]),\n initialAdminGroupPolicy,\n initialMemberGroupPolicy,\n initialOrganizationPolicy,\n organizationMetadataContainer: buildCoreContainerBootstrapInput(\n input.response,\n input.response.organizationMetadataContainer,\n input.organizationMetadataBootstrap,\n ),\n organizationProfileDocument: buildOrganizationProfileBootstrapInput({\n containerId: input.organizationMetadataBootstrap.containerId,\n materializedDocument:\n input.organizationMetadataBootstrap.organizationProfileDocument,\n request:\n input.organizationMetadataBootstrap.organizationProfileDocumentRequest,\n response: input.response,\n snapshot: input.organizationMetadataBootstrap.organizationProfileSnapshot,\n }),\n rosterProfileContainer: input.response.rosterProfileContainer\n ? buildCoreContainerBootstrapInput(\n input.response,\n input.response.rosterProfileContainer,\n input.rosterProfileBootstrap,\n )\n : undefined,\n rosterProfileDocument: buildRosterProfileBootstrapInput({\n containerId: input.rosterProfileBootstrap.containerId,\n initialUpdate: input.rosterProfileBootstrap.profileDocumentInitialUpdate,\n materializedDocument: input.rosterProfileBootstrap.profileDocument,\n request: input.rosterProfileBootstrap.profileDocumentRequest,\n response: input.response,\n }),\n systemContainers: buildSystemContainersBootstrapInput(input),\n };\n}\n\nexport async function persistOrganizationProvisioningState(\n input: PersistOrganizationProvisioningStateInput,\n): Promise<void> {\n try {\n const artifacts = await buildProvisioningPersistenceArtifacts(input);\n const persisted = await persistRegistrationBootstrapFromExecSql(\n createExecSql(input.dbClient),\n {\n acknowledgedAccessHeads: artifacts.acknowledgedAccessHeads,\n authoredDiscoveryHeads: artifacts.authoredDiscoveryHeads,\n canStartDurableMutation: input.canStartDurableMutation,\n onPersistQueued: input.onPersistQueued,\n containerId: input.containerId,\n documentProjectors: input.documentProjectors,\n initialAdminGroupPolicy: artifacts.initialAdminGroupPolicy,\n initialMemberGroupPolicy: artifacts.initialMemberGroupPolicy,\n initialOrganizationPolicy: artifacts.initialOrganizationPolicy,\n organizationId: input.response.organizationId,\n // The provisioning response does not expose the root container's own\n // timestamps. Its metadata document is created in the same transaction,\n // so its server timestamp is the acknowledged remote anchor for the\n // locally persisted root row.\n rootContainerServerTimestamp:\n input.response.rootMetadataDocument.createdAt,\n rootMetadataAccessEpoch: input.response.rootMetadataAccessEpoch,\n rootMetadataAccessStateHash: input.response.rootMetadataAccessStateHash,\n rootMetadataDocumentId: input.response.rootMetadataDocumentId,\n rootMetadataInitialUpdate: input.bootstrap.initialUpdate,\n rootMetadataInitialUpdateCommitted: coreMetadataInitialUpdateCommitted(\n input.response,\n input.rootMetadataDocumentRequest.initialSync.outgoingUpdates[0]?.id,\n ),\n rootMetadataSnapshot: bytesToBase64(input.bootstrap.initialUpdate),\n rootMetadataState: persistedDocumentCreateStateFromResponse(\n input.rootMetadataDocument.plan,\n input.response.rootMetadataDocument,\n ),\n ...(artifacts.rosterProfileContainer\n ? { rosterProfileContainer: artifacts.rosterProfileContainer }\n : {}),\n organizationMetadataContainer: artifacts.organizationMetadataContainer,\n ...(artifacts.organizationProfileDocument\n ? {\n organizationProfileDocument:\n artifacts.organizationProfileDocument,\n }\n : {}),\n ...(artifacts.rosterProfileDocument\n ? { rosterProfileDocument: artifacts.rosterProfileDocument }\n : {}),\n ...(artifacts.systemContainers\n ? { systemContainers: artifacts.systemContainers }\n : {}),\n userId: input.response.userId,\n },\n );\n input.log?.(\n persisted\n ? \"Local organization bootstrap persisted\"\n : \"Local organization bootstrap skipped: identity replaced\",\n );\n if (persisted)\n await input.primePrincipalHistory?.({\n database: input.dbClient,\n isCurrent: input.canStartDurableMutation ?? (() => true),\n organizationId: input.response.organizationId,\n policies: {\n adminGroup: artifacts.initialAdminGroupPolicy,\n memberGroup: artifacts.initialMemberGroupPolicy,\n organization: artifacts.initialOrganizationPolicy,\n },\n userId: input.response.userId,\n });\n } catch (error: unknown) {\n if (input.logError) {\n input.logError(\"Failed to persist registration data\", error);\n } else {\n console.error(\"Failed to persist registration data:\", error);\n }\n throw error;\n }\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { ContainerSystemSlot } from "../../internal/validators/containerSystemSlot.js";
2
2
  import type { PrincipalPolicyBundleResponse } from "../../internal/validators/response/index.js";
3
3
  import type { DocumentProjectorRegistryInput } from "../../data/documents/documentKinds.js";
4
+ import { type AuthoredDiscoveryHead } from "../../data/persistence/documents/documentDiscoveryEvidencePersistence.js";
4
5
  import { type LocallyAcknowledgedAccessManifestHead } from "../../data/persistence/locallyAcknowledgedCheckpointPersistence.js";
5
6
  import type { DocumentRecord } from "../../data/sqlite/documentPersistence.js";
6
7
  import { type ExecSql, type ExecSqlClientLike } from "../../data/sqlite/sqlSchema.js";
@@ -27,6 +28,8 @@ interface ProvisionedProfileDocumentBootstrapInput {
27
28
  }
28
29
  export interface RegistrationBootstrapInput {
29
30
  acknowledgedAccessHeads: readonly LocallyAcknowledgedAccessManifestHead[];
31
+ /** Seeded documents' acknowledged signed heads; see the discovery cache. */
32
+ authoredDiscoveryHeads: readonly AuthoredDiscoveryHead[];
30
33
  /** Checked inside the mutation queue claim; false skips every write. */
31
34
  canStartDurableMutation?: (() => boolean) | undefined;
32
35
  /**
@@ -2,10 +2,12 @@ import { createDocument, encodeVersionVector, importUpdates, } from "../../inter
2
2
  import { getScopedPeerSeed } from "../../data/crdtPeerSeed.js";
3
3
  import { createPendingUpdateFields } from "../../data/documents/documentSync.js";
4
4
  import { sqlContainerContentsPersistence, } from "../../data/persistence/container-contents/containerContentsPersistence.js";
5
+ import { primeAuthoredDocumentDiscoveryHeads, } from "../../data/persistence/documents/documentDiscoveryEvidencePersistence.js";
5
6
  import { DOCUMENTS_APP_KIND, sqlDocumentsPersistence, } from "../../data/persistence/documents/documentsPersistence.js";
6
7
  import { advanceLocallyAcknowledgedAccessManifestHeadsAtomically, } from "../../data/persistence/locallyAcknowledgedCheckpointPersistence.js";
8
+ import { documentContainerProjectionTables } from "../../data/sqlite/schema.js";
7
9
  import { getClientSQLitePersistenceRuntime } from "../../data/sqlite/sqlitePersistenceRuntime.js";
8
- import { createExecSql, runSerializedSqlMutation, } from "../../data/sqlite/sqlSchema.js";
10
+ import { createExecSql, ensureSqlTables, runSerializedSqlMutation, } from "../../data/sqlite/sqlSchema.js";
9
11
  import { persistDocumentState } from "../documents/persistence.js";
10
12
  import { ORGANIZATION_PROFILE_DOCUMENT_KIND } from "../organizations/organizationProfile.js";
11
13
  import { ORGANIZATION_METADATA_CONTAINER_NAME, ORGANIZATION_ROSTER_PROFILE_CONTAINER_NAME, ROSTER_PROFILE_DOCUMENT_KIND, } from "../organizations/rosterProfileContainer.js";
@@ -175,6 +177,7 @@ export async function persistRegistrationBootstrapFromExecSql(execSql, input) {
175
177
  // Idempotent DDL stays outside the atomic boundary.
176
178
  await sqlContainerContentsPersistence.ensureSchema(lockedExecSql);
177
179
  await sqlDocumentsPersistence.ensureSchema(lockedExecSql);
180
+ await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);
178
181
  // Pre-commit currency guard: the write sequence awaits real work, so
179
182
  // the identity can be replaced mid-sequence. The guard runs
180
183
  // synchronously with the COMMIT dispatch, so a refusal rolls the whole
@@ -197,6 +200,9 @@ export async function persistRegistrationBootstrapFromExecSql(execSql, input) {
197
200
  await persistNamedChildContainerBootstrap(lockedExecSql, input, input.organizationMetadataContainer, ORGANIZATION_METADATA_CONTAINER_NAME);
198
201
  await persistProfileDocumentBootstrap(lockedExecSql, input, input.organizationProfileDocument, ORGANIZATION_PROFILE_DOCUMENT_KIND);
199
202
  await persistSystemContainersBootstrap(lockedExecSql, input);
203
+ // After the checkpoints above: discovery reuses a cached head only
204
+ // while its access-manifest checkpoint still matches.
205
+ await primeAuthoredDocumentDiscoveryHeads(lockedExecSql, input.authoredDiscoveryHeads);
200
206
  }, () => !input.canStartDurableMutation || input.canStartDurableMutation());
201
207
  return committed;
202
208
  });
@@ -1 +1 @@
1
- {"version":3,"file":"persistRegistrationBootstrap.js","sourceRoot":"","sources":["persistRegistrationBootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createDocument,\n encodeVersionVector,\n importUpdates,\n} from \"@tearleads/loro\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { getScopedPeerSeed } from \"../../data/crdtPeerSeed\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport { createPendingUpdateFields } from \"../../data/documents/documentSync\";\nimport {\n type ContainerMetadataRecord,\n sqlContainerContentsPersistence,\n} from \"../../data/persistence/container-contents/containerContentsPersistence\";\nimport {\n DOCUMENTS_APP_KIND,\n sqlDocumentsPersistence,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport {\n advanceLocallyAcknowledgedAccessManifestHeadsAtomically,\n type LocallyAcknowledgedAccessManifestHead,\n} from \"../../data/persistence/locallyAcknowledgedCheckpointPersistence\";\nimport type { DocumentRecord } from \"../../data/sqlite/documentPersistence\";\nimport { getClientSQLitePersistenceRuntime } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport {\n createExecSql,\n type ExecSql,\n type ExecSqlClientLike,\n runSerializedSqlMutation,\n} from \"../../data/sqlite/sqlSchema\";\nimport { persistDocumentState } from \"../documents/persistence\";\nimport { ORGANIZATION_PROFILE_DOCUMENT_KIND } from \"../organizations/organizationProfile\";\nimport {\n ORGANIZATION_METADATA_CONTAINER_NAME,\n ORGANIZATION_ROSTER_PROFILE_CONTAINER_NAME,\n ROSTER_PROFILE_DOCUMENT_KIND,\n} from \"../organizations/rosterProfileContainer\";\nimport { enqueueInitialContainerMetadataUpdate } from \"./registrationBootstrapPendingUpdates\";\nimport { persistRegistrationPrincipalPolicies } from \"./registrationPrincipalPolicyPersistence\";\n\ninterface ProvisionedContainerBootstrapInput {\n accessEpoch: number;\n accessStateHash: string;\n containerId: string;\n createdAt: string;\n metadataDocumentId: string;\n metadataSnapshot: string;\n metadataState: Pick<\n DocumentRecord,\n | \"documentId\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\"\n >;\n systemSlot: ContainerSystemSlot;\n updatedAt: string;\n}\n\ninterface ProvisionedProfileDocumentBootstrapInput {\n accessEpoch: number;\n accessStateHash: string;\n containerId: string;\n documentId: string;\n documentState: ProvisionedContainerBootstrapInput[\"metadataState\"];\n initialUpdate: Uint8Array;\n initialUpdateCommitted: boolean;\n localId: string;\n}\n\nexport interface RegistrationBootstrapInput {\n acknowledgedAccessHeads: readonly LocallyAcknowledgedAccessManifestHead[];\n /** Checked inside the mutation queue claim; false skips every write. */\n canStartDurableMutation?: (() => boolean) | undefined;\n /**\n * @internal Test-only synchronization seam. Invoked synchronously,\n * immediately before this persist joins the serialized mutation queue —\n * no interleaving can separate the two. Lets identity-race tests\n * deterministically place an identity replacement inside the queue-wait\n * window instead of sleeping.\n */\n onPersistQueued?: (() => void) | undefined;\n containerId: string;\n initialAdminGroupPolicy: PrincipalPolicyBundleResponse;\n initialMemberGroupPolicy: PrincipalPolicyBundleResponse;\n initialOrganizationPolicy: PrincipalPolicyBundleResponse;\n rootMetadataAccessEpoch: number;\n rootMetadataAccessStateHash: string;\n rootContainerServerTimestamp: string;\n rootMetadataDocumentId: string;\n rootMetadataInitialUpdate: Uint8Array;\n rootMetadataInitialUpdateCommitted?: boolean | undefined;\n rootMetadataSnapshot: string;\n rootMetadataState: ProvisionedContainerBootstrapInput[\"metadataState\"];\n rosterProfileContainer?: ProvisionedContainerBootstrapInput & {\n metadataInitialUpdate: Uint8Array;\n metadataInitialUpdateCommitted?: boolean | undefined;\n };\n organizationMetadataContainer?: ProvisionedContainerBootstrapInput & {\n metadataInitialUpdate: Uint8Array;\n metadataInitialUpdateCommitted?: boolean | undefined;\n };\n organizationProfileDocument?: ProvisionedProfileDocumentBootstrapInput;\n rosterProfileDocument?: ProvisionedProfileDocumentBootstrapInput;\n // Additional app-owned system containers provisioned with the organization\n // (e.g. a trash bin). Each carries its own display name and icon (unlike the\n // roster/organization-metadata containers, whose names are fixed), since the\n // caller declares them.\n systemContainers?: Array<\n ProvisionedContainerBootstrapInput & {\n icon: string | null;\n name: string;\n }\n >;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n organizationId: string;\n userId: string;\n}\nasync function persistProvisionedContainerBootstrap(\n execSql: ExecSql,\n input: {\n container: ProvisionedContainerBootstrapInput;\n icon: string | null;\n name: string;\n organizationId: string;\n parentId: string | null;\n },\n): Promise<void> {\n const { container } = input;\n const metadataState = container.metadataState;\n const record: ContainerMetadataRecord = {\n accessEpoch: container.accessEpoch,\n accessStateHash: container.accessStateHash,\n documentId: container.metadataDocumentId,\n id: container.containerId,\n lastCommitLsn: null,\n metadataUpdates: container.metadataSnapshot,\n snapshotEndVersion: \"\",\n contentKeyBundle: metadataState.contentKeyBundle ?? null,\n documentKekTargets: metadataState.documentKekTargets ?? null,\n documentManifestBundle: metadataState.documentManifestBundle ?? null,\n };\n await sqlContainerContentsPersistence.saveContainer(\n execSql,\n {\n id: container.containerId,\n effectiveAccessLevel: \"admin\",\n organizationId: input.organizationId,\n parentId: input.parentId,\n metadataDocumentId: container.metadataDocumentId,\n systemSlot: container.systemSlot,\n name: input.name,\n icon: input.icon,\n },\n record,\n {\n localUpdatedAt: container.updatedAt,\n serverTimestamps: {\n createdAt: container.createdAt,\n updatedAt: container.updatedAt,\n },\n },\n );\n}\n\nasync function persistRootContainerBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n): Promise<void> {\n const rootRecord: ContainerMetadataRecord = {\n accessEpoch: input.rootMetadataAccessEpoch,\n accessStateHash: input.rootMetadataAccessStateHash,\n documentId: input.rootMetadataDocumentId,\n id: input.containerId,\n lastCommitLsn: null,\n metadataUpdates: input.rootMetadataSnapshot,\n snapshotEndVersion: \"\",\n contentKeyBundle: input.rootMetadataState.contentKeyBundle ?? null,\n documentKekTargets: input.rootMetadataState.documentKekTargets ?? null,\n documentManifestBundle:\n input.rootMetadataState.documentManifestBundle ?? null,\n };\n await sqlContainerContentsPersistence.saveContainer(\n execSql,\n {\n id: input.containerId,\n effectiveAccessLevel: \"admin\",\n organizationId: input.organizationId,\n parentId: null,\n metadataDocumentId: input.rootMetadataDocumentId,\n name: \"/\",\n icon: null,\n },\n rootRecord,\n {\n localUpdatedAt: input.rootContainerServerTimestamp,\n serverTimestamps: {\n createdAt: input.rootContainerServerTimestamp,\n updatedAt: input.rootContainerServerTimestamp,\n },\n },\n );\n await enqueueInitialContainerMetadataUpdate(\n execSql,\n input.containerId,\n input.rootMetadataInitialUpdate,\n input.rootMetadataInitialUpdateCommitted,\n );\n}\n\n// Persist reserved profile containers using their fixed topology: roster profiles\n// inherit the personal root; shared organization metadata has an independent root.\nasync function persistNamedChildContainerBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n container: RegistrationBootstrapInput[\"rosterProfileContainer\"],\n name: string,\n): Promise<void> {\n if (!container) {\n return;\n }\n\n await persistProvisionedContainerBootstrap(execSql, {\n container,\n icon: null,\n name,\n organizationId: input.organizationId,\n parentId:\n container === input.organizationMetadataContainer\n ? null\n : input.containerId,\n });\n await enqueueInitialContainerMetadataUpdate(\n execSql,\n container.containerId,\n container.metadataInitialUpdate,\n container.metadataInitialUpdateCommitted,\n );\n}\n\nasync function persistSystemContainersBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n): Promise<void> {\n const systemContainers = input.systemContainers;\n if (!systemContainers) {\n return;\n }\n\n for (const systemContainer of systemContainers) {\n await persistProvisionedContainerBootstrap(execSql, {\n container: systemContainer,\n icon: systemContainer.icon,\n name: systemContainer.name,\n organizationId: input.organizationId,\n parentId: input.containerId,\n });\n // Provisioned system-container metadata is already committed remotely in\n // the organization transaction. Persist the initialized snapshot locally,\n // but do not queue a duplicate write with a second update id.\n }\n}\n\n// The ONE persist shape for the provisioned profile documents (organization\n// profile and roster profile): the input carries exactly the bootstrap\n// fields, so only the document kind and the host's projectors join it.\nasync function persistProfileDocumentBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n profileDocument: ProvisionedProfileDocumentBootstrapInput | undefined,\n documentKind: string,\n): Promise<void> {\n if (!profileDocument) {\n return;\n }\n\n await persistInitialDocumentBootstrap(execSql, {\n ...profileDocument,\n documentKind,\n documentProjectors: input.documentProjectors,\n });\n}\n\nexport async function persistInitialDocumentBootstrap(\n execSql: ExecSql,\n input: {\n accessEpoch: number;\n accessStateHash: string;\n containerId: string;\n documentId: string;\n documentKind: string;\n documentProjectors: DocumentProjectorRegistryInput | undefined;\n documentState: Pick<\n DocumentRecord,\n \"contentKeyBundle\" | \"documentKekTargets\" | \"documentManifestBundle\"\n >;\n initialUpdate: Uint8Array;\n initialUpdateCommitted: boolean;\n localId: string;\n },\n): Promise<void> {\n const doc = await createDocument(await getScopedPeerSeed(DOCUMENTS_APP_KIND));\n importUpdates(doc, [input.initialUpdate]);\n const pendingUpdate = input.initialUpdateCommitted\n ? undefined\n : (createPendingUpdateFields(input.initialUpdate) ?? undefined);\n\n await persistDocumentState({\n currentDoc: doc,\n currentRecord: null,\n documentProjectors: input.documentProjectors ?? [],\n execSql,\n localId: input.localId,\n patch: {\n accessEpoch: input.accessEpoch,\n accessStateHash: input.accessStateHash,\n containerId: input.containerId,\n contentKeyBundle: input.documentState.contentKeyBundle ?? null,\n documentId: input.documentId,\n // Successful provisioning makes this device's user the founding admin.\n // Stores can open before discovery returns the same access level.\n effectiveAccessLevel: \"admin\",\n documentKekTargets: input.documentState.documentKekTargets ?? null,\n documentKind: input.documentKind,\n documentManifestBundle:\n input.documentState.documentManifestBundle ?? null,\n // The create-only persistence primitive stores this frontier and the\n // full-history checkpoint in one transaction.\n snapshotEndVersion: encodeVersionVector(doc),\n },\n pendingUpdate,\n persistence: sqlDocumentsPersistence,\n });\n}\n\n/**\n * Persists the local root-container bootstrap created during successful\n * registration so container contents can initialize from SQLite on first\n * login — atomically: every write lands inside ONE transaction whose last\n * act re-checks identity currency, so an identity replaced anywhere between\n * the queue claim and the commit rolls the entire bootstrap back instead of\n * leaving a partial one. Resolves false when either currency check rejected\n * the write, so callers do not report a bootstrap that was never persisted.\n */\nexport async function persistRegistrationBootstrapFromExecSql(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n): Promise<boolean> {\n input.onPersistQueued?.();\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n // In-mutex currency check, adjacent to the serialized-mutation claim\n // (see persistDocumentState): the identity can be replaced while this\n // persist waits for the queue, and its bootstrap must not be written\n // through a client the replacement closed or renewed.\n if (input.canStartDurableMutation && !input.canStartDurableMutation()) {\n return false;\n }\n // Idempotent DDL stays outside the atomic boundary.\n await sqlContainerContentsPersistence.ensureSchema(lockedExecSql);\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n // Pre-commit currency guard: the write sequence awaits real work, so\n // the identity can be replaced mid-sequence. The guard runs\n // synchronously with the COMMIT dispatch, so a refusal rolls the whole\n // write set back and a pass cannot go stale before the commit is sent —\n // the partial-persist window a single entry check leaves open.\n const { committed } = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async () => {\n await advanceLocallyAcknowledgedAccessManifestHeadsAtomically({\n execSql: lockedExecSql,\n heads: input.acknowledgedAccessHeads,\n });\n await persistRegistrationPrincipalPolicies({\n adminGroup: input.initialAdminGroupPolicy,\n execSql: lockedExecSql,\n memberGroup: input.initialMemberGroupPolicy,\n organization: input.initialOrganizationPolicy,\n });\n await persistRootContainerBootstrap(lockedExecSql, input);\n await persistNamedChildContainerBootstrap(\n lockedExecSql,\n input,\n input.rosterProfileContainer,\n ORGANIZATION_ROSTER_PROFILE_CONTAINER_NAME,\n );\n await persistProfileDocumentBootstrap(\n lockedExecSql,\n input,\n input.rosterProfileDocument,\n ROSTER_PROFILE_DOCUMENT_KIND,\n );\n await persistNamedChildContainerBootstrap(\n lockedExecSql,\n input,\n input.organizationMetadataContainer,\n ORGANIZATION_METADATA_CONTAINER_NAME,\n );\n await persistProfileDocumentBootstrap(\n lockedExecSql,\n input,\n input.organizationProfileDocument,\n ORGANIZATION_PROFILE_DOCUMENT_KIND,\n );\n await persistSystemContainersBootstrap(lockedExecSql, input);\n },\n () => !input.canStartDurableMutation || input.canStartDurableMutation(),\n );\n return committed;\n });\n}\n\nexport async function persistRegistrationBootstrap(\n client: ExecSqlClientLike,\n input: RegistrationBootstrapInput,\n): Promise<void> {\n await persistRegistrationBootstrapFromExecSql(createExecSql(client), input);\n}\n"]}
1
+ {"version":3,"file":"persistRegistrationBootstrap.js","sourceRoot":"","sources":["persistRegistrationBootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createDocument,\n encodeVersionVector,\n importUpdates,\n} from \"@tearleads/loro\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { getScopedPeerSeed } from \"../../data/crdtPeerSeed\";\nimport type { DocumentProjectorRegistryInput } from \"../../data/documents/documentKinds\";\nimport { createPendingUpdateFields } from \"../../data/documents/documentSync\";\nimport {\n type ContainerMetadataRecord,\n sqlContainerContentsPersistence,\n} from \"../../data/persistence/container-contents/containerContentsPersistence\";\nimport {\n type AuthoredDiscoveryHead,\n primeAuthoredDocumentDiscoveryHeads,\n} from \"../../data/persistence/documents/documentDiscoveryEvidencePersistence\";\nimport {\n DOCUMENTS_APP_KIND,\n sqlDocumentsPersistence,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport {\n advanceLocallyAcknowledgedAccessManifestHeadsAtomically,\n type LocallyAcknowledgedAccessManifestHead,\n} from \"../../data/persistence/locallyAcknowledgedCheckpointPersistence\";\nimport type { DocumentRecord } from \"../../data/sqlite/documentPersistence\";\nimport { documentContainerProjectionTables } from \"../../data/sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport {\n createExecSql,\n type ExecSql,\n type ExecSqlClientLike,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../data/sqlite/sqlSchema\";\nimport { persistDocumentState } from \"../documents/persistence\";\nimport { ORGANIZATION_PROFILE_DOCUMENT_KIND } from \"../organizations/organizationProfile\";\nimport {\n ORGANIZATION_METADATA_CONTAINER_NAME,\n ORGANIZATION_ROSTER_PROFILE_CONTAINER_NAME,\n ROSTER_PROFILE_DOCUMENT_KIND,\n} from \"../organizations/rosterProfileContainer\";\nimport { enqueueInitialContainerMetadataUpdate } from \"./registrationBootstrapPendingUpdates\";\nimport { persistRegistrationPrincipalPolicies } from \"./registrationPrincipalPolicyPersistence\";\n\ninterface ProvisionedContainerBootstrapInput {\n accessEpoch: number;\n accessStateHash: string;\n containerId: string;\n createdAt: string;\n metadataDocumentId: string;\n metadataSnapshot: string;\n metadataState: Pick<\n DocumentRecord,\n | \"documentId\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\"\n >;\n systemSlot: ContainerSystemSlot;\n updatedAt: string;\n}\n\ninterface ProvisionedProfileDocumentBootstrapInput {\n accessEpoch: number;\n accessStateHash: string;\n containerId: string;\n documentId: string;\n documentState: ProvisionedContainerBootstrapInput[\"metadataState\"];\n initialUpdate: Uint8Array;\n initialUpdateCommitted: boolean;\n localId: string;\n}\n\nexport interface RegistrationBootstrapInput {\n acknowledgedAccessHeads: readonly LocallyAcknowledgedAccessManifestHead[];\n /** Seeded documents' acknowledged signed heads; see the discovery cache. */\n authoredDiscoveryHeads: readonly AuthoredDiscoveryHead[];\n /** Checked inside the mutation queue claim; false skips every write. */\n canStartDurableMutation?: (() => boolean) | undefined;\n /**\n * @internal Test-only synchronization seam. Invoked synchronously,\n * immediately before this persist joins the serialized mutation queue —\n * no interleaving can separate the two. Lets identity-race tests\n * deterministically place an identity replacement inside the queue-wait\n * window instead of sleeping.\n */\n onPersistQueued?: (() => void) | undefined;\n containerId: string;\n initialAdminGroupPolicy: PrincipalPolicyBundleResponse;\n initialMemberGroupPolicy: PrincipalPolicyBundleResponse;\n initialOrganizationPolicy: PrincipalPolicyBundleResponse;\n rootMetadataAccessEpoch: number;\n rootMetadataAccessStateHash: string;\n rootContainerServerTimestamp: string;\n rootMetadataDocumentId: string;\n rootMetadataInitialUpdate: Uint8Array;\n rootMetadataInitialUpdateCommitted?: boolean | undefined;\n rootMetadataSnapshot: string;\n rootMetadataState: ProvisionedContainerBootstrapInput[\"metadataState\"];\n rosterProfileContainer?: ProvisionedContainerBootstrapInput & {\n metadataInitialUpdate: Uint8Array;\n metadataInitialUpdateCommitted?: boolean | undefined;\n };\n organizationMetadataContainer?: ProvisionedContainerBootstrapInput & {\n metadataInitialUpdate: Uint8Array;\n metadataInitialUpdateCommitted?: boolean | undefined;\n };\n organizationProfileDocument?: ProvisionedProfileDocumentBootstrapInput;\n rosterProfileDocument?: ProvisionedProfileDocumentBootstrapInput;\n // Additional app-owned system containers provisioned with the organization\n // (e.g. a trash bin). Each carries its own display name and icon (unlike the\n // roster/organization-metadata containers, whose names are fixed), since the\n // caller declares them.\n systemContainers?: Array<\n ProvisionedContainerBootstrapInput & {\n icon: string | null;\n name: string;\n }\n >;\n documentProjectors?: DocumentProjectorRegistryInput | undefined;\n organizationId: string;\n userId: string;\n}\nasync function persistProvisionedContainerBootstrap(\n execSql: ExecSql,\n input: {\n container: ProvisionedContainerBootstrapInput;\n icon: string | null;\n name: string;\n organizationId: string;\n parentId: string | null;\n },\n): Promise<void> {\n const { container } = input;\n const metadataState = container.metadataState;\n const record: ContainerMetadataRecord = {\n accessEpoch: container.accessEpoch,\n accessStateHash: container.accessStateHash,\n documentId: container.metadataDocumentId,\n id: container.containerId,\n lastCommitLsn: null,\n metadataUpdates: container.metadataSnapshot,\n snapshotEndVersion: \"\",\n contentKeyBundle: metadataState.contentKeyBundle ?? null,\n documentKekTargets: metadataState.documentKekTargets ?? null,\n documentManifestBundle: metadataState.documentManifestBundle ?? null,\n };\n await sqlContainerContentsPersistence.saveContainer(\n execSql,\n {\n id: container.containerId,\n effectiveAccessLevel: \"admin\",\n organizationId: input.organizationId,\n parentId: input.parentId,\n metadataDocumentId: container.metadataDocumentId,\n systemSlot: container.systemSlot,\n name: input.name,\n icon: input.icon,\n },\n record,\n {\n localUpdatedAt: container.updatedAt,\n serverTimestamps: {\n createdAt: container.createdAt,\n updatedAt: container.updatedAt,\n },\n },\n );\n}\n\nasync function persistRootContainerBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n): Promise<void> {\n const rootRecord: ContainerMetadataRecord = {\n accessEpoch: input.rootMetadataAccessEpoch,\n accessStateHash: input.rootMetadataAccessStateHash,\n documentId: input.rootMetadataDocumentId,\n id: input.containerId,\n lastCommitLsn: null,\n metadataUpdates: input.rootMetadataSnapshot,\n snapshotEndVersion: \"\",\n contentKeyBundle: input.rootMetadataState.contentKeyBundle ?? null,\n documentKekTargets: input.rootMetadataState.documentKekTargets ?? null,\n documentManifestBundle:\n input.rootMetadataState.documentManifestBundle ?? null,\n };\n await sqlContainerContentsPersistence.saveContainer(\n execSql,\n {\n id: input.containerId,\n effectiveAccessLevel: \"admin\",\n organizationId: input.organizationId,\n parentId: null,\n metadataDocumentId: input.rootMetadataDocumentId,\n name: \"/\",\n icon: null,\n },\n rootRecord,\n {\n localUpdatedAt: input.rootContainerServerTimestamp,\n serverTimestamps: {\n createdAt: input.rootContainerServerTimestamp,\n updatedAt: input.rootContainerServerTimestamp,\n },\n },\n );\n await enqueueInitialContainerMetadataUpdate(\n execSql,\n input.containerId,\n input.rootMetadataInitialUpdate,\n input.rootMetadataInitialUpdateCommitted,\n );\n}\n\n// Persist reserved profile containers using their fixed topology: roster profiles\n// inherit the personal root; shared organization metadata has an independent root.\nasync function persistNamedChildContainerBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n container: RegistrationBootstrapInput[\"rosterProfileContainer\"],\n name: string,\n): Promise<void> {\n if (!container) {\n return;\n }\n\n await persistProvisionedContainerBootstrap(execSql, {\n container,\n icon: null,\n name,\n organizationId: input.organizationId,\n parentId:\n container === input.organizationMetadataContainer\n ? null\n : input.containerId,\n });\n await enqueueInitialContainerMetadataUpdate(\n execSql,\n container.containerId,\n container.metadataInitialUpdate,\n container.metadataInitialUpdateCommitted,\n );\n}\n\nasync function persistSystemContainersBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n): Promise<void> {\n const systemContainers = input.systemContainers;\n if (!systemContainers) {\n return;\n }\n\n for (const systemContainer of systemContainers) {\n await persistProvisionedContainerBootstrap(execSql, {\n container: systemContainer,\n icon: systemContainer.icon,\n name: systemContainer.name,\n organizationId: input.organizationId,\n parentId: input.containerId,\n });\n // Provisioned system-container metadata is already committed remotely in\n // the organization transaction. Persist the initialized snapshot locally,\n // but do not queue a duplicate write with a second update id.\n }\n}\n\n// The ONE persist shape for the provisioned profile documents (organization\n// profile and roster profile): the input carries exactly the bootstrap\n// fields, so only the document kind and the host's projectors join it.\nasync function persistProfileDocumentBootstrap(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n profileDocument: ProvisionedProfileDocumentBootstrapInput | undefined,\n documentKind: string,\n): Promise<void> {\n if (!profileDocument) {\n return;\n }\n\n await persistInitialDocumentBootstrap(execSql, {\n ...profileDocument,\n documentKind,\n documentProjectors: input.documentProjectors,\n });\n}\n\nexport async function persistInitialDocumentBootstrap(\n execSql: ExecSql,\n input: {\n accessEpoch: number;\n accessStateHash: string;\n containerId: string;\n documentId: string;\n documentKind: string;\n documentProjectors: DocumentProjectorRegistryInput | undefined;\n documentState: Pick<\n DocumentRecord,\n \"contentKeyBundle\" | \"documentKekTargets\" | \"documentManifestBundle\"\n >;\n initialUpdate: Uint8Array;\n initialUpdateCommitted: boolean;\n localId: string;\n },\n): Promise<void> {\n const doc = await createDocument(await getScopedPeerSeed(DOCUMENTS_APP_KIND));\n importUpdates(doc, [input.initialUpdate]);\n const pendingUpdate = input.initialUpdateCommitted\n ? undefined\n : (createPendingUpdateFields(input.initialUpdate) ?? undefined);\n\n await persistDocumentState({\n currentDoc: doc,\n currentRecord: null,\n documentProjectors: input.documentProjectors ?? [],\n execSql,\n localId: input.localId,\n patch: {\n accessEpoch: input.accessEpoch,\n accessStateHash: input.accessStateHash,\n containerId: input.containerId,\n contentKeyBundle: input.documentState.contentKeyBundle ?? null,\n documentId: input.documentId,\n // Successful provisioning makes this device's user the founding admin.\n // Stores can open before discovery returns the same access level.\n effectiveAccessLevel: \"admin\",\n documentKekTargets: input.documentState.documentKekTargets ?? null,\n documentKind: input.documentKind,\n documentManifestBundle:\n input.documentState.documentManifestBundle ?? null,\n // The create-only persistence primitive stores this frontier and the\n // full-history checkpoint in one transaction.\n snapshotEndVersion: encodeVersionVector(doc),\n },\n pendingUpdate,\n persistence: sqlDocumentsPersistence,\n });\n}\n\n/**\n * Persists the local root-container bootstrap created during successful\n * registration so container contents can initialize from SQLite on first\n * login — atomically: every write lands inside ONE transaction whose last\n * act re-checks identity currency, so an identity replaced anywhere between\n * the queue claim and the commit rolls the entire bootstrap back instead of\n * leaving a partial one. Resolves false when either currency check rejected\n * the write, so callers do not report a bootstrap that was never persisted.\n */\nexport async function persistRegistrationBootstrapFromExecSql(\n execSql: ExecSql,\n input: RegistrationBootstrapInput,\n): Promise<boolean> {\n input.onPersistQueued?.();\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n // In-mutex currency check, adjacent to the serialized-mutation claim\n // (see persistDocumentState): the identity can be replaced while this\n // persist waits for the queue, and its bootstrap must not be written\n // through a client the replacement closed or renewed.\n if (input.canStartDurableMutation && !input.canStartDurableMutation()) {\n return false;\n }\n // Idempotent DDL stays outside the atomic boundary.\n await sqlContainerContentsPersistence.ensureSchema(lockedExecSql);\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);\n // Pre-commit currency guard: the write sequence awaits real work, so\n // the identity can be replaced mid-sequence. The guard runs\n // synchronously with the COMMIT dispatch, so a refusal rolls the whole\n // write set back and a pass cannot go stale before the commit is sent —\n // the partial-persist window a single entry check leaves open.\n const { committed } = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async () => {\n await advanceLocallyAcknowledgedAccessManifestHeadsAtomically({\n execSql: lockedExecSql,\n heads: input.acknowledgedAccessHeads,\n });\n await persistRegistrationPrincipalPolicies({\n adminGroup: input.initialAdminGroupPolicy,\n execSql: lockedExecSql,\n memberGroup: input.initialMemberGroupPolicy,\n organization: input.initialOrganizationPolicy,\n });\n await persistRootContainerBootstrap(lockedExecSql, input);\n await persistNamedChildContainerBootstrap(\n lockedExecSql,\n input,\n input.rosterProfileContainer,\n ORGANIZATION_ROSTER_PROFILE_CONTAINER_NAME,\n );\n await persistProfileDocumentBootstrap(\n lockedExecSql,\n input,\n input.rosterProfileDocument,\n ROSTER_PROFILE_DOCUMENT_KIND,\n );\n await persistNamedChildContainerBootstrap(\n lockedExecSql,\n input,\n input.organizationMetadataContainer,\n ORGANIZATION_METADATA_CONTAINER_NAME,\n );\n await persistProfileDocumentBootstrap(\n lockedExecSql,\n input,\n input.organizationProfileDocument,\n ORGANIZATION_PROFILE_DOCUMENT_KIND,\n );\n await persistSystemContainersBootstrap(lockedExecSql, input);\n // After the checkpoints above: discovery reuses a cached head only\n // while its access-manifest checkpoint still matches.\n await primeAuthoredDocumentDiscoveryHeads(\n lockedExecSql,\n input.authoredDiscoveryHeads,\n );\n },\n () => !input.canStartDurableMutation || input.canStartDurableMutation(),\n );\n return committed;\n });\n}\n\nexport async function persistRegistrationBootstrap(\n client: ExecSqlClientLike,\n input: RegistrationBootstrapInput,\n): Promise<void> {\n await persistRegistrationBootstrapFromExecSql(createExecSql(client), input);\n}\n"]}
@@ -0,0 +1,45 @@
1
+ import type { PrincipalPolicyBundleResponse } from "../../internal/validators/response/index.js";
2
+ import type { PrincipalHistoryProtectionLease } from "../../data/principals/principalHistoryProtection.js";
3
+ import type { ExecSql, ExecSqlClientLike } from "../../data/sqlite/sqlSchema.js";
4
+ import type { TrustedUserIdentity } from "../../data/trustedUserIdentity/index.js";
5
+ /** The version-1 policies a provisioning request signed and its response acknowledged. */
6
+ interface ProvisionedPrincipalPolicies {
7
+ readonly adminGroup: PrincipalPolicyBundleResponse;
8
+ readonly memberGroup: PrincipalPolicyBundleResponse;
9
+ readonly organization: PrincipalPolicyBundleResponse;
10
+ }
11
+ /**
12
+ * Records verified recovery progress for an organization's founding policy
13
+ * heads, so the device's first scoped recovery of them needs no history read.
14
+ * It is bound to the provisioning scope: the database the bootstrap committed
15
+ * to and the identity that signed it. Failure leaves the online path.
16
+ */
17
+ export type ProvisionedPrincipalHistoryPrimer = (input: {
18
+ /** The database client the provisioning bootstrap committed to. */
19
+ readonly database: ExecSqlClientLike;
20
+ /** Whether the identity that provisioned is still the active one. */
21
+ readonly isCurrent: () => boolean;
22
+ readonly organizationId: string;
23
+ readonly policies: ProvisionedPrincipalPolicies;
24
+ readonly userId: string;
25
+ }) => Promise<void>;
26
+ /** The runtime seams priming reads; none of them writes durable state. */
27
+ interface ProvisionedPrincipalHistoryRuntime {
28
+ readonly bindLease: () => PrincipalHistoryProtectionLease | undefined;
29
+ /** The runtime executor, only while `database` is its ready database. */
30
+ readonly execSqlFor: (database: ExecSqlClientLike) => ExecSql | null;
31
+ readonly logError: (message: string | Error, cause?: unknown) => void;
32
+ /** Read-only: the identity the trust store already pins for a user. */
33
+ readonly loadPinnedIdentity: (execSql: ExecSql, userId: string) => Promise<TrustedUserIdentity | null>;
34
+ readonly signingFingerprint: () => string | null;
35
+ }
36
+ /**
37
+ * Binds priming to the exact provisioning scope, captured before any await:
38
+ * the bootstrap's database and runtime executor, the identity whose key signed
39
+ * the founding states, and a protection lease for that identity. Every later
40
+ * step, and every progress write inside its transaction, rechecks that scope,
41
+ * so a switched identity or database aborts priming without a durable write.
42
+ * Priming never writes a trust pin; it only reads the founder's existing one.
43
+ */
44
+ export declare function createProvisionedPrincipalHistoryPrimer(runtime: ProvisionedPrincipalHistoryRuntime): ProvisionedPrincipalHistoryPrimer;
45
+ export {};
@@ -0,0 +1,104 @@
1
+ import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
2
+ import { principalPolicyReferenceFromBundle } from "../../data/principals/principalPolicyAdminSigners.js";
3
+ import { createPrincipalCurrentRecoveryBatch } from "../principals/principalCurrentRecoveryBatch.js";
4
+ import { queuePrincipalRecovery } from "../principals/principalRecoveryQueue.js";
5
+ /**
6
+ * Serves only the acknowledged initial heads, each complete in one page. The
7
+ * ordinary verifier still checks every signature, the directory binding and
8
+ * strict Admins rules before any progress is saved.
9
+ */
10
+ function provisionedPolicyPages(policies) {
11
+ const bundles = [
12
+ policies.organization,
13
+ policies.adminGroup,
14
+ policies.memberGroup,
15
+ ];
16
+ return {
17
+ async *getPrincipalPolicyPages(principalType, principalId, options = {}) {
18
+ const bundle = bundles.find(({ currentState }) => currentState.principalType === principalType &&
19
+ currentState.principalId === principalId);
20
+ if (!bundle ||
21
+ options.resume !== undefined ||
22
+ (options.afterVersion ?? 0) !== 0 ||
23
+ (options.stateHash !== undefined &&
24
+ options.stateHash !== bundle.currentState.stateHash))
25
+ throw new Error("Provisioned principal history holds only the acknowledged initial heads");
26
+ yield {
27
+ ok: true,
28
+ data: {
29
+ ...structuredClone(bundle),
30
+ historyPage: { afterVersion: 0, nextAfterVersion: null },
31
+ },
32
+ };
33
+ },
34
+ };
35
+ }
36
+ async function primeProvisionedPrincipalHistory(input) {
37
+ const { recover } = createPrincipalCurrentRecoveryBatch();
38
+ const options = {
39
+ apiClient: provisionedPolicyPages(input.policies),
40
+ execSql: input.execSql,
41
+ offline: false,
42
+ organizationId: input.organizationId,
43
+ protection: input.protection,
44
+ resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,
45
+ stillCurrent: input.stillCurrent,
46
+ };
47
+ // Scoped recovery of each group also completes the directory and strict
48
+ // Admins stages; Members reuses them through the shared batch.
49
+ for (const group of [input.policies.adminGroup, input.policies.memberGroup])
50
+ await recover({
51
+ ...options,
52
+ reference: principalPolicyReferenceFromBundle(group),
53
+ });
54
+ }
55
+ /**
56
+ * Binds priming to the exact provisioning scope, captured before any await:
57
+ * the bootstrap's database and runtime executor, the identity whose key signed
58
+ * the founding states, and a protection lease for that identity. Every later
59
+ * step, and every progress write inside its transaction, rechecks that scope,
60
+ * so a switched identity or database aborts priming without a durable write.
61
+ * Priming never writes a trust pin; it only reads the founder's existing one.
62
+ */
63
+ export function createProvisionedPrincipalHistoryPrimer(runtime) {
64
+ return async (input) => {
65
+ try {
66
+ await primeInProvisioningScope(runtime, input);
67
+ }
68
+ catch (error) {
69
+ runtime.logError("Provisioned principal history was not primed; recovery reads it online", error);
70
+ }
71
+ };
72
+ }
73
+ async function primeInProvisioningScope(runtime, input) {
74
+ // Everything below is captured synchronously, before the first await.
75
+ const founderFingerprint = input.policies.organization.currentState.signerUserKeyFingerprint;
76
+ const execSql = runtime.execSqlFor(input.database);
77
+ const scopeCurrent = () => execSql !== null &&
78
+ input.isCurrent() &&
79
+ runtime.execSqlFor(input.database) === execSql &&
80
+ runtime.signingFingerprint() === founderFingerprint;
81
+ const lease = scopeCurrent() ? runtime.bindLease() : undefined;
82
+ if (!execSql || !lease)
83
+ return;
84
+ const resolveTrustedUserIdentity = async (signerUserId) => {
85
+ if (signerUserId !== input.userId)
86
+ return null;
87
+ assertProjectionVerificationCurrent(scopeCurrent);
88
+ const identity = await runtime.loadPinnedIdentity(execSql, input.userId);
89
+ assertProjectionVerificationCurrent(scopeCurrent);
90
+ return identity?.signingKeyFingerprint === founderFingerprint
91
+ ? identity
92
+ : null;
93
+ };
94
+ await queuePrincipalRecovery(execSql, input.organizationId, () => lease(({ protection, stillCurrent }) => primeProvisionedPrincipalHistory({
95
+ execSql,
96
+ organizationId: input.organizationId,
97
+ policies: input.policies,
98
+ protection,
99
+ resolveTrustedUserIdentity,
100
+ // Progress writes check this inside their transactions.
101
+ stillCurrent: () => stillCurrent() && scopeCurrent(),
102
+ })));
103
+ }
104
+ //# sourceMappingURL=provisionedPrincipalHistory.js.map