@yielded/auth-persistence 0.1.0-beta.31 → 0.1.0-beta.32

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 (113) hide show
  1. package/README.md +9 -2
  2. package/dist/Adapter.mjs +8 -8
  3. package/dist/OAuthPersistence.mjs +10 -5
  4. package/dist/OAuthPersistence.mjs.map +1 -1
  5. package/dist/internal/configuration.d.mts +31 -5
  6. package/dist/internal/configuration.mjs.map +1 -1
  7. package/dist/internal/email-native.mjs +10 -2
  8. package/dist/internal/email-native.mjs.map +1 -1
  9. package/dist/internal/email-policy.mjs +3 -2
  10. package/dist/internal/email-policy.mjs.map +1 -1
  11. package/dist/internal/models/oauth-model.d.mts +4 -2
  12. package/dist/internal/models/oauth-model.mjs.map +1 -1
  13. package/dist/internal/oauth/native-accounts.d.mts +1 -1
  14. package/dist/internal/oauth/native-accounts.mjs +6 -6
  15. package/dist/internal/oauth/native-accounts.mjs.map +1 -1
  16. package/dist/internal/oauth/native-connected.d.mts +1 -1
  17. package/dist/internal/oauth/native-connected.mjs +1 -1
  18. package/dist/internal/oauth/native-registration.mjs +19 -8
  19. package/dist/internal/oauth/native-registration.mjs.map +1 -1
  20. package/dist/internal/oauth/native-sign-in.d.mts +1 -1
  21. package/dist/internal/oauth/native-sign-in.mjs +1 -1
  22. package/dist/internal/oauth/native-state.mjs +21 -11
  23. package/dist/internal/oauth/native-state.mjs.map +1 -1
  24. package/dist/internal/oauth/state.d.mts +1 -1
  25. package/dist/internal/oauth/state.mjs +1 -1
  26. package/dist/internal/oauth-managed.mjs +182 -0
  27. package/dist/internal/oauth-managed.mjs.map +1 -0
  28. package/dist/internal/passkey-managed.mjs +1 -1
  29. package/dist/internal/passkey-native-registration.mjs +1 -1
  30. package/dist/internal/passkey-native-state.mjs +33 -23
  31. package/dist/internal/passkey-native-state.mjs.map +1 -1
  32. package/dist/internal/passkey-native-write.mjs +3 -3
  33. package/dist/internal/passkey-native-write.mjs.map +1 -1
  34. package/dist/internal/passkey-native.d.mts +15 -7
  35. package/dist/internal/passkey-native.mjs +2 -1
  36. package/dist/internal/passkey-native.mjs.map +1 -1
  37. package/dist/internal/passkey-policy.mjs +9 -7
  38. package/dist/internal/passkey-policy.mjs.map +1 -1
  39. package/dist/internal/password-native.mjs +9 -6
  40. package/dist/internal/password-native.mjs.map +1 -1
  41. package/dist/internal/password-policy.mjs +7 -6
  42. package/dist/internal/password-policy.mjs.map +1 -1
  43. package/dist/internal/persistence.mjs +96 -37
  44. package/dist/internal/persistence.mjs.map +1 -1
  45. package/dist/internal/phone-native.mjs +1 -1
  46. package/dist/internal/phone-native.mjs.map +1 -1
  47. package/dist/internal/session-native-authority.mjs +6 -5
  48. package/dist/internal/session-native-authority.mjs.map +1 -1
  49. package/dist/internal/session-native-login.d.mts +2 -2
  50. package/dist/internal/session-native-login.mjs +2 -1
  51. package/dist/internal/session-native-login.mjs.map +1 -1
  52. package/dist/internal/session-native-pending-read.mjs +26 -20
  53. package/dist/internal/session-native-pending-read.mjs.map +1 -1
  54. package/dist/internal/session-native-record.mjs +6 -4
  55. package/dist/internal/session-native-record.mjs.map +1 -1
  56. package/dist/internal/session-native-state.mjs +3 -0
  57. package/dist/internal/session-native-state.mjs.map +1 -1
  58. package/dist/internal/session-native-stateful.d.mts +2 -2
  59. package/dist/internal/session-native-stateful.mjs +65 -37
  60. package/dist/internal/session-native-stateful.mjs.map +1 -1
  61. package/dist/internal/session-native-step-up.d.mts +2 -2
  62. package/dist/internal/session-native-step-up.mjs +14 -18
  63. package/dist/internal/session-native-step-up.mjs.map +1 -1
  64. package/dist/internal/session-native-validity.mjs +3 -1
  65. package/dist/internal/session-native-validity.mjs.map +1 -1
  66. package/dist/internal/sql-authority.mjs +5 -1
  67. package/dist/internal/sql-authority.mjs.map +1 -1
  68. package/dist/internal/sql-storage-validation.mjs +2 -1
  69. package/dist/internal/sql-storage-validation.mjs.map +1 -1
  70. package/dist/internal/sql-table.d.mts +1 -0
  71. package/dist/internal/sql-table.mjs.map +1 -1
  72. package/dist/internal/step-up-state.mjs +19 -6
  73. package/dist/internal/step-up-state.mjs.map +1 -1
  74. package/dist/internal/storage-mapping.mjs +1 -1
  75. package/dist/internal/storage-tables.d.mts +237 -0
  76. package/dist/internal/storage-tables.mjs +68 -0
  77. package/dist/internal/storage-tables.mjs.map +1 -1
  78. package/dist/internal/storage-validation.d.mts +3 -1
  79. package/dist/internal/storage-validation.mjs +70 -17
  80. package/dist/internal/storage-validation.mjs.map +1 -1
  81. package/dist/internal/totp-native.mjs +1 -1
  82. package/package.json +1 -1
  83. package/src/OAuthPersistence.ts +7 -2
  84. package/src/internal/configuration.ts +46 -7
  85. package/src/internal/email-native.ts +16 -6
  86. package/src/internal/email-policy.ts +12 -3
  87. package/src/internal/models/oauth-model.ts +7 -1
  88. package/src/internal/oauth/native-accounts.ts +3 -3
  89. package/src/internal/oauth/native-registration.ts +17 -6
  90. package/src/internal/oauth/native-state.ts +38 -18
  91. package/src/internal/oauth-managed.ts +277 -0
  92. package/src/internal/passkey-native-state.ts +59 -52
  93. package/src/internal/passkey-native-write.ts +2 -2
  94. package/src/internal/passkey-native.ts +4 -2
  95. package/src/internal/passkey-policy.ts +13 -9
  96. package/src/internal/password-native.ts +17 -9
  97. package/src/internal/password-policy.ts +16 -8
  98. package/src/internal/persistence.ts +216 -70
  99. package/src/internal/phone-native.ts +1 -1
  100. package/src/internal/session-native-authority.ts +23 -7
  101. package/src/internal/session-native-login.ts +6 -3
  102. package/src/internal/session-native-pending-read.ts +46 -33
  103. package/src/internal/session-native-record.ts +6 -4
  104. package/src/internal/session-native-state.ts +3 -0
  105. package/src/internal/session-native-stateful.ts +144 -51
  106. package/src/internal/session-native-step-up.ts +27 -23
  107. package/src/internal/session-native-validity.ts +3 -1
  108. package/src/internal/sql-authority.ts +5 -1
  109. package/src/internal/sql-storage-validation.ts +53 -46
  110. package/src/internal/sql-table.ts +1 -0
  111. package/src/internal/step-up-state.ts +43 -6
  112. package/src/internal/storage-tables.ts +76 -0
  113. package/src/internal/storage-validation.ts +127 -27
