@yielded/auth-persistence-drizzle 0.1.0-beta.14 → 0.1.0-beta.15

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 +143 -29
  3. package/dist/Mysql2.d.mts +130 -16
  4. package/dist/Pglite.d.mts +130 -16
  5. package/dist/Postgres.d.mts +131 -17
  6. package/dist/SqliteBun.d.mts +141 -27
  7. package/dist/SqliteDo.d.mts +145 -31
  8. package/dist/SqliteNode.d.mts +135 -21
  9. package/dist/SqliteWasm.d.mts +145 -31
  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 +8 -8
  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,3 +1,4 @@
1
+ import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
1
2
  import type { LifecycleHooks, HookConfigurationError } from "@yielded/auth/Hooks";
2
3
  import {
3
4
  AuthenticationAuthority,
@@ -65,7 +66,10 @@ export const makeMysqlAuthenticationAuthorityServices = <
65
66
  Effect.flatMap(
66
67
  Effect.map(acquireTransactionService(DatabaseService), configuration),
67
68
  (configuration) => makeTargetAuthenticationAuthorityServices<Claims>(mapping, configuration),
68
- ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
69
+ ).pipe(
70
+ Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)),
71
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
72
+ );
69
73
 
70
74
  export const makeMysqlPendingAuthenticationServices = <
71
75
  Claims,
@@ -80,7 +84,10 @@ export const makeMysqlPendingAuthenticationServices = <
80
84
  Effect.flatMap(
81
85
  Effect.map(acquireTransactionService(DatabaseService), configuration),
82
86
  (configuration) => makeTargetPendingAuthenticationServices<Claims>(mapping, configuration),
83
- ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
87
+ ).pipe(
88
+ Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)),
89
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
90
+ );
84
91
 
85
92
  export const makeMysqlStatefulSessionServices = <
86
93
  Claims,
@@ -97,7 +104,10 @@ export const makeMysqlStatefulSessionServices = <
97
104
  Effect.flatMap(
98
105
  Effect.map(acquireTransactionService(DatabaseService), configuration),
99
106
  (configuration) => makeTargetStatefulSessionServices<Claims>(mapping, configuration),
100
- ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
107
+ ).pipe(
108
+ Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)),
109
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
110
+ );
101
111
 
102
112
  export const makeMysqlSignedSessionValidityServices = <
103
113
  S extends AnyMySqlTable,
@@ -110,7 +120,10 @@ export const makeMysqlSignedSessionValidityServices = <
110
120
  Effect.flatMap(
111
121
  Effect.map(acquireTransactionService(DatabaseService), configuration),
112
122
  (configuration) => makeTargetSignedSessionValidityServices(mapping, configuration),
113
- ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
123
+ ).pipe(
124
+ Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)),
125
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
126
+ );
114
127
 
115
128
  export function coordinateMysqlAuthenticationAuthority<
116
129
  D extends Database,
@@ -193,7 +206,7 @@ export function coordinateMysqlAuthenticationAuthority<
193
206
  E | SessionUnavailable | HookConfigurationError | SqlError | DatabaseError,
194
207
  Exclude<R, AuthenticationAuthority> | LifecycleHooks | DatabaseRequirements
195
208
  > {
196
- return Effect.flatMap(acquire, (database) =>
209
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
197
210
  coordinateTargetAuthenticationAuthority<
198
211
  Claims,
199
212
  Transaction,
@@ -215,7 +228,7 @@ export function coordinateMysqlAuthenticationAuthority<
215
228
  ? work
216
229
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
217
230
  },
218
- ),
231
+ ).pipe(Effect.provideService(NativeDatabase, database)),
219
232
  );
220
233
  }
221
234
 
@@ -306,7 +319,7 @@ export function coordinateMysqlPendingAuthentication<
306
319
  E | SessionUnavailable | HookConfigurationError | SqlError | DatabaseError,
307
320
  Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements
308
321
  > {
309
- return Effect.flatMap(acquire, (database) =>
322
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
310
323
  coordinateTargetPendingAuthentication<Claims, Transaction, A, E, Exclude<R, TargetId>>(
311
324
  database,
312
325
  options.mapping,
@@ -322,7 +335,7 @@ export function coordinateMysqlPendingAuthentication<
322
335
  ? work
323
336
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
324
337
  },
325
- ),
338
+ ).pipe(Effect.provideService(NativeDatabase, database)),
326
339
  );
