{"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 * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\n\nimport type { TableModel as Table, SqlExpression } from \"../table-model\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\n\ntype Column<T extends Table> = T[\"column\"];\nexport type OAuthAction = OAuthActionAuthorization[\"challenge\"][\"action\"];\n\nexport interface OAuthClock<Expression extends SqlExpression = SqlExpression> {\n  readonly encodeInstant: (millis: number) => unknown;\n  readonly decodeInstant: (value: unknown) => number;\n  /** Actual engine wall clock sampled after locks, not transaction-start time.\n   * PostgreSQL uses clock_timestamp(), never now()/CURRENT_TIMESTAMP. D1 repeats\n   * its primary-engine sample bounds in final guards. Return integer milliseconds. */\n  readonly engineNowMillis: Expression;\n  /** Convert a stored timestamp expression to integer milliseconds. */\n  readonly toMillis: (expression: Expression) => Expression;\n  readonly fromMillis: (expression: Expression) => Expression;\n}\n\nexport interface OAuthSubjectReadTable<\n  S extends Table,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: S[\"table\"];\n  readonly id: Column<S>;\n  readonly status: Column<S>;\n  readonly securityRevision: Column<S>;\n  readonly isActiveStatus: (value: unknown) => boolean;\n  readonly activeCondition: Expression;\n  readonly decodeAuthenticationRequirement: (\n    row: S[\"select\"],\n  ) =>\n    | AuthenticationRequirement\n    | Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n}\n\nexport interface OAuthSubjectTable<\n  S extends Table,\n  Expression extends SqlExpression = SqlExpression,\n> extends OAuthSubjectReadTable<S, Expression> {\n  readonly nextSecurityRevision: (current: SecurityRevision) => SecurityRevision;\n}\n\nexport interface OAuthOwnershipReadTable<O extends Table, N> {\n  readonly table: O[\"table\"];\n  readonly identityKey: Column<O>;\n  readonly provider: Column<O>;\n  readonly issuer: Column<O>;\n  readonly externalSubject: Column<O>;\n  readonly subjectId: Column<O>;\n  readonly decodeSubjectId: (row: O[\"select\"]) => N;\n}\n\nexport interface OAuthOwnershipTable<O extends Table, N> extends OAuthOwnershipReadTable<O, N> {\n  readonly encodeInsert: (input: {\n    readonly identity: typeof OAuthExternalIdentity.Type;\n    readonly identityKey: string;\n    readonly subjectId: N;\n  }) => O[\"insert\"];\n}\n\nexport interface OAuthCredentialReadTable<\n  C extends Table,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: C[\"table\"];\n  readonly moduleId: Column<C>;\n  readonly credentialId: Column<C>;\n  readonly subjectId: Column<C>;\n  readonly identityKey: Column<C>;\n  readonly credentialRevision: Column<C>;\n  readonly status: Column<C>;\n  readonly isActiveStatus: (value: unknown) => boolean;\n  readonly activeCondition: Expression;\n}\n\nexport interface OAuthCredentialTable<\n  C extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> extends OAuthCredentialReadTable<C, Expression> {\n  readonly encodeInsert: (input: {\n    readonly moduleId: string;\n    readonly subjectId: N;\n    readonly identityKey: string;\n    readonly credentialId: string;\n    readonly credentialRevision: SecurityRevision;\n  }) => C[\"insert\"];\n  /** This slice removes login rows. Historical records belong in separate audit storage. */\n  readonly removal: \"delete\";\n}\n\nexport interface OAuthAuthorityReadTable<\n  C extends Table,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: C[\"table\"];\n  readonly subjectId: Column<C>;\n  readonly credentialId: Column<C>;\n  readonly revision: Column<C>;\n  readonly status: Column<C>;\n  readonly isActiveStatus: (value: unknown) => boolean;\n  readonly activeCondition: Expression;\n}\n\nexport interface OAuthAuthorityTable<\n  C extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> extends OAuthAuthorityReadTable<C, Expression> {\n  readonly encodeInsert: (input: {\n    readonly subjectId: N;\n    readonly credentialId: string;\n    readonly revision: SecurityRevision;\n  }) => C[\"insert\"];\n}\n\n/** Live ceremonies only. Predicate columns enforce access before deletion; the\n * snapshot retains the exact authenticated context and encrypted protocol data. */\nexport interface OAuthFlowTable<F extends Table> {\n  readonly table: F[\"table\"];\n  readonly moduleId: Column<F>;\n  readonly flowId: Column<F>;\n  readonly purpose: Column<F>;\n  readonly generation: Column<F>;\n  readonly provider: Column<F>;\n  readonly callbackId: Column<F>;\n  readonly issuer: Column<F>;\n  readonly responseIssuerMode: Column<F>;\n  readonly subjectId: Column<F>;\n  readonly stateDigest: Column<F>;\n  readonly binderVerifier: Column<F>;\n  readonly binderExpiresAt: Column<F>;\n  readonly snapshot: Column<F>;\n  readonly issuedAt: Column<F>;\n  readonly expiresAt: Column<F>;\n  readonly encodeInsert: (input: {\n    readonly moduleId: string;\n    readonly flowId: string;\n    readonly purpose: \"sign-in\" | \"link\" | \"connect\";\n  }) => F[\"insert\"];\n}\n\nexport const OAuthEligibilityFact = Schema.Struct({\n  credentialId: Schema.NonEmptyString.check(Schema.isMaxLength(256)),\n  revision: SecurityRevision,\n  usablePrimary: Schema.Boolean,\n  factors: Schema.Array(AuthenticationFactor).check(Schema.isMaxLength(8)),\n  userVerified: Schema.Boolean,\n  phishingResistant: Schema.Boolean,\n});\n\nexport type OAuthEligibilityFact = typeof OAuthEligibilityFact.Type;\n\n/** Each descriptor reads only its own subject-scoped method rows. The native row\n * projector and SQL condition must express the same installed method eligibility.\n * All source/identifier/policy mutations advance subject securityRevision. D1 also\n * guards exact selected IDs/versions and absence/count assumptions, never just a\n * stale boolean. An over-limit graph fails closed rather than truncating. */\nexport interface OAuthEligibilityTable<\n  T extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: T[\"table\"];\n  readonly subjectId: Column<T>;\n  readonly credentialId: Column<T>;\n  readonly revision: Column<T>;\n  readonly scope: string;\n  readonly condition: (subjectId: N) => Expression;\n  readonly decode: (row: T[\"select\"]) => OAuthEligibilityFact | undefined;\n}\n\nexport interface OAuthCleanupTable<\n  T extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: T[\"table\"];\n  readonly subjectId: Column<T>;\n  /** Bound to this subject's old revision; no opaque independently committing service. */\n  readonly condition: (input: {\n    readonly subjectId: N;\n    readonly revision: OAuthAccountRevision;\n    readonly removedCredentialId?: string;\n  }) => Expression;\n  readonly disposition: \"delete\";\n}\n\nexport interface OAuthRegistrationGuardTable<\n  T extends Table,\n  Registration,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: T[\"table\"];\n  readonly orderBy: Column<T>;\n  readonly condition: (input: {\n    readonly intent: OAuthRegistrationIntent;\n    readonly registration: Registration;\n    readonly nativeSubjectId?: N;\n  }) => Expression;\n}\n\nexport interface OAuthRegistrationGuardDescriptor<\n  Registration,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n  Descriptor extends object = object,\n> {\n  readonly table: Descriptor;\n  readonly orderBy: string;\n  readonly condition: OAuthRegistrationGuardTable<Table, Registration, N, Expression>[\"condition\"];\n}\n\nexport const oauthRegistrationGuardTable = <\n  T extends Table,\n  Registration,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n>(\n  input: OAuthRegistrationGuardTable<T, Registration, N, Expression>,\n): OAuthRegistrationGuardDescriptor<Registration, N, Expression, T[\"table\"]> =>\n  Object.freeze({\n    table: input.table,\n    orderBy: input.orderBy,\n    condition: input.condition,\n  });\n\n/** Heterogeneous descriptors are made by typed factories and projected privately. */\nexport interface OAuthEligibilityDescriptor<\n  N,\n  Expression extends SqlExpression = SqlExpression,\n  Descriptor extends object = object,\n> {\n  readonly _tag: \"OAuthEligibilityDescriptor\";\n  readonly scope: string;\n  readonly table: Descriptor;\n  readonly subjectId: string;\n  readonly credentialId: string;\n  readonly revision: string;\n  readonly condition: (subjectId: N) => Expression;\n  readonly decode: (row: unknown) => OAuthEligibilityFact | undefined;\n}\n\nexport const oauthEligibilityTable = <\n  T extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n>(\n  input: OAuthEligibilityTable<T, N, Expression>,\n): OAuthEligibilityDescriptor<N, Expression, T[\"table\"]> => {\n  const { table, subjectId, credentialId, revision, scope, condition, decode } = input;\n\n  return Object.freeze({\n    _tag: \"OAuthEligibilityDescriptor\",\n    table,\n    subjectId,\n    credentialId,\n    revision,\n    scope,\n    condition,\n    // The query owner supplies rows selected from this descriptor's mapped table.\n    decode: (row: unknown) => decode(row as T[\"select\"]),\n  });\n};\n\nexport interface OAuthCleanupDescriptor<\n  N,\n  Expression extends SqlExpression = SqlExpression,\n  Descriptor extends object = object,\n> {\n  readonly table: Descriptor;\n  readonly subjectId: string;\n  readonly condition: OAuthCleanupTable<Table, N, Expression>[\"condition\"];\n}\n\nexport const oauthCleanupTable = <\n  T extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n>(\n  input: OAuthCleanupTable<T, N, Expression>,\n): OAuthCleanupDescriptor<N, Expression, T[\"table\"]> =>\n  Object.freeze({ table: input.table, subjectId: input.subjectId, condition: input.condition });\n\n/** Original application binding and retained decision are encoded in snapshot. */\nexport interface OAuthRegistrationIntentTable<I extends Table> {\n  readonly table: I[\"table\"];\n  readonly moduleId: Column<I>;\n  readonly reference: Column<I>;\n  readonly flowId: Column<I>;\n  readonly identityKey: Column<I>;\n  readonly snapshot: Column<I>;\n  readonly expiresAt: Column<I>;\n  readonly retentionUntil: Column<I>;\n  readonly encodeInsert: (intent: OAuthRegistrationIntent) => I[\"insert\"];\n}\n\nexport interface OAuthD1Mapping {\n  readonly d1: { readonly primary: true };\n}\n\nexport const requiredOAuthSignInConstraints = {\n  flow: \"unique(flow.moduleId,flow.flowId)\",\n  stateDigest: \"unique(flow.stateDigest)\",\n  ownership: \"unique(ownership.identityKey)\",\n  credentialId: \"unique(credential.credentialId)\",\n  credentialIdentity: \"unique(credential.identityKey)\",\n  authorityCredential: \"unique(authority.subjectId,authority.credentialId)\",\n} as const;\n\nexport const requiredOAuthRegistrationConstraints = {\n  intentReference: \"unique(intent.moduleId,intent.reference)\",\n  intentFlow: \"unique(intent.moduleId,intent.flowId)\",\n  ownership: \"unique(ownership.identityKey)\",\n  credentialId: \"unique(credential.credentialId)\",\n  credentialIdentity: \"unique(credential.identityKey)\",\n  authorityCredential: \"unique(authority.subjectId,authority.credentialId)\",\n} as const;\n\nexport interface OAuthSignInMapping<\n  S extends Table,\n  O extends Table,\n  C extends Table,\n  AC extends Table,\n  F extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly subject: OAuthSubjectReadTable<S, Expression>;\n  readonly ownership: OAuthOwnershipReadTable<O, N>;\n  readonly credential: OAuthCredentialReadTable<C, Expression>;\n  readonly authority: OAuthAuthorityReadTable<AC, Expression>;\n  readonly flow: OAuthFlowTable<F>;\n  readonly subjectId: SubjectIdCodec<N>;\n  readonly clock: OAuthClock<Expression>;\n  readonly constraints: typeof requiredOAuthSignInConstraints;\n}\n\nexport interface OAuthRegistrationIntentMapping<\n  O extends Table,\n  I extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly ownership: OAuthOwnershipReadTable<O, N>;\n  readonly intent: OAuthRegistrationIntentTable<I>;\n  readonly clock: OAuthClock<Expression>;\n  readonly constraints: Pick<\n    typeof requiredOAuthRegistrationConstraints,\n    \"intentReference\" | \"intentFlow\" | \"ownership\"\n  >;\n  readonly eligible: (intent: OAuthRegistrationIntent) => Expression;\n}\n\nexport interface OAuthRegistrationMapping<\n  Registration,\n  S extends Table,\n  O extends Table,\n  C extends Table,\n  AC extends Table,\n  I extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n  Descriptor extends object = object,\n> {\n  readonly registration: Schema.Codec<Registration, unknown, never, never>;\n  readonly ownership: OAuthOwnershipTable<O, N>;\n  readonly intent: OAuthRegistrationIntentTable<I>;\n  readonly subject: OAuthSubjectReadTable<S, Expression>;\n  readonly credential: OAuthCredentialTable<C, N, Expression>;\n  readonly authority: OAuthAuthorityTable<AC, N, Expression>;\n  readonly subjectId: SubjectIdCodec<N>;\n  readonly clock: OAuthClock<Expression>;\n  readonly constraints: typeof requiredOAuthRegistrationConstraints;\n  readonly inspect: (input: {\n    readonly intent: OAuthRegistrationIntent;\n    readonly registration: Registration;\n  }) => Effect.Effect<\n    { readonly fingerprint: string; readonly eligible: boolean },\n    PersistenceMappingError\n  >;\n  readonly eligibility: {\n    readonly guards?: ReadonlyArray<\n      OAuthRegistrationGuardDescriptor<Registration, N, Expression, Descriptor>\n    >;\n    readonly admission: (input: {\n      readonly intent: OAuthRegistrationIntent;\n      readonly registration: Registration;\n      readonly nativeSubjectId?: N;\n    }) => Expression;\n    readonly postcondition: (input: {\n      readonly intent: OAuthRegistrationIntent;\n      readonly registration: Registration;\n      readonly nativeSubjectId?: N;\n    }) => Expression;\n  };\n  readonly allocateSubjectId: Effect.Effect<N, PersistenceMappingError>;\n  readonly allocateCredentialId: Effect.Effect<string, PersistenceMappingError>;\n  readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n  readonly encodeSubjectInsert: (\n    input: {\n      readonly intent: OAuthRegistrationIntent;\n      readonly registration: Registration;\n      readonly requestId: string;\n    },\n    ids: { readonly subjectId: N; readonly securityRevision: SecurityRevision },\n  ) => S[\"insert\"];\n}\n\nexport interface OAuthAccountsMapping<\n  S extends Table,\n  O extends Table,\n  C extends Table,\n  AC extends Table,\n  F extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n  Descriptor extends object = object,\n> {\n  readonly subject: OAuthSubjectTable<S, Expression>;\n  readonly ownership: OAuthOwnershipTable<O, N>;\n  readonly credential: OAuthCredentialTable<C, N, Expression>;\n  readonly authority: OAuthAuthorityTable<AC, N, Expression>;\n  readonly flow: OAuthFlowTable<F>;\n  readonly subjectId: SubjectIdCodec<N>;\n  readonly clock: OAuthClock<Expression>;\n  readonly constraints: typeof requiredOAuthSignInConstraints;\n  /** Self-contained SQL predicate rechecking this invocation's current permission\n   * to view login metadata. Evaluated in every releasing read, alongside active\n   * subject/credential authority and ownership. Do not trust public assurance as\n   * credential provenance; bind session policy to application-owned rows as needed. */\n  readonly metadataAccess: (input: {\n    readonly invocation: OAuthLinkedAccountsRead[\"invocation\"];\n    readonly moduleId: string;\n    readonly subjectId: N;\n  }) => Expression;\n  readonly eligibility: ReadonlyArray<OAuthEligibilityDescriptor<N, Expression, Descriptor>>;\n  readonly cleanup: ReadonlyArray<OAuthCleanupDescriptor<N, Expression, Descriptor>>;\n  readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n  /** Indexed same-owner reference predicate for any installed grant/application references. */\n  readonly otherReferences: (input: {\n    readonly identityKey: string;\n    readonly subjectId: N;\n  }) => Expression;\n  readonly allocateCredentialId: Effect.Effect<string, PersistenceMappingError>;\n  readonly allocateRevision: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n}\n\nexport interface OAuthRegistrationAuthority<Registration> {\n  /** Only the first confirmed registration supplies its private authentication handoff. */\n  readonly authentication?: \"first-confirmed-registration\";\n  readonly read: (\n    access: OAuthRegistrationAccess,\n  ) => Effect.Effect<OAuthRegistrationInspection | undefined, OAuthUnavailable>;\n  readonly inspect: (input: {\n    readonly intent: OAuthRegistrationIntent;\n    readonly registration: Registration;\n  }) => Effect.Effect<\n    {\n      readonly fingerprint: TokenDigest;\n      readonly eligible: boolean;\n    },\n    OAuthUnavailable\n  >;\n  readonly register: <A>(\n    input: {\n      readonly access: OAuthRegistrationAccess;\n      readonly intent: OAuthRegistrationIntent;\n      readonly commandId: typeof OAuthCommandId.Type;\n      readonly registration: Registration;\n      readonly fingerprint: TokenDigest;\n      readonly payload: string;\n      readonly requestId: string;\n    },\n    prepare: PrepareOAuthCommit<OAuthRegistrationDecision, A>,\n  ) => Effect.Effect<PreparedCommit<A>, OAuthUnavailable>;\n  readonly cleanup: <A>(\n    input: OAuthCleanupInput,\n    prepare: PrepareOAuthCommit<CleanupResult, A>,\n  ) => Effect.Effect<PreparedCommit<A>, OAuthUnavailable>;\n}\n"],"mappings":";;;;AAoKA,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"}