@@ -1 +1 @@
1
- {"version":3,"file":"password-policy.mjs","names":[],"sources":["../../src/internal/password-policy.ts"],"sourcesContent":["import type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport {\n PasswordUnavailable,\n snapshotPasswordCredential,\n snapshotPasswordRequirement,\n snapshotPasswordRevision,\n type PasswordAction,\n type PasswordCredentialSnapshot,\n type PasswordMutationInput,\n} from \"@yielded/auth/Password\";\nimport type { ProofRedemptionPlan } from \"@yielded/auth/Proofs\";\nimport {\n snapshotAuthenticationEvidence,\n type AuthenticationEvidence,\n type AuthenticationRequirement,\n type SecurityRevision,\n} from \"@yielded/auth/Sessions\";\nimport { DateTime, Effect, Redacted } from \"effect\";\n\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\n\nconst unavailable = () => PasswordUnavailable.make({});\n\nexport const samePasswordIdentifier = (left: LoginIdentifier, right: LoginIdentifier) =>\n left.namespace === right.namespace && left.value === right.value;\n\nexport const samePasswordCredential = (\n left: PasswordCredentialSnapshot,\n right: PasswordCredentialSnapshot,\n) =>\n left.moduleId === right.moduleId &&\n left.revision.subjectId === right.revision.subjectId &&\n left.revision.securityRevision === right.revision.securityRevision &&\n left.credentialId === right.credentialId &&\n left.credentialRevision === right.credentialRevision &&\n left.verifierVersion === right.verifierVersion &&\n left.normalization === right.normalization &&\n left.identifierVerifiedAtMillis === right.identifierVerifiedAtMillis &&\n left.revision.credentials.length === right.revision.credentials.length &&\n left.revision.credentials.every((entry) =>\n right.revision.credentials.some(\n (other) => other.credentialId === entry.credentialId && other.revision === entry.revision,\n ),\n ) &&\n left.identifierBindingRevision === right.identifierBindingRevision &&\n samePasswordIdentifier(left.identifier, right.identifier) &&\n Redacted.value(left.verifier) === Redacted.value(right.verifier);\n\nexport const passwordEvidenceSatisfiedAt = (\n evidence: AuthenticationEvidence,\n requirement: AuthenticationRequirement,\n now: number,\n): boolean => {\n if (evidence.proofs.length > 64 || evidence.revision.credentials.length > 64) return false;\n const revisions = new Map<string, string>();\n\n for (const item of evidence.revision.credentials) {\n if (revisions.has(item.credentialId)) return false;\n revisions.set(item.credentialId, item.revision);\n }\n if (evidence.proofs.some((proof) => !revisions.has(proof.credentialId))) return false;\n if (evidence.proofs.some((proof) => now < DateTime.toEpochMillis(proof.verifiedAt))) return false;\n\n const eligible = evidence.proofs.filter((proof) => {\n const age = now - DateTime.toEpochMillis(proof.verifiedAt);\n\n return age >= 0 && age < requirement.maximumAgeMillis;\n });\n\n const factors = new Set(eligible.flatMap((proof) => proof.factors));\n const credentials = new Set(eligible.map((proof) => proof.credentialId));\n\n return requirement.alternatives.some(\n (alternative) =>\n alternative.factors.every((factor) => factors.has(factor)) &&\n credentials.size >= alternative.minimumCredentials &&\n eligible.some(\n (proof) =>\n (!alternative.userVerified || proof.userVerified) &&\n (!alternative.phishingResistant || proof.phishingResistant),\n ),\n );\n};\n\nexport const snapshotPasswordMutation = Effect.fn(\"PasswordPersistence.snapshotMutation\")(\n function* (input: PasswordMutationInput) {\n const expectedRevision = snapshotPasswordRevision(input.expectedRevision);\n\n const evidence = yield* snapshotAuthenticationEvidence(input.authorization.evidence).pipe(\n Effect.mapError(unavailable),\n );\n\n const requirement = yield* snapshotPasswordRequirement(input.authorization.requirement);\n\n const credential =\n input.credential === undefined\n ? undefined\n : yield* snapshotPasswordCredential(input.credential);\n\n return Object.freeze({\n ...input,\n expectedRevision,\n replacement: Object.freeze({\n verifier: Redacted.make(Redacted.value(input.replacement.verifier)),\n normalization: input.replacement.normalization,\n }),\n invalidation: Object.freeze({ ...input.invalidation }),\n ...(credential === undefined ? {} : { credential }),\n authorization: Object.freeze({\n challenge: Object.freeze({\n ...input.authorization.challenge,\n revision: snapshotPasswordRevision(input.authorization.challenge.revision),\n }),\n evidence,\n requirement,\n }),\n });\n },\n);\n\nexport const passwordProofRedemptionMatches = (\n input: PasswordMutationInput & { readonly redemption: ProofRedemptionPlan },\n) => {\n const completion = input.redemption.input;\n const binding = completion.binding;\n\n if (\n completion.moduleId !== `${input.moduleId}/reset` ||\n completion.purpose !== \"password-reset\" ||\n binding._tag !== \"Subject\" ||\n input.credential === undefined ||\n binding.revision.subjectId !== input.expectedRevision.subjectId ||\n binding.revision.securityRevision !== input.expectedRevision.securityRevision ||\n !samePasswordIdentifier(binding.identifier, input.credential.identifier)\n )\n return false;\n\n const expected = [...input.expectedRevision.credentials].sort((left, right) =>\n left.credentialId.localeCompare(right.credentialId),\n );\n\n const actual = [...binding.revision.credentials].sort((left, right) =>\n left.credentialId.localeCompare(right.credentialId),\n );\n\n return (\n expected.length === actual.length &&\n expected.every(\n (item, index) =>\n item.credentialId === actual[index]!.credentialId &&\n item.revision === actual[index]!.revision,\n )\n );\n};\n\nexport interface PasswordWorkflowPolicy {\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n readonly subject: {\n readonly nextSecurityRevision?: (\n current: SecurityRevision,\n ) => Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;\n };\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n}\n\nexport interface PasswordWorkflowOptions {\n readonly mode: \"interactive\" | \"synchronous\";\n readonly locking: boolean;\n readonly coordinated?: boolean;\n readonly standaloneGuard: Effect.Effect<void, PasswordUnavailable>;\n readonly proof?: AnyProofPersistenceMapping;\n}\n\nexport const allocatePasswordValue = <A>(\n mode: PasswordWorkflowOptions[\"mode\"],\n asynchronous: Effect.Effect<A, PersistenceMappingError> | undefined,\n synchronous: (() => A) | undefined,\n): Effect.Effect<A, PasswordUnavailable | PersistenceMappingError> =>\n mode !== \"synchronous\" && asynchronous !== undefined\n ? asynchronous\n : synchronous === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: synchronous,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n\nexport const allocatePasswordNextSecurityRevision = (\n policy: PasswordWorkflowPolicy,\n mode: PasswordWorkflowOptions[\"mode\"],\n current: SecurityRevision,\n) =>\n allocatePasswordValue(\n mode,\n policy.subject.nextSecurityRevision?.(current) ?? policy.allocateRevision,\n policy.subject.nextSecurityRevisionSync === undefined\n ? policy.allocateRevisionSync\n : () => policy.subject.nextSecurityRevisionSync!(current),\n );\n\nexport const passwordMutationEvidenceMatches = (input: PasswordMutationInput) =>\n !input.expectedRevision.credentials.some(\n (expected) =>\n !input.authorization.evidence.revision.credentials.some(\n (actual) =>\n actual.credentialId === expected.credentialId && actual.revision === expected.revision,\n ),\n );\n\nexport const validatePasswordMutation = Effect.fnUntraced(function* (\n policy: PasswordWorkflowPolicy,\n input: PasswordMutationInput,\n action: PasswordAction,\n current: Pick<\n PasswordMutationRead,\n \"subject\" | \"identifierCurrent\" | \"credentials\" | \"snapshot\" | \"requirement\"\n >,\n now: number,\n) {\n if (\n current.subject === undefined ||\n !current.subject.active ||\n current.subject.securityRevision !== input.expectedRevision.securityRevision\n )\n return undefined;\n const { challenge, evidence } = input.authorization;\n\n if (\n challenge.moduleId !== input.moduleId ||\n challenge.action !== action ||\n challenge.commandId !== input.commandId ||\n challenge.revision.subjectId !== input.expectedRevision.subjectId ||\n challenge.revision.securityRevision !== input.expectedRevision.securityRevision ||\n (evidence.flowId as string) !== (input.commandId as string) ||\n evidence.bindingDigest !== challenge.bindingDigest ||\n evidence.revision.subjectId !== input.expectedRevision.subjectId ||\n evidence.revision.securityRevision !== input.expectedRevision.securityRevision ||\n (action === \"add-password\" &&\n (input.credential !== undefined || challenge.targetCredentialId !== undefined))\n )\n return undefined;\n if (!passwordMutationEvidenceMatches(input)) return undefined;\n if (input.credential !== undefined && !current.identifierCurrent) return undefined;\n\n const expected = new Map(\n [...input.expectedRevision.credentials, ...evidence.revision.credentials].map((item) => [\n item.credentialId,\n item,\n ]),\n );\n\n if (current.credentials.length !== expected.size) return undefined;\n for (const credential of current.credentials) {\n const wanted = expected.get(credential.credentialId);\n\n if (wanted === undefined || credential.revision !== wanted.revision || !credential.active)\n return undefined;\n expected.delete(wanted.credentialId);\n }\n if (expected.size !== 0) return undefined;\n if (input.credential !== undefined) {\n const snapshot = yield* current.snapshot;\n\n if (snapshot === undefined || !samePasswordCredential(snapshot, input.credential))\n return undefined;\n }\n const requirement = yield* current.requirement;\n\n if (\n !passwordEvidenceSatisfiedAt(evidence, input.authorization.requirement, now) ||\n !passwordEvidenceSatisfiedAt(evidence, requirement, now)\n )\n return undefined;\n if (\n input.invalidation.existingSessions === \"immediate\" &&\n policy.sessionInvalidation !== \"same-authority-immediate\"\n )\n return undefined;\n\n return now;\n});\n\n/** Decoded subject-first snapshot used only for this action's policy decision. */\nexport interface PasswordMutationRead {\n readonly subject:\n | { readonly active: boolean; readonly securityRevision: SecurityRevision }\n | undefined;\n readonly identifierCurrent: boolean;\n readonly credentials: ReadonlyArray<{\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n readonly active: boolean;\n }>;\n readonly snapshot: Effect.Effect<\n PasswordCredentialSnapshot | undefined,\n PasswordUnavailable | PersistenceMappingError\n >;\n readonly requirement: Effect.Effect<\n AuthenticationRequirement,\n PasswordUnavailable | PersistenceMappingError\n >;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"password-policy.mjs","names":[],"sources":["../../src/internal/password-policy.ts"],"sourcesContent":["import type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport { AuthenticationClock } from \"@yielded/auth/Operations\";\nimport {\n PasswordUnavailable,\n snapshotPasswordCredential,\n snapshotPasswordRequirement,\n snapshotPasswordRevision,\n type PasswordAction,\n type PasswordCredentialSnapshot,\n type PasswordMutationInput,\n} from \"@yielded/auth/Password\";\nimport type { ProofRedemptionPlan } from \"@yielded/auth/Proofs\";\nimport {\n snapshotAuthenticationEvidence,\n type AuthenticationEvidence,\n type AuthenticationRequirement,\n type SecurityRevision,\n} from \"@yielded/auth/Sessions\";\nimport { DateTime, Effect, Redacted } from \"effect\";\n\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\n\nconst unavailable = () => PasswordUnavailable.make({});\n\nexport const samePasswordIdentifier = (left: LoginIdentifier, right: LoginIdentifier) =>\n left.namespace === right.namespace && left.value === right.value;\n\nexport const samePasswordCredential = (\n left: PasswordCredentialSnapshot,\n right: PasswordCredentialSnapshot,\n) =>\n left.moduleId === right.moduleId &&\n left.revision.subjectId === right.revision.subjectId &&\n left.revision.securityRevision === right.revision.securityRevision &&\n left.credentialId === right.credentialId &&\n left.credentialRevision === right.credentialRevision &&\n left.verifierVersion === right.verifierVersion &&\n left.normalization === right.normalization &&\n left.identifierVerifiedAtMillis === right.identifierVerifiedAtMillis &&\n left.revision.credentials.length === right.revision.credentials.length &&\n left.revision.credentials.every((entry) =>\n right.revision.credentials.some(\n (other) => other.credentialId === entry.credentialId && other.revision === entry.revision,\n ),\n ) &&\n left.identifierBindingRevision === right.identifierBindingRevision &&\n samePasswordIdentifier(left.identifier, right.identifier) &&\n Redacted.value(left.verifier) === Redacted.value(right.verifier);\n\nexport const passwordEvidenceSatisfiedAt = Effect.fnUntraced(function* (\n evidence: AuthenticationEvidence,\n requirement: AuthenticationRequirement,\n now: number,\n): Effect.fn.Return<boolean> {\n const { futureToleranceMillis } = yield* AuthenticationClock;\n\n if (evidence.proofs.length > 64 || evidence.revision.credentials.length > 64) return false;\n const revisions = new Map<string, string>();\n\n for (const item of evidence.revision.credentials) {\n if (revisions.has(item.credentialId)) return false;\n revisions.set(item.credentialId, item.revision);\n }\n if (evidence.proofs.some((proof) => !revisions.has(proof.credentialId))) return false;\n if (\n evidence.proofs.some(\n (proof) => DateTime.toEpochMillis(proof.verifiedAt) - now > futureToleranceMillis,\n )\n )\n return false;\n\n const eligible = evidence.proofs.filter((proof) => {\n const age = Math.max(0, now - DateTime.toEpochMillis(proof.verifiedAt));\n\n return age < requirement.maximumAgeMillis;\n });\n\n const factors = new Set(eligible.flatMap((proof) => proof.factors));\n const credentials = new Set(eligible.map((proof) => proof.credentialId));\n\n return requirement.alternatives.some(\n (alternative) =>\n alternative.factors.every((factor) => factors.has(factor)) &&\n credentials.size >= alternative.minimumCredentials &&\n eligible.some(\n (proof) =>\n (!alternative.userVerified || proof.userVerified) &&\n (!alternative.phishingResistant || proof.phishingResistant),\n ),\n );\n});\n\nexport const snapshotPasswordMutation = Effect.fn(\"PasswordPersistence.snapshotMutation\")(\n function* (input: PasswordMutationInput) {\n const expectedRevision = snapshotPasswordRevision(input.expectedRevision);\n\n const evidence = yield* snapshotAuthenticationEvidence(input.authorization.evidence).pipe(\n Effect.mapError(unavailable),\n );\n\n const requirement = yield* snapshotPasswordRequirement(input.authorization.requirement);\n\n const credential =\n input.credential === undefined\n ? undefined\n : yield* snapshotPasswordCredential(input.credential);\n\n return Object.freeze({\n ...input,\n expectedRevision,\n replacement: Object.freeze({\n verifier: Redacted.make(Redacted.value(input.replacement.verifier)),\n normalization: input.replacement.normalization,\n }),\n invalidation: Object.freeze({ ...input.invalidation }),\n ...(credential === undefined ? {} : { credential }),\n authorization: Object.freeze({\n challenge: Object.freeze({\n ...input.authorization.challenge,\n revision: snapshotPasswordRevision(input.authorization.challenge.revision),\n }),\n evidence,\n requirement,\n }),\n });\n },\n);\n\nexport const passwordProofRedemptionMatches = (\n input: PasswordMutationInput & { readonly redemption: ProofRedemptionPlan },\n) => {\n const completion = input.redemption.input;\n const binding = completion.binding;\n\n if (\n completion.moduleId !== `${input.moduleId}/reset` ||\n completion.purpose !== \"password-reset\" ||\n binding._tag !== \"Subject\" ||\n input.credential === undefined ||\n binding.revision.subjectId !== input.expectedRevision.subjectId ||\n binding.revision.securityRevision !== input.expectedRevision.securityRevision ||\n !samePasswordIdentifier(binding.identifier, input.credential.identifier)\n )\n return false;\n\n const expected = [...input.expectedRevision.credentials].sort((left, right) =>\n left.credentialId.localeCompare(right.credentialId),\n );\n\n const actual = [...binding.revision.credentials].sort((left, right) =>\n left.credentialId.localeCompare(right.credentialId),\n );\n\n return (\n expected.length === actual.length &&\n expected.every(\n (item, index) =>\n item.credentialId === actual[index]!.credentialId &&\n item.revision === actual[index]!.revision,\n )\n );\n};\n\nexport interface PasswordWorkflowPolicy {\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n readonly subject: {\n readonly nextSecurityRevision?: (\n current: SecurityRevision,\n ) => Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;\n };\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n}\n\nexport interface PasswordWorkflowOptions {\n readonly mode: \"interactive\" | \"synchronous\";\n readonly locking: boolean;\n readonly coordinated?: boolean;\n readonly standaloneGuard: Effect.Effect<void, PasswordUnavailable>;\n readonly proof?: AnyProofPersistenceMapping;\n}\n\nexport const allocatePasswordValue = <A>(\n mode: PasswordWorkflowOptions[\"mode\"],\n asynchronous: Effect.Effect<A, PersistenceMappingError> | undefined,\n synchronous: (() => A) | undefined,\n): Effect.Effect<A, PasswordUnavailable | PersistenceMappingError> =>\n mode !== \"synchronous\" && asynchronous !== undefined\n ? asynchronous\n : synchronous === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: synchronous,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n\nexport const allocatePasswordNextSecurityRevision = (\n policy: PasswordWorkflowPolicy,\n mode: PasswordWorkflowOptions[\"mode\"],\n current: SecurityRevision,\n) =>\n allocatePasswordValue(\n mode,\n policy.subject.nextSecurityRevision?.(current) ?? policy.allocateRevision,\n policy.subject.nextSecurityRevisionSync === undefined\n ? policy.allocateRevisionSync\n : () => policy.subject.nextSecurityRevisionSync!(current),\n );\n\nexport const passwordMutationEvidenceMatches = (input: PasswordMutationInput) =>\n !input.expectedRevision.credentials.some(\n (expected) =>\n !input.authorization.evidence.revision.credentials.some(\n (actual) =>\n actual.credentialId === expected.credentialId && actual.revision === expected.revision,\n ),\n );\n\nexport const validatePasswordMutation = Effect.fnUntraced(function* (\n policy: PasswordWorkflowPolicy,\n input: PasswordMutationInput,\n action: PasswordAction,\n current: Pick<\n PasswordMutationRead,\n \"subject\" | \"identifierCurrent\" | \"credentials\" | \"snapshot\" | \"requirement\"\n >,\n now: number,\n) {\n if (\n current.subject === undefined ||\n !current.subject.active ||\n current.subject.securityRevision !== input.expectedRevision.securityRevision\n )\n return undefined;\n const { challenge, evidence } = input.authorization;\n\n if (\n challenge.moduleId !== input.moduleId ||\n challenge.action !== action ||\n challenge.commandId !== input.commandId ||\n challenge.revision.subjectId !== input.expectedRevision.subjectId ||\n challenge.revision.securityRevision !== input.expectedRevision.securityRevision ||\n (evidence.flowId as string) !== (input.commandId as string) ||\n evidence.bindingDigest !== challenge.bindingDigest ||\n evidence.revision.subjectId !== input.expectedRevision.subjectId ||\n evidence.revision.securityRevision !== input.expectedRevision.securityRevision ||\n (action === \"add-password\" &&\n (input.credential !== undefined || challenge.targetCredentialId !== undefined))\n )\n return undefined;\n if (!passwordMutationEvidenceMatches(input)) return undefined;\n if (input.credential !== undefined && !current.identifierCurrent) return undefined;\n\n const expected = new Map(\n [...input.expectedRevision.credentials, ...evidence.revision.credentials].map((item) => [\n item.credentialId,\n item,\n ]),\n );\n\n if (current.credentials.length !== expected.size) return undefined;\n for (const credential of current.credentials) {\n const wanted = expected.get(credential.credentialId);\n\n if (wanted === undefined || credential.revision !== wanted.revision || !credential.active)\n return undefined;\n expected.delete(wanted.credentialId);\n }\n if (expected.size !== 0) return undefined;\n if (input.credential !== undefined) {\n const snapshot = yield* current.snapshot;\n\n if (snapshot === undefined || !samePasswordCredential(snapshot, input.credential))\n return undefined;\n }\n const requirement = yield* current.requirement;\n\n if (\n !(yield* passwordEvidenceSatisfiedAt(evidence, input.authorization.requirement, now)) ||\n !(yield* passwordEvidenceSatisfiedAt(evidence, requirement, now))\n )\n return undefined;\n if (\n input.invalidation.existingSessions === \"immediate\" &&\n policy.sessionInvalidation !== \"same-authority-immediate\"\n )\n return undefined;\n\n return now;\n});\n\n/** Decoded subject-first snapshot used only for this action's policy decision. */\nexport interface PasswordMutationRead {\n readonly subject:\n | { readonly active: boolean; readonly securityRevision: SecurityRevision }\n | undefined;\n readonly identifierCurrent: boolean;\n readonly credentials: ReadonlyArray<{\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n readonly active: boolean;\n }>;\n readonly snapshot: Effect.Effect<\n PasswordCredentialSnapshot | undefined,\n PasswordUnavailable | PersistenceMappingError\n >;\n readonly requirement: Effect.Effect<\n AuthenticationRequirement,\n PasswordUnavailable | PersistenceMappingError\n >;\n}\n"],"mappings":"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"}
@@ -4,7 +4,9 @@ import { requireStandalone } from "./standalone.mjs";
4
4
  import { SqlBatchCommit } from "./sql-commit.mjs";