327
340
  }
328
341
 
@@ -452,7 +465,7 @@ export function coordinateMysqlStatefulSessions<
452
465
  E | SessionUnavailable | HookConfigurationError | SqlError | DatabaseError,
453
466
  Exclude<R, PersistenceId | RepositoryId> | LifecycleHooks | DatabaseRequirements
454
467
  > {
455
- return Effect.flatMap(acquire, (database) =>
468
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
456
469
  coordinateTargetStatefulSessions<
457
470
  Claims,
458
471
  Transaction,
@@ -481,7 +494,7 @@ export function coordinateMysqlStatefulSessions<
481
494
  ? work
482
495
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
483
496
  },
484
- ),
497
+ ).pipe(Effect.provideService(NativeDatabase, database)),
485
498
  );
486
499
  }
487
500
 
@@ -566,7 +579,7 @@ export function coordinateMysqlSignedSessionValidity<
566
579
  E | SessionUnavailable | HookConfigurationError | SqlError | DatabaseError,
567
580
  Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements
568
581
  > {
569
- return Effect.flatMap(acquire, (database) =>
582
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
570
583
  coordinateTargetSignedSessionValidity<Transaction, A, E, Exclude<R, TargetId>>(
571
584
  database,
572
585
  options.mapping,
@@ -582,7 +595,7 @@ export function coordinateMysqlSignedSessionValidity<
582
595
  ? work
583
596
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
584
597
  },
585
- ),
598
+ ).pipe(Effect.provideService(NativeDatabase, database)),
586
599
  );
587
600
  }
588
601
 
@@ -605,7 +618,10 @@ export const makeMysqlSessionStepUpServices = <
605
618
  Effect.flatMap(
606
619
  Effect.map(acquireTransactionService(DatabaseService), configuration),
607
620
  (configuration) => makeTargetSessionStepUpServices(mapping, target, configuration),
608
- ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
621
+ ).pipe(
622
+ Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)),
623
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(DatabaseService)),
624
+ );
609
625
 
610
626
  export function coordinateMysqlSessionStepUp<
611
627
  Claims,
@@ -735,7 +751,7 @@ export function coordinateMysqlSessionStepUp<
735
751
  E | SessionUnavailable | HookConfigurationError | SqlError | DatabaseError,
736
752
  Exclude<R, Id> | LifecycleHooks | DatabaseRequirements
737
753
  > {
738
- return Effect.flatMap(acquire, (database) =>
754
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
739
755
  coordinateTargetSessionStepUp<
740
756
  Claims,
741
757
  Id,
@@ -759,6 +775,6 @@ export function coordinateMysqlSessionStepUp<
759
775
  ? work
760
776
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
761
777
  },
762
- ),
778
+ ).pipe(Effect.provideService(NativeDatabase, database)),
763
779
  );
764
780
  }
@@ -5,16 +5,17 @@ import type {
5
5
  EmailSqlDatabase,
6
6
  ProofSqlDatabase,
7
7
  } from "@yielded/auth-persistence/Adapter";
8
- import { type Context, Effect } from "effect";
8
+ import { Effect } from "effect";
9
9
 
10
10
  /** Drizzle omits its captured $client from database class types, and only D1
11
11
  * exposes batch. Its generic query builders implement the SQL kernel contracts
12
12
  * through drizzleQueryOperations. The selected driver mode controls native calls. */
