@yielded/auth-persistence-drizzle 0.1.0-beta.14 → 0.1.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/D1.d.mts +123 -9
- package/dist/Libsql.d.mts +141 -27
- package/dist/Mysql2.d.mts +124 -10
- package/dist/Pglite.d.mts +124 -10
- package/dist/Postgres.d.mts +129 -15
- package/dist/SqliteBun.d.mts +135 -21
- package/dist/SqliteDo.d.mts +135 -21
- package/dist/SqliteNode.d.mts +135 -21
- package/dist/SqliteWasm.d.mts +135 -21
- package/dist/drizzle/d1-emails.d.mts +3 -3
- package/dist/drizzle/d1-emails.mjs +56 -11
- package/dist/drizzle/d1-emails.mjs.map +1 -1
- package/dist/drizzle/d1-identity.mjs +9 -2
- package/dist/drizzle/d1-identity.mjs.map +1 -1
- package/dist/drizzle/d1-oauth.d.mts +6 -6
- package/dist/drizzle/d1-oauth.mjs +8 -8
- package/dist/drizzle/d1-oauth.mjs.map +1 -1
- package/dist/drizzle/d1-passkey.d.mts +2 -1
- package/dist/drizzle/d1-passkey.mjs +10 -8
- package/dist/drizzle/d1-passkey.mjs.map +1 -1
- package/dist/drizzle/d1-password-prepared.d.mts +1 -1
- package/dist/drizzle/d1-password-prepared.mjs +16 -5
- package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +2 -2
- package/dist/drizzle/d1-passwords.mjs +19 -6
- package/dist/drizzle/d1-passwords.mjs.map +1 -1
- package/dist/drizzle/d1-phone.d.mts +2 -1
- package/dist/drizzle/d1-phone.mjs +4 -2
- package/dist/drizzle/d1-phone.mjs.map +1 -1
- package/dist/drizzle/d1-proofs.d.mts +1 -1
- package/dist/drizzle/d1-proofs.mjs +18 -7
- package/dist/drizzle/d1-proofs.mjs.map +1 -1
- package/dist/drizzle/d1-sessions.d.mts +6 -5
- package/dist/drizzle/d1-sessions.mjs +29 -19
- package/dist/drizzle/d1-sessions.mjs.map +1 -1
- package/dist/drizzle/d1-totp.d.mts +2 -1
- package/dist/drizzle/d1-totp.mjs +4 -2
- package/dist/drizzle/d1-totp.mjs.map +1 -1
- package/dist/drizzle/email-registration.d.mts +5 -1
- package/dist/drizzle/email-registration.mjs +48 -4
- package/dist/drizzle/email-registration.mjs.map +1 -1
- package/dist/drizzle/email-target.d.mts +1 -0
- package/dist/drizzle/email-target.mjs +9 -0
- package/dist/drizzle/email-target.mjs.map +1 -1
- package/dist/drizzle/mysql-emails.d.mts +4 -4
- package/dist/drizzle/mysql-emails.mjs +8 -7
- package/dist/drizzle/mysql-emails.mjs.map +1 -1
- package/dist/drizzle/mysql-identity.mjs +11 -4
- package/dist/drizzle/mysql-identity.mjs.map +1 -1
- package/dist/drizzle/mysql-password-prepared.d.mts +2 -2
- package/dist/drizzle/mysql-password-prepared.mjs +4 -3
- package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
- package/dist/drizzle/mysql-passwords.d.mts +3 -3
- package/dist/drizzle/mysql-passwords.mjs +7 -6
- package/dist/drizzle/mysql-passwords.mjs.map +1 -1
- package/dist/drizzle/mysql-proofs.d.mts +2 -2
- package/dist/drizzle/mysql-proofs.mjs +4 -3
- package/dist/drizzle/mysql-proofs.mjs.map +1 -1
- package/dist/drizzle/mysql-sessions.d.mts +6 -6
- package/dist/drizzle/mysql-sessions.mjs +16 -15
- package/dist/drizzle/mysql-sessions.mjs.map +1 -1
- package/dist/drizzle/native-database.mjs +1 -1
- package/dist/drizzle/native-database.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-drivers.mjs +10 -8
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-flow.mjs +62 -13
- package/dist/drizzle/oauth-connected-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-input.mjs +6 -0
- package/dist/drizzle/oauth-connected-input.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-maintenance.mjs +3 -3
- package/dist/drizzle/oauth-connected-maintenance.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-target.d.mts +116 -2
- package/dist/drizzle/oauth-connected-target.mjs +5 -3
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
- package/dist/drizzle/oauth-drivers.mjs +8 -8
- package/dist/drizzle/oauth-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-target.d.mts +3 -3
- package/dist/drizzle/oauth-target.mjs +8 -6
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey-drivers.mjs +4 -4
- package/dist/drizzle/passkey-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-drivers.mjs +4 -4
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-target.d.mts +1 -1
- package/dist/drizzle/password-prepared-sql.mjs +5 -0
- package/dist/drizzle/password-prepared-sql.mjs.map +1 -1
- package/dist/drizzle/password-prepared-target.d.mts +2 -1
- package/dist/drizzle/password-prepared-target.mjs +5 -0
- package/dist/drizzle/password-prepared-target.mjs.map +1 -1
- package/dist/drizzle/password-registration.d.mts +1 -1
- package/dist/drizzle/password-registration.mjs +2 -0
- package/dist/drizzle/password-registration.mjs.map +1 -1
- package/dist/drizzle/password-target.d.mts +1 -0
- package/dist/drizzle/password-target.mjs +6 -0
- package/dist/drizzle/password-target.mjs.map +1 -1
- package/dist/drizzle/pg-emails.d.mts +4 -4
- package/dist/drizzle/pg-emails.mjs +8 -7
- package/dist/drizzle/pg-emails.mjs.map +1 -1
- package/dist/drizzle/pg-identity.mjs +12 -5
- package/dist/drizzle/pg-identity.mjs.map +1 -1
- package/dist/drizzle/pg-password-prepared.d.mts +2 -2
- package/dist/drizzle/pg-password-prepared.mjs +4 -3
- package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
- package/dist/drizzle/pg-passwords.d.mts +3 -3
- package/dist/drizzle/pg-passwords.mjs +7 -6
- package/dist/drizzle/pg-passwords.mjs.map +1 -1
- package/dist/drizzle/pg-proofs.d.mts +2 -2
- package/dist/drizzle/pg-proofs.mjs +4 -3
- package/dist/drizzle/pg-proofs.mjs.map +1 -1
- package/dist/drizzle/pg-sessions.d.mts +6 -6
- package/dist/drizzle/pg-sessions.mjs +16 -15
- package/dist/drizzle/pg-sessions.mjs.map +1 -1
- package/dist/drizzle/phone-target.mjs +11 -2
- package/dist/drizzle/phone-target.mjs.map +1 -1
- package/dist/drizzle/proof-target.d.mts +1 -0
- package/dist/drizzle/proof-target.mjs +2 -0
- package/dist/drizzle/proof-target.mjs.map +1 -1
- package/dist/drizzle/query-operations.mjs +2 -0
- package/dist/drizzle/query-operations.mjs.map +1 -1
- package/dist/drizzle/session-target.d.mts +1 -0
- package/dist/drizzle/session-target.mjs +9 -6
- package/dist/drizzle/session-target.mjs.map +1 -1
- package/dist/drizzle/sqlite-emails.mjs +8 -7
- package/dist/drizzle/sqlite-emails.mjs.map +1 -1
- package/dist/drizzle/sqlite-identity.mjs +7 -2
- package/dist/drizzle/sqlite-identity.mjs.map +1 -1
- package/dist/drizzle/sqlite-password-prepared.mjs +4 -3
- package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
- package/dist/drizzle/sqlite-passwords.mjs +7 -6
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
- package/dist/drizzle/sqlite-proofs.mjs +4 -3
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
- package/dist/drizzle/sqlite-sessions.mjs +16 -15
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
- package/dist/drizzle/storage-validation.mjs +234 -0
- package/dist/drizzle/storage-validation.mjs.map +1 -0
- package/dist/drizzle/totp-target.mjs +5 -2
- package/dist/drizzle/totp-target.mjs.map +1 -1
- package/dist/drizzle/transaction-mysql.mjs +1 -1
- package/package.json +1 -1
- package/src/drizzle/d1-emails.ts +158 -40
- package/src/drizzle/d1-identity.ts +13 -0
- package/src/drizzle/d1-oauth.ts +8 -8
- package/src/drizzle/d1-passkey.ts +10 -8
- package/src/drizzle/d1-password-prepared.ts +14 -2
- package/src/drizzle/d1-passwords.ts +22 -4
- package/src/drizzle/d1-phone.ts +4 -2
- package/src/drizzle/d1-proofs.ts +55 -3
- package/src/drizzle/d1-sessions.ts +67 -18
- package/src/drizzle/d1-totp.ts +4 -2
- package/src/drizzle/email-registration.ts +160 -12
- package/src/drizzle/email-target.ts +22 -4
- package/src/drizzle/mysql-emails.ts +17 -7
- package/src/drizzle/mysql-identity.ts +13 -0
- package/src/drizzle/mysql-password-prepared.ts +7 -3
- package/src/drizzle/mysql-passwords.ts +13 -6
- package/src/drizzle/mysql-proofs.ts +7 -3
- package/src/drizzle/mysql-sessions.ts +31 -15
- package/src/drizzle/native-database.ts +5 -4
- package/src/drizzle/oauth-connected-drivers.ts +10 -8
- package/src/drizzle/oauth-connected-flow.ts +98 -10
- package/src/drizzle/oauth-connected-input.ts +7 -0
- package/src/drizzle/oauth-connected-maintenance.ts +3 -2
- package/src/drizzle/oauth-connected-target.ts +4 -2
- package/src/drizzle/oauth-drivers.ts +8 -8
- package/src/drizzle/oauth-target.ts +13 -7
- package/src/drizzle/passkey-drivers.ts +4 -4
- package/src/drizzle/passkey-write-drivers.ts +8 -5
- package/src/drizzle/password-prepared-sql.ts +13 -1
- package/src/drizzle/password-prepared-target.ts +7 -1
- package/src/drizzle/password-registration.ts +10 -3
- package/src/drizzle/password-target.ts +22 -4
- package/src/drizzle/pg-emails.ts +17 -7
- package/src/drizzle/pg-identity.ts +13 -0
- package/src/drizzle/pg-password-prepared.ts +7 -3
- package/src/drizzle/pg-passwords.ts +13 -6
- package/src/drizzle/pg-proofs.ts +7 -3
- package/src/drizzle/pg-sessions.ts +31 -15
- package/src/drizzle/phone-target.ts +30 -5
- package/src/drizzle/proof-target.ts +10 -2
- package/src/drizzle/query-operations.ts +2 -0
- package/src/drizzle/session-target.ts +20 -3
- package/src/drizzle/sqlite-emails.ts +17 -7
- package/src/drizzle/sqlite-identity.ts +5 -0
- package/src/drizzle/sqlite-password-prepared.ts +7 -3
- package/src/drizzle/sqlite-passwords.ts +13 -6
- package/src/drizzle/sqlite-proofs.ts +7 -3
- package/src/drizzle/sqlite-sessions.ts +31 -15
- package/src/drizzle/storage-validation.ts +285 -0
- package/src/drizzle/totp-target.ts +16 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { randomId } from \"@yielded/auth-crypto\";\nimport { NativeDatabase } from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n TotpConfigurationError,\n type TotpUnavailable,\n TotpMutation,\n TotpPolicy,\n TotpPersistence,\n} from \"@yielded/auth/Totp\";\nimport type { Table } from \"drizzle-orm\";\n/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */\nimport { Context, Effect, Schema } from \"effect\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type { PersistenceMappingError } from \"./model\";\nimport { nativeDatabase } from \"./native-database\";\nimport type { SuppliedService } from \"./SuppliedService\";\nimport {\n type TotpMapping,\n type TotpMappingSource,\n type TotpPersistenceServices,\n requiredTotpConstraints,\n} from \"./totp-model\";\nimport {\n captureTotp,\n CurrentTotpTransaction,\n invariant,\n mutateTotp,\n unavailable,\n} from \"./totp-state\";\nimport {\n coordinateTransactionOwner,\n makeTransactionExecution,\n sqlClientTransactionStandaloneGuard,\n type TransactionExecution,\n type TransactionTargetConfiguration,\n type TransactionCoordinatorError,\n} from \"./transaction-execution\";\nimport type { TransactionNativeDatabase } from \"./transaction-owner\";\nexport type TotpTargetConfiguration = TransactionTargetConfiguration<TotpUnavailable>;\n\nexport type TotpCoordinatorError<E> =\n | TransactionCoordinatorError<E, TotpUnavailable>\n | TotpConfigurationError\n | PersistenceMappingError;\n\nexport const sqlClientTotpStandaloneGuard = (\n service: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],\n) => sqlClientTransactionStandaloneGuard(unavailable, service);\n\nconst validateMapping = <M>(original: M, configuration: TotpTargetConfiguration): M => {\n const mapping = original as any;\n\n invariant(mapping.moduleId.length > 0);\n Schema.decodeSync(TotpPolicy)(mapping.policy);\n for (const [key, value] of Object.entries(requiredTotpConstraints))\n invariant(mapping.constraints?.[key] === value);\n if (configuration.mode === \"batch\") invariant(mapping.d1?.primary === true);\n\n return Object.freeze({\n ...mapping,\n policy: Object.freeze({ ...mapping.policy }),\n subject: Object.freeze({ ...mapping.subject }),\n factor: Object.freeze({ ...mapping.factor }),\n credential: Object.freeze({ ...mapping.credential }),\n subjectIds: Object.freeze({ ...mapping.subjectIds }),\n });\n};\n\nconst services = Effect.fnUntraced(function* (\n mapping: any,\n execution: TransactionExecution<TotpUnavailable, CurrentTotpTransaction>,\n): Effect.fn.Return<TotpPersistenceServices, never, LifecycleHooks> {\n const hooks = yield* LifecycleHooks;\n\n return {\n totpPersistence: TotpPersistence.of({\n snapshot: Effect.fn(\"TotpNative.snapshot\")(\n function* (input) {\n const captured = { ...input };\n\n invariant(captured.moduleId === mapping.moduleId);\n yield* execution.admit;\n\n return yield* execution\n .run(\n Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot),\n false,\n )\n .pipe(Effect.provideService(LifecycleHooks, hooks));\n },\n Effect.catchDefect(() => Effect.fail(unavailable())),\n ),\n mutate: (original, prepare) =>\n Effect.suspend(() => {\n // Detach caller-owned payloads before any driver or hook can suspend.\n const codec = Schema.toCodecIso(TotpMutation);\n const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));\n\n return execution.admit.pipe(\n Effect.andThen(\n execution.run(\n Effect.gen(function* () {\n const decision = yield* mutateTotp(mapping, input),\n owner = yield* CurrentTotpTransaction;\n\n owner.guards.push(owner.journal.prepare(undefined));\n const receipt = prepare(decision, owner.journal);\n\n invariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n owner.guards.push(receipt as any);\n\n return receipt;\n }),\n ),\n ),\n Effect.provideService(LifecycleHooks, hooks),\n );\n }).pipe(Effect.catchDefect(() => Effect.fail(unavailable()))),\n }),\n };\n});\n\nexport const makeTargetTotpPersistence = <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n RSetup = never,\n>(\n source: TotpMappingSource<TotpMapping<S, F, C, N>, RSetup>,\n configuration: TotpTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n const execution = yield* makeTransactionExecution(\n CurrentTotpTransaction,\n configuration,\n unavailable,\n randomId,\n );\n\n return yield* services(mapping, execution);\n });\n\nexport const coordinateTargetTotp = <M, A, E, R, RSetup = never>(\n database: TransactionNativeDatabase,\n source: TotpMappingSource<M, RSetup>,\n configuration: TotpTargetConfiguration,\n body: (\n transaction: any,\n services: TotpPersistenceServices,\n append: (statement: Statement<any>) => void,\n ) => Effect.Effect<A, E, R>,\n): Effect.Effect<A, TotpCoordinatorError<E>, R | RSetup | LifecycleHooks> =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n return yield* coordinateTransactionOwner(\n database,\n CurrentTotpTransaction,\n configuration,\n Effect.void,\n unavailable,\n randomId,\n (execution) => services(mapping, execution),\n (transaction, acquireServices, append) =>\n Effect.flatMap(acquireServices, (boundServices) =>\n body(transaction, boundServices, append),\n ),\n );\n });\n\ntype TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => any }\n ? Parameters<Parameters<D[\"transaction\"]>[0]>[0]\n : never;\n\n/** Concrete driver wrappers select transaction mode; cryptography always precedes these owners. */\nexport const makeTotpTarget = <\n DatabaseId,\n D extends { readonly transaction: any },\n T extends Table,\n Extra = unknown,\n Synchronous extends boolean = false,\n>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: TotpTargetConfiguration,\n) => {\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence>)\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence | TxId> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence | TxId>)\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n Exclude<R, TotpPersistence> | LifecycleHooks | RSetup | DatabaseRequirements\n > {\n return Effect.flatMap(acquire, (database) =>\n coordinateTargetTotp(\n database as any,\n options.mapping,\n configuration,\n (transaction: TransactionOf<Database>, services) => {\n const provided = Context.make(TotpPersistence, services.totpPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n return {\n makeTotpPersistenceServices: <S extends T, F extends T, C extends T, N, RSetup = never>(\n mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>,\n ) =>\n makeTargetTotpPersistence(mapping, configuration).pipe(\n Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),\n ),\n coordinateTotpPersistence,\n };\n};\n"],"mappings":";;;;;;;;;;AA+CA,MAAa,gCACX,YACG,oCAAoC,aAAa,OAAO;AAE7D,MAAM,mBAAsB,UAAa,kBAA8C;CACrF,MAAM,UAAU;CAEhB,UAAU,QAAQ,SAAS,SAAS,CAAC;CACrC,OAAO,WAAW,UAAU,CAAC,CAAC,QAAQ,MAAM;CAC5C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,uBAAuB,GAC/D,UAAU,QAAQ,cAAc,SAAS,KAAK;CAChD,IAAI,cAAc,SAAS,SAAS,UAAU,QAAQ,IAAI,YAAY,IAAI;CAE1E,OAAO,OAAO,OAAO;EACnB,GAAG;EACH,QAAQ,OAAO,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC;EAC3C,SAAS,OAAO,OAAO,EAAE,GAAG,QAAQ,QAAQ,CAAC;EAC7C,QAAQ,OAAO,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC;EAC3C,YAAY,OAAO,OAAO,EAAE,GAAG,QAAQ,WAAW,CAAC;EACnD,YAAY,OAAO,OAAO,EAAE,GAAG,QAAQ,WAAW,CAAC;CACrD,CAAC;AACH;AAEA,MAAM,WAAW,OAAO,WAAW,WACjC,SACA,WACkE;CAClE,MAAM,QAAQ,OAAO;CAErB,OAAO,EACL,iBAAiB,gBAAgB,GAAG;EAClC,UAAU,OAAO,GAAG,qBAAqB,CAAC,CACxC,WAAW,OAAO;GAChB,MAAM,WAAW,EAAE,GAAG,MAAM;GAE5B,UAAU,SAAS,aAAa,QAAQ,QAAQ;GAChD,OAAO,UAAU;GAEjB,OAAO,OAAO,UACX,IACC,OAAO,IAAI,YAAY,SAAS,SAAS,SAAS,IAAI,UAAU,OAAO,QAAQ,GAC/E,KACF,CAAC,CACA,KAAK,OAAO,eAAe,gBAAgB,KAAK,CAAC;EACtD,GACA,OAAO,kBAAkB,OAAO,KAAK,YAAY,CAAC,CAAC,CACrD;EACA,SAAS,UAAU,YACjB,OAAO,cAAc;GAEnB,MAAM,QAAQ,OAAO,WAAW,YAAY;GAC5C,MAAM,QAAQ,OAAO,WAAW,KAAK,CAAC,CAAC,OAAO,WAAW,KAAK,CAAC,CAAC,QAAQ,CAAC;GAEzE,OAAO,UAAU,MAAM,KACrB,OAAO,QACL,UAAU,IACR,OAAO,IAAI,aAAa;IACtB,MAAM,WAAW,OAAO,WAAW,SAAS,KAAK,GAC/C,QAAQ,OAAO;IAEjB,MAAM,OAAO,KAAK,MAAM,QAAQ,QAAQ,KAAA,CAAS,CAAC;IAClD,MAAM,UAAU,QAAQ,UAAU,MAAM,OAAO;IAE/C,UAAU,SAAS,SAAS,oBAAoB,OAAO,SAAS,QAAQ,IAAI,CAAC;IAC7E,MAAM,OAAO,KAAK,OAAc;IAEhC,OAAO;GACT,CAAC,CACH,CACF,GACA,OAAO,eAAe,gBAAgB,KAAK,CAC7C;EACF,CAAC,CAAC,CAAC,KAAK,OAAO,kBAAkB,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC;CAChE,CAAC,EACH;AACF,CAAC;AAED,MAAa,6BAOX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,MAAM;CAEhF,MAAM,UAAU,OAAO,OAAO,IAAI;EAChC,WAAW,gBAAgB,UAAU,aAAa;EAClD,aAAa,uBAAuB,KAAK,CAAC,CAAC;CAC7C,CAAC;CAED,MAAM,YAAY,OAAO,yBACvB,wBACA,eACA,aACA,QACF;CAEA,OAAO,OAAO,SAAS,SAAS,SAAS;AAC3C,CAAC;AAEH,MAAa,wBACX,UACA,QACA,eACA,SAMA,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,MAAM;CAEhF,MAAM,UAAU,OAAO,OAAO,IAAI;EAChC,WAAW,gBAAgB,UAAU,aAAa;EAClD,aAAa,uBAAuB,KAAK,CAAC,CAAC;CAC7C,CAAC;CAED,OAAO,OAAO,2BACZ,UACA,wBACA,eACA,OAAO,MACP,aACA,WACC,cAAc,SAAS,SAAS,SAAS,IACzC,aAAa,iBAAiB,WAC7B,OAAO,QAAQ,kBAAkB,kBAC/B,KAAK,aAAa,eAAe,MAAM,CACzC,CACJ;AACF,CAAC;;AAOH,MAAa,kBAOX,iBACA,kBACG;CAyDH,SAAS,0BAeP,SACA,SAIA,MAKA;EACA,OAAO,OAAO,QAAQ,UAAU,aAC9B,qBACE,UACA,QAAQ,SACR,gBACC,aAAsC,aAAa;GAClD,MAAM,WAAW,QAAQ,KAAK,iBAAiB,SAAS,eAAe;GACvE,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;GAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;EAC1F,CACF,CACF;CACF;CAEA,OAAO;EACL,8BACE,YAEA,0BAA0B,SAAS,aAAa,CAAC,CAAC,KAChD,OAAO,qBAAqB,gBAAgB,eAAe,eAAe,CAAC,CAC7E;EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { randomId } from \"@yielded/auth-crypto\";\nimport { NativeDatabase } from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n TotpConfigurationError,\n type TotpUnavailable,\n TotpMutation,\n TotpPolicy,\n TotpPersistence,\n} from \"@yielded/auth/Totp\";\nimport type { Table } from \"drizzle-orm\";\n/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */\nimport { Context, Effect, Schema } from \"effect\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type { PersistenceMappingError } from \"./model\";\nimport { nativeDatabase } from \"./native-database\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\nimport {\n type TotpMapping,\n type TotpMappingSource,\n type TotpPersistenceServices,\n requiredTotpConstraints,\n} from \"./totp-model\";\nimport {\n captureTotp,\n CurrentTotpTransaction,\n invariant,\n mutateTotp,\n unavailable,\n} from \"./totp-state\";\nimport {\n coordinateTransactionOwner,\n makeTransactionExecution,\n sqlClientTransactionStandaloneGuard,\n type TransactionExecution,\n type TransactionTargetConfiguration,\n type TransactionCoordinatorError,\n} from \"./transaction-execution\";\nimport type { TransactionNativeDatabase } from \"./transaction-owner\";\nexport type TotpTargetConfiguration = TransactionTargetConfiguration<TotpUnavailable>;\n\nexport type TotpCoordinatorError<E> =\n | TransactionCoordinatorError<E, TotpUnavailable>\n | TotpConfigurationError\n | PersistenceMappingError;\n\nexport const sqlClientTotpStandaloneGuard = (\n service: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],\n) => sqlClientTransactionStandaloneGuard(unavailable, service);\n\nconst validateMapping = <M>(original: M, configuration: TotpTargetConfiguration): M => {\n const mapping = original as any;\n\n invariant(mapping.moduleId.length > 0);\n Schema.decodeSync(TotpPolicy)(mapping.policy);\n for (const [key, value] of Object.entries(requiredTotpConstraints))\n invariant(mapping.constraints?.[key] === value);\n if (configuration.mode === \"batch\") invariant(mapping.d1?.primary === true);\n\n return Object.freeze({\n ...mapping,\n policy: Object.freeze({ ...mapping.policy }),\n subject: Object.freeze({ ...mapping.subject }),\n factor: Object.freeze({ ...mapping.factor }),\n credential: Object.freeze({ ...mapping.credential }),\n subjectIds: Object.freeze({ ...mapping.subjectIds }),\n });\n};\n\nconst services = Effect.fnUntraced(function* (\n mapping: any,\n execution: TransactionExecution<TotpUnavailable, CurrentTotpTransaction>,\n): Effect.fn.Return<TotpPersistenceServices, never, LifecycleHooks> {\n const hooks = yield* LifecycleHooks;\n\n return {\n totpPersistence: TotpPersistence.of({\n snapshot: Effect.fn(\"TotpNative.snapshot\")(\n function* (input) {\n const captured = { ...input };\n\n invariant(captured.moduleId === mapping.moduleId);\n yield* execution.admit;\n\n return yield* execution\n .run(\n Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot),\n false,\n )\n .pipe(Effect.provideService(LifecycleHooks, hooks));\n },\n Effect.catchDefect(() => Effect.fail(unavailable())),\n ),\n mutate: (original, prepare) =>\n Effect.suspend(() => {\n // Detach caller-owned payloads before any driver or hook can suspend.\n const codec = Schema.toCodecIso(TotpMutation);\n const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));\n\n return execution.admit.pipe(\n Effect.andThen(\n execution.run(\n Effect.gen(function* () {\n const decision = yield* mutateTotp(mapping, input),\n owner = yield* CurrentTotpTransaction;\n\n owner.guards.push(owner.journal.prepare(undefined));\n const receipt = prepare(decision, owner.journal);\n\n invariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n owner.guards.push(receipt as any);\n\n return receipt;\n }),\n ),\n ),\n Effect.provideService(LifecycleHooks, hooks),\n );\n }).pipe(Effect.catchDefect(() => Effect.fail(unavailable()))),\n }),\n };\n});\n\nexport const makeTargetTotpPersistence = <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n RSetup = never,\n>(\n source: TotpMappingSource<TotpMapping<S, F, C, N>, RSetup>,\n configuration: TotpTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n const execution = yield* makeTransactionExecution(\n CurrentTotpTransaction,\n configuration,\n unavailable,\n randomId,\n );\n\n return yield* services(mapping, execution);\n });\n\nexport const coordinateTargetTotp = <M, A, E, R, RSetup = never>(\n database: TransactionNativeDatabase,\n source: TotpMappingSource<M, RSetup>,\n configuration: TotpTargetConfiguration,\n body: (\n transaction: any,\n services: TotpPersistenceServices,\n append: (statement: Statement<any>) => void,\n ) => Effect.Effect<A, E, R>,\n): Effect.Effect<A, TotpCoordinatorError<E>, R | RSetup | LifecycleHooks | NativeDatabase> =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n return yield* coordinateTransactionOwner(\n database,\n CurrentTotpTransaction,\n configuration,\n Effect.void,\n unavailable,\n randomId,\n (execution) => services(mapping, execution),\n (transaction, acquireServices, append) =>\n Effect.flatMap(acquireServices, (boundServices) =>\n body(transaction, boundServices, append),\n ),\n );\n });\n\ntype TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => any }\n ? Parameters<Parameters<D[\"transaction\"]>[0]>[0]\n : never;\n\n/** Concrete driver wrappers select transaction mode; cryptography always precedes these owners. */\nexport const makeTotpTarget = <\n DatabaseId,\n D extends { readonly transaction: any },\n T extends Table,\n Extra = unknown,\n Synchronous extends boolean = false,\n>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: TotpTargetConfiguration,\n) => {\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence>)\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence | TxId> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence | TxId>)\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n Exclude<R, TotpPersistence> | LifecycleHooks | RSetup | DatabaseRequirements\n > {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateTargetTotp(\n database as any,\n options.mapping,\n configuration,\n (\n transaction: TransactionOf<Database>,\n services,\n ): Effect.Effect<A, E, Exclude<R, TotpPersistence>> => {\n const provided = Context.make(TotpPersistence, services.totpPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ).pipe(Effect.provideService(NativeDatabase, database)),\n );\n }\n\n return {\n makeTotpPersistenceServices: <S extends T, F extends T, C extends T, N, RSetup = never>(\n mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>,\n ) =>\n makeTargetTotpPersistence(mapping, configuration).pipe(\n Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),\n ),\n coordinateTotpPersistence,\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import { EffectMysql2Transaction } from "drizzle-orm/effect-mysql2";
|
|
3
2
|
import { makeWithTransaction } from "effect/sql/SqlClient";
|
|
3
|
+
import { EffectMysql2Transaction } from "drizzle-orm/effect-mysql2";
|
|
4
4
|
//#region src/drizzle/transaction-mysql.ts
|
|
5
5
|
/** Locking discovery and later SQL policy predicates must see the same current
|
|
6
6
|
* authority. MySQL's default repeatable-read snapshot is unsuitable after a
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@yielded/auth-persistence-drizzle","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@yielded/auth-persistence-drizzle","version":"0.1.0-beta.16","dependencies":{"@noble/hashes":"2.3.0","@yielded/auth":"0.1.0-beta.16","@yielded/auth-crypto":"0.1.0-beta.16","@yielded/auth-persistence":"0.1.0-beta.16"},"devDependencies":{"@effect/platform-bun":"4.0.0","@effect/platform-node":"4.0.0","@effect/sql-d1":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-mysql2":"4.0.0","@effect/sql-pg":"4.0.0","@effect/sql-pglite":"4.0.0","@effect/sql-sqlite-bun":"4.0.0","@effect/sql-sqlite-do":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/sql-sqlite-wasm":"4.0.0","@effect/vitest":"4.0.0","drizzle-orm":"1.0.0-rc.4","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"@effect/sql-d1":">=4.0.0","@effect/sql-libsql":">=4.0.0","@effect/sql-mysql2":">=4.0.0","@effect/sql-pg":">=4.0.0","@effect/sql-pglite":">=4.0.0","@effect/sql-sqlite-bun":">=4.0.0","@effect/sql-sqlite-do":">=4.0.0","@effect/sql-sqlite-node":">=4.0.0","@effect/sql-sqlite-wasm":">=4.0.0","drizzle-orm":">=1.0.0-rc.4","effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./D1":{"types":"./dist/D1.d.mts","default":"./dist/D1.mjs"},"./Libsql":{"types":"./dist/Libsql.d.mts","default":"./dist/Libsql.mjs"},"./Mysql2":{"types":"./dist/Mysql2.d.mts","default":"./dist/Mysql2.mjs"},"./Pglite":{"types":"./dist/Pglite.d.mts","default":"./dist/Pglite.mjs"},"./Postgres":{"types":"./dist/Postgres.d.mts","default":"./dist/Postgres.mjs"},"./SqliteBun":{"types":"./dist/SqliteBun.d.mts","default":"./dist/SqliteBun.mjs"},"./SqliteDo":{"types":"./dist/SqliteDo.d.mts","default":"./dist/SqliteDo.mjs"},"./SqliteNode":{"types":"./dist/SqliteNode.d.mts","default":"./dist/SqliteNode.mjs"},"./SqliteWasm":{"types":"./dist/SqliteWasm.d.mts","default":"./dist/SqliteWasm.mjs"}},"description":"Drizzle persistence, table mappings, and migration adapters for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence-drizzle"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests","example:totp":"bun test/fixtures/totp-sqlite-bun.ts"},"peerDependenciesMeta":{"@effect/sql-d1":{"optional":true},"@effect/sql-libsql":{"optional":true},"@effect/sql-mysql2":{"optional":true},"@effect/sql-pg":{"optional":true},"@effect/sql-pglite":{"optional":true},"@effect/sql-sqlite-bun":{"optional":true},"@effect/sql-sqlite-do":{"optional":true},"@effect/sql-sqlite-node":{"optional":true},"@effect/sql-sqlite-wasm":{"optional":true}}}
|
package/src/drizzle/d1-emails.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* oxlint-disable no-explicit-any -- D1 batches bridge consumer-owned Drizzle tables. */
|
|
2
2
|
import type { D1Client } from "@effect/sql-d1/D1Client";
|
|
3
|
+
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
3
4
|
import {
|
|
4
5
|
EmailAddressPersistence,
|
|
5
6
|
EmailSignInTargets,
|
|
@@ -49,7 +50,7 @@ import {
|
|
|
49
50
|
type EmailRegistrationMapping,
|
|
50
51
|
type EmailSignInMapping,
|
|
51
52
|
} from "./email-model";
|
|
52
|
-
import type
|
|
53
|
+
import { type EmailRegistrationAuthority, readEmailRegistrationTarget } from "./email-registration";
|
|
53
54
|
import {
|
|
54
55
|
CurrentEmailSql,
|
|
55
56
|
currentAddress,
|
|
@@ -63,7 +64,9 @@ import {
|
|
|
63
64
|
type EmailSqlDatabase,
|
|
64
65
|
} from "./email-sql";
|
|
65
66
|
import { column, isMappedConstraintConflict, PersistenceMappingError, updateValues } from "./model";
|
|
67
|
+
import { nativeDatabase } from "./native-database";
|
|
66
68
|
import type { D1ProofPersistenceMapping } from "./proof-model";
|
|
69
|
+
import { validateDrizzleStorage } from "./storage-validation";
|
|
67
70
|
import type { SuppliedService } from "./SuppliedService";
|
|
68
71
|
|
|
69
72
|
type PlanPrepare<Method extends (...args: any[]) => any, A> = (
|
|
@@ -966,6 +969,7 @@ const registrationPlan = Effect.fn("Drizzle.registrationPlan")(function* <Regist
|
|
|
966
969
|
allocated: {
|
|
967
970
|
readonly credentialId?: string;
|
|
968
971
|
readonly securityRevision?: SecurityRevision;
|
|
972
|
+
readonly displacedSecurityRevision?: SecurityRevision;
|
|
969
973
|
readonly identifierRevision?: SecurityRevision;
|
|
970
974
|
readonly credentialRevision?: SecurityRevision;
|
|
971
975
|
readonly nativeSubjectId?: unknown;
|
|
@@ -1000,6 +1004,21 @@ const registrationPlan = Effect.fn("Drizzle.registrationPlan")(function* <Regist
|
|
|
1000
1004
|
)
|
|
1001
1005
|
return { receipt: prepare({ _tag: "Rejected" }, journal), statements: [] };
|
|
1002
1006
|
|
|
1007
|
+
const target =
|
|
1008
|
+
mapping.mode === "atomic"
|
|
1009
|
+
? yield* readEmailRegistrationTarget(mapping, input.identifier, false)
|
|
1010
|
+
: undefined;
|
|
1011
|
+
|
|
1012
|
+
if (target?._tag === "Rejected")
|
|
1013
|
+
return { receipt: prepare({ _tag: "Rejected" }, journal), statements: [] };
|
|
1014
|
+
if (
|
|
1015
|
+
target?._tag === "Reserved" &&
|
|
1016
|
+
(allocated.displacedSecurityRevision === undefined ||
|
|
1017
|
+
allocated.displacedSecurityRevision === target.securityRevision ||
|
|
1018
|
+
allocated.identifierRevision === target.bindingRevision)
|
|
1019
|
+
)
|
|
1020
|
+
return yield* unavailable();
|
|
1021
|
+
|
|
1003
1022
|
const intent = {
|
|
1004
1023
|
moduleId: input.moduleId,
|
|
1005
1024
|
commandId: input.commandId,
|
|
@@ -1062,6 +1081,30 @@ const registrationPlan = Effect.fn("Drizzle.registrationPlan")(function* <Regist
|
|
|
1062
1081
|
const nativeSubjectId = allocated.nativeSubjectId;
|
|
1063
1082
|
|
|
1064
1083
|
desired = { _tag: "Registered" };
|
|
1084
|
+
const i = mapping.identifier;
|
|
1085
|
+
const s = mapping.subject;
|
|
1086
|
+
const marker = `effect-auth-proof-guard:protected:${input.completion.input.continuationId}`;
|
|
1087
|
+
|
|
1088
|
+
if (target?._tag === "Reserved") {
|
|
1089
|
+
// The planning reads hold no locks. Guard both ownership and the displaced
|
|
1090
|
+
// subject revision before any provisioning or invalidation can commit.
|
|
1091
|
+
statements.push(
|
|
1092
|
+
yield* assertion(
|
|
1093
|
+
and(
|
|
1094
|
+
existsSql(sql`select 1 from ${i.table} where
|
|
1095
|
+
${column(i.table, i.namespace)}=${sql.param(input.identifier.namespace, column(i.table, i.namespace))}
|
|
1096
|
+
and ${column(i.table, i.value)}=${sql.param(input.identifier.value, column(i.table, i.value))}
|
|
1097
|
+
and ${column(i.table, i.subjectId)}=${sql.param(target.nativeSubjectId, column(i.table, i.subjectId))}
|
|
1098
|
+
and ${column(i.table, i.bindingRevision)}=${sql.param(target.bindingRevision, column(i.table, i.bindingRevision))}
|
|
1099
|
+
and ${column(i.table, i.verifiedAt)} is null`),
|
|
1100
|
+
existsSql(sql`select 1 from ${s.table} where
|
|
1101
|
+
${column(s.table, s.id)}=${sql.param(target.nativeSubjectId, column(s.table, s.id))}
|
|
1102
|
+
and ${column(s.table, s.securityRevision)}=${sql.param(target.securityRevision, column(s.table, s.securityRevision))}`),
|
|
1103
|
+
)!,
|
|
1104
|
+
marker,
|
|
1105
|
+
),
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1065
1108
|
statements.push(
|
|
1066
1109
|
yield* statement(
|
|
1067
1110
|
database.insert(mapping.subject.table).values(
|
|
@@ -1071,19 +1114,55 @@ const registrationPlan = Effect.fn("Drizzle.registrationPlan")(function* <Regist
|
|
|
1071
1114
|
}),
|
|
1072
1115
|
),
|
|
1073
1116
|
),
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1117
|
+
...(target?._tag === "Reserved"
|
|
1118
|
+
? [
|
|
1119
|
+
yield* statement(
|
|
1120
|
+
database
|
|
1121
|
+
.update(i.table)
|
|
1122
|
+
.set(
|
|
1123
|
+
updateValues([
|
|
1124
|
+
[i.subjectId, nativeSubjectId],
|
|
1125
|
+
[i.verifiedAt, mapping.encodeInstant(transitionMillis)],
|
|
1126
|
+
[i.bindingRevision, allocated.identifierRevision],
|
|
1127
|
+
]),
|
|
1128
|
+
)
|
|
1129
|
+
.where(
|
|
1130
|
+
and(
|
|
1131
|
+
eq(column(i.table, i.namespace), input.identifier.namespace),
|
|
1132
|
+
eq(column(i.table, i.value), input.identifier.value),
|
|
1133
|
+
eq(column(i.table, i.subjectId), target.nativeSubjectId),
|
|
1134
|
+
eq(column(i.table, i.bindingRevision), target.bindingRevision),
|
|
1135
|
+
sql`${column(i.table, i.verifiedAt)} is null`,
|
|
1136
|
+
),
|
|
1137
|
+
),
|
|
1138
|
+
),
|
|
1139
|
+
yield* statement(
|
|
1140
|
+
database
|
|
1141
|
+
.update(s.table)
|
|
1142
|
+
.set(updateValues([[s.securityRevision, allocated.displacedSecurityRevision]]))
|
|
1143
|
+
.where(
|
|
1144
|
+
and(
|
|
1145
|
+
eq(column(s.table, s.id), target.nativeSubjectId),
|
|
1146
|
+
eq(column(s.table, s.securityRevision), target.securityRevision),
|
|
1147
|
+
),
|
|
1148
|
+
),
|
|
1149
|
+
),
|
|
1150
|
+
]
|
|
1151
|
+
: [
|
|
1152
|
+
yield* statement(
|
|
1153
|
+
database.insert(i.table).values(
|
|
1154
|
+
driverValues(
|
|
1155
|
+
i.encodeVerifiedInsert({
|
|
1156
|
+
identifier: input.identifier,
|
|
1157
|
+
subjectId: nativeSubjectId,
|
|
1158
|
+
verifiedAtMillis: transitionMillis,
|
|
1159
|
+
bindingRevision: allocated.identifierRevision,
|
|
1160
|
+
}),
|
|
1161
|
+
[[i.verifiedAt, mapping.encodeInstant(transitionMillis)]],
|
|
1162
|
+
),
|
|
1163
|
+
),
|
|
1164
|
+
),
|
|
1165
|
+
]),
|
|
1087
1166
|
yield* statement(
|
|
1088
1167
|
database.insert(mapping.credential.table).values(
|
|
1089
1168
|
mapping.credential.encodeVerifiedInsert({
|
|
@@ -1145,6 +1224,11 @@ const registrationPlan = Effect.fn("Drizzle.registrationPlan")(function* <Regist
|
|
|
1145
1224
|
);
|
|
1146
1225
|
|
|
1147
1226
|
applied = and(
|
|
1227
|
+
target?._tag === "Reserved"
|
|
1228
|
+
? existsSql(sql`select 1 from ${s.table} where
|
|
1229
|
+
${sId}=${sql.param(target.nativeSubjectId, sId)}
|
|
1230
|
+
and ${sRevision}=${sql.param(allocated.displacedSecurityRevision, sRevision)}`)
|
|
1231
|
+
: sql`true`,
|
|
1148
1232
|
existsSql(
|
|
1149
1233
|
sql`select 1 from ${mapping.subject.table} where ${sId}=${sql.param(nativeSubjectId, sId)} and ${sStatus}=${sql.param(mapping.subject.d1ActiveStatusValue, sStatus)} and ${sRevision}=${sql.param(allocated.securityRevision, sRevision)}`,
|
|
1150
1234
|
),
|
|
@@ -1224,6 +1308,10 @@ const makeRegistrationPlans = <Registration>(
|
|
|
1224
1308
|
? yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync)
|
|
1225
1309
|
: undefined;
|
|
1226
1310
|
|
|
1311
|
+
const displacedSecurityRevision = atomic
|
|
1312
|
+
? yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync)
|
|
1313
|
+
: undefined;
|
|
1314
|
+
|
|
1227
1315
|
const identifierRevision = atomic
|
|
1228
1316
|
? yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync)
|
|
1229
1317
|
: undefined;
|
|
@@ -1253,6 +1341,7 @@ const makeRegistrationPlans = <Registration>(
|
|
|
1253
1341
|
{
|
|
1254
1342
|
...(credentialId === undefined ? {} : { credentialId }),
|
|
1255
1343
|
...(securityRevision === undefined ? {} : { securityRevision }),
|
|
1344
|
+
...(displacedSecurityRevision === undefined ? {} : { displacedSecurityRevision }),
|
|
1256
1345
|
...(identifierRevision === undefined ? {} : { identifierRevision }),
|
|
1257
1346
|
...(credentialRevision === undefined ? {} : { credentialRevision }),
|
|
1258
1347
|
...(nativeSubjectId === undefined ? {} : { nativeSubjectId }),
|
|
@@ -1271,29 +1360,40 @@ export const makeD1EmailSignInServices = <
|
|
|
1271
1360
|
>(
|
|
1272
1361
|
mapping: EmailSignInMapping<S, I, C, NativeId>,
|
|
1273
1362
|
) =>
|
|
1274
|
-
Effect.
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1363
|
+
Effect.flatMap(nativeDatabase(DatabaseService), (database) =>
|
|
1364
|
+
validateDrizzleStorage(mapping).pipe(
|
|
1365
|
+
Effect.provideService(NativeDatabase, database),
|
|
1366
|
+
Effect.mapError(unavailable),
|
|
1367
|
+
Effect.as({
|
|
1368
|
+
emailSignInTargets: EmailSignInTargets.of({
|
|
1369
|
+
lookup: (input) => {
|
|
1370
|
+
if (!validEmailSignInConstraints(mapping as any)) return Effect.fail(unavailable());
|
|
1371
|
+
|
|
1372
|
+
return emailLookupRows(mapping as any, input.moduleId, input.identifier).pipe(
|
|
1373
|
+
Effect.flatMap((rows) => {
|
|
1374
|
+
const row = rows[0];
|
|
1375
|
+
|
|
1376
|
+
if (row === undefined) return Effect.succeed(Option.none());
|
|
1377
|
+
|
|
1378
|
+
return decodeEmailSnapshot(
|
|
1379
|
+
mapping as any,
|
|
1380
|
+
input.moduleId,
|
|
1381
|
+
input.identifier,
|
|
1382
|
+
row,
|
|
1383
|
+
).pipe(
|
|
1384
|
+
Effect.map((snapshot) =>
|
|
1385
|
+
snapshot === undefined ? Option.none() : Option.some(snapshot),
|
|
1386
|
+
),
|
|
1387
|
+
);
|
|
1388
|
+
}),
|
|
1389
|
+
Effect.provideService(CurrentD1PlanningDatabase, database),
|
|
1390
|
+
translateFailure,
|
|
1289
1391
|
);
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
}),
|
|
1296
|
-
}));
|
|
1392
|
+
},
|
|
1393
|
+
}),
|
|
1394
|
+
}),
|
|
1395
|
+
),
|
|
1396
|
+
);
|
|
1297
1397
|
|
|
1298
1398
|
export const makeD1EmailAddressServices = Effect.fnUntraced(function* <
|
|
1299
1399
|
S extends AnySQLiteTable,
|
|
@@ -1333,6 +1433,11 @@ export const makeD1EmailAddressServices = Effect.fnUntraced(function* <
|
|
|
1333
1433
|
) {
|
|
1334
1434
|
const database = yield* DatabaseService;
|
|
1335
1435
|
|
|
1436
|
+
yield* validateDrizzleStorage({ ...mapping, proof: proofMapping }).pipe(
|
|
1437
|
+
Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
|
|
1438
|
+
Effect.mapError(unavailable),
|
|
1439
|
+
);
|
|
1440
|
+
|
|
1336
1441
|
const hooks = yield* LifecycleHooks;
|
|
1337
1442
|
|
|
1338
1443
|
const plans = makeAddressPlans(
|
|
@@ -1419,6 +1524,11 @@ export const makeD1EmailRegistrationServices = Effect.fnUntraced(function* <
|
|
|
1419
1524
|
) {
|
|
1420
1525
|
const database = yield* DatabaseService;
|
|
1421
1526
|
|
|
1527
|
+
yield* validateDrizzleStorage({ ...mapping, proof: proofMapping }).pipe(
|
|
1528
|
+
Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
|
|
1529
|
+
Effect.mapError(unavailable),
|
|
1530
|
+
);
|
|
1531
|
+
|
|
1422
1532
|
const hooks = yield* LifecycleHooks;
|
|
1423
1533
|
|
|
1424
1534
|
const plans = makeRegistrationPlans(
|
|
@@ -1507,8 +1617,12 @@ export function coordinateD1EmailAddress<
|
|
|
1507
1617
|
CoordinatorError<E> | DatabaseError,
|
|
1508
1618
|
Exclude<R, EmailAddressPersistence | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
1509
1619
|
> {
|
|
1510
|
-
return Effect.flatMap(acquire, (database) =>
|
|
1620
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
1511
1621
|
Effect.gen(function* () {
|
|
1622
|
+
yield* validateDrizzleStorage({
|
|
1623
|
+
...options.mapping,
|
|
1624
|
+
proof: options.proofMapping,
|
|
1625
|
+
}).pipe(Effect.mapError(unavailable));
|
|
1512
1626
|
const hooks = yield* LifecycleHooks;
|
|
1513
1627
|
|
|
1514
1628
|
if (yield* hasCommitScope) return yield* unavailable();
|
|
@@ -1622,7 +1736,7 @@ export function coordinateD1EmailAddress<
|
|
|
1622
1736
|
).pipe(Effect.provideService(LifecycleHooks, hooks));
|
|
1623
1737
|
|
|
1624
1738
|
return result.value;
|
|
1625
|
-
}),
|
|
1739
|
+
}).pipe(Effect.provideService(NativeDatabase, database)),
|
|
1626
1740
|
);
|
|
1627
1741
|
}
|
|
1628
1742
|
|
|
@@ -1678,8 +1792,12 @@ export function coordinateD1EmailRegistration<
|
|
|
1678
1792
|
CoordinatorError<E> | DatabaseError,
|
|
1679
1793
|
Exclude<R, TargetId | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
1680
1794
|
> {
|
|
1681
|
-
return Effect.flatMap(acquire, (database) =>
|
|
1795
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
1682
1796
|
Effect.gen(function* () {
|
|
1797
|
+
yield* validateDrizzleStorage({
|
|
1798
|
+
...options.mapping,
|
|
1799
|
+
proof: options.proofMapping,
|
|
1800
|
+
}).pipe(Effect.mapError(unavailable));
|
|
1683
1801
|
const hooks = yield* LifecycleHooks;
|
|
1684
1802
|
|
|
1685
1803
|
if (yield* hasCommitScope) return yield* unavailable();
|
|
@@ -1777,7 +1895,7 @@ export function coordinateD1EmailRegistration<
|
|
|
1777
1895
|
).pipe(Effect.provideService(LifecycleHooks, hooks));
|
|
1778
1896
|
|
|
1779
1897
|
return result.value;
|
|
1780
|
-
}),
|
|
1898
|
+
}).pipe(Effect.provideService(NativeDatabase, database)),
|
|
1781
1899
|
);
|
|
1782
1900
|
}
|
|
1783
1901
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { D1Client } from "@effect/sql-d1/D1Client";
|
|
2
|
+
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
2
3
|
import {
|
|
3
4
|
ExternalIdentityMutation,
|
|
4
5
|
type ExternalIdentity,
|
|
@@ -34,6 +35,8 @@ import {
|
|
|
34
35
|
type D1GeneratedIdentityMapping,
|
|
35
36
|
type D1SubjectProvisioningMapping,
|
|
36
37
|
} from "./model";
|
|
38
|
+
import { nativeDatabase } from "./native-database";
|
|
39
|
+
import { validateDrizzleStorage } from "./storage-validation";
|
|
37
40
|
|
|
38
41
|
type RuntimeDatabase = EffectSQLiteD1Database<any> & { readonly $client: D1Client };
|
|
39
42
|
const unavailable = () => IdentityUnavailable.make();
|
|
@@ -100,6 +103,11 @@ export const makeD1SubjectProvisioningServices = Effect.fnUntraced(function* <
|
|
|
100
103
|
>(mapping: D1SubjectProvisioningMapping<Subject, Identifier, Request, NativeId>) {
|
|
101
104
|
const database = yield* DatabaseService;
|
|
102
105
|
|
|
106
|
+
yield* validateDrizzleStorage(mapping).pipe(
|
|
107
|
+
Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
|
|
108
|
+
Effect.mapError(() => IdentityUnavailable.make()),
|
|
109
|
+
);
|
|
110
|
+
|
|
103
111
|
const db = database as RuntimeDatabase;
|
|
104
112
|
const requestTable = mapping.provisioningRequest.table;
|
|
105
113
|
|
|
@@ -262,6 +270,11 @@ export const makeD1ExternalIdentityServices = Effect.fnUntraced(function* <
|
|
|
262
270
|
>(mapping: D1ExternalIdentityMapping<Subject, External, NativeId>) {
|
|
263
271
|
const database = yield* DatabaseService;
|
|
264
272
|
|
|
273
|
+
yield* validateDrizzleStorage(mapping).pipe(
|
|
274
|
+
Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
|
|
275
|
+
Effect.mapError(() => IdentityUnavailable.make()),
|
|
276
|
+
);
|
|
277
|
+
|
|
265
278
|
const db = database as RuntimeDatabase;
|
|
266
279
|
const externalTable = mapping.externalIdentity.table;
|
|
267
280
|
|
package/src/drizzle/d1-oauth.ts
CHANGED
|
@@ -131,7 +131,7 @@ export function coordinateD1OAuthSignIn<
|
|
|
131
131
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
132
132
|
Exclude<R, OAuthSignInPersistence | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
133
133
|
> {
|
|
134
|
-
return Effect.flatMap(acquire, (database) =>
|
|
134
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
135
135
|
coordinateTargetOAuthSignIn<
|
|
136
136
|
never,
|
|
137
137
|
A,
|
|
@@ -162,7 +162,7 @@ export function coordinateD1OAuthSignIn<
|
|
|
162
162
|
|
|
163
163
|
return yield* owner.close(Effect.provideContext(body, provided));
|
|
164
164
|
}),
|
|
165
|
-
),
|
|
165
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
166
166
|
);
|
|
167
167
|
}
|
|
168
168
|
|
|
@@ -191,7 +191,7 @@ export function coordinateD1OAuthRegistrationIntents<
|
|
|
191
191
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
192
192
|
Exclude<R, OAuthRegistrationIntents | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
193
193
|
> {
|
|
194
|
-
return Effect.flatMap(acquire, (database) =>
|
|
194
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
195
195
|
coordinateTargetOAuthRegistrationIntents<
|
|
196
196
|
never,
|
|
197
197
|
A,
|
|
@@ -219,7 +219,7 @@ export function coordinateD1OAuthRegistrationIntents<
|
|
|
219
219
|
|
|
220
220
|
return yield* owner.close(Effect.provideContext(body, provided));
|
|
221
221
|
}),
|
|
222
|
-
),
|
|
222
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
223
223
|
);
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -246,7 +246,7 @@ export function coordinateD1OAuthAccounts<
|
|
|
246
246
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
247
247
|
Exclude<R, OAuthAccountsPersistence | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
248
248
|
> {
|
|
249
|
-
return Effect.flatMap(acquire, (database) =>
|
|
249
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
250
250
|
coordinateTargetOAuthAccounts<
|
|
251
251
|
never,
|
|
252
252
|
A,
|
|
@@ -281,7 +281,7 @@ export function coordinateD1OAuthAccounts<
|
|
|
281
281
|
|
|
282
282
|
return yield* owner.close(Effect.provideContext(body, provided));
|
|
283
283
|
}),
|
|
284
|
-
),
|
|
284
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
285
285
|
);
|
|
286
286
|
}
|
|
287
287
|
|
|
@@ -314,7 +314,7 @@ export function coordinateD1OAuthRegistration<
|
|
|
314
314
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
315
315
|
Exclude<R, TargetId | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
316
316
|
> {
|
|
317
|
-
return Effect.flatMap(acquire, (database) =>
|
|
317
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
318
318
|
coordinateTargetOAuthRegistration<
|
|
319
319
|
Registration,
|
|
320
320
|
never,
|
|
@@ -346,6 +346,6 @@ export function coordinateD1OAuthRegistration<
|
|
|
346
346
|
|
|
347
347
|
return yield* owner.close(Effect.provideContext(body, provided));
|
|
348
348
|
}),
|
|
349
|
-
),
|
|
349
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
350
350
|
);
|
|
351
351
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { D1Client } from "@effect/sql-d1/D1Client";
|
|
2
|
+
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
2
3
|
import type { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
3
4
|
import {
|
|
4
5
|
PasskeyUnavailable,
|
|
@@ -13,6 +14,7 @@ import { Effect, Context } from "effect";
|
|
|
13
14
|
import { Database as DatabaseService } from "./d1-database";
|
|
14
15
|
import { makeD1Owner } from "./d1-planning";
|
|
15
16
|
import { D1BatchStatements } from "./D1BatchStatements";
|
|
17
|
+
import { nativeDatabase } from "./native-database";
|
|
16
18
|
import { makePasskeyTarget } from "./passkey-drivers";
|
|
17
19
|
import type {
|
|
18
20
|
D1PasskeyMapping,
|
|
@@ -96,7 +98,7 @@ export function coordinatePasskeyPersistence<
|
|
|
96
98
|
| DatabaseRequirements
|
|
97
99
|
| RSetup
|
|
98
100
|
> {
|
|
99
|
-
return Effect.flatMap(acquire, (database) =>
|
|
101
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
100
102
|
coordinateTargetPasskey(database, options.mapping, configuration, (_, services, append) =>
|
|
101
103
|
Effect.gen(function* () {
|
|
102
104
|
const original = services.passkeyPersistence;
|
|
@@ -123,7 +125,7 @@ export function coordinatePasskeyPersistence<
|
|
|
123
125
|
|
|
124
126
|
return yield* owner.close(Effect.provideContext(body, provided));
|
|
125
127
|
}),
|
|
126
|
-
),
|
|
128
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
127
129
|
);
|
|
128
130
|
}
|
|
129
131
|
|
|
@@ -158,7 +160,7 @@ export function coordinatePasskeyRegistrationCeremony<
|
|
|
158
160
|
| DatabaseRequirements
|
|
159
161
|
| RSetup
|
|
160
162
|
> {
|
|
161
|
-
return Effect.flatMap(acquire, (database) =>
|
|
163
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
162
164
|
coordinateTargetPasskeyRegistration(
|
|
163
165
|
database,
|
|
164
166
|
options.mapping,
|
|
@@ -189,7 +191,7 @@ export function coordinatePasskeyRegistrationCeremony<
|
|
|
189
191
|
|
|
190
192
|
return yield* owner.close(Effect.provideContext(body, provided));
|
|
191
193
|
}),
|
|
192
|
-
),
|
|
194
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
193
195
|
);
|
|
194
196
|
}
|
|
195
197
|
|
|
@@ -241,7 +243,7 @@ export function coordinatePasskeyManagement<
|
|
|
241
243
|
| DatabaseRequirements
|
|
242
244
|
| RSetup
|
|
243
245
|
> {
|
|
244
|
-
return Effect.flatMap(acquire, (database) =>
|
|
246
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
245
247
|
coordinateTargetPasskeyManagement(
|
|
246
248
|
database,
|
|
247
249
|
options.mapping,
|
|
@@ -286,7 +288,7 @@ export function coordinatePasskeyManagement<
|
|
|
286
288
|
|
|
287
289
|
return yield* owner.close(Effect.provideContext(body, context));
|
|
288
290
|
}),
|
|
289
|
-
),
|
|
291
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
290
292
|
);
|
|
291
293
|
}
|
|
292
294
|
|
|
@@ -330,7 +332,7 @@ export function coordinatePasskeyRegistration<
|
|
|
330
332
|
| DatabaseRequirements
|
|
331
333
|
| RSetup
|
|
332
334
|
> {
|
|
333
|
-
return Effect.flatMap(acquire, (database) =>
|
|
335
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
334
336
|
coordinateTargetPasskeyRegistrationWriter(
|
|
335
337
|
database,
|
|
336
338
|
options.mapping,
|
|
@@ -372,6 +374,6 @@ export function coordinatePasskeyRegistration<
|
|
|
372
374
|
|
|
373
375
|
return yield* owner.close(Effect.provideContext(body, context));
|
|
374
376
|
}),
|
|
375
|
-
),
|
|
377
|
+
).pipe(Effect.provideService(NativeDatabase, database)),
|
|
376
378
|
);
|
|
377
379
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* oxlint-disable no-explicit-any -- driver exports preserve concrete consumer mappings. */
|
|
2
2
|
import type { D1Client } from "@effect/sql-d1/D1Client";
|
|
3
|
+
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
3
4
|
import {
|
|
4
5
|
coordinateCommit,
|
|
5
6
|
CurrentCommitJournal,
|
|
@@ -39,6 +40,7 @@ import { CurrentD1PlanningDatabase, makeD1Owner } from "./d1-planning";
|
|
|
39
40
|
import { checkD1ProofCompletion, compileD1ProofCompletionPlan } from "./d1-proofs";
|
|
40
41
|
import { D1BatchStatements } from "./D1BatchStatements";
|
|
41
42
|
import { PersistenceMappingError, column, updateValues } from "./model";
|
|
43
|
+
import { nativeDatabase } from "./native-database";
|
|
42
44
|
import type {
|
|
43
45
|
D1PasswordPreparedPersistenceMapping,
|
|
44
46
|
D1PasswordPreparedProofMapping,
|
|
@@ -57,6 +59,7 @@ import {
|
|
|
57
59
|
unavailable,
|
|
58
60
|
} from "./password-prepared-state";
|
|
59
61
|
import { CurrentPasswordSql, type PasswordSqlDatabase } from "./password-sql";
|
|
62
|
+
import { validateDrizzleStorage } from "./storage-validation";
|
|
60
63
|
import type { SuppliedService } from "./SuppliedService";
|
|
61
64
|
|
|
62
65
|
type PlanPrepare<Method extends (...args: any[]) => any, A> = (
|
|
@@ -990,6 +993,11 @@ export const makeD1PasswordPreparedPersistenceServices = Effect.fnUntraced(funct
|
|
|
990
993
|
) {
|
|
991
994
|
const database = yield* DatabaseService;
|
|
992
995
|
|
|
996
|
+
yield* validateDrizzleStorage({ ...mapping, proof: proofMapping }).pipe(
|
|
997
|
+
Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
|
|
998
|
+
Effect.mapError(unavailable),
|
|
999
|
+
);
|
|
1000
|
+
|
|
993
1001
|
const hooks = yield* LifecycleHooks;
|
|
994
1002
|
const plans = makePreparedPlans(mapping as unknown as Mapping, proofMapping);
|
|
995
1003
|
|
|
@@ -1079,8 +1087,12 @@ export function coordinateD1PasswordPreparedPersistence<
|
|
|
1079
1087
|
E | PasswordUnavailable | HookConfigurationError | DatabaseError,
|
|
1080
1088
|
Exclude<R, TargetId | D1BatchStatements> | LifecycleHooks | DatabaseRequirements
|
|
1081
1089
|
> {
|
|
1082
|
-
return Effect.flatMap(acquire, (database) =>
|
|
1090
|
+
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
1083
1091
|
Effect.gen(function* () {
|
|
1092
|
+
yield* validateDrizzleStorage({
|
|
1093
|
+
...options.mapping,
|
|
1094
|
+
proof: options.proofMapping,
|
|
1095
|
+
}).pipe(Effect.mapError(unavailable));
|
|
1084
1096
|
const hooks = yield* LifecycleHooks;
|
|
1085
1097
|
|
|
1086
1098
|
if (yield* hasCommitScope) return yield* unavailable();
|
|
@@ -1206,7 +1218,7 @@ export function coordinateD1PasswordPreparedPersistence<
|
|
|
1206
1218
|
).pipe(Effect.provideService(LifecycleHooks, hooks));
|
|
1207
1219
|
|
|
1208
1220
|
return result.value;
|
|
1209
|
-
}),
|
|
1221
|
+
}).pipe(Effect.provideService(NativeDatabase, database)),
|
|
1210
1222
|
);
|
|
1211
1223
|
}
|
|
1212
1224
|
|