5
5
  import { makeNativeProofServices } from "./proof-native.mjs";
6
6
  import { makeNativeEmailAddressServices } from "./email-native.mjs";
7
+ import { validateStorageBatch, withStorageValidation } from "./storage-validation.mjs";
7
8
  import { storageTables, tableDefinition } from "./storage-tables.mjs";
9
+ import { makeManagedOAuth } from "./oauth-managed.mjs";
8
10
  import { makeManagedPasskeys } from "./passkey-managed.mjs";
9
11
  import { makeNativePasswordServices } from "./password-native.mjs";
10
12
  import { makeComposedPhoneTargets } from "./phone-composed.mjs";
@@ -15,14 +17,14 @@ import { makeNativePendingAuthenticationServices } from "./session-native-login.
15
17
  import { makeNativeStatefulSessionServices } from "./session-native-stateful.mjs";
16
18
  import { makeNativeSessionStepUpServices } from "./session-native-step-up.mjs";
17
19
  import { makeMappings } from "./storage-mapping.mjs";
18
- import { validateStorageBatch, withStorageValidation } from "./storage-validation.mjs";
19
20
  import { Context, Effect, Layer, Schema } from "effect";
20
21
  import { SqlClient } from "effect/sql";
21
22
  import { EmailAddressPersistence, EmailUnavailable } from "@yielded/auth/Email";
22
23
  import { hasCommitScope } from "@yielded/auth/Hooks";
24
+ import { OAuthConnectedPersistence, OAuthConnectedRevocations, OAuthSignInPersistence, OAuthUnavailable } from "@yielded/auth/OAuth";
23
25
  import { PasskeyCredentials, PasskeyManagementPersistence, PasskeyPersistence, PasskeyUnavailable } from "@yielded/auth/Passkey";
24
26
  import { PasswordPersistence, PasswordUnavailable } from "@yielded/auth/Password";
25
- import { hooksLayer } from "@yielded/auth/Persistence";
27
+ import { hooksLayer, reportAuthDiagnostic } from "@yielded/auth/Persistence";
26
28
  import { PhoneOtpUnavailable, PhoneSignInTargets } from "@yielded/auth/PhoneOtp";
27
29
  import { ProofPersistence, ProofUnavailable } from "@yielded/auth/Proofs";
28
30
  import { AuthenticationAuthority, SessionUnavailable } from "@yielded/auth/Sessions";
@@ -45,27 +47,37 @@ const timestampKeys = /* @__PURE__ */ new Set([
45
47
  "admittedAt",
46
48
  "deadline",
47
49
  "occurredAt",
48
- "dedupUntil"
50
+ "dedupUntil",
51
+ "binderExpiresAt",
52
+ "refreshClaimedAt",
53
+ "refreshClaimExpiresAt",
54
+ "claimedAt",
55
+ "claimExpiresAt"
49
56
  ]);
