@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.
Files changed (190) hide show
  1. package/dist/D1.d.mts +123 -9
  2. package/dist/Libsql.d.mts +141 -27
  3. package/dist/Mysql2.d.mts +124 -10
  4. package/dist/Pglite.d.mts +124 -10
  5. package/dist/Postgres.d.mts +129 -15
  6. package/dist/SqliteBun.d.mts +135 -21
  7. package/dist/SqliteDo.d.mts +135 -21
  8. package/dist/SqliteNode.d.mts +135 -21
  9. package/dist/SqliteWasm.d.mts +135 -21
  10. package/dist/drizzle/d1-emails.d.mts +3 -3
  11. package/dist/drizzle/d1-emails.mjs +56 -11
  12. package/dist/drizzle/d1-emails.mjs.map +1 -1
  13. package/dist/drizzle/d1-identity.mjs +9 -2
  14. package/dist/drizzle/d1-identity.mjs.map +1 -1
  15. package/dist/drizzle/d1-oauth.d.mts +6 -6
  16. package/dist/drizzle/d1-oauth.mjs +8 -8
  17. package/dist/drizzle/d1-oauth.mjs.map +1 -1
  18. package/dist/drizzle/d1-passkey.d.mts +2 -1
  19. package/dist/drizzle/d1-passkey.mjs +10 -8
  20. package/dist/drizzle/d1-passkey.mjs.map +1 -1
  21. package/dist/drizzle/d1-password-prepared.d.mts +1 -1
  22. package/dist/drizzle/d1-password-prepared.mjs +16 -5
  23. package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
  24. package/dist/drizzle/d1-passwords.d.mts +2 -2
  25. package/dist/drizzle/d1-passwords.mjs +19 -6
  26. package/dist/drizzle/d1-passwords.mjs.map +1 -1
  27. package/dist/drizzle/d1-phone.d.mts +2 -1
  28. package/dist/drizzle/d1-phone.mjs +4 -2
  29. package/dist/drizzle/d1-phone.mjs.map +1 -1
  30. package/dist/drizzle/d1-proofs.d.mts +1 -1
  31. package/dist/drizzle/d1-proofs.mjs +18 -7
  32. package/dist/drizzle/d1-proofs.mjs.map +1 -1
  33. package/dist/drizzle/d1-sessions.d.mts +6 -5
  34. package/dist/drizzle/d1-sessions.mjs +29 -19
  35. package/dist/drizzle/d1-sessions.mjs.map +1 -1
  36. package/dist/drizzle/d1-totp.d.mts +2 -1
  37. package/dist/drizzle/d1-totp.mjs +4 -2
  38. package/dist/drizzle/d1-totp.mjs.map +1 -1
  39. package/dist/drizzle/email-registration.d.mts +5 -1
  40. package/dist/drizzle/email-registration.mjs +48 -4
  41. package/dist/drizzle/email-registration.mjs.map +1 -1
  42. package/dist/drizzle/email-target.d.mts +1 -0
  43. package/dist/drizzle/email-target.mjs +9 -0
  44. package/dist/drizzle/email-target.mjs.map +1 -1
  45. package/dist/drizzle/mysql-emails.d.mts +4 -4
  46. package/dist/drizzle/mysql-emails.mjs +8 -7
  47. package/dist/drizzle/mysql-emails.mjs.map +1 -1
  48. package/dist/drizzle/mysql-identity.mjs +11 -4
  49. package/dist/drizzle/mysql-identity.mjs.map +1 -1
  50. package/dist/drizzle/mysql-password-prepared.d.mts +2 -2
  51. package/dist/drizzle/mysql-password-prepared.mjs +4 -3
  52. package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
  53. package/dist/drizzle/mysql-passwords.d.mts +3 -3
  54. package/dist/drizzle/mysql-passwords.mjs +7 -6
  55. package/dist/drizzle/mysql-passwords.mjs.map +1 -1
  56. package/dist/drizzle/mysql-proofs.d.mts +2 -2
  57. package/dist/drizzle/mysql-proofs.mjs +4 -3
  58. package/dist/drizzle/mysql-proofs.mjs.map +1 -1
  59. package/dist/drizzle/mysql-sessions.d.mts +6 -6
  60. package/dist/drizzle/mysql-sessions.mjs +16 -15
  61. package/dist/drizzle/mysql-sessions.mjs.map +1 -1
  62. package/dist/drizzle/native-database.mjs +1 -1
  63. package/dist/drizzle/native-database.mjs.map +1 -1
  64. package/dist/drizzle/oauth-connected-drivers.mjs +10 -8
  65. package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
  66. package/dist/drizzle/oauth-connected-flow.mjs +62 -13
  67. package/dist/drizzle/oauth-connected-flow.mjs.map +1 -1
  68. package/dist/drizzle/oauth-connected-input.mjs +6 -0
  69. package/dist/drizzle/oauth-connected-input.mjs.map +1 -1
  70. package/dist/drizzle/oauth-connected-maintenance.mjs +3 -3
  71. package/dist/drizzle/oauth-connected-maintenance.mjs.map +1 -1
  72. package/dist/drizzle/oauth-connected-target.d.mts +116 -2
  73. package/dist/drizzle/oauth-connected-target.mjs +5 -3
  74. package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
  75. package/dist/drizzle/oauth-drivers.mjs +8 -8
  76. package/dist/drizzle/oauth-drivers.mjs.map +1 -1
  77. package/dist/drizzle/oauth-target.d.mts +3 -3
  78. package/dist/drizzle/oauth-target.mjs +8 -6
  79. package/dist/drizzle/oauth-target.mjs.map +1 -1
  80. package/dist/drizzle/passkey-drivers.mjs +4 -4
  81. package/dist/drizzle/passkey-drivers.mjs.map +1 -1
  82. package/dist/drizzle/passkey-write-drivers.mjs +4 -4
  83. package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
  84. package/dist/drizzle/passkey-write-target.d.mts +1 -1
  85. package/dist/drizzle/password-prepared-sql.mjs +5 -0
  86. package/dist/drizzle/password-prepared-sql.mjs.map +1 -1
  87. package/dist/drizzle/password-prepared-target.d.mts +2 -1
  88. package/dist/drizzle/password-prepared-target.mjs +5 -0
  89. package/dist/drizzle/password-prepared-target.mjs.map +1 -1
  90. package/dist/drizzle/password-registration.d.mts +1 -1
  91. package/dist/drizzle/password-registration.mjs +2 -0
  92. package/dist/drizzle/password-registration.mjs.map +1 -1
  93. package/dist/drizzle/password-target.d.mts +1 -0
  94. package/dist/drizzle/password-target.mjs +6 -0
  95. package/dist/drizzle/password-target.mjs.map +1 -1
  96. package/dist/drizzle/pg-emails.d.mts +4 -4
  97. package/dist/drizzle/pg-emails.mjs +8 -7
  98. package/dist/drizzle/pg-emails.mjs.map +1 -1
  99. package/dist/drizzle/pg-identity.mjs +12 -5
  100. package/dist/drizzle/pg-identity.mjs.map +1 -1
  101. package/dist/drizzle/pg-password-prepared.d.mts +2 -2
  102. package/dist/drizzle/pg-password-prepared.mjs +4 -3
  103. package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
  104. package/dist/drizzle/pg-passwords.d.mts +3 -3
  105. package/dist/drizzle/pg-passwords.mjs +7 -6
  106. package/dist/drizzle/pg-passwords.mjs.map +1 -1
  107. package/dist/drizzle/pg-proofs.d.mts +2 -2
  108. package/dist/drizzle/pg-proofs.mjs +4 -3
  109. package/dist/drizzle/pg-proofs.mjs.map +1 -1
  110. package/dist/drizzle/pg-sessions.d.mts +6 -6
  111. package/dist/drizzle/pg-sessions.mjs +16 -15
  112. package/dist/drizzle/pg-sessions.mjs.map +1 -1
  113. package/dist/drizzle/phone-target.mjs +11 -2
  114. package/dist/drizzle/phone-target.mjs.map +1 -1
  115. package/dist/drizzle/proof-target.d.mts +1 -0
  116. package/dist/drizzle/proof-target.mjs +2 -0
  117. package/dist/drizzle/proof-target.mjs.map +1 -1
  118. package/dist/drizzle/query-operations.mjs +2 -0
  119. package/dist/drizzle/query-operations.mjs.map +1 -1
  120. package/dist/drizzle/session-target.d.mts +1 -0
  121. package/dist/drizzle/session-target.mjs +9 -6
  122. package/dist/drizzle/session-target.mjs.map +1 -1
  123. package/dist/drizzle/sqlite-emails.mjs +8 -7
  124. package/dist/drizzle/sqlite-emails.mjs.map +1 -1
  125. package/dist/drizzle/sqlite-identity.mjs +7 -2
  126. package/dist/drizzle/sqlite-identity.mjs.map +1 -1
  127. package/dist/drizzle/sqlite-password-prepared.mjs +4 -3
  128. package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
  129. package/dist/drizzle/sqlite-passwords.mjs +7 -6
  130. package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
  131. package/dist/drizzle/sqlite-proofs.mjs +4 -3
  132. package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
  133. package/dist/drizzle/sqlite-sessions.mjs +16 -15
  134. package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
  135. package/dist/drizzle/storage-validation.mjs +234 -0
  136. package/dist/drizzle/storage-validation.mjs.map +1 -0
  137. package/dist/drizzle/totp-target.mjs +5 -2
  138. package/dist/drizzle/totp-target.mjs.map +1 -1
  139. package/dist/drizzle/transaction-mysql.mjs +1 -1
  140. package/package.json +1 -1
  141. package/src/drizzle/d1-emails.ts +158 -40
  142. package/src/drizzle/d1-identity.ts +13 -0
  143. package/src/drizzle/d1-oauth.ts +8 -8
  144. package/src/drizzle/d1-passkey.ts +10 -8
  145. package/src/drizzle/d1-password-prepared.ts +14 -2
  146. package/src/drizzle/d1-passwords.ts +22 -4
  147. package/src/drizzle/d1-phone.ts +4 -2
  148. package/src/drizzle/d1-proofs.ts +55 -3
  149. package/src/drizzle/d1-sessions.ts +67 -18
  150. package/src/drizzle/d1-totp.ts +4 -2
  151. package/src/drizzle/email-registration.ts +160 -12
  152. package/src/drizzle/email-target.ts +22 -4
  153. package/src/drizzle/mysql-emails.ts +17 -7
  154. package/src/drizzle/mysql-identity.ts +13 -0
  155. package/src/drizzle/mysql-password-prepared.ts +7 -3
  156. package/src/drizzle/mysql-passwords.ts +13 -6
  157. package/src/drizzle/mysql-proofs.ts +7 -3
  158. package/src/drizzle/mysql-sessions.ts +31 -15
  159. package/src/drizzle/native-database.ts +5 -4
  160. package/src/drizzle/oauth-connected-drivers.ts +10 -8
  161. package/src/drizzle/oauth-connected-flow.ts +98 -10
  162. package/src/drizzle/oauth-connected-input.ts +7 -0
  163. package/src/drizzle/oauth-connected-maintenance.ts +3 -2
  164. package/src/drizzle/oauth-connected-target.ts +4 -2
  165. package/src/drizzle/oauth-drivers.ts +8 -8
  166. package/src/drizzle/oauth-target.ts +13 -7
  167. package/src/drizzle/passkey-drivers.ts +4 -4
  168. package/src/drizzle/passkey-write-drivers.ts +8 -5
  169. package/src/drizzle/password-prepared-sql.ts +13 -1
  170. package/src/drizzle/password-prepared-target.ts +7 -1
  171. package/src/drizzle/password-registration.ts +10 -3
  172. package/src/drizzle/password-target.ts +22 -4
  173. package/src/drizzle/pg-emails.ts +17 -7
  174. package/src/drizzle/pg-identity.ts +13 -0
  175. package/src/drizzle/pg-password-prepared.ts +7 -3
  176. package/src/drizzle/pg-passwords.ts +13 -6
  177. package/src/drizzle/pg-proofs.ts +7 -3
  178. package/src/drizzle/pg-sessions.ts +31 -15
  179. package/src/drizzle/phone-target.ts +30 -5
  180. package/src/drizzle/proof-target.ts +10 -2
  181. package/src/drizzle/query-operations.ts +2 -0
  182. package/src/drizzle/session-target.ts +20 -3
  183. package/src/drizzle/sqlite-emails.ts +17 -7
  184. package/src/drizzle/sqlite-identity.ts +5 -0
  185. package/src/drizzle/sqlite-password-prepared.ts +7 -3
  186. package/src/drizzle/sqlite-passwords.ts +13 -6
  187. package/src/drizzle/sqlite-proofs.ts +7 -3
  188. package/src/drizzle/sqlite-sessions.ts +31 -15
  189. package/src/drizzle/storage-validation.ts +285 -0
  190. 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":"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"}
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":";;;;;;;;;;;AAgDA,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,OAAO,uBAAuB,OAAO,CAAC,CAAC,KACrC,OAAO,eAAe,uBAAuB,KAAK,CAAC,CAAC,CAAC,CACvD;CAEA,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,uBAAuB,OAAO,CAAC,CAAC,KACrC,OAAO,eAAe,uBAAuB,KAAK,CAAC,CAAC,CAAC,CACvD;CAEA,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,eAAe,OAAO,IAAI,aAC9C,qBACE,UACA,QAAQ,SACR,gBAEE,aACA,aACqD;GACrD,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,CAAC,CAAC,KAAK,OAAO,eAAe,gBAAgB,QAAQ,CAAC,CACxD;CACF;CAEA,OAAO;EACL,8BACE,YAEA,0BAA0B,SAAS,aAAa,CAAC,CAAC,KAChD,OAAO,qBAAqB,gBAAgB,eAAe,eAAe,CAAC,CAC7E;EACF;CACF;AACF"}
@@ -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.14","dependencies":{"@noble/hashes":"2.3.0","@yielded/auth":"0.1.0-beta.14","@yielded/auth-crypto":"0.1.0-beta.14","@yielded/auth-persistence":"0.1.0-beta.14"},"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}}}
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}}}
@@ -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 { EmailRegistrationAuthority } from "./email-registration";
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
- yield* statement(
1075
- database.insert(mapping.identifier.table).values(
1076
- driverValues(
1077
- mapping.identifier.encodeVerifiedInsert({
1078
- identifier: input.identifier,
1079
- subjectId: nativeSubjectId,
1080
- verifiedAtMillis: transitionMillis,
1081
- bindingRevision: allocated.identifierRevision,
1082
- }),
1083
- [[mapping.identifier.verifiedAt, mapping.encodeInstant(transitionMillis)]],
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.map(DatabaseService, (database) => ({
1275
- emailSignInTargets: EmailSignInTargets.of({
1276
- lookup: (input) => {
1277
- if (!validEmailSignInConstraints(mapping as any)) return Effect.fail(unavailable());
1278
-
1279
- return emailLookupRows(mapping as any, input.moduleId, input.identifier).pipe(
1280
- Effect.flatMap((rows) => {
1281
- const row = rows[0];
1282
-
1283
- if (row === undefined) return Effect.succeed(Option.none());
1284
-
1285
- return decodeEmailSnapshot(mapping as any, input.moduleId, input.identifier, row).pipe(
1286
- Effect.map((snapshot) =>
1287
- snapshot === undefined ? Option.none() : Option.some(snapshot),
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
- Effect.provideService(CurrentD1PlanningDatabase, database),
1292
- translateFailure,
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
 
@@ -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