13
- export const nativeDatabase = <Id, Database>(databaseService: Context.Key<Id, Database>) =>
13
+ export const nativeDatabase = <Database, E, R>(acquire: Effect.Effect<Database, E, R>) =>
14
14
  Effect.map(
15
- Effect.service(databaseService),
15
+ acquire,
16
16
  (database) =>
17
- database as unknown as TransactionNativeDatabase &
17
+ database as unknown as Database &
18
+ TransactionNativeDatabase &
18
19
  SessionSqlDatabase &
19
20
  PasswordSqlDatabase &
20
21
  EmailSqlDatabase &
@@ -144,7 +144,7 @@ export const makeOAuthConnectedTarget = <
144
144
  OAuthCoordinatorError<E> | DatabaseError,
145
145
  Exclude<R, OAuthConnectedPersistence> | LifecycleHooks | DatabaseRequirements
146
146
  > {
147
- return Effect.flatMap(acquire, (database) =>
147
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
148
148
  coordinateTargetOAuthConnected<TransactionOf<D>, A, E, Exclude<R, OAuthConnectedPersistence>>(
149
149
  database,
150
150
  options.mapping,
@@ -164,7 +164,7 @@ export const makeOAuthConnectedTarget = <
164
164
  ? work
165
165
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
166
166
  },
167
- ),
167
+ ).pipe(Effect.provideService(NativeDatabase, database)),
168
168
  );
169
169
  }
170
170
  function coordinateOAuthConnectedRevocations<
@@ -260,7 +260,7 @@ export const makeOAuthConnectedTarget = <
260
260
  OAuthCoordinatorError<E> | DatabaseError,
261
261
  Exclude<R, OAuthConnectedRevocations> | LifecycleHooks | DatabaseRequirements
262
262
  > {
263
- return Effect.flatMap(acquire, (database) =>
263
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
264
264
  coordinateTargetOAuthConnectedRevocations<
265
265
  TransactionOf<D>,
266
266
  A,
@@ -285,7 +285,7 @@ export const makeOAuthConnectedTarget = <
285
285
  ? work
286
286
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
287
287
  },
288
- ),
288
+ ).pipe(Effect.provideService(NativeDatabase, database)),
289
289
  );
290
290
  }
291
291
 
@@ -364,7 +364,7 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
364
364
  | LifecycleHooks
365
365
  | DatabaseRequirements
366
366
  > {
367
- return Effect.flatMap(acquire, (database) =>
367
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
368
368
  coordinateTargetOAuthConnected<
369
369
  Database,
370
370
  A,
@@ -388,6 +388,8 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
388
388
  settleSignIn: (input, prepare) => owner.run(original.settleSignIn(input, prepare)),
389
389
  capture: (input) => owner.run(original.capture(input)),
390
390
  issue: (input, prepare) => owner.run(original.issue(input, prepare)),
391
+ prepare: (input, prepare) => owner.run(original.prepare(input, prepare)),
392
+ inspectPrepared: (input) => owner.run(original.inspectPrepared(input)),
391
393
  preflight: (input) => owner.run(original.preflight(input)),
392
394
  claim: (input, prepare) => owner.run(original.claim(input, prepare)),
393
395
  inspectGrant: (input) => owner.run(original.inspectGrant(input)),
@@ -408,7 +410,7 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
408
410
 
409
411
  return yield* owner.close(Effect.provideContext(body, provided));
410
412
  }),
411
- ),
413
+ ).pipe(Effect.provideService(NativeDatabase, database)),
412
414
  );
413
415
  }
414
416
  function coordinateOAuthConnectedRevocations<
@@ -436,7 +438,7 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
436
438
  | LifecycleHooks
437
439
  | DatabaseRequirements
438
440
  > {
439
- return Effect.flatMap(acquire, (database) =>
441
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
440
442
  coordinateTargetOAuthConnectedRevocations<
441
443
  Database,
442
444
  A,
@@ -465,7 +467,7 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
465
467
 
466
468
  return yield* owner.close(Effect.provideContext(body, provided));
467
469
  }),
468
- ),
470
+ ).pipe(Effect.provideService(NativeDatabase, database)),
469
471
  );
470
472
  }
471
473
 
@@ -84,9 +84,11 @@ export const expected = (flow: M.OAuthConnectedPendingFlow) => ({
84
84
  configuration: S.configuration(flow),
85
85
  });
86
86
 