50
57
  const createPersistence = (backend) => {
51
58
  const make = (auth) => {
52
- const features = Object.values(auth.strategies).map((strategy) => strategy.persistence);
53
- const phone = features.some((feature) => feature?.kind === "phone");
54
- const password = features.some((feature) => feature?.kind === "password");
55
- const passkeys = features.filter((feature) => feature?.kind === "passkey");
56
- const management = features.some((feature) => feature?.kind === "password" && feature.management);
57
- const email = features.some((feature) => feature?.kind === "email" && feature.addresses);
59
+ const features = Object.values(auth.strategies).flatMap((strategy) => strategy.persistence === void 0 ? [] : [strategy.persistence]);
60
+ const phone = features.some((feature) => feature.kind === "phone");
61
+ const password = features.some((feature) => feature.kind === "password");
62
+ const passkeys = features.filter((feature) => feature.kind === "passkey");
63
+ const oauth = features.filter((feature) => feature?.kind === "oauth");
64
+ const oauthSignIn = oauth.some((feature) => feature.signIn);
65
+ const oauthConnected = oauth.some((feature) => feature.connected !== void 0);
66
+ const stateful = auth.sessionMode === "stateful";
67
+ const stateless = auth.sessionMode === "stateless" && features.length > 0 && features.every((feature) => feature?.kind === "oauth");
68
+ const management = features.some((feature) => feature.kind === "password" && feature.management);
69
+ const email = features.some((feature) => feature.kind === "email" && feature.addresses);
58
70
  const proofs = phone || management || email;
59
- const roles = [
60
- "identifiers",
61
- "credentials",
62
- "sessions",
63
- "pending"
64
- ];
71
+ const roles = ["identifiers", "credentials"];
72
+ if (stateful) roles.push("sessions");
73
+ roles.push("pending");
65
74
  if (password) roles.push("passwords");
66
75
  if (email) roles.push("emailCredentials");
67
76
  if (passkeys.length > 0) roles.push("passkeyCredentials", "passkeyFlows");
68
77
  if (proofs) roles.push("proofs");
78
+ if (oauth.length > 0) roles.push("oauthIdentities", "oauthCredentials");
79
+ if (oauthSignIn) roles.push("oauthSignInFlows");
80
+ if (oauthConnected) roles.push("oauthConnectedFlows", "oauthConnectedGrants", "oauthConnectedRevocations");
69
81
  const ConfigKey = Context.Service()(`@yielded/auth-persistence/${auth.namespace}/Config`);
70
82
  const Config = Object.assign(ConfigKey, { layer: (value) => Layer.succeed(ConfigKey, value) });
71
83
  const ProvisioningKey = Context.Service()(`@yielded/auth-persistence/${auth.namespace}/Provisioning`);
@@ -130,8 +142,7 @@ const createPersistence = (backend) => {
130
142
  orElse: () => void 0
131
143
  });
132
144
  if (dialect === void 0) return yield* configError("Use an explicit adapter for this SQL dialect");
133
- if (auth.sessionMode !== "stateful") return yield* configError("The composed layer currently requires stateful sessions");
134
- if (features.some((feature) => feature === void 0 || "lifecycle" in feature && feature.lifecycle || feature.kind === "email" && !feature.addresses)) return yield* configError("Use explicit services for strategies without composed persistence support");
145
+ if (features.some((feature) => "lifecycle" in feature && feature.lifecycle || feature.kind === "email" && !feature.addresses)) return yield* configError("Use explicit services for strategies without composed persistence support");
135
146
  if (storage.namespace !== auth.namespace) return yield* configError("Persistence configuration belongs to a different Auth definition");
136
147
  const validations = [];
137
148
  for (const role of roles) {
@@ -152,14 +163,19 @@ const createPersistence = (backend) => {
152
163
  yield* validateStorageBatch(dialect, validations);
153
164
  const nativeTables = backend.nativeTables(database);
154
165
  const mappings = yield* makeMappings(storage, nativeTables);
155
- const sessionMapping = mappings.sessions(auth.claims, auth.sessions.moduleId);
166
+ const sessionMapping = stateful ? mappings.sessions(auth.claims, auth.sessions.moduleId) : void 0;
156
167
  const pendingMapping = mappings.pending(auth.claims, auth.sessions.moduleId);
157
- const sessionServices = yield* makeNativeStatefulSessionServices(nativeTables, sessionMapping);
158
- const { authenticationAuthority } = yield* makeNativeAuthenticationAuthorityServices(nativeTables, sessionMapping);
168
+ const { authenticationAuthority } = yield* makeNativeAuthenticationAuthorityServices(nativeTables, sessionMapping ?? {
169
+ ...pendingMapping,
170
+ pending: {
171
+ pending: pendingMapping.pending,
172
+ login: pendingMapping.login
173
+ }
174
+ });
159
175
  const { pendingAuthentication } = yield* makeNativePendingAuthenticationServices(nativeTables, pendingMapping);
160
176
  const { sessionStepUpPersistence } = yield* makeNativeSessionStepUpServices(nativeTables, {
161
177
  ...pendingMapping,
162
- source: {
178
+ source: sessionMapping === void 0 ? { kind: "StatelessSigned" } : {
163
179
  kind: "Stateful",
164
180
  session: sessionMapping.session,
165
181
  sessionId: sessionMapping.sessionId,
@@ -167,7 +183,11 @@ const createPersistence = (backend) => {
167
183
  }
168
184
  });
169
185
  const { sessionCleanup } = yield* makeNativeSessionCleanupServices(nativeTables, pendingMapping);
170
- let context = Context.make(AuthenticationAuthority, authenticationAuthority).pipe(Context.add(auth.sessions.StatefulSessionPersistence, sessionServices.statefulSessionPersistence), Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository), Context.add(auth.sessions.PendingAuthentication, pendingAuthentication), Context.add(auth.sessions.SessionStepUpPersistence, sessionStepUpPersistence), Context.add(auth.sessions.SessionCleanup, sessionCleanup));
186
+ let context = Context.make(AuthenticationAuthority, authenticationAuthority).pipe(Context.add(auth.sessions.PendingAuthentication, pendingAuthentication), Context.add(auth.sessions.SessionStepUpPersistence, sessionStepUpPersistence), Context.add(auth.sessions.SessionCleanup, sessionCleanup));
187
+ if (sessionMapping !== void 0) {
188
+ const sessionServices = yield* makeNativeStatefulSessionServices(nativeTables, sessionMapping);
189
+ context = context.pipe(Context.add(auth.sessions.StatefulSessionPersistence, sessionServices.statefulSessionPersistence), Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository));
190
+ }
171
191
  const proofMapping = proofs ? mappings.proofs() : void 0;
172
192
  if (proofMapping !== void 0) {
173
193
  const services = yield* makeNativeProofServices(backend.nativeTables(database), proofMapping);
@@ -186,23 +206,28 @@ const createPersistence = (backend) => {
186
206
  context = Context.add(context, key, registration);
187
207
  }
188
208
  if (email) context = Context.add(context, EmailAddressPersistence, (yield* makeNativeEmailAddressServices(backend.nativeTables(database), mappings.emails(), proofMapping)).emailAddressPersistence);
189
- if (phone) context = Context.add(context, PhoneSignInTargets, yield* makeComposedPhoneTargets(backend.nativeTables(database), storage, mappings.proofs(), features.flatMap((feature) => feature?.kind === "phone" ? [feature.moduleId] : [])));
209
+ if (phone) context = Context.add(context, PhoneSignInTargets, yield* makeComposedPhoneTargets(backend.nativeTables(database), storage, mappings.proofs(), features.flatMap((feature) => feature.kind === "phone" ? [feature.moduleId] : [])));
190
210
  if (passkeys.length > 0) {
191
211
  const services = makeManagedPasskeys({
192
212
  storage,
193
213
  namespace: auth.namespace,
194
214
  dialect,
195
215
  features: passkeys,
196
- passwordModules: features.flatMap((feature) => feature?.kind === "password" ? [feature.moduleId] : [])
216
+ passwordModules: features.flatMap((feature) => feature.kind === "password" ? [feature.moduleId] : [])
197
217
  }, backend.nativeTables(database));
198
218
  context = Context.merge(context, yield* services);
199
219
  }
220
+ if (oauth.length > 0) context = Context.merge(context, yield* makeManagedOAuth(storage, nativeTables, oauth));
200
221
  return context;
201
- }).pipe(Effect.provideService(SqlBatchCommit, backend.batch?.(database)))).pipe(withStorageValidation, Effect.mapError((error) => Schema.is(PersistenceConfigurationError)(error) ? error : configError("Cannot acquire SQL persistence")))).pipe(Layer.provide(hooksLayer));
222
+ }).pipe(Effect.provideService(SqlBatchCommit, backend.batch?.(database)))).pipe(withStorageValidation)).pipe(Layer.provide(hooksLayer));
202
223
  return {
203
224
  Config,
204
225
  Provisioning: ProvisioningKey,
205
226
  layer: Layer.effectContext(Effect.gen(function* () {
227
+ if (!stateful && !stateless) {
228
+ if (auth.sessionMode === "stateless") return yield* configError("Composed stateless sessions support only OAuth strategies; use explicit persistence for other strategies");
229
+ return yield* configError("Composed persistence supports stateful or OAuth-only stateless sessions; state-assisted validity and other session modes require explicit persistence");
230
+ }
206
231
  const scope = yield* Effect.scope;
207
232
  const captured = yield* Effect.context();
208
233
  const client = Context.get(captured, SqlClient.SqlClient);
@@ -212,16 +237,13 @@ const createPersistence = (backend) => {
212
237
  if (yield* hasCommitScope) return yield* Effect.fail(unavailable());
213
238
  yield* requireStandalone(unavailable, client.transactionService);
214
239
  }
215
- const acquired = yield* initialize.pipe(Effect.mapError(unavailable));
240
+ const acquired = yield* initialize.pipe(Effect.tapError((error) => reportAuthDiagnostic("persistence-initialization", Schema.is(PersistenceConfigurationError)(error) ? "configuration" : Schema.is(PersistenceMappingError)(error) ? "mapping" : "unavailable")), Effect.mapError(unavailable));
216
241
  const value = Context.getOrUndefined(acquired, key);
217
242
  return value === void 0 ? yield* Effect.fail(unavailable()) : value;
218
243
  });
219
244
  const sessionUnavailable = () => SessionUnavailable.make({});
220
245
  const authority = service(AuthenticationAuthority, sessionUnavailable, false);
221
246
  const authorityMutation = service(AuthenticationAuthority, sessionUnavailable);
222
- const sessions = service(auth.sessions.StatefulSessionPersistence, sessionUnavailable, false);
223
- const sessionMutations = service(auth.sessions.StatefulSessionPersistence, sessionUnavailable);
224
- const repository = service(auth.sessions.SessionRepository, sessionUnavailable, false);
225
247
  const pendingRead = service(auth.sessions.PendingAuthentication, sessionUnavailable, false);
226
248
  const pendingMutation = service(auth.sessions.PendingAuthentication, sessionUnavailable);
227
249
  const stepUpRead = service(auth.sessions.SessionStepUpPersistence, sessionUnavailable, false);
@@ -231,14 +253,7 @@ const createPersistence = (backend) => {
231
253
  capture: (subjectId, credentialIds) => Effect.flatMap(authority, (s) => s.capture(subjectId, credentialIds)),
232
254
  requirements: (evidence) => Effect.flatMap(authority, (s) => s.requirements(evidence)),
233
255
  approve: (input, prepare) => Effect.flatMap(authorityMutation, (s) => s.approve(input, prepare))
234
- }).pipe(Context.add(auth.sessions.StatefulSessionPersistence, {
235
- establish: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.establish(input, prepare)),
236
- verify: (input) => Effect.flatMap(sessions, (s) => s.verify(input)),
237
- rotate: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.rotate(input, prepare)),
238
- revokeDigest: (digest, prepare) => Effect.flatMap(sessionMutations, (s) => s.revokeDigest(digest, prepare)),
239
- revoke: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.revoke(input, prepare)),
240
- revokeAll: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.revokeAll(input, prepare))
241
- }), Context.add(auth.sessions.SessionRepository, { list: (input) => Effect.flatMap(repository, (s) => s.list(input)) }), Context.add(auth.sessions.PendingAuthentication, {
256
+ }).pipe(Context.add(auth.sessions.PendingAuthentication, {
242
257
  create: (input, now, prepare) => Effect.flatMap(pendingMutation, (s) => s.create(input, now, prepare)),
243
258
  read: (input) => Effect.flatMap(pendingRead, (s) => s.read(input)),
244
259
  reject: (input, prepare) => Effect.flatMap(pendingMutation, (s) => s.reject(input, prepare))
@@ -248,6 +263,19 @@ const createPersistence = (backend) => {
248
263
  reject: (input, prepare) => Effect.flatMap(stepUpMutation, (s) => s.reject(input, prepare)),
249
264
  complete: (plan, prepare) => Effect.flatMap(stepUpMutation, (s) => s.complete(plan, prepare))
250
265
  }), Context.add(auth.sessions.SessionCleanup, { cleanup: (input) => Effect.flatMap(cleanup, (s) => s.cleanup(input)) }));
266
+ if (stateful) {
267
+ const sessions = service(auth.sessions.StatefulSessionPersistence, sessionUnavailable, false);
268
+ const sessionMutations = service(auth.sessions.StatefulSessionPersistence, sessionUnavailable);
269
+ const repository = service(auth.sessions.SessionRepository, sessionUnavailable, false);
270
+ context = context.pipe(Context.add(auth.sessions.StatefulSessionPersistence, {
271
+ establish: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.establish(input, prepare)),
272
+ verify: (input) => Effect.flatMap(sessions, (s) => s.verify(input)),
273
+ rotate: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.rotate(input, prepare)),
274
+ revokeDigest: (digest, prepare) => Effect.flatMap(sessionMutations, (s) => s.revokeDigest(digest, prepare)),
275
+ revoke: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.revoke(input, prepare)),
276
+ revokeAll: (input, prepare) => Effect.flatMap(sessionMutations, (s) => s.revokeAll(input, prepare))
277
+ }), Context.add(auth.sessions.SessionRepository, { list: (input) => Effect.flatMap(repository, (s) => s.list(input)) }));
278
+ }
251
279
  if (proofs) {
252
280
  const persistence = service(ProofPersistence, () => ProofUnavailable.make({}));
253
281
  context = Context.add(context, ProofPersistence, {
@@ -313,6 +341,37 @@ const createPersistence = (backend) => {
313
341
  }));
314
342
  }
315
343
  }
344
+ const oauthUnavailable = () => OAuthUnavailable.make({});
345
+ function oauthService(key, moduleId, capability) {
346
+ return oauth.some((feature) => feature.moduleId === moduleId && (capability === "signIn" ? feature.signIn : feature.connected !== void 0)) ? service(key, oauthUnavailable) : Effect.fail(oauthUnavailable());
347
+ }
348
+ if (oauthSignIn) {
349
+ const persistence = (moduleId) => oauthService(OAuthSignInPersistence, moduleId, "signIn");
350
+ context = Context.add(context, OAuthSignInPersistence, {
351
+ issue: (input, prepare) => Effect.flatMap(persistence(input.context.moduleId), (s) => s.issue(input, prepare)),
352
+ consume: (input, prepare) => Effect.flatMap(persistence(input.moduleId), (s) => s.consume(input, prepare)),
353
+ resolve: (input) => Effect.flatMap(persistence(input.moduleId), (s) => s.resolve(input)),
354
+ cleanup: (input, prepare) => Effect.flatMap(persistence(input.moduleId), (s) => s.cleanup(input, prepare))
355
+ });
356
+ }
357
+ if (oauthConnected) {
358
+ const persistence = (moduleId) => oauthService(OAuthConnectedPersistence, moduleId, "connected");
359
+ const revocations = (moduleId) => oauthService(OAuthConnectedRevocations, moduleId, "connected");
360
+ context = context.pipe(Context.add(OAuthConnectedPersistence, {
361
+ read: (input) => Effect.flatMap(persistence(input.moduleId), (s) => s.read(input)),
362
+ issue: (input, prepare) => Effect.flatMap(persistence(input.context.moduleId), (s) => s.issue(input, prepare)),
363
+ consume: (input, prepare) => Effect.flatMap(persistence(input.moduleId), (s) => s.consume(input, prepare)),
364
+ settle: (input, prepare) => Effect.flatMap(persistence(input.grant.context.moduleId), (s) => s.settle(input, prepare)),
365
+ list: (input) => Effect.flatMap(persistence(input.authorization.moduleId), (s) => s.list(input)),
366
+ disconnect: (input, prepare) => Effect.flatMap(persistence(input.key.moduleId), (s) => s.disconnect(input, prepare)),
367
+ claimRefresh: (input, prepare) => Effect.flatMap(persistence(input.grant.context.moduleId), (s) => s.claimRefresh(input, prepare)),
368
+ settleRefresh: (input, prepare) => Effect.flatMap(persistence(input.claim.grant.context.moduleId), (s) => s.settleRefresh(input, prepare)),
369
+ cleanup: (input, prepare) => Effect.flatMap(persistence(input.moduleId), (s) => s.cleanup(input, prepare))
370
+ }), Context.add(OAuthConnectedRevocations, {
371
+ claim: (input, prepare) => Effect.flatMap(revocations(input.moduleId), (s) => s.claim(input, prepare)),
372
+ settle: (input, prepare) => Effect.flatMap(revocations(input.claim.job.grant.context.moduleId), (s) => s.settle(input, prepare))
373
+ }));
374
+ }
316
375
  return context;
317
376
  })),
