{"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 * as Effect from \"effect/Effect\";\nimport type * as Redacted from \"effect/Redacted\";\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":";;AA+HA,MAAa,8BAA2D;CACtE,YAAY;CACZ,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;AAChB;AAmEA,MAAa,0CAAmF;CAC9F,YAAY;CACZ,mBAAmB;CACnB,qBAAqB;AACvB"}