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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +6 -6
  2. package/dist/Adapter.d.mts +1 -1
  3. package/dist/Testing.d.mts +44 -0
  4. package/dist/Testing.mjs +310 -0
  5. package/dist/Testing.mjs.map +1 -0
  6. package/dist/internal/configuration.d.mts +18 -8
  7. package/dist/internal/configuration.mjs.map +1 -1
  8. package/dist/internal/models/oauth-model.d.mts +10 -1
  9. package/dist/internal/models/oauth-model.mjs.map +1 -1
  10. package/dist/internal/models/password-model.d.mts +2 -1
  11. package/dist/internal/models/password-model.mjs.map +1 -1
  12. package/dist/internal/oauth/native-accounts.mjs +42 -1
  13. package/dist/internal/oauth/native-accounts.mjs.map +1 -1
  14. package/dist/internal/oauth/native-state.d.mts +1 -0
  15. package/dist/internal/oauth/native-state.mjs +2 -2
  16. package/dist/internal/oauth/native-state.mjs.map +1 -1
  17. package/dist/internal/passkey-managed.mjs +4 -2
  18. package/dist/internal/passkey-managed.mjs.map +1 -1
  19. package/dist/internal/password-native.mjs +14 -0
  20. package/dist/internal/password-native.mjs.map +1 -1
  21. package/dist/internal/password-registration-native.d.mts +1 -1
  22. package/dist/internal/persistence.d.mts +3 -0
  23. package/dist/internal/persistence.mjs +4 -6
  24. package/dist/internal/persistence.mjs.map +1 -1
  25. package/dist/internal/registration.mjs +17 -8
  26. package/dist/internal/registration.mjs.map +1 -1
  27. package/dist/internal/session-native-authority.mjs +2 -1
  28. package/dist/internal/session-native-authority.mjs.map +1 -1
  29. package/dist/internal/session-native-login.mjs +2 -1
  30. package/dist/internal/session-native-login.mjs.map +1 -1
  31. package/dist/internal/session-native-pending-read.mjs +1 -1
  32. package/dist/internal/session-native-pending-read.mjs.map +1 -1
  33. package/dist/internal/session-native-state.mjs +21 -8
  34. package/dist/internal/session-native-state.mjs.map +1 -1
  35. package/dist/internal/session-native-stateful.mjs +2 -1
  36. package/dist/internal/session-native-stateful.mjs.map +1 -1
  37. package/dist/internal/session-native-step-up.mjs +4 -2
  38. package/dist/internal/session-native-step-up.mjs.map +1 -1
  39. package/dist/internal/sql-change.mjs +11 -1
  40. package/dist/internal/sql-change.mjs.map +1 -1
  41. package/dist/internal/sqlite-policy-guard.mjs +23 -0
  42. package/dist/internal/sqlite-policy-guard.mjs.map +1 -0
  43. package/dist/internal/storage-mapping.d.mts +9 -5
  44. package/dist/internal/storage-mapping.mjs +16 -4
  45. package/dist/internal/storage-mapping.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/src/Testing.ts +652 -0
  48. package/src/internal/configuration.ts +26 -8
  49. package/src/internal/models/oauth-model.ts +10 -0
  50. package/src/internal/models/password-model.ts +2 -1
  51. package/src/internal/oauth/native-accounts.ts +72 -1
  52. package/src/internal/oauth/native-state.ts +6 -2
  53. package/src/internal/passkey-managed.ts +8 -2
  54. package/src/internal/password-native.ts +28 -2
  55. package/src/internal/persistence.ts +174 -164
  56. package/src/internal/registration.ts +53 -40
  57. package/src/internal/session-native-authority.ts +3 -1
  58. package/src/internal/session-native-login.ts +3 -1
  59. package/src/internal/session-native-pending-read.ts +1 -1
  60. package/src/internal/session-native-state.ts +29 -10
  61. package/src/internal/session-native-stateful.ts +3 -1
  62. package/src/internal/session-native-step-up.ts +5 -2
  63. package/src/internal/sql-change.ts +14 -1
  64. package/src/internal/sqlite-policy-guard.ts +34 -0
  65. package/src/internal/storage-mapping.ts +40 -4