318
377
  managed: (options) => layout(options, true),
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.mjs","names":[],"sources":["../../src/internal/persistence.ts"],"sourcesContent":["import { EmailAddressPersistence, EmailUnavailable } from \"@yielded/auth/Email\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { hasCommitScope } from \"@yielded/auth/Hooks\";\nimport {\n PasskeyCredentials,\n PasskeyManagementPersistence,\n PasskeyPersistence,\n PasskeyUnavailable,\n} from \"@yielded/auth/Passkey\";\nimport { PasswordPersistence, PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { hooksLayer } from \"@yielded/auth/Persistence\";\nimport { PhoneSignInTargets, PhoneOtpUnavailable } from \"@yielded/auth/PhoneOtp\";\nimport { ProofPersistence, ProofUnavailable } from \"@yielded/auth/Proofs\";\nimport { AuthenticationAuthority, SessionUnavailable } from \"@yielded/auth/Sessions\";\nimport { Context, type Crypto, Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport {\n PersistenceConfigurationError,\n type ClaimsCodec,\n type ConfigId,\n type Definition,\n type PersistenceApi,\n type Ports,\n type Roles,\n type Provisioning,\n type ProvisioningRequirement,\n type StorageLayout,\n type SubjectMapping,\n type SubjectOptions,\n type PasskeyFeature,\n type PasskeyRequirement,\n} from \"./configuration\";\nimport { makeNativeEmailAddressServices } from \"./email-native\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { makeManagedPasskeys } from \"./passkey-managed\";\nimport { makeNativePasswordServices } from \"./password-native\";\nimport { makeComposedPhoneTargets } from \"./phone-composed\";\nimport { makeNativeProofServices } from \"./proof-native\";\nimport { makeRegistrationAuthority } from \"./registration\";\nimport type { PasswordRegistrationAuthority } from \"./registration-contract\";\nimport { makeNativeAuthenticationAuthorityServices } from \"./session-native-authority\";\nimport { makeNativeSessionCleanupServices } from \"./session-native-cleanup\";\nimport { makeNativePendingAuthenticationServices } from \"./session-native-login\";\nimport { makeNativeStatefulSessionServices } from \"./session-native-stateful\";\nimport { makeNativeSessionStepUpServices } from \"./session-native-step-up\";\nimport { SqlBatchCommit } from \"./sql-commit\";\nimport { requireStandalone } from \"./standalone\";\nimport { makeMappings } from \"./storage-mapping\";\nimport {\n tableDefinition,\n storageTables,\n type StorageRole,\n type StorageTable,\n} from \"./storage-tables\";\nimport {\n validateStorageBatch,\n withStorageValidation,\n type StorageValidation,\n} from \"./storage-validation\";\n\nexport interface Backend<T extends object, R, Database extends object = object> {\n readonly makeTable: (definition: StorageTable) => T;\n readonly describe: (table: T) => StorageTable;\n readonly acquire: Effect.Effect<Database, PersistenceConfigurationError, R | SqlClient.SqlClient>;\n readonly nativeTables: (database: Database) => NativeSqlTables;\n /** Fixed atomic batches replace interactive transactions on backends such as D1. */\n readonly batch?: (database: Database) => NonNullable<SqlBatchCommit[\"Service\"]>;\n}\n\nconst configError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappingError = (cause: unknown) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause });\n\nconst timestampKeys = new Set([\n \"verifiedAt\",\n \"createdAt\",\n \"lastIssueAt\",\n \"issuedAt\",\n \"expiresAt\",\n \"absoluteExpiresAt\",\n \"retentionUntil\",\n \"claimDeadline\",\n \"retryAt\",\n \"admittedAt\",\n \"deadline\",\n \"occurredAt\",\n \"dedupUntil\",\n]);\n\nexport const createPersistence = <T extends object, R, Database extends object = object>(\n backend: Backend<T, R, Database>,\n): PersistenceApi<T, R> => {\n const make = <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(\n auth: A & Definition<C, Id>,\n ) => {\n const features = Object.values(auth.strategies).map((strategy) => strategy.persistence);\n const phone = features.some((feature) => feature?.kind === \"phone\");\n const password = features.some((feature) => feature?.kind === \"password\");\n\n const passkeys = features.filter(\n (feature): feature is PasskeyFeature => feature?.kind === \"passkey\",\n );\n\n const management = features.some(\n (feature) => feature?.kind === \"password\" && feature.management,\n );\n\n const email = features.some((feature) => feature?.kind === \"email\" && feature.addresses);\n const proofs = phone || management || email;\n\n const roles: StorageRole[] = [\"identifiers\", \"credentials\", \"sessions\", \"pending\"];\n\n if (password) roles.push(\"passwords\");\n if (email) roles.push(\"emailCredentials\");\n if (passkeys.length > 0) roles.push(\"passkeyCredentials\", \"passkeyFlows\");\n if (proofs) roles.push(\"proofs\");\n\n const ConfigKey = Context.Service<\n ConfigId<A[\"namespace\"]>,\n StorageLayout<T, Roles<C, Id, A>>\n >()(`@yielded/auth-persistence/${auth.namespace}/Config`);\n\n const Config = Object.assign(ConfigKey, {\n layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.succeed(ConfigKey, value),\n });\n\n const ProvisioningKey = Context.Service<ProvisioningRequirement<A>, Provisioning<A>>()(\n `@yielded/auth-persistence/${auth.namespace}/Provisioning`,\n );\n\n const layout = <N, Instant>(\n options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<StorageRole, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n },\n managed: boolean,\n ): StorageLayout<T, Roles<C, Id, A>> => {\n const subject = options.subjects;\n\n if (passkeys.length > 0 && options.timestamps !== undefined)\n throw configError(\n \"Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation\",\n );\n const description = backend.describe(subject.table);\n const idColumn = description.columns[subject.id];\n\n for (const key of [subject.id, subject.status, subject.securityRevision]) {\n if (description.columns[key] === undefined)\n throw configError(`Missing subject column ${key}`);\n }\n if (subject.activeValue === undefined)\n throw configError(\"An explicit active subject value is required\");\n\n if (idColumn === undefined || idColumn.type === \"boolean\")\n throw configError(\"Subject ID must map a text or integer column\");\n\n const prefix = options.prefix;\n\n if (managed && (prefix === undefined || !/^[A-Za-z_][A-Za-z0-9_]{0,100}$/.test(prefix)))\n throw configError(\"Managed persistence requires an explicit SQL table prefix\");\n\n const schema: Partial<Record<StorageRole, T>> = { ...options.tables };\n\n for (const role of roles) {\n if (schema[role] === undefined && managed) {\n const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);\n\n const adjusted =\n options.timestamps === undefined\n ? definition\n : {\n ...definition,\n columns: Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => [\n key,\n timestampKeys.has(key)\n ? { ...column, type: options.timestamps?.type ?? column.type }\n : column,\n ]),\n ),\n };\n\n schema[role] = backend.makeTable(adjusted);\n }\n }\n for (const role of roles) {\n if (schema[role] === undefined) throw configError(`Missing ${role} table`);\n }\n const instantCodec = options.timestamps?.codec;\n\n const decodeInstant =\n instantCodec === undefined\n ? Schema.decodeUnknownEffect(Schema.Int)\n : Schema.decodeUnknownEffect(instantCodec);\n\n const decodeInstantSync =\n instantCodec === undefined\n ? Schema.decodeUnknownSync(Schema.Int)\n : Schema.decodeUnknownSync(instantCodec);\n\n const subjects: SubjectMapping = {\n table: subject.table,\n id: subject.id,\n status: subject.status,\n securityRevision: subject.securityRevision,\n activeValue: subject.activeValue,\n requirements: subject.requirements,\n actionRequirements: subject.actionRequirements ?? subject.requirements,\n toSubject: (id) =>\n Schema.decodeUnknownEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toNative: (id) =>\n Schema.encodeEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toSubjectSync: Schema.decodeUnknownSync(subject.idCodec),\n toNativeSync: Schema.encodeSync(subject.idCodec),\n };\n\n return Object.freeze({\n namespace: auth.namespace,\n schema: Object.freeze(schema) as Readonly<Record<Roles<C, Id, A>, T>>,\n tables: schema,\n subjects,\n encodeInstant:\n instantCodec === undefined ? (millis: number) => millis : Schema.encodeSync(instantCodec),\n decodeInstant: (value: unknown) => decodeInstant(value).pipe(Effect.mapError(mappingError)),\n decodeInstantSync,\n });\n };\n\n const services = Layer.effectContext(\n Effect.flatMap(backend.acquire, (database) =>\n Effect.gen(function* () {\n const storage = yield* ConfigKey;\n const client = yield* SqlClient.SqlClient;\n\n const dialect = client.onDialectOrElse({\n pg: () => \"pg\" as const,\n sqlite: () => \"sqlite\" as const,\n orElse: () => undefined,\n });\n\n if (dialect === undefined)\n return yield* configError(\"Use an explicit adapter for this SQL dialect\");\n if (auth.sessionMode !== \"stateful\")\n return yield* configError(\"The composed layer currently requires stateful sessions\");\n if (\n features.some(\n (feature) =>\n feature === undefined ||\n (\"lifecycle\" in feature && feature.lifecycle) ||\n (feature.kind === \"email\" && !feature.addresses),\n )\n )\n return yield* configError(\n \"Use explicit services for strategies without composed persistence support\",\n );\n if (storage.namespace !== auth.namespace)\n return yield* configError(\n \"Persistence configuration belongs to a different Auth definition\",\n );\n const validations: StorageValidation[] = [];\n\n for (const role of roles) {\n const table = (storage.schema as Partial<Record<StorageRole, T>>)[role];\n\n if (table === undefined) return yield* configError(`Missing ${role} table`);\n const description = backend.describe(table);\n const columns = description.columns;\n\n for (const name of Object.keys(storageTables[role].columns)) {\n if (columns[name] === undefined)\n return yield* configError(`Missing ${role}.${name} column`);\n }\n validations.push({ table: description, required: storageTables[role].unique });\n }\n validations.push({\n table: backend.describe(storage.subjects.table as T),\n required: [[storage.subjects.id]],\n });\n yield* validateStorageBatch(dialect, validations);\n const nativeTables = backend.nativeTables(database);\n const mappings = yield* makeMappings(storage, nativeTables);\n const sessionMapping = mappings.sessions(auth.claims, auth.sessions.moduleId);\n const pendingMapping = mappings.pending(auth.claims, auth.sessions.moduleId);\n\n const sessionServices = yield* makeNativeStatefulSessionServices(\n nativeTables,\n sessionMapping,\n );\n\n const { authenticationAuthority } = yield* makeNativeAuthenticationAuthorityServices(\n nativeTables,\n sessionMapping,\n );\n\n const { pendingAuthentication } = yield* makeNativePendingAuthenticationServices(\n nativeTables,\n pendingMapping,\n );\n\n const { sessionStepUpPersistence } = yield* makeNativeSessionStepUpServices(\n nativeTables,\n {\n ...pendingMapping,\n source: {\n kind: \"Stateful\",\n session: sessionMapping.session,\n sessionId: sessionMapping.sessionId,\n constraints: { sessionDigest: \"unique(session.digest)\" },\n },\n },\n );\n\n const { sessionCleanup } = yield* makeNativeSessionCleanupServices(\n nativeTables,\n pendingMapping,\n );\n\n let context: Context.Context<never> = Context.make(\n AuthenticationAuthority,\n authenticationAuthority,\n ).pipe(\n Context.add(\n auth.sessions.StatefulSessionPersistence,\n sessionServices.statefulSessionPersistence,\n ),\n Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository),\n Context.add(auth.sessions.PendingAuthentication, pendingAuthentication),\n Context.add(auth.sessions.SessionStepUpPersistence, sessionStepUpPersistence),\n Context.add(auth.sessions.SessionCleanup, sessionCleanup),\n );\n\n const proofMapping = proofs ? mappings.proofs() : undefined;\n\n if (proofMapping !== undefined) {\n const services = yield* makeNativeProofServices(\n backend.nativeTables(database),\n proofMapping,\n );\n\n context = Context.add(context, ProofPersistence, services.proofPersistence);\n }\n\n if (password) {\n const mapping = mappings.passwords();\n\n const services = yield* makeNativePasswordServices(\n backend.nativeTables(database),\n mapping,\n proofMapping,\n );\n\n context = Context.add(context, PasswordPersistence, services.passwordPersistence);\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n const registration = yield* makeRegistrationAuthority(\n backend.nativeTables(database),\n mappings.passwords(),\n ProvisioningKey,\n name,\n );\n\n context = Context.add(context, key, registration);\n }\n if (email)\n context = Context.add(\n context,\n EmailAddressPersistence,\n (yield* makeNativeEmailAddressServices(\n backend.nativeTables(database),\n mappings.emails(),\n proofMapping,\n )).emailAddressPersistence,\n );\n\n if (phone)\n context = Context.add(\n context,\n PhoneSignInTargets,\n yield* makeComposedPhoneTargets(\n backend.nativeTables(database),\n storage,\n mappings.proofs(),\n features.flatMap((feature) =>\n feature?.kind === \"phone\" ? [feature.moduleId] : [],\n ),\n ),\n );\n\n if (passkeys.length > 0) {\n // Auth capability metadata determines whether PasskeyConfig is required.\n const services = makeManagedPasskeys(\n {\n storage,\n namespace: auth.namespace,\n dialect,\n features: passkeys,\n passwordModules: features.flatMap((feature) =>\n feature?.kind === \"password\" ? [feature.moduleId] : [],\n ),\n },\n backend.nativeTables(database),\n ) as Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n | PasskeyRequirement<A>\n | Crypto.Crypto\n | LifecycleHooks\n | SqlClient.SqlClient\n | SqlBatchCommit\n >;\n\n context = Context.merge(context, yield* services);\n }\n\n // The checked capability metadata above determines exactly these service keys.\n return context as Context.Context<Ports<C, Id, A>>;\n }).pipe(Effect.provideService(SqlBatchCommit, backend.batch?.(database))),\n ).pipe(\n withStorageValidation,\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configError(\"Cannot acquire SQL persistence\"),\n ),\n ),\n ).pipe(Layer.provide(hooksLayer));\n\n const layer = Layer.effectContext(\n Effect.gen(function* () {\n const scope = yield* Effect.scope;\n const captured = yield* Effect.context<Layer.Services<typeof services>>();\n const client = Context.get(captured, SqlClient.SqlClient);\n\n // Construction uses the layer's exact environment and lifetime, never the\n // first operation's SQL transaction, service overrides, or request scope.\n // Cache the full exit: concurrent callers share failures/interruption too,\n // and cannot retry partially completed setup within this acquired layer.\n const initialize = yield* Effect.cached(\n Layer.buildWithScope(services, scope).pipe(Effect.setContext(captured)),\n );\n\n const service = Effect.fnUntraced(function* <I, S, Failure>(\n key: Context.Key<I, S>,\n unavailable: () => Failure,\n standalone = true,\n ): Effect.fn.Return<S, Failure> {\n // Reject unsupported ownership before setup can perform any writes.\n // Session/authority reads retain their existing ambient-read semantics.\n if (standalone) {\n if (yield* hasCommitScope) return yield* Effect.fail(unavailable());\n yield* requireStandalone(unavailable, client.transactionService);\n }\n const acquired = yield* initialize.pipe(Effect.mapError(unavailable));\n const value = Context.getOrUndefined(acquired, key);\n\n return value === undefined ? yield* Effect.fail(unavailable()) : value;\n });\n\n const sessionUnavailable = () => SessionUnavailable.make({});\n const authority = service(AuthenticationAuthority, sessionUnavailable, false);\n const authorityMutation = service(AuthenticationAuthority, sessionUnavailable);\n\n const sessions = service(\n auth.sessions.StatefulSessionPersistence,\n sessionUnavailable,\n false,\n );\n\n const sessionMutations = service(\n auth.sessions.StatefulSessionPersistence,\n sessionUnavailable,\n );\n\n const repository = service(auth.sessions.SessionRepository, sessionUnavailable, false);\n const pendingRead = service(auth.sessions.PendingAuthentication, sessionUnavailable, false);\n const pendingMutation = service(auth.sessions.PendingAuthentication, sessionUnavailable);\n\n const stepUpRead = service(\n auth.sessions.SessionStepUpPersistence,\n sessionUnavailable,\n false,\n );\n\n const stepUpMutation = service(auth.sessions.SessionStepUpPersistence, sessionUnavailable);\n const cleanup = service(auth.sessions.SessionCleanup, sessionUnavailable);\n\n let context: Context.Context<never> = Context.make(AuthenticationAuthority, {\n capture: (subjectId, credentialIds) =>\n Effect.flatMap(authority, (s) => s.capture(subjectId, credentialIds)),\n requirements: (evidence) => Effect.flatMap(authority, (s) => s.requirements(evidence)),\n approve: (input, prepare) =>\n Effect.flatMap(authorityMutation, (s) => s.approve(input, prepare)),\n }).pipe(\n Context.add(auth.sessions.StatefulSessionPersistence, {\n establish: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.establish(input, prepare)),\n verify: (input) => Effect.flatMap(sessions, (s) => s.verify(input)),\n rotate: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.rotate(input, prepare)),\n revokeDigest: (digest, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.revokeDigest(digest, prepare)),\n revoke: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.revoke(input, prepare)),\n revokeAll: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.revokeAll(input, prepare)),\n }),\n Context.add(auth.sessions.SessionRepository, {\n list: (input) => Effect.flatMap(repository, (s) => s.list(input)),\n }),\n Context.add(auth.sessions.PendingAuthentication, {\n create: (input, now, prepare) =>\n Effect.flatMap(pendingMutation, (s) => s.create(input, now, prepare)),\n read: (input) => Effect.flatMap(pendingRead, (s) => s.read(input)),\n reject: (input, prepare) =>\n Effect.flatMap(pendingMutation, (s) => s.reject(input, prepare)),\n }),\n Context.add(auth.sessions.SessionStepUpPersistence, {\n create: (input, now, prepare) =>\n Effect.flatMap(stepUpMutation, (s) => s.create(input, now, prepare)),\n read: (input) => Effect.flatMap(stepUpRead, (s) => s.read(input)),\n reject: (input, prepare) =>\n Effect.flatMap(stepUpMutation, (s) => s.reject(input, prepare)),\n complete: (plan, prepare) =>\n Effect.flatMap(stepUpMutation, (s) => s.complete(plan, prepare)),\n }),\n Context.add(auth.sessions.SessionCleanup, {\n cleanup: (input) => Effect.flatMap(cleanup, (s) => s.cleanup(input)),\n }),\n );\n\n if (proofs) {\n const persistence = service(ProofPersistence, () => ProofUnavailable.make({}));\n\n context = Context.add(context, ProofPersistence, {\n issue: (input, prepare) => Effect.flatMap(persistence, (s) => s.issue(input, prepare)),\n redeem: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.redeem(input, prepare)),\n cancel: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.cancel(input, prepare)),\n cleanup: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.cleanup(input, prepare)),\n });\n }\n if (password) {\n const persistence = service(PasswordPersistence, () => PasswordUnavailable.make({}));\n\n context = Context.add(context, PasswordPersistence, {\n findCredential: (input) => Effect.flatMap(persistence, (s) => s.findCredential(input)),\n rehashIfCurrent: (input) =>\n Effect.flatMap(persistence, (s) => s.rehashIfCurrent(input)),\n readForSubject: (input) => Effect.flatMap(persistence, (s) => s.readForSubject(input)),\n recoveryTarget: (input) => Effect.flatMap(persistence, (s) => s.recoveryTarget(input)),\n addIfAbsent: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.addIfAbsent(input, prepare)),\n replaceIfCurrent: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.replaceIfCurrent(input, prepare)),\n resetWithProof: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.resetWithProof(input, prepare)),\n });\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n // The heterogeneous strategy table erases the registration input type;\n // its decoded value is forwarded unchanged to the same authority key.\n const registration = service(\n key as Context.Key<unknown, PasswordRegistrationAuthority<unknown>>,\n () => PasswordUnavailable.make({}),\n );\n\n context = Context.add(context, key, {\n register: (input, prepare) =>\n Effect.flatMap(registration, (s) => s.register(input, prepare)),\n } satisfies PasswordRegistrationAuthority<unknown>);\n }\n if (email) {\n const persistence = service(EmailAddressPersistence, () => EmailUnavailable.make({}));\n\n context = Context.add(context, EmailAddressPersistence, {\n target: (input) => Effect.flatMap(persistence, (s) => s.target(input)),\n verifyWithProof: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.verifyWithProof(input, prepare)),\n changeWithProof: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.changeWithProof(input, prepare)),\n });\n }\n if (phone) {\n const unavailable = () => PhoneOtpUnavailable.make({});\n const targets = service(PhoneSignInTargets, unavailable);\n\n context = context.pipe(\n Context.add(PhoneSignInTargets, {\n lookup: (input) => Effect.flatMap(targets, (s) => s.lookup(input)),\n }),\n );\n }\n if (passkeys.length > 0) {\n const unavailable = () => PasskeyUnavailable.make({});\n const credentials = service(PasskeyCredentials, unavailable);\n const persistence = service(PasskeyPersistence, unavailable);\n\n context = context.pipe(\n Context.add(PasskeyCredentials, {\n lookup: (input) => Effect.flatMap(credentials, (s) => s.lookup(input)),\n listForSubject: (input) =>\n Effect.flatMap(credentials, (s) => s.listForSubject(input)),\n }),\n Context.add(PasskeyPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.issue(input, prepare)),\n context: (input) => Effect.flatMap(persistence, (s) => s.context(input)),\n consume: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.consume(input, prepare)),\n cleanup: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.cleanup(input, prepare)),\n }),\n );\n if (passkeys.some((feature) => feature.management)) {\n const manager = service(PasskeyManagementPersistence, unavailable);\n\n context = context.pipe(\n Context.add(PasskeyManagementPersistence, {\n list: (input) => Effect.flatMap(manager, (s) => s.list(input)),\n completeEnrollment: (input, prepare) =>\n Effect.flatMap(manager, (s) => s.completeEnrollment(input, prepare)),\n inspectRemove: (input) => Effect.flatMap(manager, (s) => s.inspectRemove(input)),\n remove: (input, prepare) =>\n Effect.flatMap(manager, (s) => s.remove(input, prepare)),\n rename: (input, prepare) =>\n Effect.flatMap(manager, (s) => s.rename(input, prepare)),\n }),\n );\n }\n }\n\n // Match the same capability-selected service keys as the acquired graph.\n return context as Context.Context<Ports<C, Id, A>>;\n }),\n );\n\n return {\n Config,\n Provisioning: ProvisioningKey,\n layer,\n managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, true),\n map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Partial<Record<StorageRole, T>>;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, false),\n };\n };\n\n return { make };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"persistence.mjs","names":[],"sources":["../../src/internal/persistence.ts"],"sourcesContent":["import { EmailAddressPersistence, EmailUnavailable } from \"@yielded/auth/Email\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { hasCommitScope } from \"@yielded/auth/Hooks\";\nimport {\n OAuthConnectedPersistence,\n OAuthConnectedRevocations,\n OAuthSignInPersistence,\n OAuthUnavailable,\n} from \"@yielded/auth/OAuth\";\nimport {\n PasskeyCredentials,\n PasskeyManagementPersistence,\n PasskeyPersistence,\n PasskeyUnavailable,\n} from \"@yielded/auth/Passkey\";\nimport { PasswordPersistence, PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { hooksLayer, reportAuthDiagnostic } from \"@yielded/auth/Persistence\";\nimport { PhoneSignInTargets, PhoneOtpUnavailable } from \"@yielded/auth/PhoneOtp\";\nimport { ProofPersistence, ProofUnavailable } from \"@yielded/auth/Proofs\";\nimport { AuthenticationAuthority, SessionUnavailable } from \"@yielded/auth/Sessions\";\nimport { Context, type Crypto, Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport {\n PersistenceConfigurationError,\n type ClaimsCodec,\n type ConfigId,\n type Definition,\n type PersistenceApi,\n type Ports,\n type Roles,\n type Provisioning,\n type ProvisioningRequirement,\n type StorageLayout,\n type SubjectMapping,\n type SubjectOptions,\n type PasskeyFeature,\n type PasskeyRequirement,\n type OAuthFeature,\n} from \"./configuration\";\nimport { makeNativeEmailAddressServices } from \"./email-native\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { makeManagedOAuth } from \"./oauth-managed\";\nimport { makeManagedPasskeys } from \"./passkey-managed\";\nimport { makeNativePasswordServices } from \"./password-native\";\nimport { makeComposedPhoneTargets } from \"./phone-composed\";\nimport { makeNativeProofServices } from \"./proof-native\";\nimport { makeRegistrationAuthority } from \"./registration\";\nimport type { PasswordRegistrationAuthority } from \"./registration-contract\";\nimport { makeNativeAuthenticationAuthorityServices } from \"./session-native-authority\";\nimport { makeNativeSessionCleanupServices } from \"./session-native-cleanup\";\nimport { makeNativePendingAuthenticationServices } from \"./session-native-login\";\nimport { makeNativeStatefulSessionServices } from \"./session-native-stateful\";\nimport { makeNativeSessionStepUpServices } from \"./session-native-step-up\";\nimport { SqlBatchCommit } from \"./sql-commit\";\nimport { requireStandalone } from \"./standalone\";\nimport { makeMappings } from \"./storage-mapping\";\nimport {\n tableDefinition,\n storageTables,\n type StorageRole,\n type StorageTable,\n} from \"./storage-tables\";\nimport {\n validateStorageBatch,\n withStorageValidation,\n type StorageValidation,\n} from \"./storage-validation\";\n\nexport interface Backend<T extends object, R, Database extends object = object> {\n readonly makeTable: (definition: StorageTable) => T;\n readonly describe: (table: T) => StorageTable;\n readonly acquire: Effect.Effect<Database, PersistenceConfigurationError, R | SqlClient.SqlClient>;\n readonly nativeTables: (database: Database) => NativeSqlTables;\n /** Fixed atomic batches replace interactive transactions on backends such as D1. */\n readonly batch?: (database: Database) => NonNullable<SqlBatchCommit[\"Service\"]>;\n}\n\nconst configError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappingError = (cause: unknown) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause });\n\nconst timestampKeys = new Set([\n \"verifiedAt\",\n \"createdAt\",\n \"lastIssueAt\",\n \"issuedAt\",\n \"expiresAt\",\n \"absoluteExpiresAt\",\n \"retentionUntil\",\n \"claimDeadline\",\n \"retryAt\",\n \"admittedAt\",\n \"deadline\",\n \"occurredAt\",\n \"dedupUntil\",\n \"binderExpiresAt\",\n \"refreshClaimedAt\",\n \"refreshClaimExpiresAt\",\n \"claimedAt\",\n \"claimExpiresAt\",\n]);\n\nexport const createPersistence = <T extends object, R, Database extends object = object>(\n backend: Backend<T, R, Database>,\n): PersistenceApi<T, R> => {\n const make = <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(\n auth: A & Definition<C, Id>,\n ) => {\n const features = Object.values(auth.strategies).flatMap((strategy) =>\n strategy.persistence === undefined ? [] : [strategy.persistence],\n );\n\n const phone = features.some((feature) => feature.kind === \"phone\");\n const password = features.some((feature) => feature.kind === \"password\");\n\n const passkeys = features.filter(\n (feature): feature is PasskeyFeature => feature.kind === \"passkey\",\n );\n\n const oauth = features.filter((feature): feature is OAuthFeature => feature?.kind === \"oauth\");\n const oauthSignIn = oauth.some((feature) => feature.signIn);\n const oauthConnected = oauth.some((feature) => feature.connected !== undefined);\n const stateful = auth.sessionMode === \"stateful\";\n\n const stateless =\n auth.sessionMode === \"stateless\" &&\n features.length > 0 &&\n features.every((feature) => feature?.kind === \"oauth\");\n\n const management = features.some(\n (feature) => feature.kind === \"password\" && feature.management,\n );\n\n const email = features.some((feature) => feature.kind === \"email\" && feature.addresses);\n const proofs = phone || management || email;\n\n const roles: StorageRole[] = [\"identifiers\", \"credentials\"];\n\n if (stateful) roles.push(\"sessions\");\n roles.push(\"pending\");\n if (password) roles.push(\"passwords\");\n if (email) roles.push(\"emailCredentials\");\n if (passkeys.length > 0) roles.push(\"passkeyCredentials\", \"passkeyFlows\");\n if (proofs) roles.push(\"proofs\");\n if (oauth.length > 0) roles.push(\"oauthIdentities\", \"oauthCredentials\");\n if (oauthSignIn) roles.push(\"oauthSignInFlows\");\n if (oauthConnected)\n roles.push(\"oauthConnectedFlows\", \"oauthConnectedGrants\", \"oauthConnectedRevocations\");\n\n const ConfigKey = Context.Service<\n ConfigId<A[\"namespace\"]>,\n StorageLayout<T, Roles<C, Id, A>>\n >()(`@yielded/auth-persistence/${auth.namespace}/Config`);\n\n const Config = Object.assign(ConfigKey, {\n layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.succeed(ConfigKey, value),\n });\n\n const ProvisioningKey = Context.Service<ProvisioningRequirement<A>, Provisioning<A>>()(\n `@yielded/auth-persistence/${auth.namespace}/Provisioning`,\n );\n\n const layout = <N, Instant>(\n options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<StorageRole, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n },\n managed: boolean,\n ): StorageLayout<T, Roles<C, Id, A>> => {\n const subject = options.subjects;\n\n if (passkeys.length > 0 && options.timestamps !== undefined)\n throw configError(\n \"Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation\",\n );\n const description = backend.describe(subject.table);\n const idColumn = description.columns[subject.id];\n\n for (const key of [subject.id, subject.status, subject.securityRevision]) {\n if (description.columns[key] === undefined)\n throw configError(`Missing subject column ${key}`);\n }\n if (subject.activeValue === undefined)\n throw configError(\"An explicit active subject value is required\");\n\n if (idColumn === undefined || idColumn.type === \"boolean\")\n throw configError(\"Subject ID must map a text or integer column\");\n\n const prefix = options.prefix;\n\n if (managed && (prefix === undefined || !/^[A-Za-z_][A-Za-z0-9_]{0,100}$/.test(prefix)))\n throw configError(\"Managed persistence requires an explicit SQL table prefix\");\n\n const schema: Partial<Record<StorageRole, T>> = { ...options.tables };\n\n for (const role of roles) {\n if (schema[role] === undefined && managed) {\n const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);\n\n const adjusted =\n options.timestamps === undefined\n ? definition\n : {\n ...definition,\n columns: Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => [\n key,\n timestampKeys.has(key)\n ? { ...column, type: options.timestamps?.type ?? column.type }\n : column,\n ]),\n ),\n };\n\n schema[role] = backend.makeTable(adjusted);\n }\n }\n for (const role of roles) {\n if (schema[role] === undefined) throw configError(`Missing ${role} table`);\n }\n const instantCodec = options.timestamps?.codec;\n\n const decodeInstant =\n instantCodec === undefined\n ? Schema.decodeUnknownEffect(Schema.Int)\n : Schema.decodeUnknownEffect(instantCodec);\n\n const decodeInstantSync =\n instantCodec === undefined\n ? Schema.decodeUnknownSync(Schema.Int)\n : Schema.decodeUnknownSync(instantCodec);\n\n const subjects: SubjectMapping = {\n table: subject.table,\n id: subject.id,\n status: subject.status,\n securityRevision: subject.securityRevision,\n activeValue: subject.activeValue,\n requirements: subject.requirements,\n actionRequirements: subject.actionRequirements ?? subject.requirements,\n toSubject: (id) =>\n Schema.decodeUnknownEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toNative: (id) =>\n Schema.encodeEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toSubjectSync: Schema.decodeUnknownSync(subject.idCodec),\n toNativeSync: Schema.encodeSync(subject.idCodec),\n };\n\n return Object.freeze({\n namespace: auth.namespace,\n schema: Object.freeze(schema) as Readonly<Record<Roles<C, Id, A>, T>>,\n tables: schema,\n subjects,\n encodeInstant:\n instantCodec === undefined ? (millis: number) => millis : Schema.encodeSync(instantCodec),\n decodeInstant: (value: unknown) => decodeInstant(value).pipe(Effect.mapError(mappingError)),\n decodeInstantSync,\n });\n };\n\n const services = Layer.effectContext(\n Effect.flatMap(backend.acquire, (database) =>\n Effect.gen(function* () {\n const storage = yield* ConfigKey;\n const client = yield* SqlClient.SqlClient;\n\n const dialect = client.onDialectOrElse({\n pg: () => \"pg\" as const,\n sqlite: () => \"sqlite\" as const,\n orElse: () => undefined,\n });\n\n if (dialect === undefined)\n return yield* configError(\"Use an explicit adapter for this SQL dialect\");\n if (\n features.some(\n (feature) =>\n (\"lifecycle\" in feature && feature.lifecycle) ||\n (feature.kind === \"email\" && !feature.addresses),\n )\n )\n return yield* configError(\n \"Use explicit services for strategies without composed persistence support\",\n );\n if (storage.namespace !== auth.namespace)\n return yield* configError(\n \"Persistence configuration belongs to a different Auth definition\",\n );\n const validations: StorageValidation[] = [];\n\n for (const role of roles) {\n const table = (storage.schema as Partial<Record<StorageRole, T>>)[role];\n\n if (table === undefined) return yield* configError(`Missing ${role} table`);\n const description = backend.describe(table);\n const columns = description.columns;\n\n for (const name of Object.keys(storageTables[role].columns)) {\n if (columns[name] === undefined)\n return yield* configError(`Missing ${role}.${name} column`);\n }\n validations.push({ table: description, required: storageTables[role].unique });\n }\n validations.push({\n table: backend.describe(storage.subjects.table as T),\n required: [[storage.subjects.id]],\n });\n yield* validateStorageBatch(dialect, validations);\n const nativeTables = backend.nativeTables(database);\n const mappings = yield* makeMappings(storage, nativeTables);\n\n const sessionMapping = stateful\n ? mappings.sessions(auth.claims, auth.sessions.moduleId)\n : undefined;\n\n const pendingMapping = mappings.pending(auth.claims, auth.sessions.moduleId);\n\n const { authenticationAuthority } = yield* makeNativeAuthenticationAuthorityServices(\n nativeTables,\n sessionMapping ?? {\n ...pendingMapping,\n pending: { pending: pendingMapping.pending, login: pendingMapping.login },\n },\n );\n\n const { pendingAuthentication } = yield* makeNativePendingAuthenticationServices(\n nativeTables,\n pendingMapping,\n );\n\n const { sessionStepUpPersistence } = yield* makeNativeSessionStepUpServices(\n nativeTables,\n {\n ...pendingMapping,\n source:\n sessionMapping === undefined\n ? { kind: \"StatelessSigned\" }\n : {\n kind: \"Stateful\",\n session: sessionMapping.session,\n sessionId: sessionMapping.sessionId,\n constraints: { sessionDigest: \"unique(session.digest)\" },\n },\n },\n );\n\n const { sessionCleanup } = yield* makeNativeSessionCleanupServices(\n nativeTables,\n pendingMapping,\n );\n\n let context: Context.Context<never> = Context.make(\n AuthenticationAuthority,\n authenticationAuthority,\n ).pipe(\n Context.add(auth.sessions.PendingAuthentication, pendingAuthentication),\n Context.add(auth.sessions.SessionStepUpPersistence, sessionStepUpPersistence),\n Context.add(auth.sessions.SessionCleanup, sessionCleanup),\n );\n\n if (sessionMapping !== undefined) {\n const sessionServices = yield* makeNativeStatefulSessionServices(\n nativeTables,\n sessionMapping,\n );\n\n context = context.pipe(\n Context.add(\n auth.sessions.StatefulSessionPersistence,\n sessionServices.statefulSessionPersistence,\n ),\n Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository),\n );\n }\n\n const proofMapping = proofs ? mappings.proofs() : undefined;\n\n if (proofMapping !== undefined) {\n const services = yield* makeNativeProofServices(\n backend.nativeTables(database),\n proofMapping,\n );\n\n context = Context.add(context, ProofPersistence, services.proofPersistence);\n }\n\n if (password) {\n const mapping = mappings.passwords();\n\n const services = yield* makeNativePasswordServices(\n backend.nativeTables(database),\n mapping,\n proofMapping,\n );\n\n context = Context.add(context, PasswordPersistence, services.passwordPersistence);\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n const registration = yield* makeRegistrationAuthority(\n backend.nativeTables(database),\n mappings.passwords(),\n ProvisioningKey,\n name,\n );\n\n context = Context.add(context, key, registration);\n }\n if (email)\n context = Context.add(\n context,\n EmailAddressPersistence,\n (yield* makeNativeEmailAddressServices(\n backend.nativeTables(database),\n mappings.emails(),\n proofMapping,\n )).emailAddressPersistence,\n );\n\n if (phone)\n context = Context.add(\n context,\n PhoneSignInTargets,\n yield* makeComposedPhoneTargets(\n backend.nativeTables(database),\n storage,\n mappings.proofs(),\n features.flatMap((feature) => (feature.kind === \"phone\" ? [feature.moduleId] : [])),\n ),\n );\n\n if (passkeys.length > 0) {\n // Auth capability metadata determines whether PasskeyConfig is required.\n const services = makeManagedPasskeys(\n {\n storage,\n namespace: auth.namespace,\n dialect,\n features: passkeys,\n passwordModules: features.flatMap((feature) =>\n feature.kind === \"password\" ? [feature.moduleId] : [],\n ),\n },\n backend.nativeTables(database),\n ) as Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n | PasskeyRequirement<A>\n | Crypto.Crypto\n | LifecycleHooks\n | SqlClient.SqlClient\n | SqlBatchCommit\n >;\n\n context = Context.merge(context, yield* services);\n }\n\n if (oauth.length > 0)\n context = Context.merge(context, yield* makeManagedOAuth(storage, nativeTables, oauth));\n\n // The checked capability metadata above determines exactly these service keys.\n return context as Context.Context<Ports<C, Id, A>>;\n }).pipe(Effect.provideService(SqlBatchCommit, backend.batch?.(database))),\n ).pipe(withStorageValidation),\n ).pipe(Layer.provide(hooksLayer));\n\n const layer = Layer.effectContext(\n Effect.gen(function* () {\n if (!stateful && !stateless) {\n if (auth.sessionMode === \"stateless\")\n return yield* configError(\n \"Composed stateless sessions support only OAuth strategies; use explicit persistence for other strategies\",\n );\n\n return yield* configError(\n \"Composed persistence supports stateful or OAuth-only stateless sessions; state-assisted validity and other session modes require explicit persistence\",\n );\n }\n const scope = yield* Effect.scope;\n const captured = yield* Effect.context<Layer.Services<typeof services>>();\n const client = Context.get(captured, SqlClient.SqlClient);\n\n // Construction uses the layer's exact environment and lifetime, never the\n // first operation's SQL transaction, service overrides, or request scope.\n // Cache the full exit: concurrent callers share failures/interruption too,\n // and cannot retry partially completed setup within this acquired layer.\n const initialize = yield* Effect.cached(\n Layer.buildWithScope(services, scope).pipe(Effect.setContext(captured)),\n );\n\n const service = Effect.fnUntraced(function* <I, S, Failure>(\n key: Context.Key<I, S>,\n unavailable: () => Failure,\n standalone = true,\n ): Effect.fn.Return<S, Failure> {\n // Reject unsupported ownership before setup can perform any writes.\n // Session/authority reads retain their existing ambient-read semantics.\n if (standalone) {\n if (yield* hasCommitScope) return yield* Effect.fail(unavailable());\n yield* requireStandalone(unavailable, client.transactionService);\n }\n\n // Observe the cached failure in this invocation, not the captured setup context.\n const acquired = yield* initialize.pipe(\n Effect.tapError((error) =>\n reportAuthDiagnostic(\n \"persistence-initialization\",\n Schema.is(PersistenceConfigurationError)(error)\n ? \"configuration\"\n : Schema.is(PersistenceMappingError)(error)\n ? \"mapping\"\n : \"unavailable\",\n ),\n ),\n Effect.mapError(unavailable),\n );\n\n const value = Context.getOrUndefined(acquired, key);\n\n return value === undefined ? yield* Effect.fail(unavailable()) : value;\n });\n\n const sessionUnavailable = () => SessionUnavailable.make({});\n const authority = service(AuthenticationAuthority, sessionUnavailable, false);\n const authorityMutation = service(AuthenticationAuthority, sessionUnavailable);\n\n const pendingRead = service(auth.sessions.PendingAuthentication, sessionUnavailable, false);\n const pendingMutation = service(auth.sessions.PendingAuthentication, sessionUnavailable);\n\n const stepUpRead = service(\n auth.sessions.SessionStepUpPersistence,\n sessionUnavailable,\n false,\n );\n\n const stepUpMutation = service(auth.sessions.SessionStepUpPersistence, sessionUnavailable);\n const cleanup = service(auth.sessions.SessionCleanup, sessionUnavailable);\n\n let context: Context.Context<never> = Context.make(AuthenticationAuthority, {\n capture: (subjectId, credentialIds) =>\n Effect.flatMap(authority, (s) => s.capture(subjectId, credentialIds)),\n requirements: (evidence) => Effect.flatMap(authority, (s) => s.requirements(evidence)),\n approve: (input, prepare) =>\n Effect.flatMap(authorityMutation, (s) => s.approve(input, prepare)),\n }).pipe(\n Context.add(auth.sessions.PendingAuthentication, {\n create: (input, now, prepare) =>\n Effect.flatMap(pendingMutation, (s) => s.create(input, now, prepare)),\n read: (input) => Effect.flatMap(pendingRead, (s) => s.read(input)),\n reject: (input, prepare) =>\n Effect.flatMap(pendingMutation, (s) => s.reject(input, prepare)),\n }),\n Context.add(auth.sessions.SessionStepUpPersistence, {\n create: (input, now, prepare) =>\n Effect.flatMap(stepUpMutation, (s) => s.create(input, now, prepare)),\n read: (input) => Effect.flatMap(stepUpRead, (s) => s.read(input)),\n reject: (input, prepare) =>\n Effect.flatMap(stepUpMutation, (s) => s.reject(input, prepare)),\n complete: (plan, prepare) =>\n Effect.flatMap(stepUpMutation, (s) => s.complete(plan, prepare)),\n }),\n Context.add(auth.sessions.SessionCleanup, {\n cleanup: (input) => Effect.flatMap(cleanup, (s) => s.cleanup(input)),\n }),\n );\n\n if (stateful) {\n const sessions = service(\n auth.sessions.StatefulSessionPersistence,\n sessionUnavailable,\n false,\n );\n\n const sessionMutations = service(\n auth.sessions.StatefulSessionPersistence,\n sessionUnavailable,\n );\n\n const repository = service(auth.sessions.SessionRepository, sessionUnavailable, false);\n\n context = context.pipe(\n Context.add(auth.sessions.StatefulSessionPersistence, {\n establish: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.establish(input, prepare)),\n verify: (input) => Effect.flatMap(sessions, (s) => s.verify(input)),\n rotate: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.rotate(input, prepare)),\n revokeDigest: (digest, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.revokeDigest(digest, prepare)),\n revoke: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.revoke(input, prepare)),\n revokeAll: (input, prepare) =>\n Effect.flatMap(sessionMutations, (s) => s.revokeAll(input, prepare)),\n }),\n Context.add(auth.sessions.SessionRepository, {\n list: (input) => Effect.flatMap(repository, (s) => s.list(input)),\n }),\n );\n }\n\n if (proofs) {\n const persistence = service(ProofPersistence, () => ProofUnavailable.make({}));\n\n context = Context.add(context, ProofPersistence, {\n issue: (input, prepare) => Effect.flatMap(persistence, (s) => s.issue(input, prepare)),\n redeem: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.redeem(input, prepare)),\n cancel: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.cancel(input, prepare)),\n cleanup: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.cleanup(input, prepare)),\n });\n }\n if (password) {\n const persistence = service(PasswordPersistence, () => PasswordUnavailable.make({}));\n\n context = Context.add(context, PasswordPersistence, {\n findCredential: (input) => Effect.flatMap(persistence, (s) => s.findCredential(input)),\n rehashIfCurrent: (input) =>\n Effect.flatMap(persistence, (s) => s.rehashIfCurrent(input)),\n readForSubject: (input) => Effect.flatMap(persistence, (s) => s.readForSubject(input)),\n recoveryTarget: (input) => Effect.flatMap(persistence, (s) => s.recoveryTarget(input)),\n addIfAbsent: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.addIfAbsent(input, prepare)),\n replaceIfCurrent: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.replaceIfCurrent(input, prepare)),\n resetWithProof: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.resetWithProof(input, prepare)),\n });\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n // The heterogeneous strategy table erases the registration input type;\n // its decoded value is forwarded unchanged to the same authority key.\n const registration = service(\n key as Context.Key<unknown, PasswordRegistrationAuthority<unknown>>,\n () => PasswordUnavailable.make({}),\n );\n\n context = Context.add(context, key, {\n register: (input, prepare) =>\n Effect.flatMap(registration, (s) => s.register(input, prepare)),\n } satisfies PasswordRegistrationAuthority<unknown>);\n }\n if (email) {\n const persistence = service(EmailAddressPersistence, () => EmailUnavailable.make({}));\n\n context = Context.add(context, EmailAddressPersistence, {\n target: (input) => Effect.flatMap(persistence, (s) => s.target(input)),\n verifyWithProof: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.verifyWithProof(input, prepare)),\n changeWithProof: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.changeWithProof(input, prepare)),\n });\n }\n if (phone) {\n const unavailable = () => PhoneOtpUnavailable.make({});\n const targets = service(PhoneSignInTargets, unavailable);\n\n context = context.pipe(\n Context.add(PhoneSignInTargets, {\n lookup: (input) => Effect.flatMap(targets, (s) => s.lookup(input)),\n }),\n );\n }\n if (passkeys.length > 0) {\n const unavailable = () => PasskeyUnavailable.make({});\n const credentials = service(PasskeyCredentials, unavailable);\n const persistence = service(PasskeyPersistence, unavailable);\n\n context = context.pipe(\n Context.add(PasskeyCredentials, {\n lookup: (input) => Effect.flatMap(credentials, (s) => s.lookup(input)),\n listForSubject: (input) =>\n Effect.flatMap(credentials, (s) => s.listForSubject(input)),\n }),\n Context.add(PasskeyPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.issue(input, prepare)),\n context: (input) => Effect.flatMap(persistence, (s) => s.context(input)),\n consume: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.consume(input, prepare)),\n cleanup: (input, prepare) =>\n Effect.flatMap(persistence, (s) => s.cleanup(input, prepare)),\n }),\n );\n if (passkeys.some((feature) => feature.management)) {\n const manager = service(PasskeyManagementPersistence, unavailable);\n\n context = context.pipe(\n Context.add(PasskeyManagementPersistence, {\n list: (input) => Effect.flatMap(manager, (s) => s.list(input)),\n completeEnrollment: (input, prepare) =>\n Effect.flatMap(manager, (s) => s.completeEnrollment(input, prepare)),\n inspectRemove: (input) => Effect.flatMap(manager, (s) => s.inspectRemove(input)),\n remove: (input, prepare) =>\n Effect.flatMap(manager, (s) => s.remove(input, prepare)),\n rename: (input, prepare) =>\n Effect.flatMap(manager, (s) => s.rename(input, prepare)),\n }),\n );\n }\n }\n\n const oauthUnavailable = () => OAuthUnavailable.make({});\n\n function oauthService<I, S>(\n key: Context.Key<I, S>,\n moduleId: string,\n capability: \"signIn\" | \"connected\",\n ): Effect.Effect<S, OAuthUnavailable> {\n const enabled = oauth.some(\n (feature) =>\n feature.moduleId === moduleId &&\n (capability === \"signIn\" ? feature.signIn : feature.connected !== undefined),\n );\n\n return enabled ? service(key, oauthUnavailable) : Effect.fail(oauthUnavailable());\n }\n\n if (oauthSignIn) {\n const persistence = (moduleId: string) =>\n oauthService(OAuthSignInPersistence, moduleId, \"signIn\");\n\n context = Context.add(context, OAuthSignInPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(persistence(input.context.moduleId), (s) => s.issue(input, prepare)),\n consume: (input, prepare) =>\n Effect.flatMap(persistence(input.moduleId), (s) => s.consume(input, prepare)),\n resolve: (input) =>\n Effect.flatMap(persistence(input.moduleId), (s) => s.resolve(input)),\n cleanup: (input, prepare) =>\n Effect.flatMap(persistence(input.moduleId), (s) => s.cleanup(input, prepare)),\n });\n }\n if (oauthConnected) {\n const persistence = (moduleId: string) =>\n oauthService(OAuthConnectedPersistence, moduleId, \"connected\");\n\n const revocations = (moduleId: string) =>\n oauthService(OAuthConnectedRevocations, moduleId, \"connected\");\n\n context = context.pipe(\n Context.add(OAuthConnectedPersistence, {\n read: (input) => Effect.flatMap(persistence(input.moduleId), (s) => s.read(input)),\n issue: (input, prepare) =>\n Effect.flatMap(persistence(input.context.moduleId), (s) => s.issue(input, prepare)),\n consume: (input, prepare) =>\n Effect.flatMap(persistence(input.moduleId), (s) => s.consume(input, prepare)),\n settle: (input, prepare) =>\n Effect.flatMap(persistence(input.grant.context.moduleId), (s) =>\n s.settle(input, prepare),\n ),\n list: (input) =>\n Effect.flatMap(persistence(input.authorization.moduleId), (s) => s.list(input)),\n disconnect: (input, prepare) =>\n Effect.flatMap(persistence(input.key.moduleId), (s) =>\n s.disconnect(input, prepare),\n ),\n claimRefresh: (input, prepare) =>\n Effect.flatMap(persistence(input.grant.context.moduleId), (s) =>\n s.claimRefresh(input, prepare),\n ),\n settleRefresh: (input, prepare) =>\n Effect.flatMap(persistence(input.claim.grant.context.moduleId), (s) =>\n s.settleRefresh(input, prepare),\n ),\n cleanup: (input, prepare) =>\n Effect.flatMap(persistence(input.moduleId), (s) => s.cleanup(input, prepare)),\n }),\n Context.add(OAuthConnectedRevocations, {\n claim: (input, prepare) =>\n Effect.flatMap(revocations(input.moduleId), (s) => s.claim(input, prepare)),\n settle: (input, prepare) =>\n Effect.flatMap(revocations(input.claim.job.grant.context.moduleId), (s) =>\n s.settle(input, prepare),\n ),\n }),\n );\n }\n\n // Match the same capability-selected service keys as the acquired graph.\n return context as Context.Context<Ports<C, Id, A>>;\n }),\n );\n\n return {\n Config,\n Provisioning: ProvisioningKey,\n layer,\n managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, true),\n map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Partial<Record<StorageRole, T>>;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, false),\n };\n };\n\n return { make };\n};\n"],"mappings":"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"}
@@ -187,7 +187,7 @@ const makeNativePhoneServices = Effect.fnUntraced(function* (tables, mapping) {
187
187
  ];
188
188
  for (const originalRequirement of requirements) {
189
189
  const requirement = yield* Schema.decodeEffect(AuthenticationRequirement)(originalRequirement);
190
- if (!passwordEvidenceSatisfiedAt(evidence, requirement, captured.now)) return yield* rejected();
190
+ if (!(yield* passwordEvidenceSatisfiedAt(evidence, requirement, captured.now))) return yield* rejected();
191
191
  }
192
192
  if (evidence.proofs.length === 0) return yield* rejected();
193
193
  for (const proof of evidence.proofs) {