@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.
- package/README.md +9 -2
- package/dist/Adapter.mjs +8 -8
- package/dist/OAuthPersistence.mjs +10 -5
- package/dist/OAuthPersistence.mjs.map +1 -1
- package/dist/internal/configuration.d.mts +31 -5
- package/dist/internal/configuration.mjs.map +1 -1
- package/dist/internal/email-native.mjs +10 -2
- package/dist/internal/email-native.mjs.map +1 -1
- package/dist/internal/email-policy.mjs +3 -2
- package/dist/internal/email-policy.mjs.map +1 -1
- package/dist/internal/models/oauth-model.d.mts +4 -2
- package/dist/internal/models/oauth-model.mjs.map +1 -1
- package/dist/internal/oauth/native-accounts.d.mts +1 -1
- package/dist/internal/oauth/native-accounts.mjs +6 -6
- package/dist/internal/oauth/native-accounts.mjs.map +1 -1
- package/dist/internal/oauth/native-connected.d.mts +1 -1
- package/dist/internal/oauth/native-connected.mjs +1 -1
- package/dist/internal/oauth/native-registration.mjs +19 -8
- package/dist/internal/oauth/native-registration.mjs.map +1 -1
- package/dist/internal/oauth/native-sign-in.d.mts +1 -1
- package/dist/internal/oauth/native-sign-in.mjs +1 -1
- package/dist/internal/oauth/native-state.mjs +21 -11
- package/dist/internal/oauth/native-state.mjs.map +1 -1
- package/dist/internal/oauth/state.d.mts +1 -1
- package/dist/internal/oauth/state.mjs +1 -1
- package/dist/internal/oauth-managed.mjs +182 -0
- package/dist/internal/oauth-managed.mjs.map +1 -0
- package/dist/internal/passkey-managed.mjs +1 -1
- package/dist/internal/passkey-native-registration.mjs +1 -1
- package/dist/internal/passkey-native-state.mjs +33 -23
- package/dist/internal/passkey-native-state.mjs.map +1 -1
- package/dist/internal/passkey-native-write.mjs +3 -3
- package/dist/internal/passkey-native-write.mjs.map +1 -1
- package/dist/internal/passkey-native.d.mts +15 -7
- package/dist/internal/passkey-native.mjs +2 -1
- package/dist/internal/passkey-native.mjs.map +1 -1
- package/dist/internal/passkey-policy.mjs +9 -7
- package/dist/internal/passkey-policy.mjs.map +1 -1
- package/dist/internal/password-native.mjs +9 -6
- package/dist/internal/password-native.mjs.map +1 -1
- package/dist/internal/password-policy.mjs +7 -6
- package/dist/internal/password-policy.mjs.map +1 -1
- package/dist/internal/persistence.mjs +96 -37
- package/dist/internal/persistence.mjs.map +1 -1
- package/dist/internal/phone-native.mjs +1 -1
- package/dist/internal/phone-native.mjs.map +1 -1
- package/dist/internal/session-native-authority.mjs +6 -5
- package/dist/internal/session-native-authority.mjs.map +1 -1
- package/dist/internal/session-native-login.d.mts +2 -2
- package/dist/internal/session-native-login.mjs +2 -1
- package/dist/internal/session-native-login.mjs.map +1 -1
- package/dist/internal/session-native-pending-read.mjs +26 -20
- package/dist/internal/session-native-pending-read.mjs.map +1 -1
- package/dist/internal/session-native-record.mjs +6 -4
- package/dist/internal/session-native-record.mjs.map +1 -1
- package/dist/internal/session-native-state.mjs +3 -0
- package/dist/internal/session-native-state.mjs.map +1 -1
- package/dist/internal/session-native-stateful.d.mts +2 -2
- package/dist/internal/session-native-stateful.mjs +65 -37
- package/dist/internal/session-native-stateful.mjs.map +1 -1
- package/dist/internal/session-native-step-up.d.mts +2 -2
- package/dist/internal/session-native-step-up.mjs +14 -18
- package/dist/internal/session-native-step-up.mjs.map +1 -1
- package/dist/internal/session-native-validity.mjs +3 -1
- package/dist/internal/session-native-validity.mjs.map +1 -1
- package/dist/internal/sql-authority.mjs +5 -1
- package/dist/internal/sql-authority.mjs.map +1 -1
- package/dist/internal/sql-storage-validation.mjs +2 -1
- package/dist/internal/sql-storage-validation.mjs.map +1 -1
- package/dist/internal/sql-table.d.mts +1 -0
- package/dist/internal/sql-table.mjs.map +1 -1
- package/dist/internal/step-up-state.mjs +19 -6
- package/dist/internal/step-up-state.mjs.map +1 -1
- package/dist/internal/storage-mapping.mjs +1 -1
- package/dist/internal/storage-tables.d.mts +237 -0
- package/dist/internal/storage-tables.mjs +68 -0
- package/dist/internal/storage-tables.mjs.map +1 -1
- package/dist/internal/storage-validation.d.mts +3 -1
- package/dist/internal/storage-validation.mjs +70 -17
- package/dist/internal/storage-validation.mjs.map +1 -1
- package/dist/internal/totp-native.mjs +1 -1
- package/package.json +1 -1
- package/src/OAuthPersistence.ts +7 -2
- package/src/internal/configuration.ts +46 -7
- package/src/internal/email-native.ts +16 -6
- package/src/internal/email-policy.ts +12 -3
- package/src/internal/models/oauth-model.ts +7 -1
- package/src/internal/oauth/native-accounts.ts +3 -3
- package/src/internal/oauth/native-registration.ts +17 -6
- package/src/internal/oauth/native-state.ts +38 -18
- package/src/internal/oauth-managed.ts +277 -0
- package/src/internal/passkey-native-state.ts +59 -52
- package/src/internal/passkey-native-write.ts +2 -2
- package/src/internal/passkey-native.ts +4 -2
- package/src/internal/passkey-policy.ts +13 -9
- package/src/internal/password-native.ts +17 -9
- package/src/internal/password-policy.ts +16 -8
- package/src/internal/persistence.ts +216 -70
- package/src/internal/phone-native.ts +1 -1
- package/src/internal/session-native-authority.ts +23 -7
- package/src/internal/session-native-login.ts +6 -3
- package/src/internal/session-native-pending-read.ts +46 -33
- package/src/internal/session-native-record.ts +6 -4
- package/src/internal/session-native-state.ts +3 -0
- package/src/internal/session-native-stateful.ts +144 -51
- package/src/internal/session-native-step-up.ts +27 -23
- package/src/internal/session-native-validity.ts +3 -1
- package/src/internal/sql-authority.ts +5 -1
- package/src/internal/sql-storage-validation.ts +53 -46
- package/src/internal/sql-table.ts +1 -0
- package/src/internal/step-up-state.ts +43 -6
- package/src/internal/storage-tables.ts +76 -0
- package/src/internal/storage-validation.ts +127 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-policy.mjs","names":[],"sources":["../../src/internal/email-policy.ts"],"sourcesContent":["import {\n type EmailAddressMutation,\n type EmailAddressTarget,\n type EmailAction,\n EmailUnavailable,\n snapshotEmailCredential,\n snapshotEmailRequirement,\n snapshotEmailRevision,\n} from \"@yielded/auth/Email\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport {\n snapshotAuthenticationEvidence,\n type AuthenticationRevision,\n type AuthenticationRequirement,\n type SecurityRevision,\n} from \"@yielded/auth/Sessions\";\nimport { Effect } from \"effect\";\n\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyEmailAddressMapping } from \"./models/email-model\";\nimport { passwordEvidenceSatisfiedAt } from \"./password-policy\";\n\nconst unavailable = () => EmailUnavailable.make({});\n\nconst sameIdentifier = (left: LoginIdentifier, right: LoginIdentifier) =>\n left.namespace === right.namespace && left.value === right.value;\n\nexport type EmailWorkflowPolicy = Pick<\n AnyEmailAddressMapping,\n | \"allocateCredentialId\"\n | \"allocateCredentialIdSync\"\n | \"allocateRevision\"\n | \"allocateRevisionSync\"\n | \"sessionInvalidation\"\n | \"isIdentifierConflict\"\n | \"isCredentialConflict\"\n> & {\n readonly subject: Pick<\n AnyEmailAddressMapping[\"subject\"],\n \"nextSecurityRevision\" | \"nextSecurityRevisionSync\"\n >;\n};\n\nexport const sameEmailRevision = (left: AuthenticationRevision, right: AuthenticationRevision) => {\n if (\n left.subjectId !== right.subjectId ||\n left.securityRevision !== right.securityRevision ||\n left.credentials.length !== right.credentials.length\n )\n return false;\n\n const expected = [...left.credentials].sort((a, b) =>\n a.credentialId.localeCompare(b.credentialId),\n );\n\n const actual = [...right.credentials].sort((a, b) =>\n a.credentialId.localeCompare(b.credentialId),\n );\n\n return expected.every(\n (item, index) =>\n item.credentialId === actual[index]!.credentialId &&\n item.revision === actual[index]!.revision,\n );\n};\n\nexport const emailActionModule = (moduleId: string, action: EmailAction) =>\n `${moduleId}/${action === \"verify-address\" ? \"verify-address\" : \"change-address\"}`;\n\nexport const emailActionPurpose = (action: EmailAction) =>\n action === \"verify-address\" ? \"email-address-verification\" : \"email-address-change\";\n\nexport const emailRedemptionMatches = (input: EmailAddressMutation, action: EmailAction) => {\n const completion = input.redemption.input;\n const binding = completion.binding;\n\n return (\n completion.moduleId === emailActionModule(input.moduleId, action) &&\n completion.purpose === emailActionPurpose(action) &&\n binding._tag === \"IdentifierChange\" &&\n sameIdentifier(binding.identifier, input.target) &&\n sameEmailRevision(binding.revision, input.captured.revision)\n );\n};\n\nexport const snapshotEmailMutation = Effect.fn(\"EmailAddressPersistence.snapshotMutation\")(\n function* (input: EmailAddressMutation) {\n const evidence = yield* snapshotAuthenticationEvidence(input.authorization.evidence).pipe(\n Effect.mapError(unavailable),\n );\n\n const requirement = yield* snapshotEmailRequirement(input.authorization.requirement);\n\n const source =\n input.captured.source === undefined\n ? undefined\n : yield* snapshotEmailCredential(input.captured.source);\n\n return Object.freeze({\n ...input,\n target: Object.freeze({ ...input.target }),\n ...(input.invalidation === undefined\n ? {}\n : { invalidation: Object.freeze({ ...input.invalidation }) }),\n captured: Object.freeze({\n eligible: input.captured.eligible,\n revision: snapshotEmailRevision(input.captured.revision),\n ...(input.captured.targetIdentifierRevision === undefined\n ? {}\n : { targetIdentifierRevision: input.captured.targetIdentifierRevision }),\n ...(source === undefined ? {} : { source }),\n }),\n authorization: Object.freeze({\n challenge: Object.freeze({\n ...input.authorization.challenge,\n target: Object.freeze({ ...input.authorization.challenge.target }),\n revision: snapshotEmailRevision(input.authorization.challenge.revision),\n }),\n evidence,\n requirement,\n }),\n });\n },\n);\n\nexport const validateEmailMutation = Effect.fn(\"EmailAddressPersistence.validateAuthority\")(\n function* (\n policy: EmailWorkflowPolicy,\n input: EmailAddressMutation,\n action: EmailAction,\n current: Pick<EmailMutationRead, \"target\" | \"requirement\"> | undefined,\n now: number,\n ) {\n const confirmsExisting =\n action === \"verify-address\" && input.captured.targetIdentifierRevision !== undefined;\n\n if (\n !input.captured.eligible ||\n !emailRedemptionMatches(input, action) ||\n input.authorization.challenge.moduleId !== input.moduleId ||\n input.authorization.challenge.action !== action ||\n input.authorization.challenge.commandId !== input.commandId ||\n !sameIdentifier(input.authorization.challenge.target, input.target) ||\n input.authorization.challenge.sourceCredentialId !== input.captured.source?.credentialId ||\n !sameEmailRevision(input.authorization.challenge.revision, input.captured.revision) ||\n input.authorization.challenge.targetIdentifierRevision !==\n input.captured.targetIdentifierRevision ||\n (input.authorization.evidence.flowId as string) !== (input.commandId as string) ||\n input.authorization.evidence.bindingDigest !== input.authorization.challenge.bindingDigest ||\n !sameEmailRevision(input.authorization.evidence.revision, input.captured.revision) ||\n (action === \"verify-address\" && input.captured.source !== undefined) ||\n (action === \"change-address\" && input.captured.source === undefined) ||\n confirmsExisting !== (input.invalidation === undefined) ||\n (input.invalidation?.existingSessions === \"immediate\" &&\n policy.sessionInvalidation !== \"same-authority-immediate\")\n )\n return false;\n\n if (\n current === undefined ||\n !current.target.eligible ||\n !sameEmailRevision(current.target.revision, input.captured.revision) ||\n current.target.targetIdentifierRevision !== input.captured.targetIdentifierRevision ||\n (input.captured.source !== undefined &&\n (current.target.source === undefined ||\n current.target.source.identifierRevision !== input.captured.source.identifierRevision ||\n current.target.source.credentialRevision !== input.captured.source.credentialRevision ||\n !sameIdentifier(current.target.source.identifier, input.captured.source.identifier)))\n )\n return false;\n\n const currentRequirement = yield* current.requirement;\n\n return (\n passwordEvidenceSatisfiedAt(\n input.authorization.evidence,\n input.authorization.requirement,\n now,\n ) && passwordEvidenceSatisfiedAt(input.authorization.evidence, currentRequirement, now)\n );\n },\n);\n\nexport const allocateEmailValue = <A>(\n mode: \"interactive\" | \"synchronous\",\n asynchronous: Effect.Effect<A, PersistenceMappingError> | undefined,\n synchronous: (() => A) | undefined,\n) => {\n if (mode === \"synchronous\")\n return synchronous === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: synchronous,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n if (asynchronous !== undefined) return asynchronous;\n\n return synchronous === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: synchronous,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n};\n\nexport const allocateEmailSecurityRevision = (\n mapping: EmailWorkflowPolicy,\n mode: \"interactive\" | \"synchronous\",\n current: SecurityRevision,\n) => {\n if (mode === \"synchronous\")\n return mapping.subject.nextSecurityRevisionSync === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: () => mapping.subject.nextSecurityRevisionSync!(current),\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n if (mapping.subject.nextSecurityRevision !== undefined)\n return mapping.subject.nextSecurityRevision(current);\n if (mapping.subject.nextSecurityRevisionSync !== undefined)\n return Effect.try({\n try: () => mapping.subject.nextSecurityRevisionSync!(current),\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n\n return Effect.fail(unavailable());\n};\n\nexport interface EmailMutationRead {\n readonly target: EmailAddressTarget;\n readonly requirement: Effect.Effect<\n AuthenticationRequirement,\n EmailUnavailable | PersistenceMappingError\n >;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"email-policy.mjs","names":[],"sources":["../../src/internal/email-policy.ts"],"sourcesContent":["import {\n type EmailAddressMutation,\n type EmailAddressTarget,\n type EmailAction,\n EmailUnavailable,\n snapshotEmailCredential,\n snapshotEmailRequirement,\n snapshotEmailRevision,\n} from \"@yielded/auth/Email\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport {\n snapshotAuthenticationEvidence,\n type AuthenticationRevision,\n type AuthenticationRequirement,\n type SecurityRevision,\n} from \"@yielded/auth/Sessions\";\nimport { DateTime, Effect } from \"effect\";\n\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyEmailAddressMapping } from \"./models/email-model\";\nimport { passwordEvidenceSatisfiedAt } from \"./password-policy\";\n\nconst unavailable = () => EmailUnavailable.make({});\n\nconst sameIdentifier = (left: LoginIdentifier, right: LoginIdentifier) =>\n left.namespace === right.namespace && left.value === right.value;\n\nexport type EmailWorkflowPolicy = Pick<\n AnyEmailAddressMapping,\n | \"allocateCredentialId\"\n | \"allocateCredentialIdSync\"\n | \"allocateRevision\"\n | \"allocateRevisionSync\"\n | \"sessionInvalidation\"\n | \"isIdentifierConflict\"\n | \"isCredentialConflict\"\n> & {\n readonly subject: Pick<\n AnyEmailAddressMapping[\"subject\"],\n \"nextSecurityRevision\" | \"nextSecurityRevisionSync\"\n >;\n};\n\nexport const sameEmailRevision = (left: AuthenticationRevision, right: AuthenticationRevision) => {\n if (\n left.subjectId !== right.subjectId ||\n left.securityRevision !== right.securityRevision ||\n left.credentials.length !== right.credentials.length\n )\n return false;\n\n const expected = [...left.credentials].sort((a, b) =>\n a.credentialId.localeCompare(b.credentialId),\n );\n\n const actual = [...right.credentials].sort((a, b) =>\n a.credentialId.localeCompare(b.credentialId),\n );\n\n return expected.every(\n (item, index) =>\n item.credentialId === actual[index]!.credentialId &&\n item.revision === actual[index]!.revision,\n );\n};\n\nexport const emailActionModule = (moduleId: string, action: EmailAction) =>\n `${moduleId}/${action === \"verify-address\" ? \"verify-address\" : \"change-address\"}`;\n\nexport const emailActionPurpose = (action: EmailAction) =>\n action === \"verify-address\" ? \"email-address-verification\" : \"email-address-change\";\n\nexport const emailRedemptionMatches = (input: EmailAddressMutation, action: EmailAction) => {\n const completion = input.redemption.input;\n const binding = completion.binding;\n\n return (\n completion.moduleId === emailActionModule(input.moduleId, action) &&\n completion.purpose === emailActionPurpose(action) &&\n binding._tag === \"IdentifierChange\" &&\n sameIdentifier(binding.identifier, input.target) &&\n sameEmailRevision(binding.revision, input.captured.revision)\n );\n};\n\nexport const snapshotEmailMutation = Effect.fn(\"EmailAddressPersistence.snapshotMutation\")(\n function* (input: EmailAddressMutation) {\n const evidence = yield* snapshotAuthenticationEvidence(input.authorization.evidence).pipe(\n Effect.mapError(unavailable),\n );\n\n const requirement = yield* snapshotEmailRequirement(input.authorization.requirement);\n\n const source =\n input.captured.source === undefined\n ? undefined\n : yield* snapshotEmailCredential(input.captured.source);\n\n return Object.freeze({\n ...input,\n target: Object.freeze({ ...input.target }),\n ...(input.invalidation === undefined\n ? {}\n : { invalidation: Object.freeze({ ...input.invalidation }) }),\n captured: Object.freeze({\n eligible: input.captured.eligible,\n revision: snapshotEmailRevision(input.captured.revision),\n ...(input.captured.targetIdentifierRevision === undefined\n ? {}\n : { targetIdentifierRevision: input.captured.targetIdentifierRevision }),\n ...(source === undefined ? {} : { source }),\n }),\n authorization: Object.freeze({\n challenge: Object.freeze({\n ...input.authorization.challenge,\n target: Object.freeze({ ...input.authorization.challenge.target }),\n revision: snapshotEmailRevision(input.authorization.challenge.revision),\n }),\n evidence,\n requirement,\n }),\n });\n },\n);\n\nexport const validateEmailMutation = Effect.fn(\"EmailAddressPersistence.validateAuthority\")(\n function* (\n policy: EmailWorkflowPolicy,\n input: EmailAddressMutation,\n action: EmailAction,\n current: Pick<EmailMutationRead, \"target\" | \"requirement\"> | undefined,\n now: number,\n ) {\n const confirmsExisting =\n action === \"verify-address\" && input.captured.targetIdentifierRevision !== undefined;\n\n if (\n !input.captured.eligible ||\n !emailRedemptionMatches(input, action) ||\n input.authorization.challenge.moduleId !== input.moduleId ||\n input.authorization.challenge.action !== action ||\n input.authorization.challenge.commandId !== input.commandId ||\n !sameIdentifier(input.authorization.challenge.target, input.target) ||\n input.authorization.challenge.sourceCredentialId !== input.captured.source?.credentialId ||\n !sameEmailRevision(input.authorization.challenge.revision, input.captured.revision) ||\n input.authorization.challenge.targetIdentifierRevision !==\n input.captured.targetIdentifierRevision ||\n (input.authorization.evidence.flowId as string) !== (input.commandId as string) ||\n input.authorization.evidence.bindingDigest !== input.authorization.challenge.bindingDigest ||\n !sameEmailRevision(input.authorization.evidence.revision, input.captured.revision) ||\n (action === \"verify-address\" && input.captured.source !== undefined) ||\n (action === \"change-address\" && input.captured.source === undefined) ||\n confirmsExisting !== (input.invalidation === undefined) ||\n (input.invalidation?.existingSessions === \"immediate\" &&\n policy.sessionInvalidation !== \"same-authority-immediate\")\n )\n return false;\n\n if (\n current === undefined ||\n !current.target.eligible ||\n !sameEmailRevision(current.target.revision, input.captured.revision) ||\n current.target.targetIdentifierRevision !== input.captured.targetIdentifierRevision ||\n (input.captured.source !== undefined &&\n (current.target.source === undefined ||\n current.target.source.identifierRevision !== input.captured.source.identifierRevision ||\n current.target.source.credentialRevision !== input.captured.source.credentialRevision ||\n !sameIdentifier(current.target.source.identifier, input.captured.source.identifier)))\n )\n return false;\n\n const currentRequirement = yield* current.requirement;\n\n // Address custody retains strict future-proof rejection.\n if (\n input.authorization.evidence.proofs.some(\n (proof) => DateTime.toEpochMillis(proof.verifiedAt) > now,\n )\n )\n return false;\n\n return (\n (yield* passwordEvidenceSatisfiedAt(\n input.authorization.evidence,\n input.authorization.requirement,\n now,\n )) &&\n (yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, currentRequirement, now))\n );\n },\n);\n\nexport const allocateEmailValue = <A>(\n mode: \"interactive\" | \"synchronous\",\n asynchronous: Effect.Effect<A, PersistenceMappingError> | undefined,\n synchronous: (() => A) | undefined,\n) => {\n if (mode === \"synchronous\")\n return synchronous === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: synchronous,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n if (asynchronous !== undefined) return asynchronous;\n\n return synchronous === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: synchronous,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n};\n\nexport const allocateEmailSecurityRevision = (\n mapping: EmailWorkflowPolicy,\n mode: \"interactive\" | \"synchronous\",\n current: SecurityRevision,\n) => {\n if (mode === \"synchronous\")\n return mapping.subject.nextSecurityRevisionSync === undefined\n ? Effect.fail(unavailable())\n : Effect.try({\n try: () => mapping.subject.nextSecurityRevisionSync!(current),\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n if (mapping.subject.nextSecurityRevision !== undefined)\n return mapping.subject.nextSecurityRevision(current);\n if (mapping.subject.nextSecurityRevisionSync !== undefined)\n return Effect.try({\n try: () => mapping.subject.nextSecurityRevisionSync!(current),\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n\n return Effect.fail(unavailable());\n};\n\nexport interface EmailMutationRead {\n readonly target: EmailAddressTarget;\n readonly requirement: Effect.Effect<\n AuthenticationRequirement,\n EmailUnavailable | PersistenceMappingError\n >;\n}\n"],"mappings":"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"}
|
|
@@ -3,10 +3,10 @@ import { PersistenceMappingError } from "../mapping-error.mjs";
|
|
|
3
3
|
import { SubjectIdCodec } from "./common.mjs";
|
|
4
4
|
import { Effect, Schema } from "effect";
|
|
5
5
|
import { PreparedCommit } from "@yielded/auth/Hooks";
|
|
6
|
+
import { OAuthAccountRevision, OAuthActionAuthorization, OAuthCleanupInput, OAuthCommandId, OAuthExternalIdentity, OAuthLinkedAccountsRead, OAuthRegistrationAccess, OAuthRegistrationDecision, OAuthRegistrationInspection, OAuthRegistrationIntent, OAuthUnavailable, PrepareOAuthCommit } from "@yielded/auth/OAuth";
|
|
6
7
|
import { CleanupResult } from "@yielded/auth/Persistence";
|
|
7
8
|
import { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
8
9
|
import { TokenDigest } from "@yielded/auth/Schema";
|
|
9
|
-
import { OAuthAccountRevision, OAuthActionAuthorization, OAuthCleanupInput, OAuthCommandId, OAuthExternalIdentity, OAuthLinkedAccountsRead, OAuthRegistrationAccess, OAuthRegistrationDecision, OAuthRegistrationInspection, OAuthRegistrationIntent, OAuthUnavailable, PrepareOAuthCommit } from "@yielded/auth/OAuth";
|
|
10
10
|
declare namespace oauth_model_d_exports {
|
|
11
11
|
export { OAuthAccountsMapping, OAuthAction, OAuthAuthorityReadTable, OAuthAuthorityTable, OAuthCleanupDescriptor, OAuthCleanupTable, OAuthClock, OAuthCredentialReadTable, OAuthCredentialTable, OAuthD1Mapping, OAuthEligibilityDescriptor, OAuthEligibilityFact, OAuthEligibilityTable, OAuthFlowTable, OAuthOwnershipReadTable, OAuthOwnershipTable, OAuthRegistrationAuthority, OAuthRegistrationGuardDescriptor, OAuthRegistrationGuardTable, OAuthRegistrationIntentMapping, OAuthRegistrationIntentTable, OAuthRegistrationMapping, OAuthSignInMapping, OAuthSubjectReadTable, OAuthSubjectTable, oauthCleanupTable, oauthEligibilityTable, oauthRegistrationGuardTable, requiredOAuthRegistrationConstraints, requiredOAuthSignInConstraints };
|
|
12
12
|
}
|
|
@@ -30,7 +30,7 @@ export interface OAuthSubjectReadTable<S extends TableModel, Expression extends
|
|
|
30
30
|
readonly securityRevision: Column<S>;
|
|
31
31
|
readonly isActiveStatus: (value: unknown) => boolean;
|
|
32
32
|
readonly activeCondition: Expression;
|
|
33
|
-
readonly decodeAuthenticationRequirement: (row: S["select"]) => AuthenticationRequirement
|
|
33
|
+
readonly decodeAuthenticationRequirement: (row: S["select"]) => AuthenticationRequirement | Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;
|
|
34
34
|
}
|
|
35
35
|
export interface OAuthSubjectTable<S extends TableModel, Expression extends SqlExpression = SqlExpression> extends OAuthSubjectReadTable<S, Expression> {
|
|
36
36
|
readonly nextSecurityRevision: (current: SecurityRevision) => SecurityRevision;
|
|
@@ -303,6 +303,8 @@ export interface OAuthAccountsMapping<S extends TableModel, O extends TableModel
|
|
|
303
303
|
readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;
|
|
304
304
|
}
|
|
305
305
|
export interface OAuthRegistrationAuthority<Registration> {
|
|
306
|
+
/** Only the first confirmed registration supplies its private authentication handoff. */
|
|
307
|
+
readonly authentication?: "first-confirmed-registration";
|
|
306
308
|
readonly read: (access: OAuthRegistrationAccess) => Effect.Effect<OAuthRegistrationInspection | undefined, OAuthUnavailable>;
|
|
307
309
|
readonly inspect: (input: {
|
|
308
310
|
readonly intent: OAuthRegistrationIntent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-model.mjs","names":[],"sources":["../../../src/internal/models/oauth-model.ts"],"sourcesContent":["import type { PreparedCommit } from \"@yielded/auth/Hooks\";\nimport type {\n OAuthActionAuthorization,\n OAuthAccountRevision,\n OAuthLinkedAccountsRead,\n OAuthRegistrationIntent,\n OAuthExternalIdentity,\n OAuthRegistrationAccess,\n OAuthRegistrationInspection,\n OAuthUnavailable,\n OAuthCommandId,\n PrepareOAuthCommit,\n OAuthRegistrationDecision,\n OAuthCleanupInput,\n} from \"@yielded/auth/OAuth\";\nimport { AuthenticationFactor } from \"@yielded/auth/Operations\";\nimport type { CleanupResult } from \"@yielded/auth/Persistence\";\nimport type { TokenDigest } from \"@yielded/auth/Schema\";\nimport { type AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { type Effect, Schema } from \"effect\";\n\nimport type { TableModel as Table, SqlExpression } from \"../table-model\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\n\ntype Column<T extends Table> = T[\"column\"];\nexport type OAuthAction = OAuthActionAuthorization[\"challenge\"][\"action\"];\n\nexport interface OAuthClock<Expression extends SqlExpression = SqlExpression> {\n readonly encodeInstant: (millis: number) => unknown;\n readonly decodeInstant: (value: unknown) => number;\n /** Actual engine wall clock sampled after locks, not transaction-start time.\n * PostgreSQL uses clock_timestamp(), never now()/CURRENT_TIMESTAMP. D1 repeats\n * its primary-engine sample bounds in final guards. Return integer milliseconds. */\n readonly engineNowMillis: Expression;\n /** Convert a stored timestamp expression to integer milliseconds. */\n readonly toMillis: (expression: Expression) => Expression;\n readonly fromMillis: (expression: Expression) => Expression;\n}\n\nexport interface OAuthSubjectReadTable<\n S extends Table,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: S[\"table\"];\n readonly id: Column<S>;\n readonly status: Column<S>;\n readonly securityRevision: Column<S>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly activeCondition: Expression;\n readonly decodeAuthenticationRequirement: (row: S[\"select\"]) => AuthenticationRequirement;\n}\n\nexport interface OAuthSubjectTable<\n S extends Table,\n Expression extends SqlExpression = SqlExpression,\n> extends OAuthSubjectReadTable<S, Expression> {\n readonly nextSecurityRevision: (current: SecurityRevision) => SecurityRevision;\n}\n\nexport interface OAuthOwnershipReadTable<O extends Table, N> {\n readonly table: O[\"table\"];\n readonly identityKey: Column<O>;\n readonly provider: Column<O>;\n readonly issuer: Column<O>;\n readonly externalSubject: Column<O>;\n readonly subjectId: Column<O>;\n readonly decodeSubjectId: (row: O[\"select\"]) => N;\n}\n\nexport interface OAuthOwnershipTable<O extends Table, N> extends OAuthOwnershipReadTable<O, N> {\n readonly encodeInsert: (input: {\n readonly identity: typeof OAuthExternalIdentity.Type;\n readonly identityKey: string;\n readonly subjectId: N;\n }) => O[\"insert\"];\n}\n\nexport interface OAuthCredentialReadTable<\n C extends Table,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: C[\"table\"];\n readonly moduleId: Column<C>;\n readonly credentialId: Column<C>;\n readonly subjectId: Column<C>;\n readonly identityKey: Column<C>;\n readonly credentialRevision: Column<C>;\n readonly status: Column<C>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly activeCondition: Expression;\n}\n\nexport interface OAuthCredentialTable<\n C extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> extends OAuthCredentialReadTable<C, Expression> {\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly subjectId: N;\n readonly identityKey: string;\n readonly credentialId: string;\n readonly credentialRevision: SecurityRevision;\n }) => C[\"insert\"];\n /** This slice removes login rows. Historical records belong in separate audit storage. */\n readonly removal: \"delete\";\n}\n\nexport interface OAuthAuthorityReadTable<\n C extends Table,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: C[\"table\"];\n readonly subjectId: Column<C>;\n readonly credentialId: Column<C>;\n readonly revision: Column<C>;\n readonly status: Column<C>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly activeCondition: Expression;\n}\n\nexport interface OAuthAuthorityTable<\n C extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> extends OAuthAuthorityReadTable<C, Expression> {\n readonly encodeInsert: (input: {\n readonly subjectId: N;\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n }) => C[\"insert\"];\n}\n\n/** Live ceremonies only. Predicate columns enforce access before deletion; the\n * snapshot retains the exact authenticated context and encrypted protocol data. */\nexport interface OAuthFlowTable<F extends Table> {\n readonly table: F[\"table\"];\n readonly moduleId: Column<F>;\n readonly flowId: Column<F>;\n readonly purpose: Column<F>;\n readonly generation: Column<F>;\n readonly provider: Column<F>;\n readonly callbackId: Column<F>;\n readonly issuer: Column<F>;\n readonly responseIssuerMode: Column<F>;\n readonly subjectId: Column<F>;\n readonly stateDigest: Column<F>;\n readonly binderVerifier: Column<F>;\n readonly binderExpiresAt: Column<F>;\n readonly snapshot: Column<F>;\n readonly issuedAt: Column<F>;\n readonly expiresAt: Column<F>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly flowId: string;\n readonly purpose: \"sign-in\" | \"link\" | \"connect\";\n }) => F[\"insert\"];\n}\n\nexport const OAuthEligibilityFact = Schema.Struct({\n credentialId: Schema.NonEmptyString.check(Schema.isMaxLength(256)),\n revision: SecurityRevision,\n usablePrimary: Schema.Boolean,\n factors: Schema.Array(AuthenticationFactor).check(Schema.isMaxLength(8)),\n userVerified: Schema.Boolean,\n phishingResistant: Schema.Boolean,\n});\n\nexport type OAuthEligibilityFact = typeof OAuthEligibilityFact.Type;\n\n/** Each descriptor reads only its own subject-scoped method rows. The native row\n * projector and SQL condition must express the same installed method eligibility.\n * All source/identifier/policy mutations advance subject securityRevision. D1 also\n * guards exact selected IDs/versions and absence/count assumptions, never just a\n * stale boolean. An over-limit graph fails closed rather than truncating. */\nexport interface OAuthEligibilityTable<\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: T[\"table\"];\n readonly subjectId: Column<T>;\n readonly credentialId: Column<T>;\n readonly revision: Column<T>;\n readonly scope: string;\n readonly condition: (subjectId: N) => Expression;\n readonly decode: (row: T[\"select\"]) => OAuthEligibilityFact | undefined;\n}\n\nexport interface OAuthCleanupTable<\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: T[\"table\"];\n readonly subjectId: Column<T>;\n /** Bound to this subject's old revision; no opaque independently committing service. */\n readonly condition: (input: {\n readonly subjectId: N;\n readonly revision: OAuthAccountRevision;\n readonly removedCredentialId?: string;\n }) => Expression;\n readonly disposition: \"delete\";\n}\n\nexport interface OAuthRegistrationGuardTable<\n T extends Table,\n Registration,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: T[\"table\"];\n readonly orderBy: Column<T>;\n readonly condition: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly nativeSubjectId?: N;\n }) => Expression;\n}\n\nexport interface OAuthRegistrationGuardDescriptor<\n Registration,\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly table: Descriptor;\n readonly orderBy: string;\n readonly condition: OAuthRegistrationGuardTable<Table, Registration, N, Expression>[\"condition\"];\n}\n\nexport const oauthRegistrationGuardTable = <\n T extends Table,\n Registration,\n N,\n Expression extends SqlExpression = SqlExpression,\n>(\n input: OAuthRegistrationGuardTable<T, Registration, N, Expression>,\n): OAuthRegistrationGuardDescriptor<Registration, N, Expression, T[\"table\"]> =>\n Object.freeze({\n table: input.table,\n orderBy: input.orderBy,\n condition: input.condition,\n });\n\n/** Heterogeneous descriptors are made by typed factories and projected privately. */\nexport interface OAuthEligibilityDescriptor<\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly _tag: \"OAuthEligibilityDescriptor\";\n readonly scope: string;\n readonly table: Descriptor;\n readonly subjectId: string;\n readonly credentialId: string;\n readonly revision: string;\n readonly condition: (subjectId: N) => Expression;\n readonly decode: (row: unknown) => OAuthEligibilityFact | undefined;\n}\n\nexport const oauthEligibilityTable = <\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n>(\n input: OAuthEligibilityTable<T, N, Expression>,\n): OAuthEligibilityDescriptor<N, Expression, T[\"table\"]> => {\n const { table, subjectId, credentialId, revision, scope, condition, decode } = input;\n\n return Object.freeze({\n _tag: \"OAuthEligibilityDescriptor\",\n table,\n subjectId,\n credentialId,\n revision,\n scope,\n condition,\n // The query owner supplies rows selected from this descriptor's mapped table.\n decode: (row: unknown) => decode(row as T[\"select\"]),\n });\n};\n\nexport interface OAuthCleanupDescriptor<\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly table: Descriptor;\n readonly subjectId: string;\n readonly condition: OAuthCleanupTable<Table, N, Expression>[\"condition\"];\n}\n\nexport const oauthCleanupTable = <\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n>(\n input: OAuthCleanupTable<T, N, Expression>,\n): OAuthCleanupDescriptor<N, Expression, T[\"table\"]> =>\n Object.freeze({ table: input.table, subjectId: input.subjectId, condition: input.condition });\n\n/** Original application binding and retained decision are encoded in snapshot. */\nexport interface OAuthRegistrationIntentTable<I extends Table> {\n readonly table: I[\"table\"];\n readonly moduleId: Column<I>;\n readonly reference: Column<I>;\n readonly flowId: Column<I>;\n readonly identityKey: Column<I>;\n readonly snapshot: Column<I>;\n readonly expiresAt: Column<I>;\n readonly retentionUntil: Column<I>;\n readonly encodeInsert: (intent: OAuthRegistrationIntent) => I[\"insert\"];\n}\n\nexport interface OAuthD1Mapping {\n readonly d1: { readonly primary: true };\n}\n\nexport const requiredOAuthSignInConstraints = {\n flow: \"unique(flow.moduleId,flow.flowId)\",\n stateDigest: \"unique(flow.stateDigest)\",\n ownership: \"unique(ownership.identityKey)\",\n credentialId: \"unique(credential.credentialId)\",\n credentialIdentity: \"unique(credential.identityKey)\",\n authorityCredential: \"unique(authority.subjectId,authority.credentialId)\",\n} as const;\n\nexport const requiredOAuthRegistrationConstraints = {\n intentReference: \"unique(intent.moduleId,intent.reference)\",\n intentFlow: \"unique(intent.moduleId,intent.flowId)\",\n ownership: \"unique(ownership.identityKey)\",\n credentialId: \"unique(credential.credentialId)\",\n credentialIdentity: \"unique(credential.identityKey)\",\n authorityCredential: \"unique(authority.subjectId,authority.credentialId)\",\n} as const;\n\nexport interface OAuthSignInMapping<\n S extends Table,\n O extends Table,\n C extends Table,\n AC extends Table,\n F extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly subject: OAuthSubjectReadTable<S, Expression>;\n readonly ownership: OAuthOwnershipReadTable<O, N>;\n readonly credential: OAuthCredentialReadTable<C, Expression>;\n readonly authority: OAuthAuthorityReadTable<AC, Expression>;\n readonly flow: OAuthFlowTable<F>;\n readonly subjectId: SubjectIdCodec<N>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: typeof requiredOAuthSignInConstraints;\n}\n\nexport interface OAuthRegistrationIntentMapping<\n O extends Table,\n I extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly ownership: OAuthOwnershipReadTable<O, N>;\n readonly intent: OAuthRegistrationIntentTable<I>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: Pick<\n typeof requiredOAuthRegistrationConstraints,\n \"intentReference\" | \"intentFlow\" | \"ownership\"\n >;\n readonly eligible: (intent: OAuthRegistrationIntent) => Expression;\n}\n\nexport interface OAuthRegistrationMapping<\n Registration,\n S extends Table,\n O extends Table,\n C extends Table,\n AC extends Table,\n I extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly registration: Schema.Codec<Registration, unknown, never, never>;\n readonly ownership: OAuthOwnershipTable<O, N>;\n readonly intent: OAuthRegistrationIntentTable<I>;\n readonly subject: OAuthSubjectReadTable<S, Expression>;\n readonly credential: OAuthCredentialTable<C, N, Expression>;\n readonly authority: OAuthAuthorityTable<AC, N, Expression>;\n readonly subjectId: SubjectIdCodec<N>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: typeof requiredOAuthRegistrationConstraints;\n readonly inspect: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n }) => Effect.Effect<\n { readonly fingerprint: string; readonly eligible: boolean },\n PersistenceMappingError\n >;\n readonly eligibility: {\n readonly guards?: ReadonlyArray<\n OAuthRegistrationGuardDescriptor<Registration, N, Expression, Descriptor>\n >;\n readonly admission: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly nativeSubjectId?: N;\n }) => Expression;\n readonly postcondition: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly nativeSubjectId?: N;\n }) => Expression;\n };\n readonly allocateSubjectId: Effect.Effect<N, PersistenceMappingError>;\n readonly allocateCredentialId: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly encodeSubjectInsert: (\n input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly requestId: string;\n },\n ids: { readonly subjectId: N; readonly securityRevision: SecurityRevision },\n ) => S[\"insert\"];\n}\n\nexport interface OAuthAccountsMapping<\n S extends Table,\n O extends Table,\n C extends Table,\n AC extends Table,\n F extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly subject: OAuthSubjectTable<S, Expression>;\n readonly ownership: OAuthOwnershipTable<O, N>;\n readonly credential: OAuthCredentialTable<C, N, Expression>;\n readonly authority: OAuthAuthorityTable<AC, N, Expression>;\n readonly flow: OAuthFlowTable<F>;\n readonly subjectId: SubjectIdCodec<N>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: typeof requiredOAuthSignInConstraints;\n /** Self-contained SQL predicate rechecking this invocation's current permission\n * to view login metadata. Evaluated in every releasing read, alongside active\n * subject/credential authority and ownership. Do not trust public assurance as\n * credential provenance; bind session policy to application-owned rows as needed. */\n readonly metadataAccess: (input: {\n readonly invocation: OAuthLinkedAccountsRead[\"invocation\"];\n readonly moduleId: string;\n readonly subjectId: N;\n }) => Expression;\n readonly eligibility: ReadonlyArray<OAuthEligibilityDescriptor<N, Expression, Descriptor>>;\n readonly cleanup: ReadonlyArray<OAuthCleanupDescriptor<N, Expression, Descriptor>>;\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n /** Indexed same-owner reference predicate for any installed grant/application references. */\n readonly otherReferences: (input: {\n readonly identityKey: string;\n readonly subjectId: N;\n }) => Expression;\n readonly allocateCredentialId: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n}\n\nexport interface OAuthRegistrationAuthority<Registration> {\n readonly read: (\n access: OAuthRegistrationAccess,\n ) => Effect.Effect<OAuthRegistrationInspection | undefined, OAuthUnavailable>;\n readonly inspect: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n }) => Effect.Effect<\n {\n readonly fingerprint: TokenDigest;\n readonly eligible: boolean;\n },\n OAuthUnavailable\n >;\n readonly register: <A>(\n input: {\n readonly access: OAuthRegistrationAccess;\n readonly intent: OAuthRegistrationIntent;\n readonly commandId: typeof OAuthCommandId.Type;\n readonly registration: Registration;\n readonly fingerprint: TokenDigest;\n readonly payload: string;\n readonly requestId: string;\n },\n prepare: PrepareOAuthCommit<OAuthRegistrationDecision, A>,\n ) => Effect.Effect<PreparedCommit<A>, OAuthUnavailable>;\n readonly cleanup: <A>(\n input: OAuthCleanupInput,\n prepare: PrepareOAuthCommit<CleanupResult, A>,\n ) => Effect.Effect<PreparedCommit<A>, OAuthUnavailable>;\n}\n"],"mappings":";;;;AA+JA,MAAa,uBAAuB,OAAO,OAAO;CAChD,cAAc,OAAO,eAAe,MAAM,OAAO,YAAY,GAAG,CAAC;CACjE,UAAU;CACV,eAAe,OAAO;CACtB,SAAS,OAAO,MAAM,oBAAoB,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;CACvE,cAAc,OAAO;CACrB,mBAAmB,OAAO;AAC5B,CAAC;AAiED,MAAa,+BAMX,UAEA,OAAO,OAAO;CACZ,OAAO,MAAM;CACb,SAAS,MAAM;CACf,WAAW,MAAM;AACnB,CAAC;AAkBH,MAAa,yBAKX,UAC0D;CAC1D,MAAM,EAAE,OAAO,WAAW,cAAc,UAAU,OAAO,WAAW,WAAW;CAE/E,OAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EAEA,SAAS,QAAiB,OAAO,GAAkB;CACrD,CAAC;AACH;AAYA,MAAa,qBAKX,UAEA,OAAO,OAAO;CAAE,OAAO,MAAM;CAAO,WAAW,MAAM;CAAW,WAAW,MAAM;AAAU,CAAC;AAmB9F,MAAa,iCAAiC;CAC5C,MAAM;CACN,aAAa;CACb,WAAW;CACX,cAAc;CACd,oBAAoB;CACpB,qBAAqB;AACvB;AAEA,MAAa,uCAAuC;CAClD,iBAAiB;CACjB,YAAY;CACZ,WAAW;CACX,cAAc;CACd,oBAAoB;CACpB,qBAAqB;AACvB"}
|
|
1
|
+
{"version":3,"file":"oauth-model.mjs","names":[],"sources":["../../../src/internal/models/oauth-model.ts"],"sourcesContent":["import type { PreparedCommit } from \"@yielded/auth/Hooks\";\nimport type {\n OAuthActionAuthorization,\n OAuthAccountRevision,\n OAuthLinkedAccountsRead,\n OAuthRegistrationIntent,\n OAuthExternalIdentity,\n OAuthRegistrationAccess,\n OAuthRegistrationInspection,\n OAuthUnavailable,\n OAuthCommandId,\n PrepareOAuthCommit,\n OAuthRegistrationDecision,\n OAuthCleanupInput,\n} from \"@yielded/auth/OAuth\";\nimport { AuthenticationFactor } from \"@yielded/auth/Operations\";\nimport type { CleanupResult } from \"@yielded/auth/Persistence\";\nimport type { TokenDigest } from \"@yielded/auth/Schema\";\nimport { type AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { type Effect, Schema } from \"effect\";\n\nimport type { TableModel as Table, SqlExpression } from \"../table-model\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\n\ntype Column<T extends Table> = T[\"column\"];\nexport type OAuthAction = OAuthActionAuthorization[\"challenge\"][\"action\"];\n\nexport interface OAuthClock<Expression extends SqlExpression = SqlExpression> {\n readonly encodeInstant: (millis: number) => unknown;\n readonly decodeInstant: (value: unknown) => number;\n /** Actual engine wall clock sampled after locks, not transaction-start time.\n * PostgreSQL uses clock_timestamp(), never now()/CURRENT_TIMESTAMP. D1 repeats\n * its primary-engine sample bounds in final guards. Return integer milliseconds. */\n readonly engineNowMillis: Expression;\n /** Convert a stored timestamp expression to integer milliseconds. */\n readonly toMillis: (expression: Expression) => Expression;\n readonly fromMillis: (expression: Expression) => Expression;\n}\n\nexport interface OAuthSubjectReadTable<\n S extends Table,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: S[\"table\"];\n readonly id: Column<S>;\n readonly status: Column<S>;\n readonly securityRevision: Column<S>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly activeCondition: Expression;\n readonly decodeAuthenticationRequirement: (\n row: S[\"select\"],\n ) =>\n | AuthenticationRequirement\n | Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n}\n\nexport interface OAuthSubjectTable<\n S extends Table,\n Expression extends SqlExpression = SqlExpression,\n> extends OAuthSubjectReadTable<S, Expression> {\n readonly nextSecurityRevision: (current: SecurityRevision) => SecurityRevision;\n}\n\nexport interface OAuthOwnershipReadTable<O extends Table, N> {\n readonly table: O[\"table\"];\n readonly identityKey: Column<O>;\n readonly provider: Column<O>;\n readonly issuer: Column<O>;\n readonly externalSubject: Column<O>;\n readonly subjectId: Column<O>;\n readonly decodeSubjectId: (row: O[\"select\"]) => N;\n}\n\nexport interface OAuthOwnershipTable<O extends Table, N> extends OAuthOwnershipReadTable<O, N> {\n readonly encodeInsert: (input: {\n readonly identity: typeof OAuthExternalIdentity.Type;\n readonly identityKey: string;\n readonly subjectId: N;\n }) => O[\"insert\"];\n}\n\nexport interface OAuthCredentialReadTable<\n C extends Table,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: C[\"table\"];\n readonly moduleId: Column<C>;\n readonly credentialId: Column<C>;\n readonly subjectId: Column<C>;\n readonly identityKey: Column<C>;\n readonly credentialRevision: Column<C>;\n readonly status: Column<C>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly activeCondition: Expression;\n}\n\nexport interface OAuthCredentialTable<\n C extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> extends OAuthCredentialReadTable<C, Expression> {\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly subjectId: N;\n readonly identityKey: string;\n readonly credentialId: string;\n readonly credentialRevision: SecurityRevision;\n }) => C[\"insert\"];\n /** This slice removes login rows. Historical records belong in separate audit storage. */\n readonly removal: \"delete\";\n}\n\nexport interface OAuthAuthorityReadTable<\n C extends Table,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: C[\"table\"];\n readonly subjectId: Column<C>;\n readonly credentialId: Column<C>;\n readonly revision: Column<C>;\n readonly status: Column<C>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly activeCondition: Expression;\n}\n\nexport interface OAuthAuthorityTable<\n C extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> extends OAuthAuthorityReadTable<C, Expression> {\n readonly encodeInsert: (input: {\n readonly subjectId: N;\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n }) => C[\"insert\"];\n}\n\n/** Live ceremonies only. Predicate columns enforce access before deletion; the\n * snapshot retains the exact authenticated context and encrypted protocol data. */\nexport interface OAuthFlowTable<F extends Table> {\n readonly table: F[\"table\"];\n readonly moduleId: Column<F>;\n readonly flowId: Column<F>;\n readonly purpose: Column<F>;\n readonly generation: Column<F>;\n readonly provider: Column<F>;\n readonly callbackId: Column<F>;\n readonly issuer: Column<F>;\n readonly responseIssuerMode: Column<F>;\n readonly subjectId: Column<F>;\n readonly stateDigest: Column<F>;\n readonly binderVerifier: Column<F>;\n readonly binderExpiresAt: Column<F>;\n readonly snapshot: Column<F>;\n readonly issuedAt: Column<F>;\n readonly expiresAt: Column<F>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly flowId: string;\n readonly purpose: \"sign-in\" | \"link\" | \"connect\";\n }) => F[\"insert\"];\n}\n\nexport const OAuthEligibilityFact = Schema.Struct({\n credentialId: Schema.NonEmptyString.check(Schema.isMaxLength(256)),\n revision: SecurityRevision,\n usablePrimary: Schema.Boolean,\n factors: Schema.Array(AuthenticationFactor).check(Schema.isMaxLength(8)),\n userVerified: Schema.Boolean,\n phishingResistant: Schema.Boolean,\n});\n\nexport type OAuthEligibilityFact = typeof OAuthEligibilityFact.Type;\n\n/** Each descriptor reads only its own subject-scoped method rows. The native row\n * projector and SQL condition must express the same installed method eligibility.\n * All source/identifier/policy mutations advance subject securityRevision. D1 also\n * guards exact selected IDs/versions and absence/count assumptions, never just a\n * stale boolean. An over-limit graph fails closed rather than truncating. */\nexport interface OAuthEligibilityTable<\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: T[\"table\"];\n readonly subjectId: Column<T>;\n readonly credentialId: Column<T>;\n readonly revision: Column<T>;\n readonly scope: string;\n readonly condition: (subjectId: N) => Expression;\n readonly decode: (row: T[\"select\"]) => OAuthEligibilityFact | undefined;\n}\n\nexport interface OAuthCleanupTable<\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: T[\"table\"];\n readonly subjectId: Column<T>;\n /** Bound to this subject's old revision; no opaque independently committing service. */\n readonly condition: (input: {\n readonly subjectId: N;\n readonly revision: OAuthAccountRevision;\n readonly removedCredentialId?: string;\n }) => Expression;\n readonly disposition: \"delete\";\n}\n\nexport interface OAuthRegistrationGuardTable<\n T extends Table,\n Registration,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: T[\"table\"];\n readonly orderBy: Column<T>;\n readonly condition: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly nativeSubjectId?: N;\n }) => Expression;\n}\n\nexport interface OAuthRegistrationGuardDescriptor<\n Registration,\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly table: Descriptor;\n readonly orderBy: string;\n readonly condition: OAuthRegistrationGuardTable<Table, Registration, N, Expression>[\"condition\"];\n}\n\nexport const oauthRegistrationGuardTable = <\n T extends Table,\n Registration,\n N,\n Expression extends SqlExpression = SqlExpression,\n>(\n input: OAuthRegistrationGuardTable<T, Registration, N, Expression>,\n): OAuthRegistrationGuardDescriptor<Registration, N, Expression, T[\"table\"]> =>\n Object.freeze({\n table: input.table,\n orderBy: input.orderBy,\n condition: input.condition,\n });\n\n/** Heterogeneous descriptors are made by typed factories and projected privately. */\nexport interface OAuthEligibilityDescriptor<\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly _tag: \"OAuthEligibilityDescriptor\";\n readonly scope: string;\n readonly table: Descriptor;\n readonly subjectId: string;\n readonly credentialId: string;\n readonly revision: string;\n readonly condition: (subjectId: N) => Expression;\n readonly decode: (row: unknown) => OAuthEligibilityFact | undefined;\n}\n\nexport const oauthEligibilityTable = <\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n>(\n input: OAuthEligibilityTable<T, N, Expression>,\n): OAuthEligibilityDescriptor<N, Expression, T[\"table\"]> => {\n const { table, subjectId, credentialId, revision, scope, condition, decode } = input;\n\n return Object.freeze({\n _tag: \"OAuthEligibilityDescriptor\",\n table,\n subjectId,\n credentialId,\n revision,\n scope,\n condition,\n // The query owner supplies rows selected from this descriptor's mapped table.\n decode: (row: unknown) => decode(row as T[\"select\"]),\n });\n};\n\nexport interface OAuthCleanupDescriptor<\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly table: Descriptor;\n readonly subjectId: string;\n readonly condition: OAuthCleanupTable<Table, N, Expression>[\"condition\"];\n}\n\nexport const oauthCleanupTable = <\n T extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n>(\n input: OAuthCleanupTable<T, N, Expression>,\n): OAuthCleanupDescriptor<N, Expression, T[\"table\"]> =>\n Object.freeze({ table: input.table, subjectId: input.subjectId, condition: input.condition });\n\n/** Original application binding and retained decision are encoded in snapshot. */\nexport interface OAuthRegistrationIntentTable<I extends Table> {\n readonly table: I[\"table\"];\n readonly moduleId: Column<I>;\n readonly reference: Column<I>;\n readonly flowId: Column<I>;\n readonly identityKey: Column<I>;\n readonly snapshot: Column<I>;\n readonly expiresAt: Column<I>;\n readonly retentionUntil: Column<I>;\n readonly encodeInsert: (intent: OAuthRegistrationIntent) => I[\"insert\"];\n}\n\nexport interface OAuthD1Mapping {\n readonly d1: { readonly primary: true };\n}\n\nexport const requiredOAuthSignInConstraints = {\n flow: \"unique(flow.moduleId,flow.flowId)\",\n stateDigest: \"unique(flow.stateDigest)\",\n ownership: \"unique(ownership.identityKey)\",\n credentialId: \"unique(credential.credentialId)\",\n credentialIdentity: \"unique(credential.identityKey)\",\n authorityCredential: \"unique(authority.subjectId,authority.credentialId)\",\n} as const;\n\nexport const requiredOAuthRegistrationConstraints = {\n intentReference: \"unique(intent.moduleId,intent.reference)\",\n intentFlow: \"unique(intent.moduleId,intent.flowId)\",\n ownership: \"unique(ownership.identityKey)\",\n credentialId: \"unique(credential.credentialId)\",\n credentialIdentity: \"unique(credential.identityKey)\",\n authorityCredential: \"unique(authority.subjectId,authority.credentialId)\",\n} as const;\n\nexport interface OAuthSignInMapping<\n S extends Table,\n O extends Table,\n C extends Table,\n AC extends Table,\n F extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly subject: OAuthSubjectReadTable<S, Expression>;\n readonly ownership: OAuthOwnershipReadTable<O, N>;\n readonly credential: OAuthCredentialReadTable<C, Expression>;\n readonly authority: OAuthAuthorityReadTable<AC, Expression>;\n readonly flow: OAuthFlowTable<F>;\n readonly subjectId: SubjectIdCodec<N>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: typeof requiredOAuthSignInConstraints;\n}\n\nexport interface OAuthRegistrationIntentMapping<\n O extends Table,\n I extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly ownership: OAuthOwnershipReadTable<O, N>;\n readonly intent: OAuthRegistrationIntentTable<I>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: Pick<\n typeof requiredOAuthRegistrationConstraints,\n \"intentReference\" | \"intentFlow\" | \"ownership\"\n >;\n readonly eligible: (intent: OAuthRegistrationIntent) => Expression;\n}\n\nexport interface OAuthRegistrationMapping<\n Registration,\n S extends Table,\n O extends Table,\n C extends Table,\n AC extends Table,\n I extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly registration: Schema.Codec<Registration, unknown, never, never>;\n readonly ownership: OAuthOwnershipTable<O, N>;\n readonly intent: OAuthRegistrationIntentTable<I>;\n readonly subject: OAuthSubjectReadTable<S, Expression>;\n readonly credential: OAuthCredentialTable<C, N, Expression>;\n readonly authority: OAuthAuthorityTable<AC, N, Expression>;\n readonly subjectId: SubjectIdCodec<N>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: typeof requiredOAuthRegistrationConstraints;\n readonly inspect: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n }) => Effect.Effect<\n { readonly fingerprint: string; readonly eligible: boolean },\n PersistenceMappingError\n >;\n readonly eligibility: {\n readonly guards?: ReadonlyArray<\n OAuthRegistrationGuardDescriptor<Registration, N, Expression, Descriptor>\n >;\n readonly admission: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly nativeSubjectId?: N;\n }) => Expression;\n readonly postcondition: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly nativeSubjectId?: N;\n }) => Expression;\n };\n readonly allocateSubjectId: Effect.Effect<N, PersistenceMappingError>;\n readonly allocateCredentialId: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly encodeSubjectInsert: (\n input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n readonly requestId: string;\n },\n ids: { readonly subjectId: N; readonly securityRevision: SecurityRevision },\n ) => S[\"insert\"];\n}\n\nexport interface OAuthAccountsMapping<\n S extends Table,\n O extends Table,\n C extends Table,\n AC extends Table,\n F extends Table,\n N,\n Expression extends SqlExpression = SqlExpression,\n Descriptor extends object = object,\n> {\n readonly subject: OAuthSubjectTable<S, Expression>;\n readonly ownership: OAuthOwnershipTable<O, N>;\n readonly credential: OAuthCredentialTable<C, N, Expression>;\n readonly authority: OAuthAuthorityTable<AC, N, Expression>;\n readonly flow: OAuthFlowTable<F>;\n readonly subjectId: SubjectIdCodec<N>;\n readonly clock: OAuthClock<Expression>;\n readonly constraints: typeof requiredOAuthSignInConstraints;\n /** Self-contained SQL predicate rechecking this invocation's current permission\n * to view login metadata. Evaluated in every releasing read, alongside active\n * subject/credential authority and ownership. Do not trust public assurance as\n * credential provenance; bind session policy to application-owned rows as needed. */\n readonly metadataAccess: (input: {\n readonly invocation: OAuthLinkedAccountsRead[\"invocation\"];\n readonly moduleId: string;\n readonly subjectId: N;\n }) => Expression;\n readonly eligibility: ReadonlyArray<OAuthEligibilityDescriptor<N, Expression, Descriptor>>;\n readonly cleanup: ReadonlyArray<OAuthCleanupDescriptor<N, Expression, Descriptor>>;\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n /** Indexed same-owner reference predicate for any installed grant/application references. */\n readonly otherReferences: (input: {\n readonly identityKey: string;\n readonly subjectId: N;\n }) => Expression;\n readonly allocateCredentialId: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n}\n\nexport interface OAuthRegistrationAuthority<Registration> {\n /** Only the first confirmed registration supplies its private authentication handoff. */\n readonly authentication?: \"first-confirmed-registration\";\n readonly read: (\n access: OAuthRegistrationAccess,\n ) => Effect.Effect<OAuthRegistrationInspection | undefined, OAuthUnavailable>;\n readonly inspect: (input: {\n readonly intent: OAuthRegistrationIntent;\n readonly registration: Registration;\n }) => Effect.Effect<\n {\n readonly fingerprint: TokenDigest;\n readonly eligible: boolean;\n },\n OAuthUnavailable\n >;\n readonly register: <A>(\n input: {\n readonly access: OAuthRegistrationAccess;\n readonly intent: OAuthRegistrationIntent;\n readonly commandId: typeof OAuthCommandId.Type;\n readonly registration: Registration;\n readonly fingerprint: TokenDigest;\n readonly payload: string;\n readonly requestId: string;\n },\n prepare: PrepareOAuthCommit<OAuthRegistrationDecision, A>,\n ) => Effect.Effect<PreparedCommit<A>, OAuthUnavailable>;\n readonly cleanup: <A>(\n input: OAuthCleanupInput,\n prepare: PrepareOAuthCommit<CleanupResult, A>,\n ) => Effect.Effect<PreparedCommit<A>, OAuthUnavailable>;\n}\n"],"mappings":";;;;AAmKA,MAAa,uBAAuB,OAAO,OAAO;CAChD,cAAc,OAAO,eAAe,MAAM,OAAO,YAAY,GAAG,CAAC;CACjE,UAAU;CACV,eAAe,OAAO;CACtB,SAAS,OAAO,MAAM,oBAAoB,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;CACvE,cAAc,OAAO;CACrB,mBAAmB,OAAO;AAC5B,CAAC;AAiED,MAAa,+BAMX,UAEA,OAAO,OAAO;CACZ,OAAO,MAAM;CACb,SAAS,MAAM;CACf,WAAW,MAAM;AACnB,CAAC;AAkBH,MAAa,yBAKX,UAC0D;CAC1D,MAAM,EAAE,OAAO,WAAW,cAAc,UAAU,OAAO,WAAW,WAAW;CAE/E,OAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EAEA,SAAS,QAAiB,OAAO,GAAkB;CACrD,CAAC;AACH;AAYA,MAAa,qBAKX,UAEA,OAAO,OAAO;CAAE,OAAO,MAAM;CAAO,WAAW,MAAM;CAAW,WAAW,MAAM;AAAU,CAAC;AAmB9F,MAAa,iCAAiC;CAC5C,MAAM;CACN,aAAa;CACb,WAAW;CACX,cAAc;CACd,oBAAoB;CACpB,qBAAqB;AACvB;AAEA,MAAa,uCAAuC;CAClD,iBAAiB;CACjB,YAAY;CACZ,WAAW;CACX,cAAc;CACd,oBAAoB;CACpB,qBAAqB;AACvB"}
|
|
@@ -3,8 +3,8 @@ import { NativeSqlTables } from "../native-sql-table.mjs";
|
|
|
3
3
|
import { OAuthAccountsMapping } from "../models/oauth-model.mjs";
|
|
4
4
|
import { Crypto, Effect } from "effect";
|
|
5
5
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
6
|
-
import { SqlClient } from "effect/sql/SqlClient";
|
|
7
6
|
import * as M from "@yielded/auth/OAuth";
|
|
7
|
+
import { SqlClient } from "effect/sql/SqlClient";
|
|
8
8
|
//#region src/internal/oauth/native-accounts.d.ts
|
|
9
9
|
export type OAuthNativeAccountsMapping = OAuthAccountsMapping<TableModel, TableModel, TableModel, TableModel, TableModel, unknown, SqlExpression>;
|
|
10
10
|
export declare const makeNativeOAuthAccountsServices: (tables: NativeSqlTables, mapping: OAuthNativeAccountsMapping, batch?: {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { anySqlCondition, exactSqlText, sqlTextBytes } from "../sql-change.mjs";
|
|
2
2
|
import { CurrentSqlCommit, SqlBatchCommit, makeSqlCommitExecutor } from "../sql-commit.mjs";
|
|
3
|
-
import { makeConditionalSqlInsert } from "../session-native-record.mjs";
|
|
4
3
|
import { OAuthEligibilityFact } from "../models/oauth-model.mjs";
|
|
4
|
+
import { makeConditionalSqlInsert } from "../session-native-record.mjs";
|
|
5
5
|
import { invariant, oauthIdentityKey, sameRevision, satisfies, unavailable } from "./state.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import { makeOAuthNativeState } from "./native-state.mjs";
|
|
6
|
+
import { decodeOAuthRequirement, makeOAuthNativeState } from "./native-state.mjs";
|
|
8
7
|
import { makeOAuthNativeMutation } from "./native-mutation.mjs";
|
|
8
|
+
import { makeOAuthNativeFlow } from "./native-flow.mjs";
|
|
9
9
|
import { prepareOAuthNative } from "./native-sign-in.mjs";
|
|
10
10
|
import { Crypto, Effect, Option, Schema } from "effect";
|
|
11
|
-
import { SessionInvalidationWindow } from "@yielded/auth/Sessions";
|
|
12
11
|
import * as M from "@yielded/auth/OAuth";
|
|
12
|
+
import { SessionInvalidationWindow } from "@yielded/auth/Sessions";
|
|
13
13
|
//#region src/internal/oauth/native-accounts.ts
|
|
14
14
|
const makeNativeOAuthAccountsServices = Effect.fnUntraced(function* (tables, mapping, batch) {
|
|
15
15
|
const conditionalInsert = yield* makeConditionalSqlInsert();
|
|
@@ -174,7 +174,7 @@ const makeNativeOAuthAccountsServices = Effect.fnUntraced(function* (tables, map
|
|
|
174
174
|
credentialId,
|
|
175
175
|
credentialRevision,
|
|
176
176
|
revision,
|
|
177
|
-
requirement: mapping.subject
|
|
177
|
+
requirement: yield* decodeOAuthRequirement(mapping.subject, current.subject)
|
|
178
178
|
});
|
|
179
179
|
return yield* prepareOAuthNative({
|
|
180
180
|
_tag: "Linked",
|
|
@@ -250,7 +250,7 @@ const makeNativeOAuthAccountsServices = Effect.fnUntraced(function* (tables, map
|
|
|
250
250
|
}
|
|
251
251
|
const methods = [...eligible.values()];
|
|
252
252
|
const facts = methods.map((entry) => entry.fact);
|
|
253
|
-
const requirement = mapping.subject
|
|
253
|
+
const requirement = yield* decodeOAuthRequirement(mapping.subject, current.subject);
|
|
254
254
|
if (!facts.some((fact) => fact.usablePrimary) || !satisfies(facts, requirement)) return yield* prepareOAuthNative({ _tag: "LastSignInMethod" }, prepare);
|
|
255
255
|
const present = (entry) => anySqlCondition(entry.conditions);
|
|
256
256
|
const remaining = sql.and([anySqlCondition(methods.filter((entry) => entry.fact.usablePrimary).map(present)), anySqlCondition(requirement.alternatives.map((alternative) => sql.and([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-accounts.mjs","names":[],"sources":["../../../src/internal/oauth/native-accounts.ts"],"sourcesContent":["import type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport * as M from \"@yielded/auth/OAuth\";\nimport { SessionInvalidationWindow } from \"@yielded/auth/Sessions\";\nimport { Crypto, Effect, Option, Schema } from \"effect\";\nimport type { SqlClient } from \"effect/sql/SqlClient\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport { type OAuthAccountsMapping, OAuthEligibilityFact } from \"../models/oauth-model\";\nimport type { NativeSqlTables } from \"../native-sql-table\";\nimport { makeConditionalSqlInsert } from \"../session-native-record\";\nimport { anySqlCondition, exactSqlText, sqlTextBytes } from \"../sql-change\";\nimport { makeSqlCommitExecutor, SqlBatchCommit, CurrentSqlCommit } from \"../sql-commit\";\nimport type { SqlExpression, TableModel } from \"../table-model\";\nimport { makeOAuthNativeFlow } from \"./native-flow\";\nimport { makeOAuthNativeMutation } from \"./native-mutation\";\nimport { prepareOAuthNative } from \"./native-sign-in\";\nimport { makeOAuthNativeState } from \"./native-state\";\nimport { invariant, oauthIdentityKey, sameRevision, satisfies, unavailable } from \"./state\";\n\n// Physical metadata is validated by the adapter; schema values remain typed.\nexport type OAuthNativeAccountsMapping = OAuthAccountsMapping<\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n unknown,\n SqlExpression\n>;\n\nexport const makeNativeOAuthAccountsServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: OAuthNativeAccountsMapping,\n batch?: SqlBatchCommit[\"Service\"],\n): Effect.fn.Return<\n { readonly oauthAccountsPersistence: M.OAuthAccountsPersistence[\"Service\"] },\n M.OAuthUnavailable,\n SqlClient | LifecycleHooks | Crypto.Crypto\n> {\n const conditionalInsert = yield* makeConditionalSqlInsert();\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const crypto = yield* Crypto.Crypto;\n const external = yield* Effect.serviceOption(CurrentSqlCommit);\n const state = yield* makeOAuthNativeState(tables, mapping);\n const mutation = yield* makeOAuthNativeMutation(tables, mapping, batch !== undefined);\n\n const flow = yield* makeOAuthNativeFlow(\n tables,\n mapping,\n M.OAuthLinkFlow,\n \"link\",\n (value) => value.context.revision.subjectId,\n batch !== undefined,\n );\n\n const { sql, now, credential, authority } = state;\n\n const c = mapping.credential;\n const a = mapping.authority;\n\n const run = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n mode: \"transaction\" | \"statement\" = \"transaction\",\n ) => {\n const work = Effect.provideService(effect, Crypto.Crypto, crypto);\n\n return batch === undefined\n ? executor.run(work, mode)\n : executor.batch(work).pipe(Effect.provideService(SqlBatchCommit, batch));\n };\n\n const read = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n executor.read(Effect.provideService(effect, Crypto.Crypto, crypto));\n\n const credentialCondition = (nativeId: unknown, key: string, id: string, revision: unknown) =>\n sql.and([\n sql`${credential.column(c.subjectId)} = ${credential.value(c.subjectId, nativeId)}`,\n exactSqlText(sql, credential.column(c.identityKey), credential.value(c.identityKey, key)),\n exactSqlText(sql, credential.column(c.credentialId), credential.value(c.credentialId, id)),\n exactSqlText(\n sql,\n credential.column(c.credentialRevision),\n credential.value(c.credentialRevision, revision),\n ),\n tables.expression(c.activeCondition),\n ]);\n\n const service: M.OAuthAccountsPersistence[\"Service\"] = {\n list: (original) =>\n read(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthLinkedAccountsRead, original);\n const nativeId = yield* mapping.subjectId.toNative(input.invocation.subjectId);\n\n const metadataAccess = tables.expression(\n mapping.metadataAccess({\n invocation: input.invocation,\n moduleId: input.moduleId,\n subjectId: nativeId,\n }),\n );\n\n const s = mapping.subject;\n const orderedId = yield* sqlTextBytes(credential.column(c.credentialId));\n\n const cursorCondition =\n input.cursor === undefined\n ? sql``\n : sql`and ${orderedId} > ${yield* sqlTextBytes(credential.value(c.credentialId, input.cursor))}`;\n\n // Bound candidate work before resolving identities. Each final read uses\n // its columns' own codecs and rechecks live ownership/authority/policy.\n // A removed candidate can leave a short page; the cursor still advances.\n // Match exact credential identity even when the column's collation does not.\n const rows = yield* sql`select ${credential.fields(\"page_\")} from ${credential.name}\n where ${exactSqlText(sql, credential.column(c.moduleId), credential.value(c.moduleId, input.moduleId))}\n and ${credential.column(c.subjectId)} = ${credential.value(c.subjectId, nativeId)}\n and ${tables.expression(c.activeCondition)} and ${metadataAccess}\n and exists(select 1 from ${state.subject.name}\n where ${state.subject.column(s.id)} = ${state.subject.value(s.id, nativeId)}\n and ${tables.expression(s.activeCondition)})\n ${cursorCondition}\n order by ${orderedId} limit ${input.limit + 1}`;\n\n const selected = rows.slice(0, input.limit);\n const items: Array<M.OAuthLinkedAccount> = [];\n let cursor: string | undefined;\n\n for (const row of selected) {\n const credentialId = yield* Schema.decodeUnknownEffect(\n M.OAuthLinkedAccount.fields.credentialId,\n )(credential.decode(row, \"page_\")[c.credentialId]);\n\n cursor = credentialId;\n\n const current = yield* state.readCredential(\n {\n moduleId: input.moduleId,\n subjectId: input.invocation.subjectId,\n credentialId,\n },\n metadataAccess,\n );\n\n if (current !== undefined)\n items.push(\n M.OAuthLinkedAccount.make({\n credentialId: current.credentialId,\n ...current.identity,\n }),\n );\n }\n\n return M.snapshotOAuthSync(M.OAuthLinkedAccountsListResult, {\n items,\n ...(rows.length > input.limit && cursor !== undefined ? { cursor } : {}),\n });\n }),\n ),\n capture: (input) =>\n read(Effect.map(state.capture(input.subjectId, false), (current) => current?.revision)),\n issue: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthLinkFlow, original);\n // Flow issue has no protected authority mutation; completion owns the one\n // subject-first recheck of this authenticated begin authorization.\n const issued = yield* flow.issue(input);\n\n return yield* prepareOAuthNative(\n issued ? { _tag: \"Issued\", flow: input } : { _tag: \"Rejected\" },\n prepare,\n );\n }),\n flow.mysql ? \"transaction\" : \"statement\",\n ),\n consume: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthLinkAccess, original);\n const consumed = yield* flow.consume(input);\n\n return yield* prepareOAuthNative(\n consumed === undefined ? { _tag: \"Rejected\" } : { _tag: \"Consumed\", flow: consumed },\n prepare,\n );\n }),\n flow.mysql ? \"transaction\" : \"statement\",\n ),\n link: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const flow = M.snapshotOAuthSync(M.OAuthLinkFlow, original.flow);\n const verified = M.snapshotOAuthSync(M.OAuthVerifiedExternalIdentity, original.identity);\n const context = flow.context;\n\n const current = yield* mutation.capture(context.revision.subjectId, batch === undefined);\n const rejected = () => prepareOAuthNative({ _tag: \"Rejected\" } as const, prepare);\n\n if (\n current === undefined ||\n !sameRevision(context.revision, current.revision) ||\n context.provider !== verified.identity.provider ||\n context.issuer !== verified.identity.issuer ||\n current.now >= context.expiresAtMillis\n )\n return yield* rejected();\n\n const deadline = Math.min(\n context.expiresAtMillis,\n context.authorization.validUntilMillis,\n );\n\n const before = sql.and([\n mutation.authorityCondition(current.nativeId, current.revision),\n sql`${now} < ${deadline}`,\n ]);\n\n if (batch !== undefined) yield* mutation.assert(before);\n const identityKey = yield* mutation.ensureOwnership(verified.identity, current.nativeId);\n\n if (identityKey === undefined)\n return yield* prepareOAuthNative({ _tag: \"Conflict\" }, prepare);\n\n const identityCondition = exactSqlText(\n sql,\n credential.column(c.identityKey),\n credential.value(c.identityKey, identityKey),\n );\n\n // Fixed D1 plans classify an existing login before staging writes. Native\n // owners attempt the unique insert and read only its conflict outcome.\n const existing =\n batch === undefined\n ? []\n : yield* sql`select ${credential.fields(\"login_\")} from ${credential.name} where ${identityCondition} and ${before}`;\n\n invariant(existing.length <= 1);\n let credentialId = yield* mapping.allocateCredentialId;\n let credentialRevision = yield* mapping.allocateRevision;\n let changed = false;\n let revision = current.revision;\n\n if (existing.length === 0) {\n const values = {\n ...c.encodeInsert({\n moduleId: context.moduleId,\n subjectId: current.nativeId,\n identityKey,\n credentialId,\n credentialRevision,\n }),\n [c.moduleId]: context.moduleId,\n [c.subjectId]: current.nativeId,\n [c.identityKey]: identityKey,\n [c.credentialId]: credentialId,\n [c.credentialRevision]: credentialRevision,\n };\n\n invariant(c.isActiveStatus(values[c.status]));\n\n const inserted = yield* mutation.insertUnique(\n sql`${conditionalInsert(credential, values, before)} ${sql.onDialectOrElse({ mysql: () => sql``, orElse: () => sql`on conflict do nothing` })}`,\n );\n\n changed = inserted === 1;\n }\n if (changed) {\n const factor = {\n ...a.encodeInsert({\n subjectId: current.nativeId,\n credentialId,\n revision: credentialRevision,\n }),\n [a.subjectId]: current.nativeId,\n [a.credentialId]: credentialId,\n [a.revision]: credentialRevision,\n };\n\n invariant(a.isActiveStatus(factor[a.status]));\n invariant(\n (yield* mutation.change(\n conditionalInsert(\n authority,\n factor,\n sql.and([\n before,\n sql`exists(select 1 from ${credential.name} where ${credentialCondition(current.nativeId, identityKey, credentialId, credentialRevision)})`,\n ]),\n ),\n )) === 1,\n );\n revision = {\n ...current.revision,\n credentials: [\n ...current.revision.credentials,\n { credentialId, revision: credentialRevision },\n ].sort((left, right) => left.credentialId.localeCompare(right.credentialId)),\n };\n } else {\n const rows =\n existing.length === 1\n ? existing\n : yield* sql`select ${credential.fields(\"login_\")} from ${credential.name} where ${identityCondition} and ${before}`;\n\n invariant(rows.length === 1);\n const row = credential.decode(rows[0]!, \"login_\");\n\n invariant(\n mapping.subjectId.equals(row[c.subjectId], current.nativeId) &&\n row[c.moduleId] === context.moduleId &&\n c.isActiveStatus(row[c.status]),\n );\n credentialId = yield* Schema.decodeUnknownEffect(\n M.OAuthCredentialSnapshot.fields.credentialId,\n )(row[c.credentialId]);\n credentialRevision = yield* Schema.decodeUnknownEffect(\n M.OAuthCredentialSnapshot.fields.credentialRevision,\n )(row[c.credentialRevision]);\n invariant(\n revision.credentials.some(\n (entry) =>\n entry.credentialId === credentialId && entry.revision === credentialRevision,\n ),\n );\n }\n if (Option.isSome(external))\n yield* mutation.finish(\n \"oauth-link-authority\",\n sql.and([\n mutation.authorityCondition(current.nativeId, revision),\n sql`${now} < ${deadline}`,\n sql`exists(select 1 from ${credential.name} where ${credentialCondition(current.nativeId, identityKey, credentialId, credentialRevision)})`,\n sql`exists(select 1 from ${mutation.ownership.name} where ${mutation.ownerCondition(identityKey, current.nativeId)})`,\n ]),\n );\n\n const result = yield* Schema.decodeEffect(Schema.toType(M.OAuthCredentialSnapshot))({\n moduleId: context.moduleId,\n identity: verified.identity,\n credentialId,\n credentialRevision,\n revision,\n requirement: mapping.subject.decodeAuthenticationRequirement(current.subject),\n });\n\n return yield* prepareOAuthNative(\n { _tag: \"Linked\", credential: result, changed },\n prepare,\n );\n }),\n ),\n readCredential: (original) =>\n read(\n Effect.suspend(() =>\n state.readCredential(M.snapshotOAuthSync(M.OAuthCredentialKey, original)),\n ),\n ),\n unlink: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const captured = M.snapshotOAuthSync(M.OAuthCredentialSnapshot, original.credential);\n\n const authorization = M.snapshotOAuthSync(\n M.OAuthActionAuthorization,\n original.authorization,\n );\n\n const invalidation = M.snapshotOAuthSync(\n SessionInvalidationWindow,\n original.invalidation,\n );\n\n invariant(\n invalidation.trigger === \"credential-change\" &&\n invalidation.oldAuthenticationEvidence === \"rejected\" &&\n (mapping.sessionInvalidation === \"same-authority-immediate\"\n ? (invalidation.existingSessions === \"immediate\" &&\n invalidation.maximumExposureMillis === 0) ||\n (invalidation.existingSessions === \"cache-expiry\" &&\n invalidation.maximumExposureMillis > 0)\n : invalidation.existingSessions === \"original-absolute-expiry\"),\n );\n\n const current = yield* mutation.capture(captured.revision.subjectId, batch === undefined);\n const rejected = () => prepareOAuthNative({ _tag: \"Rejected\" } as const, prepare);\n\n if (current === undefined || !sameRevision(current.revision, captured.revision))\n return yield* rejected();\n\n const key = yield* oauthIdentityKey(captured.identity);\n\n const target = credentialCondition(\n current.nativeId,\n key,\n captured.credentialId,\n captured.credentialRevision,\n );\n\n const eligible = new Map<\n string,\n { readonly fact: OAuthEligibilityFact; readonly conditions: Array<Fragment> }\n >();\n\n invariant(mapping.eligibility.length <= 32);\n\n const sources = mapping.eligibility.map((source) => ({\n source,\n table: tables(source.table),\n }));\n\n // Each branch owns distinct projection columns. Empty scalar subqueries\n // retain each physical SQL type across derived SELECT and UNION coercion.\n invariant(sources.reduce((count, entry) => count + entry.table.keys.length, 0) <= 1024);\n\n const branches = sources.map(({ source, table }, branch) => {\n const fields = sources.flatMap((entry, index) =>\n entry.table.keys.map(\n (key, ordinal) =>\n sql`${index === branch ? table.selectedColumn(key) : sql`(select ${entry.table.selectedColumn(key)} from ${entry.table.name} where 1 = 0)`} as ${sql(`method_${index}_${ordinal}`)}`,\n ),\n );\n\n // The bounded array ordinal is an integer SQL literal, matching the sentinel.\n return sql`select * from (select ${sql.literal(String(branch))} as method_branch, 1 as target_present, ${sql.join(\", \", false)(fields)} from ${table.name}\n where ${table.column(source.subjectId)} = ${table.value(source.subjectId, current.nativeId)} and ${tables.expression(source.condition(current.nativeId))}\n order by ${table.column(source.credentialId)} limit 65) as ${sql(`eligible_${branch}`)}`;\n });\n\n const allowed = sql.and([\n mutation.authorityCondition(current.nativeId, current.revision),\n sql`exists(select 1 from ${credential.name} where ${target} and ${exactSqlText(sql, credential.column(c.moduleId), credential.value(c.moduleId, captured.moduleId))})`,\n ]);\n\n const empty = sources.flatMap((entry, index) =>\n entry.table.keys.map(\n (key, ordinal) =>\n sql`(select ${entry.table.selectedColumn(key)} from ${entry.table.name} where 1 = 0) as ${sql(`method_${index}_${ordinal}`)}`,\n ),\n );\n\n const sentinel = sql`select -1 as method_branch, case when ${allowed} then 1 else 0 end as target_present ${empty.length === 0 ? sql`` : sql`, ${sql.join(\", \", false)(empty)}`}`;\n const candidates = yield* sql`${sql.join(\" union all \", false)([sentinel, ...branches])}`;\n const presence = candidates.find((row) => Number(row.method_branch) === -1);\n\n invariant(presence !== undefined);\n if (Number(presence.target_present) !== 1) return yield* rejected();\n\n const counts = new Map<number, number>();\n\n for (const row of candidates) {\n const branch = yield* Schema.decodeEffect(Schema.Int)(Number(row.method_branch));\n\n if (branch === -1) continue;\n const entry = sources[branch];\n\n invariant(entry !== undefined);\n const count = (counts.get(branch) ?? 0) + 1;\n\n invariant(count <= 64);\n counts.set(branch, count);\n const { source, table } = entry;\n const decoded = source.decode(table.decode(row, `method_${branch}_`));\n\n if (decoded === undefined) continue;\n const parsed = yield* Schema.decodeEffect(OAuthEligibilityFact)(decoded);\n const fact = { ...parsed, factors: [...new Set(parsed.factors)].sort() };\n\n if (\n fact.credentialId !== captured.credentialId &&\n current.revision.credentials.some(\n (item) =>\n item.credentialId === fact.credentialId && item.revision === fact.revision,\n )\n ) {\n const condition = sql`exists(select 1 from ${table.name} where\n ${table.column(source.subjectId)} = ${table.value(source.subjectId, current.nativeId)}\n and ${exactSqlText(sql, table.column(source.credentialId), table.value(source.credentialId, fact.credentialId))}\n and ${exactSqlText(sql, table.column(source.revision), table.value(source.revision, fact.revision))}\n and ${tables.expression(source.condition(current.nativeId))})`;\n\n const previous = eligible.get(fact.credentialId);\n\n if (previous === undefined)\n eligible.set(fact.credentialId, { fact, conditions: [condition] });\n else {\n const encode = Schema.encodeEffect(\n Schema.fromJsonString(Schema.toCodecJson(OAuthEligibilityFact)),\n );\n\n invariant((yield* encode(previous.fact)) === (yield* encode(fact)));\n previous.conditions.push(condition);\n }\n }\n }\n const methods = [...eligible.values()];\n const facts = methods.map((entry) => entry.fact);\n const requirement = mapping.subject.decodeAuthenticationRequirement(current.subject);\n\n if (!facts.some((fact) => fact.usablePrimary) || !satisfies(facts, requirement))\n return yield* prepareOAuthNative({ _tag: \"LastSignInMethod\" }, prepare);\n\n const present = (entry: (typeof methods)[number]) => anySqlCondition(entry.conditions);\n\n // Preserve a usable remaining method through application work. These\n // predicates describe eligible credential identities, not observed rows.\n const remaining = sql.and([\n anySqlCondition(methods.filter((entry) => entry.fact.usablePrimary).map(present)),\n anySqlCondition(\n requirement.alternatives.map((alternative) =>\n sql.and([\n ...alternative.factors.map((factor) =>\n anySqlCondition(\n methods.filter((entry) => entry.fact.factors.includes(factor)).map(present),\n ),\n ),\n sql`(${sql.join(\" + \", false)(methods.map((entry) => sql`case when ${present(entry)} then 1 else 0 end`))}) >= ${alternative.minimumCredentials}`,\n anySqlCondition(\n methods\n .filter(\n (entry) =>\n (!alternative.userVerified || entry.fact.userVerified) &&\n (!alternative.phishingResistant || entry.fact.phishingResistant),\n )\n .map(present),\n ),\n ]),\n ),\n ),\n ]);\n\n const required = sql.and([\n mutation.subjectCondition(current.nativeId, current.revision),\n mutation.factorCondition(current.nativeId, current.revision),\n sql`${now} < ${authorization.validUntilMillis}`,\n remaining,\n ]);\n\n if (batch !== undefined)\n yield* mutation.assert(\n sql.and([\n mutation.authorityCondition(current.nativeId, current.revision),\n sql`${now} < ${authorization.validUntilMillis}`,\n remaining,\n ]),\n );\n\n const nextSecurityRevision = mapping.subject.nextSecurityRevision(\n current.revision.securityRevision,\n );\n\n invariant(nextSecurityRevision !== current.revision.securityRevision);\n const subject = mutation.subject;\n\n invariant(\n (yield* mutation.change(sql`${subject.update({ [mapping.subject.securityRevision]: nextSecurityRevision })}\n where ${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, current.nativeId)} and ${required}`)) ===\n 1,\n );\n invariant(\n (yield* mutation.change(sql`delete from ${credential.name} where ${target}`)) === 1,\n );\n invariant(\n (yield* mutation.change(sql`delete from ${authority.name}\n where ${authority.column(a.subjectId)} = ${authority.value(a.subjectId, current.nativeId)}\n and ${exactSqlText(sql, authority.column(a.credentialId), authority.value(a.credentialId, captured.credentialId))}\n and ${exactSqlText(sql, authority.column(a.revision), authority.value(a.revision, captured.credentialRevision))}`)) ===\n 1,\n );\n\n const cleanup = {\n subjectId: current.nativeId,\n revision: current.revision,\n removedCredentialId: captured.credentialId,\n };\n\n invariant(mapping.cleanup.length <= 32);\n const absent = [];\n\n for (const source of mapping.cleanup) {\n const table = tables(source.table);\n\n const condition = sql.and([\n sql`${table.column(source.subjectId)} = ${table.value(source.subjectId, current.nativeId)}`,\n tables.expression(source.condition(cleanup)),\n ]);\n\n const deletion = sql`delete from ${table.name} where ${condition}`;\n\n // Deleting zero or many subject-scoped session/pending rows is valid.\n absent.push(sql`not exists(select 1 from ${table.name} where ${condition})`);\n yield* mutation.execute(deletion);\n }\n\n const referenced = sql.or([\n sql`exists(select 1 from ${credential.name} where ${exactSqlText(sql, credential.column(c.identityKey), credential.value(c.identityKey, key))})`,\n tables.expression(\n mapping.otherReferences({ identityKey: key, subjectId: current.nativeId }),\n ),\n ]);\n\n yield* mutation.releaseOwnership(key, current.nativeId, referenced);\n\n const revision = {\n ...current.revision,\n securityRevision: nextSecurityRevision,\n credentials: current.revision.credentials.filter(\n (item) => item.credentialId !== captured.credentialId,\n ),\n };\n\n yield* mutation.finish(\n \"oauth-unlink-authority\",\n sql.and([\n mutation.authorityCondition(current.nativeId, revision),\n sql`${now} < ${authorization.validUntilMillis}`,\n remaining,\n sql`not exists(select 1 from ${credential.name} where ${target})`,\n ...absent,\n ]),\n );\n\n return yield* prepareOAuthNative(\n {\n _tag: \"Unlinked\",\n result: { _tag: \"Unlinked\", credentialId: captured.credentialId, invalidation },\n },\n prepare,\n );\n }),\n ),\n cleanup: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthCleanupInput, original);\n\n return yield* prepareOAuthNative(\n yield* flow.cleanup(input.moduleId, input.limit),\n prepare,\n );\n }),\n \"statement\",\n ),\n };\n\n return { oauthAccountsPersistence: service };\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"native-accounts.mjs","names":[],"sources":["../../../src/internal/oauth/native-accounts.ts"],"sourcesContent":["import type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport * as M from \"@yielded/auth/OAuth\";\nimport { SessionInvalidationWindow } from \"@yielded/auth/Sessions\";\nimport { Crypto, Effect, Option, Schema } from \"effect\";\nimport type { SqlClient } from \"effect/sql/SqlClient\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport { type OAuthAccountsMapping, OAuthEligibilityFact } from \"../models/oauth-model\";\nimport type { NativeSqlTables } from \"../native-sql-table\";\nimport { makeConditionalSqlInsert } from \"../session-native-record\";\nimport { anySqlCondition, exactSqlText, sqlTextBytes } from \"../sql-change\";\nimport { makeSqlCommitExecutor, SqlBatchCommit, CurrentSqlCommit } from \"../sql-commit\";\nimport type { SqlExpression, TableModel } from \"../table-model\";\nimport { makeOAuthNativeFlow } from \"./native-flow\";\nimport { makeOAuthNativeMutation } from \"./native-mutation\";\nimport { prepareOAuthNative } from \"./native-sign-in\";\nimport { decodeOAuthRequirement, makeOAuthNativeState } from \"./native-state\";\nimport { invariant, oauthIdentityKey, sameRevision, satisfies, unavailable } from \"./state\";\n\n// Physical metadata is validated by the adapter; schema values remain typed.\nexport type OAuthNativeAccountsMapping = OAuthAccountsMapping<\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n unknown,\n SqlExpression\n>;\n\nexport const makeNativeOAuthAccountsServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: OAuthNativeAccountsMapping,\n batch?: SqlBatchCommit[\"Service\"],\n): Effect.fn.Return<\n { readonly oauthAccountsPersistence: M.OAuthAccountsPersistence[\"Service\"] },\n M.OAuthUnavailable,\n SqlClient | LifecycleHooks | Crypto.Crypto\n> {\n const conditionalInsert = yield* makeConditionalSqlInsert();\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const crypto = yield* Crypto.Crypto;\n const external = yield* Effect.serviceOption(CurrentSqlCommit);\n const state = yield* makeOAuthNativeState(tables, mapping);\n const mutation = yield* makeOAuthNativeMutation(tables, mapping, batch !== undefined);\n\n const flow = yield* makeOAuthNativeFlow(\n tables,\n mapping,\n M.OAuthLinkFlow,\n \"link\",\n (value) => value.context.revision.subjectId,\n batch !== undefined,\n );\n\n const { sql, now, credential, authority } = state;\n\n const c = mapping.credential;\n const a = mapping.authority;\n\n const run = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n mode: \"transaction\" | \"statement\" = \"transaction\",\n ) => {\n const work = Effect.provideService(effect, Crypto.Crypto, crypto);\n\n return batch === undefined\n ? executor.run(work, mode)\n : executor.batch(work).pipe(Effect.provideService(SqlBatchCommit, batch));\n };\n\n const read = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n executor.read(Effect.provideService(effect, Crypto.Crypto, crypto));\n\n const credentialCondition = (nativeId: unknown, key: string, id: string, revision: unknown) =>\n sql.and([\n sql`${credential.column(c.subjectId)} = ${credential.value(c.subjectId, nativeId)}`,\n exactSqlText(sql, credential.column(c.identityKey), credential.value(c.identityKey, key)),\n exactSqlText(sql, credential.column(c.credentialId), credential.value(c.credentialId, id)),\n exactSqlText(\n sql,\n credential.column(c.credentialRevision),\n credential.value(c.credentialRevision, revision),\n ),\n tables.expression(c.activeCondition),\n ]);\n\n const service: M.OAuthAccountsPersistence[\"Service\"] = {\n list: (original) =>\n read(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthLinkedAccountsRead, original);\n const nativeId = yield* mapping.subjectId.toNative(input.invocation.subjectId);\n\n const metadataAccess = tables.expression(\n mapping.metadataAccess({\n invocation: input.invocation,\n moduleId: input.moduleId,\n subjectId: nativeId,\n }),\n );\n\n const s = mapping.subject;\n const orderedId = yield* sqlTextBytes(credential.column(c.credentialId));\n\n const cursorCondition =\n input.cursor === undefined\n ? sql``\n : sql`and ${orderedId} > ${yield* sqlTextBytes(credential.value(c.credentialId, input.cursor))}`;\n\n // Bound candidate work before resolving identities. Each final read uses\n // its columns' own codecs and rechecks live ownership/authority/policy.\n // A removed candidate can leave a short page; the cursor still advances.\n // Match exact credential identity even when the column's collation does not.\n const rows = yield* sql`select ${credential.fields(\"page_\")} from ${credential.name}\n where ${exactSqlText(sql, credential.column(c.moduleId), credential.value(c.moduleId, input.moduleId))}\n and ${credential.column(c.subjectId)} = ${credential.value(c.subjectId, nativeId)}\n and ${tables.expression(c.activeCondition)} and ${metadataAccess}\n and exists(select 1 from ${state.subject.name}\n where ${state.subject.column(s.id)} = ${state.subject.value(s.id, nativeId)}\n and ${tables.expression(s.activeCondition)})\n ${cursorCondition}\n order by ${orderedId} limit ${input.limit + 1}`;\n\n const selected = rows.slice(0, input.limit);\n const items: Array<M.OAuthLinkedAccount> = [];\n let cursor: string | undefined;\n\n for (const row of selected) {\n const credentialId = yield* Schema.decodeUnknownEffect(\n M.OAuthLinkedAccount.fields.credentialId,\n )(credential.decode(row, \"page_\")[c.credentialId]);\n\n cursor = credentialId;\n\n const current = yield* state.readCredential(\n {\n moduleId: input.moduleId,\n subjectId: input.invocation.subjectId,\n credentialId,\n },\n metadataAccess,\n );\n\n if (current !== undefined)\n items.push(\n M.OAuthLinkedAccount.make({\n credentialId: current.credentialId,\n ...current.identity,\n }),\n );\n }\n\n return M.snapshotOAuthSync(M.OAuthLinkedAccountsListResult, {\n items,\n ...(rows.length > input.limit && cursor !== undefined ? { cursor } : {}),\n });\n }),\n ),\n capture: (input) =>\n read(Effect.map(state.capture(input.subjectId, false), (current) => current?.revision)),\n issue: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthLinkFlow, original);\n // Flow issue has no protected authority mutation; completion owns the one\n // subject-first recheck of this authenticated begin authorization.\n const issued = yield* flow.issue(input);\n\n return yield* prepareOAuthNative(\n issued ? { _tag: \"Issued\", flow: input } : { _tag: \"Rejected\" },\n prepare,\n );\n }),\n flow.mysql ? \"transaction\" : \"statement\",\n ),\n consume: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthLinkAccess, original);\n const consumed = yield* flow.consume(input);\n\n return yield* prepareOAuthNative(\n consumed === undefined ? { _tag: \"Rejected\" } : { _tag: \"Consumed\", flow: consumed },\n prepare,\n );\n }),\n flow.mysql ? \"transaction\" : \"statement\",\n ),\n link: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const flow = M.snapshotOAuthSync(M.OAuthLinkFlow, original.flow);\n const verified = M.snapshotOAuthSync(M.OAuthVerifiedExternalIdentity, original.identity);\n const context = flow.context;\n\n const current = yield* mutation.capture(context.revision.subjectId, batch === undefined);\n const rejected = () => prepareOAuthNative({ _tag: \"Rejected\" } as const, prepare);\n\n if (\n current === undefined ||\n !sameRevision(context.revision, current.revision) ||\n context.provider !== verified.identity.provider ||\n context.issuer !== verified.identity.issuer ||\n current.now >= context.expiresAtMillis\n )\n return yield* rejected();\n\n const deadline = Math.min(\n context.expiresAtMillis,\n context.authorization.validUntilMillis,\n );\n\n const before = sql.and([\n mutation.authorityCondition(current.nativeId, current.revision),\n sql`${now} < ${deadline}`,\n ]);\n\n if (batch !== undefined) yield* mutation.assert(before);\n const identityKey = yield* mutation.ensureOwnership(verified.identity, current.nativeId);\n\n if (identityKey === undefined)\n return yield* prepareOAuthNative({ _tag: \"Conflict\" }, prepare);\n\n const identityCondition = exactSqlText(\n sql,\n credential.column(c.identityKey),\n credential.value(c.identityKey, identityKey),\n );\n\n // Fixed D1 plans classify an existing login before staging writes. Native\n // owners attempt the unique insert and read only its conflict outcome.\n const existing =\n batch === undefined\n ? []\n : yield* sql`select ${credential.fields(\"login_\")} from ${credential.name} where ${identityCondition} and ${before}`;\n\n invariant(existing.length <= 1);\n let credentialId = yield* mapping.allocateCredentialId;\n let credentialRevision = yield* mapping.allocateRevision;\n let changed = false;\n let revision = current.revision;\n\n if (existing.length === 0) {\n const values = {\n ...c.encodeInsert({\n moduleId: context.moduleId,\n subjectId: current.nativeId,\n identityKey,\n credentialId,\n credentialRevision,\n }),\n [c.moduleId]: context.moduleId,\n [c.subjectId]: current.nativeId,\n [c.identityKey]: identityKey,\n [c.credentialId]: credentialId,\n [c.credentialRevision]: credentialRevision,\n };\n\n invariant(c.isActiveStatus(values[c.status]));\n\n const inserted = yield* mutation.insertUnique(\n sql`${conditionalInsert(credential, values, before)} ${sql.onDialectOrElse({ mysql: () => sql``, orElse: () => sql`on conflict do nothing` })}`,\n );\n\n changed = inserted === 1;\n }\n if (changed) {\n const factor = {\n ...a.encodeInsert({\n subjectId: current.nativeId,\n credentialId,\n revision: credentialRevision,\n }),\n [a.subjectId]: current.nativeId,\n [a.credentialId]: credentialId,\n [a.revision]: credentialRevision,\n };\n\n invariant(a.isActiveStatus(factor[a.status]));\n invariant(\n (yield* mutation.change(\n conditionalInsert(\n authority,\n factor,\n sql.and([\n before,\n sql`exists(select 1 from ${credential.name} where ${credentialCondition(current.nativeId, identityKey, credentialId, credentialRevision)})`,\n ]),\n ),\n )) === 1,\n );\n revision = {\n ...current.revision,\n credentials: [\n ...current.revision.credentials,\n { credentialId, revision: credentialRevision },\n ].sort((left, right) => left.credentialId.localeCompare(right.credentialId)),\n };\n } else {\n const rows =\n existing.length === 1\n ? existing\n : yield* sql`select ${credential.fields(\"login_\")} from ${credential.name} where ${identityCondition} and ${before}`;\n\n invariant(rows.length === 1);\n const row = credential.decode(rows[0]!, \"login_\");\n\n invariant(\n mapping.subjectId.equals(row[c.subjectId], current.nativeId) &&\n row[c.moduleId] === context.moduleId &&\n c.isActiveStatus(row[c.status]),\n );\n credentialId = yield* Schema.decodeUnknownEffect(\n M.OAuthCredentialSnapshot.fields.credentialId,\n )(row[c.credentialId]);\n credentialRevision = yield* Schema.decodeUnknownEffect(\n M.OAuthCredentialSnapshot.fields.credentialRevision,\n )(row[c.credentialRevision]);\n invariant(\n revision.credentials.some(\n (entry) =>\n entry.credentialId === credentialId && entry.revision === credentialRevision,\n ),\n );\n }\n if (Option.isSome(external))\n yield* mutation.finish(\n \"oauth-link-authority\",\n sql.and([\n mutation.authorityCondition(current.nativeId, revision),\n sql`${now} < ${deadline}`,\n sql`exists(select 1 from ${credential.name} where ${credentialCondition(current.nativeId, identityKey, credentialId, credentialRevision)})`,\n sql`exists(select 1 from ${mutation.ownership.name} where ${mutation.ownerCondition(identityKey, current.nativeId)})`,\n ]),\n );\n\n const result = yield* Schema.decodeEffect(Schema.toType(M.OAuthCredentialSnapshot))({\n moduleId: context.moduleId,\n identity: verified.identity,\n credentialId,\n credentialRevision,\n revision,\n requirement: yield* decodeOAuthRequirement(mapping.subject, current.subject),\n });\n\n return yield* prepareOAuthNative(\n { _tag: \"Linked\", credential: result, changed },\n prepare,\n );\n }),\n ),\n readCredential: (original) =>\n read(\n Effect.suspend(() =>\n state.readCredential(M.snapshotOAuthSync(M.OAuthCredentialKey, original)),\n ),\n ),\n unlink: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const captured = M.snapshotOAuthSync(M.OAuthCredentialSnapshot, original.credential);\n\n const authorization = M.snapshotOAuthSync(\n M.OAuthActionAuthorization,\n original.authorization,\n );\n\n const invalidation = M.snapshotOAuthSync(\n SessionInvalidationWindow,\n original.invalidation,\n );\n\n invariant(\n invalidation.trigger === \"credential-change\" &&\n invalidation.oldAuthenticationEvidence === \"rejected\" &&\n (mapping.sessionInvalidation === \"same-authority-immediate\"\n ? (invalidation.existingSessions === \"immediate\" &&\n invalidation.maximumExposureMillis === 0) ||\n (invalidation.existingSessions === \"cache-expiry\" &&\n invalidation.maximumExposureMillis > 0)\n : invalidation.existingSessions === \"original-absolute-expiry\"),\n );\n\n const current = yield* mutation.capture(captured.revision.subjectId, batch === undefined);\n const rejected = () => prepareOAuthNative({ _tag: \"Rejected\" } as const, prepare);\n\n if (current === undefined || !sameRevision(current.revision, captured.revision))\n return yield* rejected();\n\n const key = yield* oauthIdentityKey(captured.identity);\n\n const target = credentialCondition(\n current.nativeId,\n key,\n captured.credentialId,\n captured.credentialRevision,\n );\n\n const eligible = new Map<\n string,\n { readonly fact: OAuthEligibilityFact; readonly conditions: Array<Fragment> }\n >();\n\n invariant(mapping.eligibility.length <= 32);\n\n const sources = mapping.eligibility.map((source) => ({\n source,\n table: tables(source.table),\n }));\n\n // Each branch owns distinct projection columns. Empty scalar subqueries\n // retain each physical SQL type across derived SELECT and UNION coercion.\n invariant(sources.reduce((count, entry) => count + entry.table.keys.length, 0) <= 1024);\n\n const branches = sources.map(({ source, table }, branch) => {\n const fields = sources.flatMap((entry, index) =>\n entry.table.keys.map(\n (key, ordinal) =>\n sql`${index === branch ? table.selectedColumn(key) : sql`(select ${entry.table.selectedColumn(key)} from ${entry.table.name} where 1 = 0)`} as ${sql(`method_${index}_${ordinal}`)}`,\n ),\n );\n\n // The bounded array ordinal is an integer SQL literal, matching the sentinel.\n return sql`select * from (select ${sql.literal(String(branch))} as method_branch, 1 as target_present, ${sql.join(\", \", false)(fields)} from ${table.name}\n where ${table.column(source.subjectId)} = ${table.value(source.subjectId, current.nativeId)} and ${tables.expression(source.condition(current.nativeId))}\n order by ${table.column(source.credentialId)} limit 65) as ${sql(`eligible_${branch}`)}`;\n });\n\n const allowed = sql.and([\n mutation.authorityCondition(current.nativeId, current.revision),\n sql`exists(select 1 from ${credential.name} where ${target} and ${exactSqlText(sql, credential.column(c.moduleId), credential.value(c.moduleId, captured.moduleId))})`,\n ]);\n\n const empty = sources.flatMap((entry, index) =>\n entry.table.keys.map(\n (key, ordinal) =>\n sql`(select ${entry.table.selectedColumn(key)} from ${entry.table.name} where 1 = 0) as ${sql(`method_${index}_${ordinal}`)}`,\n ),\n );\n\n const sentinel = sql`select -1 as method_branch, case when ${allowed} then 1 else 0 end as target_present ${empty.length === 0 ? sql`` : sql`, ${sql.join(\", \", false)(empty)}`}`;\n const candidates = yield* sql`${sql.join(\" union all \", false)([sentinel, ...branches])}`;\n const presence = candidates.find((row) => Number(row.method_branch) === -1);\n\n invariant(presence !== undefined);\n if (Number(presence.target_present) !== 1) return yield* rejected();\n\n const counts = new Map<number, number>();\n\n for (const row of candidates) {\n const branch = yield* Schema.decodeEffect(Schema.Int)(Number(row.method_branch));\n\n if (branch === -1) continue;\n const entry = sources[branch];\n\n invariant(entry !== undefined);\n const count = (counts.get(branch) ?? 0) + 1;\n\n invariant(count <= 64);\n counts.set(branch, count);\n const { source, table } = entry;\n const decoded = source.decode(table.decode(row, `method_${branch}_`));\n\n if (decoded === undefined) continue;\n const parsed = yield* Schema.decodeEffect(OAuthEligibilityFact)(decoded);\n const fact = { ...parsed, factors: [...new Set(parsed.factors)].sort() };\n\n if (\n fact.credentialId !== captured.credentialId &&\n current.revision.credentials.some(\n (item) =>\n item.credentialId === fact.credentialId && item.revision === fact.revision,\n )\n ) {\n const condition = sql`exists(select 1 from ${table.name} where\n ${table.column(source.subjectId)} = ${table.value(source.subjectId, current.nativeId)}\n and ${exactSqlText(sql, table.column(source.credentialId), table.value(source.credentialId, fact.credentialId))}\n and ${exactSqlText(sql, table.column(source.revision), table.value(source.revision, fact.revision))}\n and ${tables.expression(source.condition(current.nativeId))})`;\n\n const previous = eligible.get(fact.credentialId);\n\n if (previous === undefined)\n eligible.set(fact.credentialId, { fact, conditions: [condition] });\n else {\n const encode = Schema.encodeEffect(\n Schema.fromJsonString(Schema.toCodecJson(OAuthEligibilityFact)),\n );\n\n invariant((yield* encode(previous.fact)) === (yield* encode(fact)));\n previous.conditions.push(condition);\n }\n }\n }\n const methods = [...eligible.values()];\n const facts = methods.map((entry) => entry.fact);\n const requirement = yield* decodeOAuthRequirement(mapping.subject, current.subject);\n\n if (!facts.some((fact) => fact.usablePrimary) || !satisfies(facts, requirement))\n return yield* prepareOAuthNative({ _tag: \"LastSignInMethod\" }, prepare);\n\n const present = (entry: (typeof methods)[number]) => anySqlCondition(entry.conditions);\n\n // Preserve a usable remaining method through application work. These\n // predicates describe eligible credential identities, not observed rows.\n const remaining = sql.and([\n anySqlCondition(methods.filter((entry) => entry.fact.usablePrimary).map(present)),\n anySqlCondition(\n requirement.alternatives.map((alternative) =>\n sql.and([\n ...alternative.factors.map((factor) =>\n anySqlCondition(\n methods.filter((entry) => entry.fact.factors.includes(factor)).map(present),\n ),\n ),\n sql`(${sql.join(\" + \", false)(methods.map((entry) => sql`case when ${present(entry)} then 1 else 0 end`))}) >= ${alternative.minimumCredentials}`,\n anySqlCondition(\n methods\n .filter(\n (entry) =>\n (!alternative.userVerified || entry.fact.userVerified) &&\n (!alternative.phishingResistant || entry.fact.phishingResistant),\n )\n .map(present),\n ),\n ]),\n ),\n ),\n ]);\n\n const required = sql.and([\n mutation.subjectCondition(current.nativeId, current.revision),\n mutation.factorCondition(current.nativeId, current.revision),\n sql`${now} < ${authorization.validUntilMillis}`,\n remaining,\n ]);\n\n if (batch !== undefined)\n yield* mutation.assert(\n sql.and([\n mutation.authorityCondition(current.nativeId, current.revision),\n sql`${now} < ${authorization.validUntilMillis}`,\n remaining,\n ]),\n );\n\n const nextSecurityRevision = mapping.subject.nextSecurityRevision(\n current.revision.securityRevision,\n );\n\n invariant(nextSecurityRevision !== current.revision.securityRevision);\n const subject = mutation.subject;\n\n invariant(\n (yield* mutation.change(sql`${subject.update({ [mapping.subject.securityRevision]: nextSecurityRevision })}\n where ${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, current.nativeId)} and ${required}`)) ===\n 1,\n );\n invariant(\n (yield* mutation.change(sql`delete from ${credential.name} where ${target}`)) === 1,\n );\n invariant(\n (yield* mutation.change(sql`delete from ${authority.name}\n where ${authority.column(a.subjectId)} = ${authority.value(a.subjectId, current.nativeId)}\n and ${exactSqlText(sql, authority.column(a.credentialId), authority.value(a.credentialId, captured.credentialId))}\n and ${exactSqlText(sql, authority.column(a.revision), authority.value(a.revision, captured.credentialRevision))}`)) ===\n 1,\n );\n\n const cleanup = {\n subjectId: current.nativeId,\n revision: current.revision,\n removedCredentialId: captured.credentialId,\n };\n\n invariant(mapping.cleanup.length <= 32);\n const absent = [];\n\n for (const source of mapping.cleanup) {\n const table = tables(source.table);\n\n const condition = sql.and([\n sql`${table.column(source.subjectId)} = ${table.value(source.subjectId, current.nativeId)}`,\n tables.expression(source.condition(cleanup)),\n ]);\n\n const deletion = sql`delete from ${table.name} where ${condition}`;\n\n // Deleting zero or many subject-scoped session/pending rows is valid.\n absent.push(sql`not exists(select 1 from ${table.name} where ${condition})`);\n yield* mutation.execute(deletion);\n }\n\n const referenced = sql.or([\n sql`exists(select 1 from ${credential.name} where ${exactSqlText(sql, credential.column(c.identityKey), credential.value(c.identityKey, key))})`,\n tables.expression(\n mapping.otherReferences({ identityKey: key, subjectId: current.nativeId }),\n ),\n ]);\n\n yield* mutation.releaseOwnership(key, current.nativeId, referenced);\n\n const revision = {\n ...current.revision,\n securityRevision: nextSecurityRevision,\n credentials: current.revision.credentials.filter(\n (item) => item.credentialId !== captured.credentialId,\n ),\n };\n\n yield* mutation.finish(\n \"oauth-unlink-authority\",\n sql.and([\n mutation.authorityCondition(current.nativeId, revision),\n sql`${now} < ${authorization.validUntilMillis}`,\n remaining,\n sql`not exists(select 1 from ${credential.name} where ${target})`,\n ...absent,\n ]),\n );\n\n return yield* prepareOAuthNative(\n {\n _tag: \"Unlinked\",\n result: { _tag: \"Unlinked\", credentialId: captured.credentialId, invalidation },\n },\n prepare,\n );\n }),\n ),\n cleanup: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotOAuthSync(M.OAuthCleanupInput, original);\n\n return yield* prepareOAuthNative(\n yield* flow.cleanup(input.moduleId, input.limit),\n prepare,\n );\n }),\n \"statement\",\n ),\n };\n\n return { oauthAccountsPersistence: service };\n});\n"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { NativeSqlTables } from "../native-sql-table.mjs";
|
|
|
2
2
|
import { OAuthNativeConnectedMapping } from "./native-connected-state.mjs";
|
|
3
3
|
import { Crypto, Effect } from "effect";
|
|
4
4
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
5
|
-
import { SqlClient } from "effect/sql/SqlClient";
|
|
6
5
|
import * as M from "@yielded/auth/OAuth";
|
|
6
|
+
import { SqlClient } from "effect/sql/SqlClient";
|
|
7
7
|
//#region src/internal/oauth/native-connected.d.ts
|
|
8
8
|
export declare const makeNativeOAuthConnectedServices: (tables: NativeSqlTables, mapping: OAuthNativeConnectedMapping, batch?: {
|
|
9
9
|
readonly client: SqlClient;
|
|
@@ -3,9 +3,9 @@ import { CurrentSqlCommit, SqlBatchCommit, makeSqlCommitExecutor } from "../sql-
|
|
|
3
3
|
import { cleanupSqlRows } from "../sql-cleanup.mjs";
|
|
4
4
|
import { makeConditionalSqlInsert } from "../session-native-record.mjs";
|
|
5
5
|
import { invariant, oauthIdentityKey, sameIdentity, sameRevision, storage, unavailable } from "./state.mjs";
|
|
6
|
+
import { connectedSummary, makeOAuthNativeConnectedState, validConnectedMetadata } from "./native-connected-state.mjs";
|
|
6
7
|
import { makeOAuthNativeFlow } from "./native-flow.mjs";
|
|
7
8
|
import { prepareOAuthNative } from "./native-sign-in.mjs";
|
|
8
|
-
import { connectedSummary, makeOAuthNativeConnectedState, validConnectedMetadata } from "./native-connected-state.mjs";
|
|
9
9
|
import { Crypto, Effect, Option, Schema } from "effect";
|
|
10
10
|
import * as M from "@yielded/auth/OAuth";
|
|
11
11
|
import * as Base64Url from "effect/encoding/Base64Url";
|
|
@@ -152,6 +152,7 @@ const makeNativeOAuthRegistrationServices = Effect.fnUntraced(function* (tables,
|
|
|
152
152
|
};
|
|
153
153
|
const read = (effect) => executor.read(Effect.provideService(effect, Crypto.Crypto, crypto));
|
|
154
154
|
return { registrationAuthority: {
|
|
155
|
+
authentication: "first-confirmed-registration",
|
|
155
156
|
read: (access) => read(Effect.map(state.read(M.snapshotOAuthSync(M.OAuthRegistrationAccess, access)), (value) => value?.inspection)),
|
|
156
157
|
inspect: (input) => read(Effect.gen(function* () {
|
|
157
158
|
const payload = yield* Schema.encodeEffect(application)(input.registration);
|
|
@@ -213,6 +214,7 @@ const makeNativeOAuthRegistrationServices = Effect.fnUntraced(function* (tables,
|
|
|
213
214
|
]);
|
|
214
215
|
let admitted = inspection.eligible && (batch === void 0 || (yield* sql`select 1 where ${eligible}`).length === 1);
|
|
215
216
|
let final = horizon(expected);
|
|
217
|
+
let authentication;
|
|
216
218
|
if (admitted) {
|
|
217
219
|
const nativeId = yield* mapping.allocateSubjectId;
|
|
218
220
|
const subjectId = yield* mapping.subjectId.toSubject(nativeId);
|
|
@@ -281,17 +283,23 @@ const makeNativeOAuthRegistrationServices = Effect.fnUntraced(function* (tables,
|
|
|
281
283
|
};
|
|
282
284
|
invariant(a.isActiveStatus(factor[a.status]));
|
|
283
285
|
yield* state.change(authority.insert(factor));
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
286
|
+
authentication = M.snapshotOAuthSync(M.OAuthRegistrationAuthentication, {
|
|
287
|
+
intent: expected,
|
|
288
|
+
credentialId,
|
|
289
|
+
credentialRevision: revision,
|
|
290
|
+
revision: {
|
|
288
291
|
subjectId,
|
|
289
292
|
securityRevision: revision,
|
|
290
293
|
credentials: [{
|
|
291
294
|
credentialId,
|
|
292
295
|
revision
|
|
293
296
|
}]
|
|
294
|
-
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
final = sql.and([
|
|
300
|
+
horizon(expected),
|
|
301
|
+
tables.expression(mapping.eligibility.postcondition(policy)),
|
|
302
|
+
mutation.authorityCondition(nativeId, authentication.revision),
|
|
295
303
|
sql`exists(select 1 from ${credential.name} where ${credential.column(c.subjectId)} = ${credential.value(c.subjectId, nativeId)} and ${exactSqlText(sql, credential.column(c.credentialId), credential.value(c.credentialId, credentialId))} and ${exactSqlText(sql, credential.column(c.credentialRevision), credential.value(c.credentialRevision, revision))} and ${exactSqlText(sql, credential.column(c.identityKey), credential.value(c.identityKey, found.identityKey))} and ${tables.expression(c.activeCondition)})`,
|
|
296
304
|
sql`exists(select 1 from ${mutation.ownership.name} where ${mutation.ownerCondition(found.identityKey, nativeId)})`
|
|
297
305
|
]);
|
|
@@ -310,10 +318,13 @@ const makeNativeOAuthRegistrationServices = Effect.fnUntraced(function* (tables,
|
|
|
310
318
|
sql`exists(select 1 from ${intent.name} where ${state.key(access.moduleId, access.reference)} and ${state.exact(i.snapshot, snapshot)})`,
|
|
311
319
|
sql`${now} < ${expected.expiresAtMillis}`
|
|
312
320
|
]));
|
|
313
|
-
return yield*
|
|
321
|
+
if (!admitted) return yield* rejected();
|
|
322
|
+
invariant(authentication !== void 0);
|
|
323
|
+
return yield* prepareOAuthNative({
|
|
314
324
|
_tag: "Registered",
|
|
315
|
-
replayed: false
|
|
316
|
-
|
|
325
|
+
replayed: false,
|
|
326
|
+
authentication
|
|
327
|
+
}, prepare);
|
|
317
328
|
}));
|
|
318
329
|
})).pipe(Effect.flatten),
|
|
319
330
|
cleanup: (input, prepare) => run(Effect.gen(function* () {
|