{"version":3,"file":"passkey-model.mjs","names":[],"sources":["../../../src/internal/models/passkey-model.ts"],"sourcesContent":["import {\n  type PasskeyCeremony,\n  type PasskeyCredential,\n  PasskeyCredentials,\n  PasskeyPersistence,\n} from \"@yielded/auth/Passkey\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport type { AuthenticationRequirement } from \"@yielded/auth/Sessions\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\n\nimport type { TableModel as Table, SqlExpression } from \"../table-model\";\nimport type { PersistenceMappingError } from \"./common\";\n\nexport type PasskeyColumn<T extends Table> = T[\"column\"];\n\nexport type PasskeyMappingSource<M, RSetup = never> =\n  | M\n  | Effect.Effect<M, PersistenceMappingError, RSetup>;\n\nexport interface PasskeyCredentialServices {\n  readonly passkeyCredentials: PasskeyCredentials[\"Service\"];\n}\n\nexport interface PasskeyPersistenceServices {\n  readonly passkeyPersistence: PasskeyPersistence[\"Service\"];\n}\n\nexport const passkeyCredentialsLayer = <E, R>(\n  services: Effect.Effect<PasskeyCredentialServices, E, R>,\n): Layer.Layer<PasskeyCredentials, E, R> =>\n  Layer.effect(\n    PasskeyCredentials,\n    Effect.map(services, (value) => value.passkeyCredentials),\n  );\n\nexport const passkeyPersistenceLayer = <E, R>(\n  services: Effect.Effect<PasskeyPersistenceServices, E, R>,\n): Layer.Layer<PasskeyPersistence, E, R> =>\n  Layer.effect(\n    PasskeyPersistence,\n    Effect.map(services, (value) => value.passkeyPersistence),\n  );\n\n/** Native IDs roundtrip exactly; protocol IDs and authentication references are\n * different identities. These callbacks never suspend inside an owner. */\nexport interface PasskeySubjectIdCodec<N> {\n  readonly toNative: (id: SubjectId) => N;\n  readonly toSubject: (id: N) => SubjectId;\n  readonly equals: (left: N, right: N) => boolean;\n}\n\nexport interface PasskeyClock<Expression extends SqlExpression = SqlExpression> {\n  readonly encodeInstant: (millis: number) => unknown;\n  readonly decodeInstant: (value: unknown) => number;\n  readonly engineNowMillis: Expression;\n  readonly toMillis: (expression: Expression) => Expression;\n  readonly fromMillis: (expression: Expression) => Expression;\n}\n\nexport interface PasskeySubjectReadTable<\n  T extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: T[\"table\"];\n  readonly id: PasskeyColumn<T>;\n  readonly status: PasskeyColumn<T>;\n  readonly securityRevision: PasskeyColumn<T>;\n  readonly decodeRequirement: (\n    row: T[\"select\"],\n  ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n  readonly decodeId: (row: Readonly<Partial<T[\"select\"]>>) => N;\n  readonly isActiveStatus: (value: unknown) => boolean;\n  readonly activeCondition: Expression;\n}\n\nexport interface PasskeyFactorReadTable<\n  T extends Table,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: T[\"table\"];\n  readonly subjectId: PasskeyColumn<T>;\n  readonly credentialId: PasskeyColumn<T>;\n  readonly revision: PasskeyColumn<T>;\n  readonly status: PasskeyColumn<T>;\n  readonly isActiveStatus: (value: unknown) => boolean;\n  readonly activeCondition: Expression;\n}\n\n/** decode uses only these declared columns. Counter columns are native integral\n * numbers; BS may use a consumer enum. Name/creation metadata is not required. */\nexport interface PasskeyCredentialReadTable<\n  T extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly table: T[\"table\"];\n  readonly credentialId: PasskeyColumn<T>;\n  readonly subjectId: PasskeyColumn<T>;\n  readonly rpId: PasskeyColumn<T>;\n  readonly protocolCredentialId: PasskeyColumn<T>;\n  readonly credentialKey: PasskeyColumn<T>;\n  readonly userHandle: PasskeyColumn<T>;\n  readonly publicKey: PasskeyColumn<T>;\n  readonly algorithm: PasskeyColumn<T>;\n  readonly profile: PasskeyColumn<T>;\n  readonly credentialRevision: PasskeyColumn<T>;\n  readonly status: PasskeyColumn<T>;\n  readonly primarySignIn: PasskeyColumn<T>;\n  readonly enrollmentUserVerified: PasskeyColumn<T>;\n  readonly backupEligible: PasskeyColumn<T>;\n  readonly backupState: PasskeyColumn<T>;\n  readonly counter: PasskeyColumn<T>;\n  readonly decode: (\n    row: Readonly<Partial<T[\"select\"]>>,\n  ) => Omit<PasskeyCredential, \"revision\" | \"active\" | \"requirement\">;\n  readonly decodeSubjectId: (row: Readonly<Partial<T[\"select\"]>>) => N;\n  readonly isActiveStatus: (value: unknown) => boolean;\n  readonly activeCondition: Expression;\n}\n\nexport const requiredPasskeyCredentialConstraints = {\n  credentialId: [\"credentialId\"],\n  credentialKey: [\"credentialKey\"],\n  factor: [\"subjectId\", \"credentialId\"],\n} as const;\n\nexport interface PasskeyCredentialMapping<\n  S extends Table,\n  C extends Table,\n  F extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly subject: PasskeySubjectReadTable<S, N, Expression>;\n  readonly credential: PasskeyCredentialReadTable<C, N, Expression>;\n  readonly authority: PasskeyFactorReadTable<F, Expression>;\n  readonly subjectIds: PasskeySubjectIdCodec<N>;\n  readonly constraints: typeof requiredPasskeyCredentialConstraints;\n}\n\nexport interface PasskeyFlowInsert {\n  readonly ceremony: PasskeyCeremony;\n}\n\n/** An immutable, single-use challenge. Consuming or expiring it deletes the row. */\nexport interface PasskeyFlowTable<T extends Table> {\n  readonly table: T[\"table\"];\n  readonly moduleId: PasskeyColumn<T>;\n  readonly flowId: PasskeyColumn<T>;\n  readonly purpose: PasskeyColumn<T>;\n  readonly snapshot: PasskeyColumn<T>;\n  readonly requestBindingVerifier: PasskeyColumn<T>;\n  readonly requestBindingExpiresAt: PasskeyColumn<T>;\n  readonly issuedAt: PasskeyColumn<T>;\n  readonly expiresAt: PasskeyColumn<T>;\n  readonly encodeInsert: (input: PasskeyFlowInsert) => T[\"insert\"];\n}\n\nexport const requiredPasskeyPersistenceConstraints = {\n  flow: [\"moduleId\", \"flowId\"],\n} as const;\n\nexport interface PasskeyCeremonyMapping<\n  Flow extends Table,\n  Expression extends SqlExpression = SqlExpression,\n> {\n  readonly moduleId: string;\n  readonly flow: PasskeyFlowTable<Flow>;\n  readonly clock: PasskeyClock<Expression>;\n  readonly constraints: typeof requiredPasskeyPersistenceConstraints;\n}\n\nexport interface PasskeyPersistenceMapping<\n  Read,\n  Flow extends Table,\n  N,\n  Expression extends SqlExpression = SqlExpression,\n  Credential extends Table = Table,\n> extends PasskeyCeremonyMapping<Flow, Expression> {\n  readonly read: Read & {\n    readonly subjectIds: PasskeySubjectIdCodec<N>;\n  };\n  readonly telemetry: {\n    readonly lastUsedAt: PasskeyColumn<Credential>;\n    readonly encodeBackupEligible: (value: boolean) => unknown;\n    readonly encodeBackupState: (value: boolean) => unknown;\n  };\n}\n\nexport interface D1PasskeyMapping {\n  readonly d1: { readonly primary: true };\n}\n"],"mappings":";;;;AA4BA,MAAa,2BACX,aAEA,MAAM,OACJ,oBACA,OAAO,IAAI,WAAW,UAAU,MAAM,kBAAkB,CAC1D;AAEF,MAAa,2BACX,aAEA,MAAM,OACJ,oBACA,OAAO,IAAI,WAAW,UAAU,MAAM,kBAAkB,CAC1D;AAgFF,MAAa,uCAAuC;CAClD,cAAc,CAAC,cAAc;CAC7B,eAAe,CAAC,eAAe;CAC/B,QAAQ,CAAC,aAAa,cAAc;AACtC;AAkCA,MAAa,wCAAwC,EACnD,MAAM,CAAC,YAAY,QAAQ,EAC7B"}