87
- export const issue = Effect.fn("oauthConnected.issue")(function* (
87
+ const retain = Effect.fn("oauthConnected.retain")(function* (
88
88
  mapping: S.Mapping,
89
- input: Input<"issue">,
89
+ input:
90
+ | ({ readonly _tag: "Prepare" } & Input<"prepare">)
91
+ | ({ readonly _tag: "Issue" } & Input<"issue">),
90
92
  ) {
91
93
  const owner = yield* CurrentOAuthTransaction;
92
94
 
@@ -95,10 +97,16 @@ export const issue = Effect.fn("oauthConnected.issue")(function* (
95
97
 
96
98
  const found = yield* S.current(mapping, c.revision.subjectId);
97
99
 
98
- if (
99
- found === undefined ||
100
- !(yield* S.action(mapping, found, input.authorization, "issue", expected(flow)))
101
- )
100
+ if (found === undefined) return { _tag: "Rejected" } as const;
101
+ if (input._tag === "Prepare") {
102
+ if (
103
+ input.authorization.moduleId !== c.moduleId ||
104
+ !sameRevision(input.authorization.revision, c.revision) ||
105
+ !sameRevision(found.revision, c.revision) ||
106
+ (yield* S.useAuthority(mapping, input.authorization, "metadata")) === undefined
107
+ )
108
+ return { _tag: "Rejected" } as const;
109
+ } else if (!(yield* S.action(mapping, found, input.authorization, "issue", expected(flow))))
102
110
  return { _tag: "Rejected" } as const;
103
111
  if (c.profile.revocation === "cohort") invariant(mapping.revocation.mode === "cohort");
104
112
  const client = yield* S.client(mapping, S.configuration(flow), true);
@@ -131,6 +139,31 @@ export const issue = Effect.fn("oauthConnected.issue")(function* (
131
139
  { limit: 1 },
132
140
  );
133
141
 
142
+ owner.postconditions.push(
143
+ sql`${mapping.clock.engineNowMillis} >= ${c.issuedAtMillis} and ${mapping.clock.engineNowMillis} < ${c.expiresAtMillis}`,
144
+ );
145
+ if (input._tag === "Issue") {
146
+ const row = prior.rows[0];
147
+
148
+ if (
149
+ row === undefined ||
150
+ command.rows[0] === undefined ||
151
+ row[f.state] !== "Prepared" ||
152
+ row[f.snapshot] !== S.flowStorage.encode(flow) ||
153
+ command.rows[0][f.flowId] !== c.flowId
154
+ )
155
+ return { _tag: "Rejected" } as const;
156
+ yield* owner.update(
157
+ f.table,
158
+ { ...key, [f.state]: "Prepared", [f.version]: row[f.version] },
159
+ { [f.state]: "Pending", [f.version]: owner.marker },
160
+ );
161
+ owner.postconditions.push(
162
+ sql`exists(select 1 from ${f.table} where ${equal(f.table, { ...key, [f.state]: "Pending", [f.version]: owner.marker })})`,
163
+ );
164
+
165
+ return { _tag: "Issued", flow } as const;
166
+ }
134
167
  if (prior.rows.length || command.rows.length) return { _tag: "Rejected" } as const;
135
168
 
136
169
  const values = {
@@ -143,7 +176,7 @@ export const issue = Effect.fn("oauthConnected.issue")(function* (
143
176
  [f.subjectId]: found.nativeId,
144
177
  [f.clientKey]: client.id,
145
178
  [f.cohortKey]: null,
146
- [f.state]: "Pending",
179
+ [f.state]: "Prepared",
147
180
  [f.version]: owner.marker,
148
181
  [f.stateDigest]: c.stateDigest,
149
182
  [f.snapshot]: S.flowStorage.encode(flow),
@@ -163,13 +196,68 @@ export const issue = Effect.fn("oauthConnected.issue")(function* (
163
196
  prior.rows = inserted.rows;
164
197
  command.rows = inserted.rows;
165
198
  if (inserted.rows[0]?.[f.version] !== owner.marker) return { _tag: "Rejected" } as const;
166
- owner.postconditions.push(
167
- sql`${mapping.clock.engineNowMillis} >= ${c.issuedAtMillis} and ${mapping.clock.engineNowMillis} < ${c.expiresAtMillis}`,
168
- );
169
199
 
170
200
  return { _tag: "Issued", flow } as const;
171
201
  });
172
202
 
203
+ export const prepare = (mapping: S.Mapping, input: Input<"prepare">) =>
204
+ retain(mapping, { _tag: "Prepare", ...input });
205
+
206
+ export const issue = (mapping: S.Mapping, input: Input<"issue">) =>
207
+ retain(mapping, { _tag: "Issue", ...input });
208
+
209
+ export const inspectPrepared = Effect.fn("oauthConnected.inspectPrepared")(function* (
210
+ mapping: S.Mapping,
211
+ access: M.OAuthConnectedPreparedAccess,
212
+ ) {
213
+ const owner = yield* CurrentOAuthTransaction;
214
+ const found = yield* S.current(mapping, access.subjectId);
215
+
216
+ if (found === undefined) return undefined;
217
+ const f = mapping.flow;
218
+
219
+ const read = yield* owner.read(
220
+ f.table,
221
+ equal(f.table, {
222
+ [f.moduleId]: access.moduleId,
223
+ [f.flowId]: access.flowId,
224
+ [f.subjectId]: found.nativeId,
225
+ }),
226
+ { limit: 1 },
227
+ );
228
+
229
+ const row = read.rows[0];
230
+
231
+ if (row === undefined || row[f.state] !== "Prepared" || row[f.snapshot] === null)
232
+ return undefined;
233
+ const flow = S.flowStorage.decode(row[f.snapshot]);
234
+ const c = flow.context;
235
+
236
+ invariant(
237
+ row[f.moduleId] === c.moduleId &&
238
+ row[f.flowId] === c.flowId &&
239
+ row[f.commandId] === c.commandId &&
240
+ mapping.subjectId.equals(found.nativeId, row[f.subjectId]) &&
241
+ row[f.clientKey] === S.clientKey(S.configuration(flow)) &&
242
+ row[f.stateDigest] === c.stateDigest &&
243
+ mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
244
+ mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,
245
+ );
246
+ const now = yield* owner.now(mapping.clock);
247
+
248
+ return c.moduleId === access.moduleId &&
249
+ c.generation === access.generation &&
250
+ c.flowId === access.flowId &&
251
+ c.commandId === access.commandId &&
252
+ c.revision.subjectId === access.subjectId &&
253
+ sameRevision(found.revision, c.revision) &&
254
+ c.requestBindingVerifier === access.requestBindingVerifier &&
255
+ c.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis &&
256
+ live(flow, now)
257
+ ? flow
258
+ : undefined;
259
+ });
260
+
173
261
  export const sameTarget = (target: M.OAuthConnectedTarget, context: M.OAuthConnectedTokenContext) =>
174
262
  target.grantId === context.grantId &&
175
263
  target.grantVersion === context.grantVersion &&
@@ -22,6 +22,11 @@ const issue = Schema.Struct({
22
22
  authorization: M.OAuthConnectedActionAuthorization,
23
23
  });
24
24
 
25
+ const preparation = Schema.Struct({
26
+ flow: M.OAuthConnectedPendingFlow,
27
+ authorization: M.OAuthConnectedUseAuthorization,
28
+ });
29
+
25
30
  const claim = Schema.Struct({
26
31
  ...issue.fields,
27
32
  access: M.OAuthConnectedAccess,
@@ -120,6 +125,8 @@ export const connectedInputs = {
120
125
  ),
121
126
  capture: snapshot(capture),
122
127
  issue: snapshot(issue),
128
+ prepare: snapshot(preparation),
129
+ inspectPrepared: snapshot(M.OAuthConnectedPreparedAccess),
123
130
  preflight: snapshot(M.OAuthConnectedAccess),
124
131
  claim: snapshot(claim),
125
132
  inspectGrant: snapshot(inspectGrant),
@@ -197,7 +197,7 @@ export const cleanup = Effect.fn("oauthConnected.cleanup")(function* (
197
197
  f.table,
198
198
  both(
199
199
  eq(col(f.table, f.moduleId), input.moduleId),
200
- sql`((${col(f.table, f.state)} = 'Pending' and ${col(f.table, f.expiresAt)} <= ${mapping.clock.encodeInstant(at)}) or (${col(f.table, f.state)} = 'Claimed' and ${col(f.table, f.claimExpiresAt)} <= ${mapping.clock.encodeInstant(at)}) or (${col(f.table, f.state)} not in ('Pending','Claimed') and ${col(f.table, f.work)} <> 'Unresolved' and ${col(f.table, f.retentionUntil)} <= ${mapping.clock.encodeInstant(at)}))`,
200
+ sql`((${col(f.table, f.state)} in ('Prepared','Pending') and ${col(f.table, f.expiresAt)} <= ${mapping.clock.encodeInstant(at)}) or (${col(f.table, f.state)} = 'Claimed' and ${col(f.table, f.claimExpiresAt)} <= ${mapping.clock.encodeInstant(at)}) or (${col(f.table, f.state)} not in ('Prepared','Pending','Claimed') and ${col(f.table, f.work)} <> 'Unresolved' and ${col(f.table, f.retentionUntil)} <= ${mapping.clock.encodeInstant(at)}))`,
201
201
  ),
202
202
  {
203
203
  limit: input.limit + 1,
@@ -250,7 +250,7 @@ export const cleanup = Effect.fn("oauthConnected.cleanup")(function* (
250
250
  state === "Claimed" ? row[f.claimExpiresAt] : row[f.expiresAt],
251
251
  );
252
252
 
253
- if ((state === "Pending" || state === "Claimed") && now >= expires) {
253
+ if ((state === "Prepared" || state === "Pending" || state === "Claimed") && now >= expires) {
254
254
  yield* owner.update(
255
255
  f.table,
256
256
  { [f.moduleId]: input.moduleId, [f.flowId]: row[f.flowId], [f.version]: row[f.version] },
@@ -263,6 +263,7 @@ export const cleanup = Effect.fn("oauthConnected.cleanup")(function* (
263
263
  owner.postconditions.push(sql`${mapping.clock.engineNowMillis} >= ${expires}`);
264
264
  terminalized++;
265
265
  } else if (
266
+ state !== "Prepared" &&
266
267
  state !== "Pending" &&
267
268
  state !== "Claimed" &&
268
269
  row[f.work] !== "Unresolved" &&
@@ -134,6 +134,8 @@ export const makeConnected = (
134
134
  ),
135
135
  capture: read(mapping, execute, F.capture),
136
136
  issue: mutation(mapping, execute, F.issue, M.OAuthConnectedIssueDecision),
137
+ prepare: mutation(mapping, execute, F.prepare, M.OAuthConnectedIssueDecision),
138
+ inspectPrepared: read(mapping, execute, F.inspectPrepared),
137
139
  preflight: read(mapping, execute, F.preflight),
138
140
  claim: mutation(mapping, execute, F.claim, M.OAuthConnectedClaimDecision),
139
141
  inspectGrant: read(mapping, execute, F.inspectGrant),
@@ -189,7 +191,7 @@ export const makeTargetOAuthConnectedServices = (
189
191
  ) => {
190
192
  const retained = captured(mapping);
191
193
 
192
- return Effect.map(makeOAuthExecution(configuration), (execution) => ({
194
+ return Effect.map(makeOAuthExecution(configuration, retained), (execution) => ({
193
195
  oauthConnectedPersistence: makeConnected(retained, execution),
194
196
  }));
195
197
  };
@@ -200,7 +202,7 @@ export const makeTargetOAuthConnectedRevocationServices = (
200
202
  ) => {
201
203
  const retained = captured(mapping);
202
204
 
203
- return Effect.map(makeOAuthExecution(configuration), (execution) => ({
205
+ return Effect.map(makeOAuthExecution(configuration, retained), (execution) => ({
204
206
  oauthConnectedRevocations: makeRevocations(retained, execution),
205
207
  }));
206
208
  };
@@ -133,7 +133,7 @@ export const makeOAuthTarget = <
133
133
  OAuthCoordinatorError<E> | DatabaseError,
134
134
  Exclude<R, OAuthSignInPersistence> | LifecycleHooks | DatabaseRequirements
135
135
  > {
136
- return Effect.flatMap(acquire, (database) =>
136
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
137
137
  coordinateTargetOAuthSignIn<
138
138
  TransactionOf<Database>,
139
139
  A,
@@ -154,7 +154,7 @@ export const makeOAuthTarget = <
154
154
  ? work
155
155
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
156
156
  },
157
- ),
157
+ ).pipe(Effect.provideService(NativeDatabase, database)),
158
158
  );
159
159
  }
160
160
  function coordinateOAuthRegistrationIntents<
@@ -250,7 +250,7 @@ export const makeOAuthTarget = <
250
250
  OAuthCoordinatorError<E> | DatabaseError,
251
251
  Exclude<R, OAuthRegistrationIntents> | LifecycleHooks | DatabaseRequirements
252
252
  > {
253
- return Effect.flatMap(acquire, (database) =>
253
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
254
254
  coordinateTargetOAuthRegistrationIntents<
255
255
  TransactionOf<Database>,
256
256
  A,
@@ -275,7 +275,7 @@ export const makeOAuthTarget = <
275
275
  ? work
276
276
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
277
277
  },
278
- ),
278
+ ).pipe(Effect.provideService(NativeDatabase, database)),
279
279
  );
280
280
  }
281
281
  function coordinateOAuthAccounts<
@@ -371,7 +371,7 @@ export const makeOAuthTarget = <
371
371
  OAuthCoordinatorError<E> | DatabaseError,
372
372
  Exclude<R, OAuthAccountsPersistence> | LifecycleHooks | DatabaseRequirements
373
373
  > {
374
- return Effect.flatMap(acquire, (database) =>
374
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
375
375
  coordinateTargetOAuthAccounts<
376
376
  TransactionOf<Database>,
377
377
  A,
@@ -396,7 +396,7 @@ export const makeOAuthTarget = <
396
396
  ? work
397
397
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
398
398
  },
399
- ),
399
+ ).pipe(Effect.provideService(NativeDatabase, database)),
400
400
  );
401
401
  }
402
402
  function coordinateOAuthRegistration<
@@ -497,7 +497,7 @@ export const makeOAuthTarget = <
497
497
  OAuthCoordinatorError<E> | DatabaseError,
498
498
  Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements
499
499
  > {
500
- return Effect.flatMap(acquire, (database) =>
500
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
501
501
  coordinateTargetOAuthRegistration<
502
502
  Registration,
503
503
  TransactionOf<Database>,
@@ -519,7 +519,7 @@ export const makeOAuthTarget = <
519
519
  ? work
520
520
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
521
521
  },
522
- ),
522
+ ).pipe(Effect.provideService(NativeDatabase, database)),
523
523
  );
524
524
  }
525
525
 
@@ -70,6 +70,7 @@ import {
70
70
  settleRegistrationIntent,
71
71
  } from "./oauth-registration";
72
72
  import { captureOAuthMapping, invariant, nonce, unavailable } from "./oauth-state";
73
+ import { validateDrizzleStorage } from "./storage-validation";
73
74
  import {
74
75
  coordinateTransactionOwner,
75
76
  makeTransactionExecution,
@@ -89,9 +90,12 @@ export const sqlClientOAuthStandaloneGuard = (
89
90
 
90
91
  export const makeOAuthExecution = Effect.fnUntraced(function* (
91
92
  configuration: OAuthTargetConfiguration,
92
- ): Effect.fn.Return<OAuthExecution, never, LifecycleHooks | NativeDatabase> {
93
+ mapping: unknown,
94
+ ): Effect.fn.Return<OAuthExecution, OAuthUnavailable, LifecycleHooks | NativeDatabase> {
93
95
  const hooks = yield* LifecycleHooks;
94
96
 
97
+ yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
98
+
95
99
  const execution = yield* makeTransactionExecution(
96
100
  CurrentOAuthTransaction,
97
101
  configuration,
@@ -393,7 +397,7 @@ export const makeTargetOAuthSignInServices = (
393
397
  ) => {
394
398
  const captured = captureOAuthMapping(mapping);
395
399
 
396
- return Effect.map(makeOAuthExecution(configuration), (execution) => ({
400
+ return Effect.map(makeOAuthExecution(configuration, captured), (execution) => ({
397
401
  oauthSignInPersistence: makeOAuthSignIn(captured, execution),
398
402
  }));
399
403
  };
@@ -404,7 +408,7 @@ export const makeTargetOAuthRegistrationIntentServices = (
404
408
  ) => {
405
409
  const captured = captureOAuthMapping(mapping);
406
410
 
407
- return Effect.map(makeOAuthExecution(configuration), (execution) => ({
411
+ return Effect.map(makeOAuthExecution(configuration, captured), (execution) => ({
408
412
  oauthRegistrationIntents: makeOAuthRegistrationIntents(captured, execution),
409
413
  }));
410
414
  };
@@ -415,7 +419,7 @@ export const makeTargetOAuthRegistrationServices = <Registration>(
415
419
  ) => {
416
420
  const captured = captureOAuthMapping(mapping);
417
421
 
418
- return Effect.map(makeOAuthExecution(configuration), (execution) => ({
422
+ return Effect.map(makeOAuthExecution(configuration, captured), (execution) => ({
419
423
  registrationAuthority: makeOAuthRegistration<Registration>(captured, execution),
420
424
  }));
421
425
  };
@@ -431,7 +435,7 @@ export const coordinateOAuthOwner = <Services, Transaction, A, E, R>(
431
435
  services: Services,
432
436
  append: (statement: Statement<any>) => void,
433
437
  ) => Effect.Effect<A, E, R>,
434
- ): Effect.Effect<A, OAuthCoordinatorError<E>, R | LifecycleHooks> => {
438
+ ): Effect.Effect<A, OAuthCoordinatorError<E>, R | LifecycleHooks | NativeDatabase> => {
435
439
  const captured = captureOAuthMapping(mapping);
436
440
 
437
441
  return Effect.flatMap(LifecycleHooks, (hooks) =>
@@ -439,7 +443,9 @@ export const coordinateOAuthOwner = <Services, Transaction, A, E, R>(
439
443
  database,
440
444
  CurrentOAuthTransaction,
441
445
  configuration,
442
- Effect.suspend(() => allocate(captured)),
446
+ validateDrizzleStorage(captured).pipe(
447
+ Effect.andThen(Effect.suspend(() => allocate(captured))),
448
+ ),
443
449
  unavailable,
444
450
  nonce,
445
451
  (execution, resources) =>
@@ -691,7 +697,7 @@ export const makeTargetOAuthAccountsServices = (
691
697
  ) => {
692
698
  const captured = captureOAuthMapping(mapping);
693
699
 
694
- return Effect.map(makeOAuthExecution(configuration), (execution) => ({
700
+ return Effect.map(makeOAuthExecution(configuration, captured), (execution) => ({
695
701
  oauthAccountsPersistence: makeOAuthAccounts(captured, execution),
696
702
  }));
697
703
  };
@@ -177,7 +177,7 @@ export const makePasskeyTarget = <
177
177
  PasskeyCoordinatorError<E> | DatabaseError,
178
178
  Exclude<R, PasskeyPersistence> | LifecycleHooks | DatabaseRequirements | RSetup
179
179
  > {
180
- return Effect.flatMap(acquire, (database) =>
180
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
181
181
  coordinateTargetPasskey(
182
182
  database,
183
183
  options.mapping,
@@ -190,7 +190,7 @@ export const makePasskeyTarget = <
190
190
  ? work
191
191
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
192
192
  },
193
- ),
193
+ ).pipe(Effect.provideService(NativeDatabase, database)),
194
194
  );
195
195
  }
196
196
  function coordinatePasskeyRegistrationCeremony<
@@ -290,7 +290,7 @@ export const makePasskeyTarget = <
290
290
  PasskeyCoordinatorError<E> | DatabaseError,
291
291
  Exclude<R, PasskeyPersistence> | LifecycleHooks | DatabaseRequirements | RSetup
292
292
  > {
293
- return Effect.flatMap(acquire, (database) =>
293
+ return Effect.flatMap(nativeDatabase(acquire), (database) =>
294
294
  coordinateTargetPasskeyRegistration(
295
295
  database,
296
296
  options.mapping,
@@ -303,7 +303,7 @@ export const makePasskeyTarget = <
303
303
  ? work
304
304
  : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
305
305
  },
306
- ),
306
+ ).pipe(Effect.provideService(NativeDatabase, database)),
307
307
  );
308
308
  }
309
309