@@ -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 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 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":";;;;AA8JA,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: (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"}
@@ -15,7 +15,8 @@ export interface PasswordSubjectTable<Subject extends TableModel, _NativeSubject
15
15
  readonly securityRevision: ColumnKey<Subject>;
16
16
  readonly isActiveStatus: (value: unknown) => boolean;
17
17
  readonly decodeRequirement: (row: Subject["select"]) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;
18
- /** Current policy for this exact credential mutation, decoded under the subject lock. */
18
+ /** Current policy for this exact credential mutation. Interactive drivers hold
19
+ * the subject lock; D1 guards the physical application columns through commit. */
19
20
  readonly decodeActionRequirement: (row: Subject["select"], action: PasswordAction) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;
20
21
  readonly nextSecurityRevision?: (current: SecurityRevision) => Effect.Effect<SecurityRevision, PersistenceMappingError>;
21
22
  readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;
@@ -1 +1 @@
1
- {"version":3,"file":"password-model.mjs","names":[],"sources":["../../../src/internal/models/password-model.ts"],"sourcesContent":["import { type LoginIdentifier } from \"@yielded/auth/Identity\";\nimport type {\n PasswordAction,\n PasswordCredentialSnapshot,\n PasswordReplacement,\n EncodedPasswordHash,\n} from \"@yielded/auth/Password\";\nimport type { AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport type { Effect, Redacted } from \"effect\";\n\nimport type { AnyTableModel, TableModel as Table, SqlExpression } from \"../table-model\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\nimport type { ProofClock } from \"./proof-model\";\n\ntype ColumnKey<T extends Table> = T[\"column\"];\n\nexport interface PasswordSubjectTable<Subject extends Table, _NativeSubjectId> {\n readonly table: Subject[\"table\"];\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly securityRevision: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly decodeRequirement: (\n row: Subject[\"select\"],\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n /** Current policy for this exact credential mutation, decoded under the subject lock. */\n readonly decodeActionRequirement: (\n row: Subject[\"select\"],\n action: PasswordAction,\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n readonly nextSecurityRevision?: (\n current: SecurityRevision,\n ) => Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;\n /** Required only by D1 conditional statements. */\n readonly d1ActiveStatusValue?: unknown;\n}\n\nexport interface PasswordIdentifierTable<\n Identifier extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: Identifier[\"table\"];\n readonly namespace: ColumnKey<Identifier>;\n readonly value: ColumnKey<Identifier>;\n readonly subjectId: ColumnKey<Identifier>;\n readonly verifiedAt: ColumnKey<Identifier>;\n readonly bindingRevision: ColumnKey<Identifier>;\n /** Consumer-owned current login/recovery eligibility, including row status. */\n readonly isCurrent: (row: Identifier[\"select\"]) => boolean;\n /** Required by D1 so current ownership/eligibility is rechecked in the batch. */\n readonly d1CurrentCondition?: (input: {\n readonly identifier: LoginIdentifier;\n readonly nativeSubjectId: NativeSubjectId;\n }) => Expression;\n readonly encodeInitialInsert: (\n identifier: LoginIdentifier,\n subjectId: NativeSubjectId,\n bindingRevision: SecurityRevision,\n ) => Identifier[\"insert\"];\n}\n\nexport interface PasswordAuthorityCredentialTable<Credential extends Table, NativeSubjectId> {\n readonly table: Credential[\"table\"];\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly revision: ColumnKey<Credential>;\n readonly status?: ColumnKey<Credential>;\n readonly isActiveStatus?: (value: unknown) => boolean;\n readonly d1ActiveStatusValue?: unknown;\n readonly encodeInsert: (input: {\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n }) => Credential[\"insert\"];\n readonly encodeRevision: (revision: SecurityRevision) => Partial<Credential[\"insert\"]>;\n}\n\nexport interface PasswordCredentialTable<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n NativeSubjectId,\n> {\n readonly table: Credential[\"table\"];\n readonly moduleId: ColumnKey<Credential>;\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly credentialRevision: ColumnKey<Credential>;\n readonly verifierVersion: ColumnKey<Credential>;\n readonly verifier: ColumnKey<Credential>;\n readonly normalization: ColumnKey<Credential>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n readonly replacement: PasswordReplacement;\n }) => Credential[\"insert\"];\n readonly encodeVerifier: (\n verifier: Redacted.Redacted<EncodedPasswordHash>,\n verifierVersion: SecurityRevision,\n ) => Partial<Credential[\"insert\"]>;\n readonly encodeReplacement: (input: {\n readonly replacement: PasswordReplacement;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n }) => Partial<Credential[\"insert\"]>;\n readonly decode: (input: {\n readonly moduleId: string;\n readonly subject: Subject[\"select\"];\n readonly identifier: Identifier[\"select\"];\n readonly credential: Credential[\"select\"];\n }) => Effect.Effect<PasswordCredentialSnapshot, PersistenceMappingError>;\n}\n\nexport interface RequiredPasswordConstraints {\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly credentialId: \"unique(credential.moduleId,credential.credentialId)\";\n}\n\nexport const requiredPasswordConstraints: RequiredPasswordConstraints = {\n identifier: \"unique(identifier.namespace,identifier.value)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n credentialId: \"unique(credential.moduleId,credential.credentialId)\",\n};\n\nexport interface PasswordPersistenceMapping<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n /** Every factor revision named by action evidence, including non-password factors. */\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordConstraints;\n readonly encodeInstant: (epochMillis: number) => unknown;\n readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n /** All semantic replacements still bump subject revision. This flag declares\n * authoritative verification's invalidation latency; cookie exposure is separate. */\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n readonly clock: ProofClock<Expression>;\n readonly d1?: { readonly primary: true };\n}\n\nexport interface PasswordRegistrationIntent<Registration> {\n readonly moduleId: string;\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: Registration;\n readonly replacement: PasswordReplacement;\n}\n\nexport interface PasswordRegistrationProvisioning<\n Registration,\n Subject extends Table,\n NativeSubjectId,\n> {\n readonly encodeSubjectInsert: (\n input: PasswordRegistrationIntent<Registration>,\n values: {\n readonly nativeSubjectId: NativeSubjectId | undefined;\n readonly securityRevision: SecurityRevision;\n },\n ) => Subject[\"insert\"];\n readonly allocateSubjectId?: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n readonly allocateSubjectIdSync?: () => NativeSubjectId;\n /** Interactive targets use this for database-generated/autoincrement keys. */\n readonly decodeGeneratedId?: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n}\n\nexport interface RequiredPasswordRegistrationConstraints {\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n}\n\nexport const requiredPasswordRegistrationConstraints: RequiredPasswordRegistrationConstraints = {\n identifier: \"unique(identifier.namespace,identifier.value)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n};\n\nexport interface PasswordRegistrationConstraintClassifier {\n readonly isIdentifierConflict: (cause: unknown) => boolean;\n readonly isCredentialConflict: (cause: unknown) => boolean;\n}\n\nexport type PasswordRegistrationMapping<\n Registration,\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationConstraintClassifier & {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordRegistrationConstraints;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n} & {\n readonly mode: \"atomic\";\n readonly provisioning: PasswordRegistrationProvisioning<Registration, Subject, NativeSubjectId> &\n (\n | {\n readonly idMode: \"allocated\";\n readonly allocateSubjectId: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n | {\n readonly idMode: \"synchronous\";\n readonly allocateSubjectIdSync: () => NativeSubjectId;\n }\n | {\n readonly idMode: \"generated\";\n readonly decodeGeneratedId: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n );\n};\n\nexport type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> =\n PasswordPersistenceMapping<\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n >;\n\nexport type AnyPasswordRegistrationMapping<\n Registration = unknown,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationMapping<\n Registration,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n>;\n"],"mappings":";;AA6HA,MAAa,8BAA2D;CACtE,YAAY;CACZ,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;AAChB;AAmEA,MAAa,0CAAmF;CAC9F,YAAY;CACZ,mBAAmB;CACnB,qBAAqB;AACvB"}
1
+ {"version":3,"file":"password-model.mjs","names":[],"sources":["../../../src/internal/models/password-model.ts"],"sourcesContent":["import { type LoginIdentifier } from \"@yielded/auth/Identity\";\nimport type {\n PasswordAction,\n PasswordCredentialSnapshot,\n PasswordReplacement,\n EncodedPasswordHash,\n} from \"@yielded/auth/Password\";\nimport type { AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport type { Effect, Redacted } from \"effect\";\n\nimport type { AnyTableModel, TableModel as Table, SqlExpression } from \"../table-model\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\nimport type { ProofClock } from \"./proof-model\";\n\ntype ColumnKey<T extends Table> = T[\"column\"];\n\nexport interface PasswordSubjectTable<Subject extends Table, _NativeSubjectId> {\n readonly table: Subject[\"table\"];\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly securityRevision: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly decodeRequirement: (\n row: Subject[\"select\"],\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n /** Current policy for this exact credential mutation. Interactive drivers hold\n * the subject lock; D1 guards the physical application columns through commit. */\n readonly decodeActionRequirement: (\n row: Subject[\"select\"],\n action: PasswordAction,\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n readonly nextSecurityRevision?: (\n current: SecurityRevision,\n ) => Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;\n /** Required only by D1 conditional statements. */\n readonly d1ActiveStatusValue?: unknown;\n}\n\nexport interface PasswordIdentifierTable<\n Identifier extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: Identifier[\"table\"];\n readonly namespace: ColumnKey<Identifier>;\n readonly value: ColumnKey<Identifier>;\n readonly subjectId: ColumnKey<Identifier>;\n readonly verifiedAt: ColumnKey<Identifier>;\n readonly bindingRevision: ColumnKey<Identifier>;\n /** Consumer-owned current login/recovery eligibility, including row status. */\n readonly isCurrent: (row: Identifier[\"select\"]) => boolean;\n /** Required by D1 so current ownership/eligibility is rechecked in the batch. */\n readonly d1CurrentCondition?: (input: {\n readonly identifier: LoginIdentifier;\n readonly nativeSubjectId: NativeSubjectId;\n }) => Expression;\n readonly encodeInitialInsert: (\n identifier: LoginIdentifier,\n subjectId: NativeSubjectId,\n bindingRevision: SecurityRevision,\n ) => Identifier[\"insert\"];\n}\n\nexport interface PasswordAuthorityCredentialTable<Credential extends Table, NativeSubjectId> {\n readonly table: Credential[\"table\"];\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly revision: ColumnKey<Credential>;\n readonly status?: ColumnKey<Credential>;\n readonly isActiveStatus?: (value: unknown) => boolean;\n readonly d1ActiveStatusValue?: unknown;\n readonly encodeInsert: (input: {\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n }) => Credential[\"insert\"];\n readonly encodeRevision: (revision: SecurityRevision) => Partial<Credential[\"insert\"]>;\n}\n\nexport interface PasswordCredentialTable<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n NativeSubjectId,\n> {\n readonly table: Credential[\"table\"];\n readonly moduleId: ColumnKey<Credential>;\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly credentialRevision: ColumnKey<Credential>;\n readonly verifierVersion: ColumnKey<Credential>;\n readonly verifier: ColumnKey<Credential>;\n readonly normalization: ColumnKey<Credential>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n readonly replacement: PasswordReplacement;\n }) => Credential[\"insert\"];\n readonly encodeVerifier: (\n verifier: Redacted.Redacted<EncodedPasswordHash>,\n verifierVersion: SecurityRevision,\n ) => Partial<Credential[\"insert\"]>;\n readonly encodeReplacement: (input: {\n readonly replacement: PasswordReplacement;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n }) => Partial<Credential[\"insert\"]>;\n readonly decode: (input: {\n readonly moduleId: string;\n readonly subject: Subject[\"select\"];\n readonly identifier: Identifier[\"select\"];\n readonly credential: Credential[\"select\"];\n }) => Effect.Effect<PasswordCredentialSnapshot, PersistenceMappingError>;\n}\n\nexport interface RequiredPasswordConstraints {\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly credentialId: \"unique(credential.moduleId,credential.credentialId)\";\n}\n\nexport const requiredPasswordConstraints: RequiredPasswordConstraints = {\n identifier: \"unique(identifier.namespace,identifier.value)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n credentialId: \"unique(credential.moduleId,credential.credentialId)\",\n};\n\nexport interface PasswordPersistenceMapping<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n /** Every factor revision named by action evidence, including non-password factors. */\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordConstraints;\n readonly encodeInstant: (epochMillis: number) => unknown;\n readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n /** All semantic replacements still bump subject revision. This flag declares\n * authoritative verification's invalidation latency; cookie exposure is separate. */\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n readonly clock: ProofClock<Expression>;\n readonly d1?: { readonly primary: true };\n}\n\nexport interface PasswordRegistrationIntent<Registration> {\n readonly moduleId: string;\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: Registration;\n readonly replacement: PasswordReplacement;\n}\n\nexport interface PasswordRegistrationProvisioning<\n Registration,\n Subject extends Table,\n NativeSubjectId,\n> {\n readonly encodeSubjectInsert: (\n input: PasswordRegistrationIntent<Registration>,\n values: {\n readonly nativeSubjectId: NativeSubjectId | undefined;\n readonly securityRevision: SecurityRevision;\n },\n ) => Subject[\"insert\"];\n readonly allocateSubjectId?: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n readonly allocateSubjectIdSync?: () => NativeSubjectId;\n /** Interactive targets use this for database-generated/autoincrement keys. */\n readonly decodeGeneratedId?: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n}\n\nexport interface RequiredPasswordRegistrationConstraints {\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n}\n\nexport const requiredPasswordRegistrationConstraints: RequiredPasswordRegistrationConstraints = {\n identifier: \"unique(identifier.namespace,identifier.value)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n};\n\nexport interface PasswordRegistrationConstraintClassifier {\n readonly isIdentifierConflict: (cause: unknown) => boolean;\n readonly isCredentialConflict: (cause: unknown) => boolean;\n}\n\nexport type PasswordRegistrationMapping<\n Registration,\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationConstraintClassifier & {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordRegistrationConstraints;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n} & {\n readonly mode: \"atomic\";\n readonly provisioning: PasswordRegistrationProvisioning<Registration, Subject, NativeSubjectId> &\n (\n | {\n readonly idMode: \"allocated\";\n readonly allocateSubjectId: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n | {\n readonly idMode: \"synchronous\";\n readonly allocateSubjectIdSync: () => NativeSubjectId;\n }\n | {\n readonly idMode: \"generated\";\n readonly decodeGeneratedId: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n );\n};\n\nexport type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> =\n PasswordPersistenceMapping<\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n >;\n\nexport type AnyPasswordRegistrationMapping<\n Registration = unknown,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationMapping<\n Registration,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n>;\n"],"mappings":";;AA8HA,MAAa,8BAA2D;CACtE,YAAY;CACZ,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;AAChB;AAmEA,MAAa,0CAAmF;CAC9F,YAAY;CACZ,mBAAmB;CACnB,qBAAqB;AACvB"}
@@ -1,4 +1,4 @@
1
- import { anySqlCondition, exactSqlText } from "../sql-change.mjs";
1
+ import { anySqlCondition, exactSqlText, sqlTextBytes } from "../sql-change.mjs";
2
2
  import { CurrentSqlCommit, SqlBatchCommit, makeSqlCommitExecutor } from "../sql-commit.mjs";
3
3
  import { makeConditionalSqlInsert } from "../session-native-record.mjs";
4
4
  import { OAuthEligibilityFact } from "../models/oauth-model.mjs";
@@ -35,6 +35,47 @@ const makeNativeOAuthAccountsServices = Effect.fnUntraced(function* (tables, map
35
35
  tables.expression(c.activeCondition)
36
36
  ]);
37
37
  return { oauthAccountsPersistence: {
38
+ list: (original) => read(Effect.gen(function* () {
39
+ const input = M.snapshotOAuthSync(M.OAuthLinkedAccountsRead, original);
40
+ const nativeId = yield* mapping.subjectId.toNative(input.invocation.subjectId);
41
+ const metadataAccess = tables.expression(mapping.metadataAccess({
42
+ invocation: input.invocation,
43
+ moduleId: input.moduleId,
44
+ subjectId: nativeId
45
+ }));
46
+ const s = mapping.subject;
47
+ const orderedId = yield* sqlTextBytes(credential.column(c.credentialId));
48
+ const cursorCondition = input.cursor === void 0 ? sql`` : sql`and ${orderedId} > ${yield* sqlTextBytes(credential.value(c.credentialId, input.cursor))}`;
49
+ const rows = yield* sql`select ${credential.fields("page_")} from ${credential.name}
50
+ where ${exactSqlText(sql, credential.column(c.moduleId), credential.value(c.moduleId, input.moduleId))}
51
+ and ${credential.column(c.subjectId)} = ${credential.value(c.subjectId, nativeId)}
52
+ and ${tables.expression(c.activeCondition)} and ${metadataAccess}
53
+ and exists(select 1 from ${state.subject.name}
54
+ where ${state.subject.column(s.id)} = ${state.subject.value(s.id, nativeId)}
55
+ and ${tables.expression(s.activeCondition)})
56
+ ${cursorCondition}
57
+ order by ${orderedId} limit ${input.limit + 1}`;
58
+ const selected = rows.slice(0, input.limit);
59
+ const items = [];
60
+ let cursor;
61
+ for (const row of selected) {
62
+ const credentialId = yield* Schema.decodeUnknownEffect(M.OAuthLinkedAccount.fields.credentialId)(credential.decode(row, "page_")[c.credentialId]);
63
+ cursor = credentialId;
64
+ const current = yield* state.readCredential({
65
+ moduleId: input.moduleId,
66
+ subjectId: input.invocation.subjectId,
67
+ credentialId
68
+ }, metadataAccess);
69
+ if (current !== void 0) items.push(M.OAuthLinkedAccount.make({
70
+ credentialId: current.credentialId,
71
+ ...current.identity
72
+ }));
73
+ }
74
+ return M.snapshotOAuthSync(M.OAuthLinkedAccountsListResult, {
75
+ items,
76
+ ...rows.length > input.limit && cursor !== void 0 ? { cursor } : {}
77
+ });
78
+ })),
38
79
  capture: (input) => read(Effect.map(state.capture(input.subjectId, false), (current) => current?.revision)),
39
80
  issue: (original, prepare) => run(Effect.gen(function* () {
40
81
  const input = M.snapshotOAuthSync(M.OAuthLinkFlow, original);
@@ -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 } 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 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 { 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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"}
@@ -4,6 +4,7 @@ import "../native-sql-table.mjs";
4
4
  import { OAuthSignInMapping } from "../models/oauth-model.mjs";
5
5
  import { Effect, Schema } from "effect";
6
6
  import { SqlClient } from "effect/sql";
7
+ import { Fragment } from "effect/sql/Statement";
7
8
  //#region src/internal/oauth/native-state.d.ts
8
9
  export type OAuthNativeReadMapping = OAuthSignInMapping<TableModel, TableModel, TableModel, TableModel, TableModel, unknown, SqlExpression>;
9
10
  //#endregion
@@ -174,7 +174,7 @@ const makeOAuthNativeState = Effect.fnUntraced(function* (tables, mapping) {
174
174
  if (result !== void 0) invariant(result.identity.provider === identity.provider && result.identity.issuer === identity.issuer && result.identity.subject === identity.subject);
175
175
  return result;
176
176
  });
177
- const readCredential = Effect.fnUntraced(function* (input) {
177
+ const readCredential = Effect.fnUntraced(function* (input, metadataAccess = sql`true`) {
178
178
  const nativeId = yield* mapping.subjectId.toNative(input.subjectId);
179
179
  let identityKey;
180
180
  const direct = credential.unencodedTextColumn?.(mapping.credential.identityKey) !== void 0 && ownership.unencodedTextColumn?.(mapping.ownership.identityKey) !== void 0;
@@ -194,7 +194,7 @@ const makeOAuthNativeState = Effect.fnUntraced(function* (tables, mapping) {
194
194
  and ${owner(o, mapping.ownership.subjectId)}
195
195
  join ${active("subject", "oauth_subject")} on ${owner(s, mapping.subject.id)}
196
196
  join ${active("authority", "oauth_authority")} on ${owner(a, mapping.authority.subjectId)}
197
- where ${owner(c, mapping.credential.subjectId)}
197
+ where ${metadataAccess} and ${owner(c, mapping.credential.subjectId)}
198
198
  and ${exact(c.column(mapping.credential.moduleId), c.value(mapping.credential.moduleId, input.moduleId))}
199
199
  and ${exact(c.column(mapping.credential.credentialId), c.value(mapping.credential.credentialId, input.credentialId))}
200
200
  order by ${a.column(mapping.authority.credentialId)} limit 65`;
@@ -1 +1 @@
1
- {"version":3,"file":"native-state.mjs","names":[],"sources":["../../../src/internal/oauth/native-state.ts"],"sourcesContent":["import {\n OAuthAccountRevision,\n OAuthCredentialSnapshot,\n OAuthExternalIdentity,\n type OAuthCredentialKey,\n} from \"@yielded/auth/OAuth\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport { Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport type { OAuthSignInMapping } from \"../models/oauth-model\";\nimport type { NativeSqlTables } from \"../native-sql-table\";\nimport { exactSqlText } from \"../sql-change\";\nimport type { SqlExpression, TableModel } from \"../table-model\";\nimport { invariant, oauthIdentityKey } from \"./state\";\n\n// Expression handles are checked by the physical compiler, not domain codecs.\nexport type OAuthNativeReadMapping = OAuthSignInMapping<\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n unknown,\n SqlExpression\n>;\n\ntype Row = Readonly<Record<string, unknown>>;\n\n/** Unlocked snapshots and explicit subject-first reads share decoding rules.\n * No observation registry or discovered-identity placeholder is retained. */\nexport const makeOAuthNativeAuthority = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: Pick<OAuthNativeReadMapping, \"subject\" | \"authority\" | \"subjectId\" | \"clock\">,\n) {\n const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n const subject = tables(mapping.subject.table);\n const authority = tables(mapping.authority.table);\n const s = subject.as(\"oauth_subject\");\n const a = authority.as(\"oauth_authority\");\n const now = tables.expression(mapping.clock.engineNowMillis);\n\n const lock = sql.onDialectOrElse({\n pg: () => sql`for update`,\n mysql: () => sql`for update`,\n orElse: () => sql``,\n });\n\n const active = (kind: \"subject\" | \"authority\", alias: string) => {\n const descriptor = mapping[kind];\n const physical = tables(descriptor.table);\n\n return sql`(select * from ${physical.name} where ${tables.expression(descriptor.activeCondition)}) as ${sql(alias)}`;\n };\n\n const revision = Effect.fnUntraced(function* (\n subjectRow: Row,\n factors: ReadonlyArray<Row>,\n nativeId: unknown,\n ) {\n invariant(mapping.subject.isActiveStatus(subjectRow[mapping.subject.status]));\n invariant(mapping.subjectId.equals(subjectRow[mapping.subject.id], nativeId));\n invariant(factors.length > 0 && factors.length <= 64);\n invariant(\n factors.every(\n (row) =>\n mapping.subjectId.equals(row[mapping.authority.subjectId], nativeId) &&\n mapping.authority.isActiveStatus(row[mapping.authority.status]),\n ),\n );\n\n const credentials = factors.map((row) => ({\n credentialId: row[mapping.authority.credentialId],\n revision: row[mapping.authority.revision],\n }));\n\n invariant(new Set(credentials.map((item) => item.credentialId)).size === credentials.length);\n\n const value = yield* Schema.decodeUnknownEffect(Schema.toType(OAuthAccountRevision))({\n subjectId: yield* mapping.subjectId.toSubject(nativeId),\n securityRevision: subjectRow[mapping.subject.securityRevision],\n credentials,\n });\n\n return {\n ...value,\n credentials: [...value.credentials].sort((left, right) =>\n left.credentialId.localeCompare(right.credentialId),\n ),\n };\n });\n\n const captureSubject = Effect.fnUntraced(function* (subjectId: SubjectId, locking: boolean) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const rows =\n yield* sql`select ${subject.fields(\"s_\")}, ${now} as engine_now from ${subject.name} where ${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, nativeId)} and ${tables.expression(mapping.subject.activeCondition)} limit 2 ${locking ? lock : sql``}`;\n\n invariant(rows.length <= 1);\n if (rows[0] === undefined) return undefined;\n const row = subject.decode(rows[0], \"s_\");\n\n invariant(mapping.subjectId.equals(row[mapping.subject.id], nativeId));\n\n return {\n nativeId,\n subject: row,\n securityRevision: yield* Schema.decodeUnknownEffect(\n OAuthAccountRevision.fields.securityRevision,\n )(row[mapping.subject.securityRevision]),\n now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0].engine_now)),\n };\n });\n\n const capture = Effect.fnUntraced(function* (subjectId: SubjectId, locking: boolean) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n if (locking) {\n // Never acquire a credential, identity, flow or policy lock before this.\n const subjects =\n yield* sql`select ${subject.fields(\"s_\")}, ${now} as engine_now from ${subject.name}\n where ${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, nativeId)}\n and ${tables.expression(mapping.subject.activeCondition)} ${lock}`;\n\n if (subjects.length === 0) return undefined;\n invariant(subjects.length === 1);\n const subjectRow = subject.decode(subjects[0]!, \"s_\");\n\n const factors = yield* sql`select ${authority.fields(\"a_\")} from ${authority.name}\n where ${authority.column(mapping.authority.subjectId)} = ${authority.value(mapping.authority.subjectId, nativeId)}\n and ${tables.expression(mapping.authority.activeCondition)}\n order by ${authority.column(mapping.authority.credentialId)} limit 65 ${lock}`;\n\n if (factors.length === 0) return undefined;\n\n return {\n nativeId,\n subject: subjectRow,\n revision: yield* revision(\n subjectRow,\n factors.map((row) => authority.decode(row, \"a_\")),\n nativeId,\n ),\n now: yield* Schema.decodeEffect(Schema.Int)(Number(subjects[0]!.engine_now)),\n };\n }\n\n // Bind each column's own native codec; the columns need not share an encoding.\n const rows = yield* sql`select ${s.fields(\"s_\")}, ${a.fields(\"a_\")}, ${now} as engine_now\n from ${active(\"subject\", \"oauth_subject\")}\n join ${active(\"authority\", \"oauth_authority\")} on\n ${a.column(mapping.authority.subjectId)} = ${a.value(mapping.authority.subjectId, nativeId)}\n where ${s.column(mapping.subject.id)} = ${s.value(mapping.subject.id, nativeId)}\n order by ${a.column(mapping.authority.credentialId)} limit 65`;\n\n if (rows.length === 0) return undefined;\n const subjectRow = s.decode(rows[0]!, \"s_\");\n\n return {\n nativeId,\n subject: subjectRow,\n revision: yield* revision(\n subjectRow,\n rows.map((row) => a.decode(row, \"a_\")),\n nativeId,\n ),\n now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0]!.engine_now)),\n };\n });\n\n return { sql, now, lock, subject, authority, capture, captureSubject, revision };\n});\n\nexport const makeOAuthNativeState = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: OAuthNativeReadMapping,\n) {\n const state = yield* makeOAuthNativeAuthority(tables, mapping);\n const { sql, subject, authority, revision } = state;\n const ownership = tables(mapping.ownership.table);\n const credential = tables(mapping.credential.table);\n const s = subject.as(\"oauth_subject\");\n const o = ownership.as(\"oauth_identity\");\n const c = credential.as(\"oauth_credential\");\n const a = authority.as(\"oauth_authority\");\n\n const exact = (\n left: Parameters<typeof exactSqlText>[1],\n right: Parameters<typeof exactSqlText>[2],\n ) => exactSqlText(sql, left, right);\n\n const active = (kind: \"subject\" | \"credential\" | \"authority\", alias: string) => {\n const descriptor = mapping[kind];\n const physical = tables(descriptor.table);\n\n return sql`(select * from ${physical.name} where ${tables.expression(descriptor.activeCondition)}) as ${sql(alias)}`;\n };\n\n const joinedIds =\n ownership.unencodedTextColumn?.(mapping.ownership.subjectId) !== undefined &&\n subject.unencodedTextColumn?.(mapping.subject.id) !== undefined &&\n credential.unencodedTextColumn?.(mapping.credential.subjectId) !== undefined &&\n authority.unencodedTextColumn?.(mapping.authority.subjectId) !== undefined;\n\n const decodeSnapshot = Effect.fnUntraced(function* (\n rows: ReadonlyArray<Row>,\n moduleId: string,\n nativeId?: unknown,\n ) {\n if (rows.length === 0) return undefined;\n const owned = o.decode(rows[0]!, \"o_\");\n\n const identity = yield* Schema.decodeUnknownEffect(OAuthExternalIdentity)({\n provider: owned[mapping.ownership.provider],\n issuer: owned[mapping.ownership.issuer],\n subject: owned[mapping.ownership.externalSubject],\n });\n\n const identityKey = yield* oauthIdentityKey(identity);\n\n invariant(owned[mapping.ownership.identityKey] === identityKey);\n const ownerId = mapping.ownership.decodeSubjectId(owned);\n\n if (nativeId !== undefined) invariant(mapping.subjectId.equals(ownerId, nativeId));\n const login = c.decode(rows[0]!, \"c_\");\n\n invariant(mapping.subjectId.equals(login[mapping.credential.subjectId], ownerId));\n invariant(login[mapping.credential.identityKey] === identityKey);\n invariant(mapping.credential.isActiveStatus(login[mapping.credential.status]));\n\n const current = yield* revision(\n s.decode(rows[0]!, \"s_\"),\n rows.map((row) => a.decode(row, \"a_\")),\n ownerId,\n );\n\n const credentialId = login[mapping.credential.credentialId];\n const credentialRevision = login[mapping.credential.credentialRevision];\n\n if (\n !current.credentials.some(\n (item) => item.credentialId === credentialId && item.revision === credentialRevision,\n )\n )\n return undefined;\n\n return yield* Schema.decodeUnknownEffect(Schema.toType(OAuthCredentialSnapshot))({\n moduleId,\n identity,\n credentialId,\n credentialRevision,\n revision: current,\n requirement: mapping.subject.decodeAuthenticationRequirement(s.decode(rows[0]!, \"s_\")),\n });\n });\n\n const resolve = Effect.fnUntraced(function* (\n moduleId: string,\n identity: typeof OAuthExternalIdentity.Type,\n ) {\n const identityKey = yield* oauthIdentityKey(identity);\n let nativeId: unknown;\n\n if (!joinedIds) {\n const found = yield* sql`select ${ownership.fields(\"o_\")} from ${ownership.name}\n where ${exact(ownership.column(mapping.ownership.identityKey), ownership.value(mapping.ownership.identityKey, identityKey))}`;\n\n if (found.length === 0) return undefined;\n invariant(found.length === 1);\n const row = ownership.decode(found[0]!, \"o_\");\n\n invariant(\n row[mapping.ownership.provider] === identity.provider &&\n row[mapping.ownership.issuer] === identity.issuer &&\n row[mapping.ownership.externalSubject] === identity.subject,\n );\n nativeId = mapping.ownership.decodeSubjectId(row);\n }\n\n const bindOwner = (table: typeof s, key: string) =>\n joinedIds\n ? exact(table.column(key), o.column(mapping.ownership.subjectId))\n : sql`${table.column(key)} = ${table.value(key, nativeId)}`;\n\n const rows =\n yield* sql`select ${o.fields(\"o_\")}, ${s.fields(\"s_\")}, ${c.fields(\"c_\")}, ${a.fields(\"a_\")}\n from ${o.name}\n join ${active(\"subject\", \"oauth_subject\")} on ${bindOwner(s, mapping.subject.id)}\n join ${active(\"credential\", \"oauth_credential\")} on ${bindOwner(c, mapping.credential.subjectId)}\n and ${exact(c.column(mapping.credential.moduleId), c.value(mapping.credential.moduleId, moduleId))}\n and ${exact(c.column(mapping.credential.identityKey), c.value(mapping.credential.identityKey, identityKey))}\n join ${active(\"authority\", \"oauth_authority\")} on ${bindOwner(a, mapping.authority.subjectId)}\n where ${exact(o.column(mapping.ownership.identityKey), o.value(mapping.ownership.identityKey, identityKey))}\n order by ${a.column(mapping.authority.credentialId)} limit 65`;\n\n const result = yield* decodeSnapshot(rows, moduleId, joinedIds ? undefined : nativeId);\n\n if (result !== undefined)\n invariant(\n result.identity.provider === identity.provider &&\n result.identity.issuer === identity.issuer &&\n result.identity.subject === identity.subject,\n );\n\n return result;\n });\n\n const readCredential = Effect.fnUntraced(function* (input: typeof OAuthCredentialKey.Type) {\n const nativeId = yield* mapping.subjectId.toNative(input.subjectId);\n let identityKey: unknown;\n\n const direct =\n credential.unencodedTextColumn?.(mapping.credential.identityKey) !== undefined &&\n ownership.unencodedTextColumn?.(mapping.ownership.identityKey) !== undefined;\n\n if (!direct) {\n const selected = yield* sql`select ${credential.fields(\"c_\")} from ${credential.name}\n where ${exact(credential.column(mapping.credential.moduleId), credential.value(mapping.credential.moduleId, input.moduleId))}\n and ${exact(credential.column(mapping.credential.credentialId), credential.value(mapping.credential.credentialId, input.credentialId))}\n and ${credential.column(mapping.credential.subjectId)} = ${credential.value(mapping.credential.subjectId, nativeId)}`;\n\n if (selected.length === 0) return undefined;\n invariant(selected.length === 1);\n identityKey = credential.decode(selected[0]!, \"c_\")[mapping.credential.identityKey];\n }\n\n const owner = (table: typeof s, key: string) =>\n sql`${table.column(key)} = ${table.value(key, nativeId)}`;\n\n const rows =\n yield* sql`select ${o.fields(\"o_\")}, ${s.fields(\"s_\")}, ${c.fields(\"c_\")}, ${a.fields(\"a_\")}\n from ${active(\"credential\", \"oauth_credential\")}\n join ${o.name} on ${direct ? exact(o.column(mapping.ownership.identityKey), c.column(mapping.credential.identityKey)) : exact(o.column(mapping.ownership.identityKey), o.value(mapping.ownership.identityKey, identityKey))}\n and ${owner(o, mapping.ownership.subjectId)}\n join ${active(\"subject\", \"oauth_subject\")} on ${owner(s, mapping.subject.id)}\n join ${active(\"authority\", \"oauth_authority\")} on ${owner(a, mapping.authority.subjectId)}\n where ${owner(c, mapping.credential.subjectId)}\n and ${exact(c.column(mapping.credential.moduleId), c.value(mapping.credential.moduleId, input.moduleId))}\n and ${exact(c.column(mapping.credential.credentialId), c.value(mapping.credential.credentialId, input.credentialId))}\n order by ${a.column(mapping.authority.credentialId)} limit 65`;\n\n return yield* decodeSnapshot(rows, input.moduleId, nativeId);\n });\n\n return { ...state, ownership, credential, resolve, readCredential };\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"native-state.mjs","names":[],"sources":["../../../src/internal/oauth/native-state.ts"],"sourcesContent":["import {\n OAuthAccountRevision,\n OAuthCredentialSnapshot,\n OAuthExternalIdentity,\n type OAuthCredentialKey,\n} from \"@yielded/auth/OAuth\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport { Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport type { OAuthSignInMapping } from \"../models/oauth-model\";\nimport type { NativeSqlTables } from \"../native-sql-table\";\nimport { exactSqlText } from \"../sql-change\";\nimport type { SqlExpression, TableModel } from \"../table-model\";\nimport { invariant, oauthIdentityKey } from \"./state\";\n\n// Expression handles are checked by the physical compiler, not domain codecs.\nexport type OAuthNativeReadMapping = OAuthSignInMapping<\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n unknown,\n SqlExpression\n>;\n\ntype Row = Readonly<Record<string, unknown>>;\n\n/** Unlocked snapshots and explicit subject-first reads share decoding rules.\n * No observation registry or discovered-identity placeholder is retained. */\nexport const makeOAuthNativeAuthority = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: Pick<OAuthNativeReadMapping, \"subject\" | \"authority\" | \"subjectId\" | \"clock\">,\n) {\n const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n const subject = tables(mapping.subject.table);\n const authority = tables(mapping.authority.table);\n const s = subject.as(\"oauth_subject\");\n const a = authority.as(\"oauth_authority\");\n const now = tables.expression(mapping.clock.engineNowMillis);\n\n const lock = sql.onDialectOrElse({\n pg: () => sql`for update`,\n mysql: () => sql`for update`,\n orElse: () => sql``,\n });\n\n const active = (kind: \"subject\" | \"authority\", alias: string) => {\n const descriptor = mapping[kind];\n const physical = tables(descriptor.table);\n\n return sql`(select * from ${physical.name} where ${tables.expression(descriptor.activeCondition)}) as ${sql(alias)}`;\n };\n\n const revision = Effect.fnUntraced(function* (\n subjectRow: Row,\n factors: ReadonlyArray<Row>,\n nativeId: unknown,\n ) {\n invariant(mapping.subject.isActiveStatus(subjectRow[mapping.subject.status]));\n invariant(mapping.subjectId.equals(subjectRow[mapping.subject.id], nativeId));\n invariant(factors.length > 0 && factors.length <= 64);\n invariant(\n factors.every(\n (row) =>\n mapping.subjectId.equals(row[mapping.authority.subjectId], nativeId) &&\n mapping.authority.isActiveStatus(row[mapping.authority.status]),\n ),\n );\n\n const credentials = factors.map((row) => ({\n credentialId: row[mapping.authority.credentialId],\n revision: row[mapping.authority.revision],\n }));\n\n invariant(new Set(credentials.map((item) => item.credentialId)).size === credentials.length);\n\n const value = yield* Schema.decodeUnknownEffect(Schema.toType(OAuthAccountRevision))({\n subjectId: yield* mapping.subjectId.toSubject(nativeId),\n securityRevision: subjectRow[mapping.subject.securityRevision],\n credentials,\n });\n\n return {\n ...value,\n credentials: [...value.credentials].sort((left, right) =>\n left.credentialId.localeCompare(right.credentialId),\n ),\n };\n });\n\n const captureSubject = Effect.fnUntraced(function* (subjectId: SubjectId, locking: boolean) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const rows =\n yield* sql`select ${subject.fields(\"s_\")}, ${now} as engine_now from ${subject.name} where ${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, nativeId)} and ${tables.expression(mapping.subject.activeCondition)} limit 2 ${locking ? lock : sql``}`;\n\n invariant(rows.length <= 1);\n if (rows[0] === undefined) return undefined;\n const row = subject.decode(rows[0], \"s_\");\n\n invariant(mapping.subjectId.equals(row[mapping.subject.id], nativeId));\n\n return {\n nativeId,\n subject: row,\n securityRevision: yield* Schema.decodeUnknownEffect(\n OAuthAccountRevision.fields.securityRevision,\n )(row[mapping.subject.securityRevision]),\n now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0].engine_now)),\n };\n });\n\n const capture = Effect.fnUntraced(function* (subjectId: SubjectId, locking: boolean) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n if (locking) {\n // Never acquire a credential, identity, flow or policy lock before this.\n const subjects =\n yield* sql`select ${subject.fields(\"s_\")}, ${now} as engine_now from ${subject.name}\n where ${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, nativeId)}\n and ${tables.expression(mapping.subject.activeCondition)} ${lock}`;\n\n if (subjects.length === 0) return undefined;\n invariant(subjects.length === 1);\n const subjectRow = subject.decode(subjects[0]!, \"s_\");\n\n const factors = yield* sql`select ${authority.fields(\"a_\")} from ${authority.name}\n where ${authority.column(mapping.authority.subjectId)} = ${authority.value(mapping.authority.subjectId, nativeId)}\n and ${tables.expression(mapping.authority.activeCondition)}\n order by ${authority.column(mapping.authority.credentialId)} limit 65 ${lock}`;\n\n if (factors.length === 0) return undefined;\n\n return {\n nativeId,\n subject: subjectRow,\n revision: yield* revision(\n subjectRow,\n factors.map((row) => authority.decode(row, \"a_\")),\n nativeId,\n ),\n now: yield* Schema.decodeEffect(Schema.Int)(Number(subjects[0]!.engine_now)),\n };\n }\n\n // Bind each column's own native codec; the columns need not share an encoding.\n const rows = yield* sql`select ${s.fields(\"s_\")}, ${a.fields(\"a_\")}, ${now} as engine_now\n from ${active(\"subject\", \"oauth_subject\")}\n join ${active(\"authority\", \"oauth_authority\")} on\n ${a.column(mapping.authority.subjectId)} = ${a.value(mapping.authority.subjectId, nativeId)}\n where ${s.column(mapping.subject.id)} = ${s.value(mapping.subject.id, nativeId)}\n order by ${a.column(mapping.authority.credentialId)} limit 65`;\n\n if (rows.length === 0) return undefined;\n const subjectRow = s.decode(rows[0]!, \"s_\");\n\n return {\n nativeId,\n subject: subjectRow,\n revision: yield* revision(\n subjectRow,\n rows.map((row) => a.decode(row, \"a_\")),\n nativeId,\n ),\n now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0]!.engine_now)),\n };\n });\n\n return { sql, now, lock, subject, authority, capture, captureSubject, revision };\n});\n\nexport const makeOAuthNativeState = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: OAuthNativeReadMapping,\n) {\n const state = yield* makeOAuthNativeAuthority(tables, mapping);\n const { sql, subject, authority, revision } = state;\n const ownership = tables(mapping.ownership.table);\n const credential = tables(mapping.credential.table);\n const s = subject.as(\"oauth_subject\");\n const o = ownership.as(\"oauth_identity\");\n const c = credential.as(\"oauth_credential\");\n const a = authority.as(\"oauth_authority\");\n\n const exact = (\n left: Parameters<typeof exactSqlText>[1],\n right: Parameters<typeof exactSqlText>[2],\n ) => exactSqlText(sql, left, right);\n\n const active = (kind: \"subject\" | \"credential\" | \"authority\", alias: string) => {\n const descriptor = mapping[kind];\n const physical = tables(descriptor.table);\n\n return sql`(select * from ${physical.name} where ${tables.expression(descriptor.activeCondition)}) as ${sql(alias)}`;\n };\n\n const joinedIds =\n ownership.unencodedTextColumn?.(mapping.ownership.subjectId) !== undefined &&\n subject.unencodedTextColumn?.(mapping.subject.id) !== undefined &&\n credential.unencodedTextColumn?.(mapping.credential.subjectId) !== undefined &&\n authority.unencodedTextColumn?.(mapping.authority.subjectId) !== undefined;\n\n const decodeSnapshot = Effect.fnUntraced(function* (\n rows: ReadonlyArray<Row>,\n moduleId: string,\n nativeId?: unknown,\n ) {\n if (rows.length === 0) return undefined;\n const owned = o.decode(rows[0]!, \"o_\");\n\n const identity = yield* Schema.decodeUnknownEffect(OAuthExternalIdentity)({\n provider: owned[mapping.ownership.provider],\n issuer: owned[mapping.ownership.issuer],\n subject: owned[mapping.ownership.externalSubject],\n });\n\n const identityKey = yield* oauthIdentityKey(identity);\n\n invariant(owned[mapping.ownership.identityKey] === identityKey);\n const ownerId = mapping.ownership.decodeSubjectId(owned);\n\n if (nativeId !== undefined) invariant(mapping.subjectId.equals(ownerId, nativeId));\n const login = c.decode(rows[0]!, \"c_\");\n\n invariant(mapping.subjectId.equals(login[mapping.credential.subjectId], ownerId));\n invariant(login[mapping.credential.identityKey] === identityKey);\n invariant(mapping.credential.isActiveStatus(login[mapping.credential.status]));\n\n const current = yield* revision(\n s.decode(rows[0]!, \"s_\"),\n rows.map((row) => a.decode(row, \"a_\")),\n ownerId,\n );\n\n const credentialId = login[mapping.credential.credentialId];\n const credentialRevision = login[mapping.credential.credentialRevision];\n\n if (\n !current.credentials.some(\n (item) => item.credentialId === credentialId && item.revision === credentialRevision,\n )\n )\n return undefined;\n\n return yield* Schema.decodeUnknownEffect(Schema.toType(OAuthCredentialSnapshot))({\n moduleId,\n identity,\n credentialId,\n credentialRevision,\n revision: current,\n requirement: mapping.subject.decodeAuthenticationRequirement(s.decode(rows[0]!, \"s_\")),\n });\n });\n\n const resolve = Effect.fnUntraced(function* (\n moduleId: string,\n identity: typeof OAuthExternalIdentity.Type,\n ) {\n const identityKey = yield* oauthIdentityKey(identity);\n let nativeId: unknown;\n\n if (!joinedIds) {\n const found = yield* sql`select ${ownership.fields(\"o_\")} from ${ownership.name}\n where ${exact(ownership.column(mapping.ownership.identityKey), ownership.value(mapping.ownership.identityKey, identityKey))}`;\n\n if (found.length === 0) return undefined;\n invariant(found.length === 1);\n const row = ownership.decode(found[0]!, \"o_\");\n\n invariant(\n row[mapping.ownership.provider] === identity.provider &&\n row[mapping.ownership.issuer] === identity.issuer &&\n row[mapping.ownership.externalSubject] === identity.subject,\n );\n nativeId = mapping.ownership.decodeSubjectId(row);\n }\n\n const bindOwner = (table: typeof s, key: string) =>\n joinedIds\n ? exact(table.column(key), o.column(mapping.ownership.subjectId))\n : sql`${table.column(key)} = ${table.value(key, nativeId)}`;\n\n const rows =\n yield* sql`select ${o.fields(\"o_\")}, ${s.fields(\"s_\")}, ${c.fields(\"c_\")}, ${a.fields(\"a_\")}\n from ${o.name}\n join ${active(\"subject\", \"oauth_subject\")} on ${bindOwner(s, mapping.subject.id)}\n join ${active(\"credential\", \"oauth_credential\")} on ${bindOwner(c, mapping.credential.subjectId)}\n and ${exact(c.column(mapping.credential.moduleId), c.value(mapping.credential.moduleId, moduleId))}\n and ${exact(c.column(mapping.credential.identityKey), c.value(mapping.credential.identityKey, identityKey))}\n join ${active(\"authority\", \"oauth_authority\")} on ${bindOwner(a, mapping.authority.subjectId)}\n where ${exact(o.column(mapping.ownership.identityKey), o.value(mapping.ownership.identityKey, identityKey))}\n order by ${a.column(mapping.authority.credentialId)} limit 65`;\n\n const result = yield* decodeSnapshot(rows, moduleId, joinedIds ? undefined : nativeId);\n\n if (result !== undefined)\n invariant(\n result.identity.provider === identity.provider &&\n result.identity.issuer === identity.issuer &&\n result.identity.subject === identity.subject,\n );\n\n return result;\n });\n\n const readCredential = Effect.fnUntraced(function* (\n input: typeof OAuthCredentialKey.Type,\n metadataAccess: Fragment = sql`true`,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(input.subjectId);\n let identityKey: unknown;\n\n const direct =\n credential.unencodedTextColumn?.(mapping.credential.identityKey) !== undefined &&\n ownership.unencodedTextColumn?.(mapping.ownership.identityKey) !== undefined;\n\n if (!direct) {\n const selected = yield* sql`select ${credential.fields(\"c_\")} from ${credential.name}\n where ${exact(credential.column(mapping.credential.moduleId), credential.value(mapping.credential.moduleId, input.moduleId))}\n and ${exact(credential.column(mapping.credential.credentialId), credential.value(mapping.credential.credentialId, input.credentialId))}\n and ${credential.column(mapping.credential.subjectId)} = ${credential.value(mapping.credential.subjectId, nativeId)}`;\n\n if (selected.length === 0) return undefined;\n invariant(selected.length === 1);\n identityKey = credential.decode(selected[0]!, \"c_\")[mapping.credential.identityKey];\n }\n\n const owner = (table: typeof s, key: string) =>\n sql`${table.column(key)} = ${table.value(key, nativeId)}`;\n\n const rows =\n yield* sql`select ${o.fields(\"o_\")}, ${s.fields(\"s_\")}, ${c.fields(\"c_\")}, ${a.fields(\"a_\")}\n from ${active(\"credential\", \"oauth_credential\")}\n join ${o.name} on ${direct ? exact(o.column(mapping.ownership.identityKey), c.column(mapping.credential.identityKey)) : exact(o.column(mapping.ownership.identityKey), o.value(mapping.ownership.identityKey, identityKey))}\n and ${owner(o, mapping.ownership.subjectId)}\n join ${active(\"subject\", \"oauth_subject\")} on ${owner(s, mapping.subject.id)}\n join ${active(\"authority\", \"oauth_authority\")} on ${owner(a, mapping.authority.subjectId)}\n where ${metadataAccess} and ${owner(c, mapping.credential.subjectId)}\n and ${exact(c.column(mapping.credential.moduleId), c.value(mapping.credential.moduleId, input.moduleId))}\n and ${exact(c.column(mapping.credential.credentialId), c.value(mapping.credential.credentialId, input.credentialId))}\n order by ${a.column(mapping.authority.credentialId)} limit 65`;\n\n return yield* decodeSnapshot(rows, input.moduleId, nativeId);\n });\n\n return { ...state, ownership, credential, resolve, readCredential };\n});\n"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import { PersistenceConfigurationError } from "./configuration.mjs";
2
2
  import { PersistenceMappingError } from "./mapping-error.mjs";
3
3
  import { anySqlCondition } from "./sql-change.mjs";
4
+ import { SqlBatchCommit } from "./sql-commit.mjs";
4
5
  import { requiredPasskeyCredentialConstraints, requiredPasskeyPersistenceConstraints } from "./models/passkey-model.mjs";
5
- import { makeNativePasskeyServices } from "./passkey-native.mjs";
6
+ import { makeBatchPasskeyServices, makeNativePasskeyServices } from "./passkey-native.mjs";
6
7
  import { makePasskeyNativeManagement } from "./passkey-native-write.mjs";
7
8
  import { storageTables } from "./storage-tables.mjs";
8
9
  import { Context, Effect, Schema } from "effect";
@@ -177,6 +178,7 @@ const mappings = Effect.fnUntraced(function* (storage, tables, passwordModules,
177
178
  });
178
179
  /** Managed and mapped tables feed the same native passkey statements. */
179
180
  const makeManagedPasskeys = Effect.fnUntraced(function* (input, tables) {
181
+ const batch = yield* SqlBatchCommit;
180
182
  const policies = yield* Effect.forEach(input.features, (feature) => Effect.map(feature.policy, (policy) => ({
181
183
  feature,
182
184
  policy
@@ -186,7 +188,7 @@ const makeManagedPasskeys = Effect.fnUntraced(function* (input, tables) {
186
188
  const managers = /* @__PURE__ */ new Map();
187
189
  for (const feature of input.features) {
188
190
  const selected = feature.management ? mapping.management(feature) : mapping.base(feature);
189
- const base = yield* makeNativePasskeyServices(tables, selected);
191
+ const base = yield* batch === void 0 ? makeNativePasskeyServices(tables, selected) : makeBatchPasskeyServices(tables, selected);
190
192
  services.set(feature.moduleId, base);
191
193
  if (feature.management) managers.set(feature.moduleId, makePasskeyNativeManagement(base, mapping.management(feature)).passkeyManagementPersistence);
192
194
  }