@yielded/auth-persistence-drizzle 0.1.0-beta.1 → 0.1.0-beta.13

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 (228) hide show
  1. package/dist/D1.d.mts +23 -18
  2. package/dist/D1.mjs +10 -4
  3. package/dist/D1.mjs.map +1 -1
  4. package/dist/Libsql.d.mts +58 -53
  5. package/dist/Libsql.mjs +20 -15
  6. package/dist/Libsql.mjs.map +1 -1
  7. package/dist/Mysql2.d.mts +58 -46
  8. package/dist/Mysql2.mjs +13 -6
  9. package/dist/Mysql2.mjs.map +1 -1
  10. package/dist/Pglite.d.mts +52 -41
  11. package/dist/Pglite.mjs +12 -7
  12. package/dist/Pglite.mjs.map +1 -1
  13. package/dist/Postgres.d.mts +59 -48
  14. package/dist/Postgres.mjs +12 -7
  15. package/dist/Postgres.mjs.map +1 -1
  16. package/dist/SqliteBun.d.mts +67 -62
  17. package/dist/SqliteBun.mjs +20 -14
  18. package/dist/SqliteBun.mjs.map +1 -1
  19. package/dist/SqliteDo.d.mts +58 -52
  20. package/dist/SqliteDo.mjs +26 -14
  21. package/dist/SqliteDo.mjs.map +1 -1
  22. package/dist/SqliteNode.d.mts +58 -53
  23. package/dist/SqliteNode.mjs +20 -14
  24. package/dist/SqliteNode.mjs.map +1 -1
  25. package/dist/SqliteWasm.d.mts +58 -53
  26. package/dist/SqliteWasm.mjs +20 -14
  27. package/dist/SqliteWasm.mjs.map +1 -1
  28. package/dist/drizzle/d1-database.d.mts +11 -0
  29. package/dist/drizzle/d1-database.mjs +8 -0
  30. package/dist/drizzle/d1-database.mjs.map +1 -0
  31. package/dist/drizzle/d1-emails.d.mts +8 -7
  32. package/dist/drizzle/d1-emails.mjs +7 -4
  33. package/dist/drizzle/d1-emails.mjs.map +1 -1
  34. package/dist/drizzle/d1-identity.mjs +12 -9
  35. package/dist/drizzle/d1-identity.mjs.map +1 -1
  36. package/dist/drizzle/d1-oauth.d.mts +10 -9
  37. package/dist/drizzle/d1-oauth.mjs +7 -4
  38. package/dist/drizzle/d1-oauth.mjs.map +1 -1
  39. package/dist/drizzle/d1-passkey.d.mts +3 -14
  40. package/dist/drizzle/d1-passkey.mjs +2 -1
  41. package/dist/drizzle/d1-passkey.mjs.map +1 -1
  42. package/dist/drizzle/d1-password-prepared.d.mts +4 -3
  43. package/dist/drizzle/d1-password-prepared.mjs +3 -1
  44. package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
  45. package/dist/drizzle/d1-passwords.d.mts +6 -5
  46. package/dist/drizzle/d1-passwords.mjs +11 -7
  47. package/dist/drizzle/d1-passwords.mjs.map +1 -1
  48. package/dist/drizzle/d1-phone.d.mts +3 -4
  49. package/dist/drizzle/d1-phone.mjs +2 -1
  50. package/dist/drizzle/d1-phone.mjs.map +1 -1
  51. package/dist/drizzle/d1-planning.d.mts +1 -1
  52. package/dist/drizzle/d1-proofs.d.mts +4 -3
  53. package/dist/drizzle/d1-proofs.mjs +3 -1
  54. package/dist/drizzle/d1-proofs.mjs.map +1 -1
  55. package/dist/drizzle/d1-sessions.d.mts +11 -10
  56. package/dist/drizzle/d1-sessions.mjs +15 -9
  57. package/dist/drizzle/d1-sessions.mjs.map +1 -1
  58. package/dist/drizzle/d1-totp.d.mts +3 -4
  59. package/dist/drizzle/d1-totp.mjs +2 -1
  60. package/dist/drizzle/d1-totp.mjs.map +1 -1
  61. package/dist/drizzle/email-registration.mjs +2 -1
  62. package/dist/drizzle/email-registration.mjs.map +1 -1
  63. package/dist/drizzle/email-target.d.mts +7 -6
  64. package/dist/drizzle/email-target.mjs +10 -10
  65. package/dist/drizzle/email-target.mjs.map +1 -1
  66. package/dist/drizzle/mysql-database.d.mts +8 -0
  67. package/dist/drizzle/mysql-database.mjs +8 -0
  68. package/dist/drizzle/mysql-database.mjs.map +1 -0
  69. package/dist/drizzle/mysql-emails.d.mts +7 -6
  70. package/dist/drizzle/mysql-emails.mjs +12 -8
  71. package/dist/drizzle/mysql-emails.mjs.map +1 -1
  72. package/dist/drizzle/mysql-identity.mjs +12 -9
  73. package/dist/drizzle/mysql-identity.mjs.map +1 -1
  74. package/dist/drizzle/mysql-password-prepared.d.mts +3 -2
  75. package/dist/drizzle/mysql-password-prepared.mjs +6 -2
  76. package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
  77. package/dist/drizzle/mysql-passwords.d.mts +6 -4
  78. package/dist/drizzle/mysql-passwords.mjs +11 -7
  79. package/dist/drizzle/mysql-passwords.mjs.map +1 -1
  80. package/dist/drizzle/mysql-proofs.d.mts +3 -2
  81. package/dist/drizzle/mysql-proofs.mjs +8 -4
  82. package/dist/drizzle/mysql-proofs.mjs.map +1 -1
  83. package/dist/drizzle/mysql-sessions.d.mts +11 -10
  84. package/dist/drizzle/mysql-sessions.mjs +16 -12
  85. package/dist/drizzle/mysql-sessions.mjs.map +1 -1
  86. package/dist/drizzle/native-database.mjs +10 -0
  87. package/dist/drizzle/native-database.mjs.map +1 -0
  88. package/dist/drizzle/oauth-connected-drivers.mjs +7 -5
  89. package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
  90. package/dist/drizzle/oauth-connected-settlement.mjs +3 -2
  91. package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
  92. package/dist/drizzle/oauth-connected-sign-in.mjs +4 -3
  93. package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -1
  94. package/dist/drizzle/oauth-connected-target.d.mts +6 -7
  95. package/dist/drizzle/oauth-connected-target.mjs +4 -5
  96. package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
  97. package/dist/drizzle/oauth-drivers.mjs +8 -6
  98. package/dist/drizzle/oauth-drivers.mjs.map +1 -1
  99. package/dist/drizzle/oauth-target.d.mts +12 -11
  100. package/dist/drizzle/oauth-target.mjs +13 -12
  101. package/dist/drizzle/oauth-target.mjs.map +1 -1
  102. package/dist/drizzle/passkey-drivers.mjs +8 -6
  103. package/dist/drizzle/passkey-drivers.mjs.map +1 -1
  104. package/dist/drizzle/passkey-write-drivers.mjs +5 -3
  105. package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
  106. package/dist/drizzle/passkey-write-target.d.mts +1 -1
  107. package/dist/drizzle/password-prepared-sql.mjs +2 -1
  108. package/dist/drizzle/password-prepared-sql.mjs.map +1 -1
  109. package/dist/drizzle/password-prepared-target.d.mts +3 -2
  110. package/dist/drizzle/password-prepared-target.mjs +4 -3
  111. package/dist/drizzle/password-prepared-target.mjs.map +1 -1
  112. package/dist/drizzle/password-registration.mjs +2 -1
  113. package/dist/drizzle/password-registration.mjs.map +1 -1
  114. package/dist/drizzle/password-target.d.mts +5 -4
  115. package/dist/drizzle/password-target.mjs +8 -8
  116. package/dist/drizzle/password-target.mjs.map +1 -1
  117. package/dist/drizzle/pg-database.d.mts +9 -0
  118. package/dist/drizzle/pg-database.mjs +8 -0
  119. package/dist/drizzle/pg-database.mjs.map +1 -0
  120. package/dist/drizzle/pg-emails.d.mts +7 -6
  121. package/dist/drizzle/pg-emails.mjs +12 -8
  122. package/dist/drizzle/pg-emails.mjs.map +1 -1
  123. package/dist/drizzle/pg-identity.mjs +12 -9
  124. package/dist/drizzle/pg-identity.mjs.map +1 -1
  125. package/dist/drizzle/pg-password-prepared.d.mts +3 -2
  126. package/dist/drizzle/pg-password-prepared.mjs +6 -2
  127. package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
  128. package/dist/drizzle/pg-passwords.d.mts +6 -4
  129. package/dist/drizzle/pg-passwords.mjs +11 -7
  130. package/dist/drizzle/pg-passwords.mjs.map +1 -1
  131. package/dist/drizzle/pg-proofs.d.mts +3 -2
  132. package/dist/drizzle/pg-proofs.mjs +8 -4
  133. package/dist/drizzle/pg-proofs.mjs.map +1 -1
  134. package/dist/drizzle/pg-sessions.d.mts +11 -10
  135. package/dist/drizzle/pg-sessions.mjs +16 -12
  136. package/dist/drizzle/pg-sessions.mjs.map +1 -1
  137. package/dist/drizzle/phone-target.d.mts +4 -3
  138. package/dist/drizzle/phone-target.mjs +12 -11
  139. package/dist/drizzle/phone-target.mjs.map +1 -1
  140. package/dist/drizzle/proof-target.d.mts +3 -2
  141. package/dist/drizzle/proof-target.mjs +5 -5
  142. package/dist/drizzle/proof-target.mjs.map +1 -1
  143. package/dist/drizzle/session-sql.d.mts +1 -0
  144. package/dist/drizzle/session-target.d.mts +10 -8
  145. package/dist/drizzle/session-target.mjs +11 -11
  146. package/dist/drizzle/session-target.mjs.map +1 -1
  147. package/dist/drizzle/sqlite-emails.mjs +9 -5
  148. package/dist/drizzle/sqlite-emails.mjs.map +1 -1
  149. package/dist/drizzle/sqlite-identity.mjs +14 -11
  150. package/dist/drizzle/sqlite-identity.mjs.map +1 -1
  151. package/dist/drizzle/sqlite-password-prepared.mjs +7 -3
  152. package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
  153. package/dist/drizzle/sqlite-passwords.mjs +10 -6
  154. package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
  155. package/dist/drizzle/sqlite-proofs.mjs +7 -3
  156. package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
  157. package/dist/drizzle/sqlite-sessions.mjs +16 -12
  158. package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
  159. package/dist/drizzle/standalone-guard.d.mts +2 -0
  160. package/dist/drizzle/standalone-guard.mjs +8 -4
  161. package/dist/drizzle/standalone-guard.mjs.map +1 -1
  162. package/dist/drizzle/totp-target.d.mts +4 -3
  163. package/dist/drizzle/totp-target.mjs +31 -28
  164. package/dist/drizzle/totp-target.mjs.map +1 -1
  165. package/package.json +1 -1
  166. package/src/D1.ts +37 -10
  167. package/src/Libsql.ts +45 -17
  168. package/src/Mysql2.ts +39 -13
  169. package/src/Pglite.ts +47 -13
  170. package/src/Postgres.ts +47 -13
  171. package/src/SqliteBun.ts +58 -30
  172. package/src/SqliteDo.ts +61 -19
  173. package/src/SqliteNode.ts +55 -28
  174. package/src/SqliteWasm.ts +55 -28
  175. package/src/drizzle/d1-database.ts +10 -0
  176. package/src/drizzle/d1-emails.ts +84 -84
  177. package/src/drizzle/d1-identity.ts +17 -20
  178. package/src/drizzle/d1-oauth.ts +19 -8
  179. package/src/drizzle/d1-passkey.ts +5 -1
  180. package/src/drizzle/d1-password-prepared.ts +38 -37
  181. package/src/drizzle/d1-passwords.ts +118 -108
  182. package/src/drizzle/d1-phone.ts +5 -1
  183. package/src/drizzle/d1-proofs.ts +29 -30
  184. package/src/drizzle/d1-sessions.ts +51 -38
  185. package/src/drizzle/d1-totp.ts +5 -1
  186. package/src/drizzle/email-registration.ts +6 -2
  187. package/src/drizzle/email-target.ts +17 -19
  188. package/src/drizzle/mysql-database.ts +8 -0
  189. package/src/drizzle/mysql-emails.ts +28 -16
  190. package/src/drizzle/mysql-identity.ts +18 -21
  191. package/src/drizzle/mysql-password-prepared.ts +10 -8
  192. package/src/drizzle/mysql-passwords.ts +21 -9
  193. package/src/drizzle/mysql-proofs.ts +16 -5
  194. package/src/drizzle/mysql-sessions.ts +40 -17
  195. package/src/drizzle/native-database.ts +22 -0
  196. package/src/drizzle/oauth-connected-drivers.ts +18 -6
  197. package/src/drizzle/oauth-connected-settlement.ts +5 -3
  198. package/src/drizzle/oauth-connected-sign-in.ts +7 -3
  199. package/src/drizzle/oauth-connected-target.ts +16 -17
  200. package/src/drizzle/oauth-drivers.ts +26 -10
  201. package/src/drizzle/oauth-target.ts +30 -42
  202. package/src/drizzle/passkey-drivers.ts +21 -13
  203. package/src/drizzle/passkey-write-drivers.ts +11 -6
  204. package/src/drizzle/password-prepared-sql.ts +2 -4
  205. package/src/drizzle/password-prepared-target.ts +9 -6
  206. package/src/drizzle/password-registration.ts +7 -8
  207. package/src/drizzle/password-target.ts +19 -18
  208. package/src/drizzle/pg-database.ts +10 -0
  209. package/src/drizzle/pg-emails.ts +28 -16
  210. package/src/drizzle/pg-identity.ts +18 -22
  211. package/src/drizzle/pg-password-prepared.ts +10 -8
  212. package/src/drizzle/pg-passwords.ts +21 -9
  213. package/src/drizzle/pg-proofs.ts +16 -5
  214. package/src/drizzle/pg-sessions.ts +40 -17
  215. package/src/drizzle/phone-target.ts +22 -17
  216. package/src/drizzle/proof-target.ts +9 -12
  217. package/src/drizzle/session-target.ts +32 -50
  218. package/src/drizzle/sqlite-emails.ts +30 -13
  219. package/src/drizzle/sqlite-identity.ts +22 -42
  220. package/src/drizzle/sqlite-password-prepared.ts +23 -9
  221. package/src/drizzle/sqlite-passwords.ts +29 -15
  222. package/src/drizzle/sqlite-proofs.ts +28 -5
  223. package/src/drizzle/sqlite-sessions.ts +49 -23
  224. package/src/drizzle/standalone-guard.ts +18 -6
  225. package/src/drizzle/totp-target.ts +61 -60
  226. package/dist/drizzle/d1-identity.d.mts +0 -30
  227. package/dist/drizzle/mysql-identity.d.mts +0 -21
  228. package/dist/drizzle/pg-identity.d.mts +0 -22
@@ -56,6 +56,7 @@ import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
56
56
  import { Cause, DateTime, Effect, Option, Predicate, Redacted, Schema, Context } from "effect";
57
57
  import type { Statement } from "effect/sql/Statement";
58
58
 
59
+ import { Database as DatabaseService } from "./d1-database";
59
60
  import { balancedD1And } from "./d1-generated-statement";
60
61
  import { CurrentD1PlanningDatabase, makeD1Owner } from "./d1-planning";
61
62
  import { compileD1ProofCompletionPlan, type D1ProtectedProofMutation } from "./d1-proofs";
@@ -411,35 +412,53 @@ const scopeEntries = (keys: PasswordScopeKeys, policy: PasswordAttemptPolicy) =>
411
412
  return entries;
412
413
  };
413
414
 
414
- const scopeAdmissionCondition = (
415
+ const livePendingAttempts = (
415
416
  mapping: Mapping,
416
417
  moduleId: string,
417
418
  action: "sign-in" | "change",
418
419
  entry: ScopeEntry,
419
- policy: PasswordAttemptPolicy,
420
420
  identifier: LoginIdentifier,
421
421
  nativeSubjectId: unknown | undefined,
422
+ activeAt: unknown,
422
423
  ) => {
423
- const c = chargeColumns(mapping);
424
424
  const a = attemptColumns(mapping);
425
425
 
426
- const pending =
426
+ return and(
427
427
  entry.kind === "action"
428
- ? and(eq(a.moduleId, moduleId), eq(a.action, action), eq(a.state, "pending"))
428
+ ? and(eq(a.moduleId, moduleId), eq(a.action, action))
429
429
  : entry.kind === "identifier"
430
430
  ? and(
431
431
  eq(a.moduleId, moduleId),
432
432
  eq(a.action, action),
433
433
  eq(a.identifierNamespace, identifier.namespace),
434
434
  eq(a.identifierValue, identifier.value),
435
- eq(a.state, "pending"),
436
435
  )
437
- : and(
438
- eq(a.moduleId, moduleId),
439
- eq(a.action, action),
440
- eq(a.subjectId, nativeSubjectId),
441
- eq(a.state, "pending"),
442
- );
436
+ : and(eq(a.moduleId, moduleId), eq(a.action, action), eq(a.subjectId, nativeSubjectId)),
437
+ eq(a.state, "pending"),
438
+ sql`${a.retentionUntil} > ${activeAt}`,
439
+ );
440
+ };
441
+
442
+ const scopeAdmissionCondition = (
443
+ mapping: Mapping,
444
+ moduleId: string,
445
+ action: "sign-in" | "change",
446
+ entry: ScopeEntry,
447
+ policy: PasswordAttemptPolicy,
448
+ identifier: LoginIdentifier,
449
+ nativeSubjectId: unknown | undefined,
450
+ ) => {
451
+ const c = chargeColumns(mapping);
452
+
453
+ const pending = livePendingAttempts(
454
+ mapping,
455
+ moduleId,
456
+ action,
457
+ entry,
458
+ identifier,
459
+ nativeSubjectId,
460
+ mapping.d1.engineNow,
461
+ );
443
462
 
444
463
  return sql`(select count(*) from ${mapping.charge.table} where ${c.moduleId} = ${sql.param(moduleId, c.moduleId)} and ${c.action} = ${sql.param(action, c.action)} and ${c.scopeKind} = ${sql.param(entry.kind, c.scopeKind)} and ${c.scopeKey} = ${sql.param(entry.key, c.scopeKey)} and ${c.occurredAt} >= ${mapping.d1.engineInstantMinus(entry.windowMillis)}) < ${entry.limit} and (select count(*) from ${mapping.attempt.table} where ${pending}) < ${policy.maximumPending}`;
445
464
  };
@@ -457,7 +476,6 @@ const readScopeAdmission = Effect.fn("DrizzleD1Password.readScopeAdmission")(fun
457
476
  const database = yield* CurrentD1PlanningDatabase;
458
477
 
459
478
  const c = chargeColumns(mapping);
460
- const a = attemptColumns(mapping);
461
479
  const admitted: ScopeEntry[] = [];
462
480
 
463
481
  for (let index = 0; index < entries.length; index++) {
@@ -478,26 +496,21 @@ const readScopeAdmission = Effect.fn("DrizzleD1Password.readScopeAdmission")(fun
478
496
  ),
479
497
  );
480
498
 
481
- const pendingWhere =
482
- entry.kind === "action"
483
- ? and(eq(a.moduleId, moduleId), eq(a.action, action), eq(a.state, "pending"))
484
- : entry.kind === "identifier"
485
- ? and(
486
- eq(a.moduleId, moduleId),
487
- eq(a.action, action),
488
- eq(a.identifierNamespace, identifier.namespace),
489
- eq(a.identifierValue, identifier.value),
490
- eq(a.state, "pending"),
491
- )
492
- : and(
493
- eq(a.moduleId, moduleId),
494
- eq(a.action, action),
495
- eq(a.subjectId, nativeSubjectId),
496
- eq(a.state, "pending"),
497
- );
498
-
499
499
  const pendingRows = yield* mapAdapter(
500
- database.select({ total: count() }).from(mapping.attempt.table).where(pendingWhere),
500
+ database
501
+ .select({ total: count() })
502
+ .from(mapping.attempt.table)
503
+ .where(
504
+ livePendingAttempts(
505
+ mapping,
506
+ moduleId,
507
+ action,
508
+ entry,
509
+ identifier,
510
+ nativeSubjectId,
511
+ mapping.encodeInstant(now),
512
+ ),
513
+ ),
501
514
  );
502
515
 
503
516
  const admittedHere =
@@ -1980,7 +1993,7 @@ const cleanupPlan = Effect.fn("Drizzle.cleanupPlan")(function* <A>(
1980
1993
  };
1981
1994
  });
1982
1995
 
1983
- export const makeD1PasswordPersistenceServices = <
1996
+ export const makeD1PasswordPersistenceServices = Effect.fnUntraced(function* <
1984
1997
  S extends AnySQLiteTable,
1985
1998
  I extends AnySQLiteTable,
1986
1999
  C extends AnySQLiteTable,
@@ -1991,7 +2004,6 @@ export const makeD1PasswordPersistenceServices = <
1991
2004
  M extends AnySQLiteTable,
1992
2005
  NativeId,
1993
2006
  >(
1994
- database: Database,
1995
2007
  mapping: D1PasswordPersistenceMapping<S, I, C, AC, A, RS, CE, M, NativeId>,
1996
2008
  proofMapping?: D1ProofPersistenceMapping<
1997
2009
  any,
@@ -2007,62 +2019,62 @@ export const makeD1PasswordPersistenceServices = <
2007
2019
  any,
2008
2020
  any
2009
2021
  >,
2010
- ) =>
2011
- Effect.gen(function* () {
2012
- const hooks = yield* LifecycleHooks;
2013
- const plans = makePasswordPlans(mapping as unknown as Mapping, proofMapping);
2022
+ ) {
2023
+ const database = yield* DatabaseService;
2014
2024
 
2015
- const run = <Out, Err, Env>(plan: Effect.Effect<Planned<Out>, Err, Env>) =>
2016
- Effect.gen(function* () {
2017
- if (yield* hasCommitScope) return yield* unavailable();
2025
+ const hooks = yield* LifecycleHooks;
2026
+ const plans = makePasswordPlans(mapping as unknown as Mapping, proofMapping);
2018
2027
 
2019
- return yield* executeStandalone(plan, 2);
2020
- }).pipe(
2021
- Effect.provideService(CurrentD1PlanningDatabase, database),
2022
- Effect.provideService(LifecycleHooks, hooks),
2023
- );
2024
-
2025
- const service: PasswordPersistence["Service"] = {
2026
- admitAttempt: (input, prepare) =>
2027
- run(plans.admitAttempt(input, prepare)).pipe(translateFailure),
2028
- settleAttempt: (input, prepare) =>
2029
- run(plans.settleAttempt(input, prepare)).pipe(translateFailure),
2030
- readForSubject: (input) =>
2031
- plans
2032
- .readForSubject(input)
2033
- .pipe(
2034
- Effect.provideService(CurrentD1PlanningDatabase, database),
2035
- Effect.provideService(LifecycleHooks, hooks),
2036
- translateFailure,
2037
- ),
2038
- recoveryTarget: (input) =>
2039
- plans
2040
- .recoveryTarget(input)
2041
- .pipe(
2042
- Effect.provideService(CurrentD1PlanningDatabase, database),
2043
- Effect.provideService(LifecycleHooks, hooks),
2044
- translateFailure,
2045
- ),
2046
- addIfAbsent: (input, prepare) =>
2047
- run(plans.addIfAbsent(input, prepare)).pipe(translateFailure),
2048
- replaceIfCurrent: (input, prepare) =>
2049
- run(plans.replaceIfCurrent(input, prepare)).pipe(translateFailure),
2050
- checkReset: (input) =>
2051
- plans
2052
- .checkReset(input)
2053
- .pipe(
2054
- Effect.provideService(CurrentD1PlanningDatabase, database),
2055
- Effect.provideService(LifecycleHooks, hooks),
2056
- translateFailure,
2057
- ),
2058
- resetWithProof: (input, prepare) =>
2059
- run(plans.resetWithProof(input, prepare)).pipe(translateFailure),
2060
- cleanupAttempts: (input, prepare) =>
2061
- run(plans.cleanupAttempts(input, prepare)).pipe(translateFailure),
2062
- };
2028
+ const run = <Out, Err, Env>(plan: Effect.Effect<Planned<Out>, Err, Env>) =>
2029
+ Effect.gen(function* () {
2030
+ if (yield* hasCommitScope) return yield* unavailable();
2063
2031
 
2064
- return { passwordPersistence: service };
2065
- });
2032
+ return yield* executeStandalone(plan, 2);
2033
+ }).pipe(
2034
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2035
+ Effect.provideService(LifecycleHooks, hooks),
2036
+ );
2037
+
2038
+ const service: PasswordPersistence["Service"] = {
2039
+ admitAttempt: (input, prepare) =>
2040
+ run(plans.admitAttempt(input, prepare)).pipe(translateFailure),
2041
+ settleAttempt: (input, prepare) =>
2042
+ run(plans.settleAttempt(input, prepare)).pipe(translateFailure),
2043
+ readForSubject: (input) =>
2044
+ plans
2045
+ .readForSubject(input)
2046
+ .pipe(
2047
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2048
+ Effect.provideService(LifecycleHooks, hooks),
2049
+ translateFailure,
2050
+ ),
2051
+ recoveryTarget: (input) =>
2052
+ plans
2053
+ .recoveryTarget(input)
2054
+ .pipe(
2055
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2056
+ Effect.provideService(LifecycleHooks, hooks),
2057
+ translateFailure,
2058
+ ),
2059
+ addIfAbsent: (input, prepare) => run(plans.addIfAbsent(input, prepare)).pipe(translateFailure),
2060
+ replaceIfCurrent: (input, prepare) =>
2061
+ run(plans.replaceIfCurrent(input, prepare)).pipe(translateFailure),
2062
+ checkReset: (input) =>
2063
+ plans
2064
+ .checkReset(input)
2065
+ .pipe(
2066
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2067
+ Effect.provideService(LifecycleHooks, hooks),
2068
+ translateFailure,
2069
+ ),
2070
+ resetWithProof: (input, prepare) =>
2071
+ run(plans.resetWithProof(input, prepare)).pipe(translateFailure),
2072
+ cleanupAttempts: (input, prepare) =>
2073
+ run(plans.cleanupAttempts(input, prepare)).pipe(translateFailure),
2074
+ };
2075
+
2076
+ return { passwordPersistence: service };
2077
+ });
2066
2078
 
2067
2079
  type CoordinatorError<E> = E | PasswordUnavailable | HookConfigurationError;
2068
2080
 
@@ -2443,7 +2455,7 @@ const makeRegistrationPlans = <Registration>(mapping: RegistrationMapping<Regist
2443
2455
  }),
2444
2456
  });
2445
2457
 
2446
- export const makeD1PasswordRegistrationServices = <
2458
+ export const makeD1PasswordRegistrationServices = Effect.fnUntraced(function* <
2447
2459
  Registration,
2448
2460
  S extends AnySQLiteTable,
2449
2461
  I extends AnySQLiteTable,
@@ -2451,30 +2463,28 @@ export const makeD1PasswordRegistrationServices = <
2451
2463
  AC extends AnySQLiteTable,
2452
2464
  Rq extends AnySQLiteTable,
2453
2465
  NativeId,
2454
- >(
2455
- database: Database,
2456
- mapping: PasswordRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>,
2457
- ) =>
2458
- Effect.gen(function* () {
2459
- const hooks = yield* LifecycleHooks;
2460
- const plans = makeRegistrationPlans(mapping as unknown as RegistrationMapping<Registration>);
2466
+ >(mapping: PasswordRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>) {
2467
+ const database = yield* DatabaseService;
2461
2468
 
2462
- const run = <Out, Err, Env>(plan: Effect.Effect<Planned<Out>, Err, Env>) =>
2463
- Effect.gen(function* () {
2464
- if (yield* hasCommitScope) return yield* unavailable();
2469
+ const hooks = yield* LifecycleHooks;
2470
+ const plans = makeRegistrationPlans(mapping as unknown as RegistrationMapping<Registration>);
2465
2471
 
2466
- return yield* executeStandalone(plan, 2);
2467
- }).pipe(
2468
- Effect.provideService(CurrentD1PlanningDatabase, database),
2469
- Effect.provideService(LifecycleHooks, hooks),
2470
- );
2472
+ const run = <Out, Err, Env>(plan: Effect.Effect<Planned<Out>, Err, Env>) =>
2473
+ Effect.gen(function* () {
2474
+ if (yield* hasCommitScope) return yield* unavailable();
2471
2475
 
2472
- const service: PasswordRegistrationAuthority<Registration> = {
2473
- register: (input, prepare) => run(plans.register(input, prepare)).pipe(translateFailure),
2474
- };
2476
+ return yield* executeStandalone(plan, 2);
2477
+ }).pipe(
2478
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2479
+ Effect.provideService(LifecycleHooks, hooks),
2480
+ );
2475
2481
 
2476
- return { registrationAuthority: service };
2477
- });
2482
+ const service: PasswordRegistrationAuthority<Registration> = {
2483
+ register: (input, prepare) => run(plans.register(input, prepare)).pipe(translateFailure),
2484
+ };
2485
+
2486
+ return { registrationAuthority: service };
2487
+ });
2478
2488
 
2479
2489
  export function coordinateD1PasswordRegistration<
2480
2490
  TargetId,
@@ -11,6 +11,7 @@ import type { EffectSQLiteD1Database } from "drizzle-orm/effect-d1";
11
11
  import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
12
12
  import { Context, Effect } from "effect";
13
13
 
14
+ import { Database as DatabaseService } from "./d1-database";
14
15
  import { makeD1Owner } from "./d1-planning";
15
16
  import { D1BatchStatements } from "./D1BatchStatements";
16
17
  import type { D1PhoneMapping, PhoneMapping, PhoneMappingSource } from "./phone-model";
@@ -26,7 +27,10 @@ const configuration = {
26
27
  };
27
28
 
28
29
  /** Reads use a primary D1 session; observations and expiry are asserted in the same batch. */
29
- const target = makePhoneTarget<Database, Table, D1PhoneMapping>(configuration);
30
+ const target = makePhoneTarget<DatabaseService, Database, Table, D1PhoneMapping>(
31
+ DatabaseService,
32
+ configuration,
33
+ );
30
34
 
31
35
  export const { makePhonePersistenceServices } = target;
32
36
 
@@ -47,6 +47,7 @@ import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
47
47
  import { Cause, Effect, Schema, Context } from "effect";
48
48
  import type { Statement } from "effect/sql/Statement";
49
49
 
50
+ import { Database as DatabaseService } from "./d1-database";
50
51
  import { balancedD1And } from "./d1-generated-statement";
51
52
  import { CurrentD1PlanningDatabase, makeD1Owner } from "./d1-planning";
52
53
  import { D1BatchStatements } from "./D1BatchStatements";
@@ -1985,7 +1986,7 @@ const makeProofPlans = (mapping: Mapping) => {
1985
1986
  };
1986
1987
  };
1987
1988
 
1988
- export const makeD1ProofPersistenceServices = <
1989
+ export const makeD1ProofPersistenceServices = Effect.fnUntraced(function* <
1989
1990
  Rq extends AnySQLiteTable,
1990
1991
  S extends AnySQLiteTable,
1991
1992
  G extends AnySQLiteTable,
@@ -1998,38 +1999,36 @@ export const makeD1ProofPersistenceServices = <
1998
1999
  I extends AnySQLiteTable,
1999
2000
  Cr extends AnySQLiteTable,
2000
2001
  NativeId,
2001
- >(
2002
- database: Database,
2003
- mapping: D1ProofPersistenceMapping<Rq, S, G, Cn, Rs, A, F, C, Sub, I, Cr, NativeId>,
2004
- ) =>
2005
- Effect.gen(function* () {
2006
- const hooks = yield* LifecycleHooks;
2007
- const plans = makeProofPlans(mapping as unknown as Mapping);
2008
-
2009
- const run = <Out, Err, Env>(plan: Effect.Effect<Planned<Out>, Err, Env>) =>
2010
- Effect.gen(function* () {
2011
- if (yield* hasCommitScope) return yield* unavailable();
2002
+ >(mapping: D1ProofPersistenceMapping<Rq, S, G, Cn, Rs, A, F, C, Sub, I, Cr, NativeId>) {
2003
+ const database = yield* DatabaseService;
2012
2004
 
2013
- return yield* executeStandalone(plan, 2);
2014
- }).pipe(
2015
- Effect.provideService(CurrentD1PlanningDatabase, database),
2016
- Effect.provideService(LifecycleHooks, hooks),
2017
- );
2005
+ const hooks = yield* LifecycleHooks;
2006
+ const plans = makeProofPlans(mapping as unknown as Mapping);
2018
2007
 
2019
- const service: ProofPersistence["Service"] = {
2020
- issue: (input, prepare) => run(plans.issue(input, prepare)).pipe(translateIssueFailure),
2021
- attempt: (input, prepare) => run(plans.attempt(input, prepare)).pipe(translateFailure),
2022
- complete: (input, prepare) => run(plans.complete(input, prepare)).pipe(translateFailure),
2023
- claimDelivery: (input, prepare) =>
2024
- run(plans.claimDelivery(input, prepare)).pipe(translateFailure),
2025
- settleDelivery: (input, prepare) =>
2026
- run(plans.settleDelivery(input, prepare)).pipe(translateFailure),
2027
- cancel: (input, prepare) => run(plans.cancel(input, prepare)).pipe(translateFailure),
2028
- cleanup: (input, prepare) => run(plans.cleanup(input, prepare)).pipe(translateFailure),
2029
- };
2008
+ const run = <Out, Err, Env>(plan: Effect.Effect<Planned<Out>, Err, Env>) =>
2009
+ Effect.gen(function* () {
2010
+ if (yield* hasCommitScope) return yield* unavailable();
2030
2011
 
2031
- return { proofPersistence: service };
2032
- });
2012
+ return yield* executeStandalone(plan, 2);
2013
+ }).pipe(
2014
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2015
+ Effect.provideService(LifecycleHooks, hooks),
2016
+ );
2017
+
2018
+ const service: ProofPersistence["Service"] = {
2019
+ issue: (input, prepare) => run(plans.issue(input, prepare)).pipe(translateIssueFailure),
2020
+ attempt: (input, prepare) => run(plans.attempt(input, prepare)).pipe(translateFailure),
2021
+ complete: (input, prepare) => run(plans.complete(input, prepare)).pipe(translateFailure),
2022
+ claimDelivery: (input, prepare) =>
2023
+ run(plans.claimDelivery(input, prepare)).pipe(translateFailure),
2024
+ settleDelivery: (input, prepare) =>
2025
+ run(plans.settleDelivery(input, prepare)).pipe(translateFailure),
2026
+ cancel: (input, prepare) => run(plans.cancel(input, prepare)).pipe(translateFailure),
2027
+ cleanup: (input, prepare) => run(plans.cleanup(input, prepare)).pipe(translateFailure),
2028
+ };
2029
+
2030
+ return { proofPersistence: service };
2031
+ });
2033
2032
 
2034
2033
  type CoordinatorError<E> = E | ProofUnavailable | HookConfigurationError;
2035
2034
 
@@ -52,6 +52,7 @@ import { Cause, Context, Data, DateTime, Effect, Schema } from "effect";
52
52
  import type * as SqlError from "effect/sql/SqlError";
53
53
  import type { Statement } from "effect/sql/Statement";
54
54
 
55
+ import { Database as DatabaseService } from "./d1-database";
55
56
  import { compactD1GeneratedStatement } from "./d1-generated-statement";
56
57
  import {
57
58
  CurrentD1PlanningDatabase,
@@ -1622,8 +1623,9 @@ export const makeD1SignedValidity = (
1622
1623
  };
1623
1624
 
1624
1625
  export const makeD1SessionServiceEffects = {
1625
- authority: <Claims>(database: Database, mapping: any) =>
1626
+ authority: <Claims>(mapping: any) =>
1626
1627
  Effect.gen(function* () {
1628
+ const database = yield* CurrentD1PlanningDatabase;
1627
1629
  const hooks = yield* LifecycleHooks;
1628
1630
  const raw = makeD1AuthenticationAuthority<Claims>(mapping);
1629
1631
 
@@ -1649,8 +1651,9 @@ export const makeD1SessionServiceEffects = {
1649
1651
 
1650
1652
  return { authenticationAuthority };
1651
1653
  }),
1652
- pending: <Claims>(database: Database, mapping: any) =>
1654
+ pending: <Claims>(mapping: any) =>
1653
1655
  Effect.gen(function* () {
1656
+ const database = yield* CurrentD1PlanningDatabase;
1654
1657
  const hooks = yield* LifecycleHooks;
1655
1658
  const raw = makeD1PendingAuthentication<Claims>(mapping);
1656
1659
 
@@ -1677,8 +1680,9 @@ export const makeD1SessionServiceEffects = {
1677
1680
 
1678
1681
  return { pendingAuthentication };
1679
1682
  }),
1680
- stateful: <Claims>(database: Database, mapping: any) =>
1683
+ stateful: <Claims>(mapping: any) =>
1681
1684
  Effect.gen(function* () {
1685
+ const database = yield* CurrentD1PlanningDatabase;
1682
1686
  const hooks = yield* LifecycleHooks;
1683
1687
  const raw = makeD1StatefulSessions<Claims>(mapping);
1684
1688
 
@@ -1711,8 +1715,9 @@ export const makeD1SessionServiceEffects = {
1711
1715
 
1712
1716
  return { statefulSessionPersistence, sessionRepository };
1713
1717
  }),
1714
- validity: (database: Database, mapping: any) =>
1718
+ validity: (mapping: any) =>
1715
1719
  Effect.gen(function* () {
1720
+ const database = yield* CurrentD1PlanningDatabase;
1716
1721
  const hooks = yield* LifecycleHooks;
1717
1722
  const raw = makeD1SignedValidity(mapping);
1718
1723
 
@@ -1832,7 +1837,6 @@ export const makeD1AuthenticationAuthorityServices = <
1832
1837
  Pending extends AnySQLiteTable,
1833
1838
  NativeSubjectId,
1834
1839
  >(
1835
- database: Database,
1836
1840
  mapping: D1AuthenticationAuthorityMapping<
1837
1841
  Claims,
1838
1842
  Subject,
@@ -1841,7 +1845,10 @@ export const makeD1AuthenticationAuthorityServices = <
1841
1845
  Pending,
1842
1846
  NativeSubjectId
1843
1847
  >,
1844
- ) => makeD1SessionServiceEffects.authority<Claims>(database, mapping as any);
1848
+ ) =>
1849
+ makeD1SessionServiceEffects
1850
+ .authority<Claims>(mapping as any)
1851
+ .pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, DatabaseService));
1845
1852
 
1846
1853
  export const makeD1PendingAuthenticationServices = <
1847
1854
  Claims,
@@ -1851,7 +1858,6 @@ export const makeD1PendingAuthenticationServices = <
1851
1858
  Flow extends AnySQLiteTable,
1852
1859
  NativeSubjectId,
1853
1860
  >(
1854
- database: Database,
1855
1861
  mapping: D1PendingAuthenticationMapping<
1856
1862
  Claims,
1857
1863
  Subject,
@@ -1860,7 +1866,10 @@ export const makeD1PendingAuthenticationServices = <
1860
1866
  Flow,
1861
1867
  NativeSubjectId
1862
1868
  >,
1863
- ) => makeD1SessionServiceEffects.pending<Claims>(database, mapping as any);
1869
+ ) =>
1870
+ makeD1SessionServiceEffects
1871
+ .pending<Claims>(mapping as any)
1872
+ .pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, DatabaseService));
1864
1873
 
1865
1874
  export const makeD1StatefulSessionServices = <
1866
1875
  Claims,
@@ -1872,7 +1881,6 @@ export const makeD1StatefulSessionServices = <
1872
1881
  NativeSubjectId,
1873
1882
  NativeSessionId,
1874
1883
  >(
1875
- database: Database,
1876
1884
  mapping: D1StatefulSessionMapping<
1877
1885
  Claims,
1878
1886
  Subject,
@@ -1883,7 +1891,10 @@ export const makeD1StatefulSessionServices = <
1883
1891
  NativeSubjectId,
1884
1892
  NativeSessionId
1885
1893
  >,
1886
- ) => makeD1SessionServiceEffects.stateful<Claims>(database, mapping as any);
1894
+ ) =>
1895
+ makeD1SessionServiceEffects
1896
+ .stateful<Claims>(mapping as any)
1897
+ .pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, DatabaseService));
1887
1898
 
1888
1899
  export const makeD1SignedSessionValidityServices = <
1889
1900
  Subject extends AnySQLiteTable,
@@ -1891,9 +1902,11 @@ export const makeD1SignedSessionValidityServices = <
1891
1902
  NativeSubjectId,
1892
1903
  NativeSessionId,
1893
1904
  >(
1894
- database: Database,
1895
1905
  mapping: D1SignedSessionValidityMapping<Subject, Tombstone, NativeSubjectId, NativeSessionId>,
1896
- ) => makeD1SessionServiceEffects.validity(database, mapping as any);
1906
+ ) =>
1907
+ makeD1SessionServiceEffects
1908
+ .validity(mapping as any)
1909
+ .pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, DatabaseService));
1897
1910
 
1898
1911
  export function coordinateD1AuthenticationAuthority<
1899
1912
  Claims,
@@ -2733,7 +2746,7 @@ export const makeD1SessionStepUp = <Claims>(
2733
2746
  };
2734
2747
  };
2735
2748
 
2736
- export const makeD1SessionStepUpServices = <
2749
+ export const makeD1SessionStepUpServices = Effect.fnUntraced(function* <
2737
2750
  Claims,
2738
2751
  Id,
2739
2752
  S extends AnySQLiteTable,
@@ -2744,39 +2757,39 @@ export const makeD1SessionStepUpServices = <
2744
2757
  NativeId,
2745
2758
  NativeSessionId,
2746
2759
  >(
2747
- database: Database,
2748
2760
  mapping: D1SessionStepUpMapping<NoInfer<Claims>, S, C, I, Session, T, NativeId, NativeSessionId>,
2749
2761
  target: Context.Service<Id, SessionStepUpPersistence<Claims>>,
2750
- ) =>
2751
- Effect.gen(function* () {
2752
- const hooks = yield* LifecycleHooks;
2753
- const raw = makeD1SessionStepUp<Claims>(mapping as any);
2762
+ ) {
2763
+ const database = yield* DatabaseService;
2754
2764
 
2755
- const run = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
2756
- Effect.gen(function* () {
2757
- if (
2758
- (yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" ||
2759
- (yield* hasCommitScope)
2760
- )
2761
- return yield* unavailable();
2765
+ const hooks = yield* LifecycleHooks;
2766
+ const raw = makeD1SessionStepUp<Claims>(mapping as any);
2762
2767
 
2763
- return yield* effect.pipe(
2764
- Effect.provideService(CurrentD1PlanningDatabase, database),
2765
- Effect.provideService(LifecycleHooks, hooks),
2766
- );
2767
- });
2768
-
2769
- const sessionStepUpPersistence = target.of({
2770
- create: (input, now, prepare) => run(raw.create(input, now, prepare)),
2771
- context: (input) => run(raw.context(input)),
2772
- read: (input) => run(raw.read(input)),
2773
- reject: (input, prepare) => run(raw.reject(input, prepare)),
2774
- complete: (plan, prepare) => run(raw.complete(plan, prepare)),
2768
+ const run = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
2769
+ Effect.gen(function* () {
2770
+ if (
2771
+ (yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" ||
2772
+ (yield* hasCommitScope)
2773
+ )
2774
+ return yield* unavailable();
2775
+
2776
+ return yield* effect.pipe(
2777
+ Effect.provideService(CurrentD1PlanningDatabase, database),
2778
+ Effect.provideService(LifecycleHooks, hooks),
2779
+ );
2775
2780
  });
2776
2781
 
2777
- return { sessionStepUpPersistence };
2782
+ const sessionStepUpPersistence = target.of({
2783
+ create: (input, now, prepare) => run(raw.create(input, now, prepare)),
2784
+ context: (input) => run(raw.context(input)),
2785
+ read: (input) => run(raw.read(input)),
2786
+ reject: (input, prepare) => run(raw.reject(input, prepare)),
2787
+ complete: (plan, prepare) => run(raw.complete(plan, prepare)),
2778
2788
  });
2779
2789
 
2790
+ return { sessionStepUpPersistence };
2791
+ });
2792
+
2780
2793
  export function coordinateD1SessionStepUp<
2781
2794
  Claims,
2782
2795
  Id,
@@ -6,6 +6,7 @@ import type { EffectSQLiteD1Database } from "drizzle-orm/effect-d1";
6
6
  import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
7
7
  import { Context, Effect } from "effect";
8
8
 
9
+ import { Database as DatabaseService } from "./d1-database";
9
10
  import { makeD1Owner } from "./d1-planning";
10
11
  import { D1BatchStatements } from "./D1BatchStatements";
11
12
  import type { D1TotpMapping, TotpMapping, TotpMappingSource } from "./totp-model";
@@ -21,7 +22,10 @@ const configuration = {
21
22
  };
22
23
 
23
24
  /** Reads use a primary D1 session; observations and expiry are asserted in the same batch. */
24
- const target = makeTotpTarget<Database, Table, D1TotpMapping>(configuration);
25
+ const target = makeTotpTarget<DatabaseService, Database, Table, D1TotpMapping>(
26
+ DatabaseService,
27
+ configuration,
28
+ );
25
29
 
26
30
  export const { makeTotpPersistenceServices } = target;
27
31
 
@@ -540,10 +540,14 @@ const prepareConflict = Effect.fn("Drizzle.prepareConflict")(function* <Registra
540
540
 
541
541
  export const makeSqlEmailRegistrationAuthority = Effect.fn("makeSqlEmailRegistrationAuthority")(
542
542
  function* <Registration>(
543
- database: EmailSqlDatabase,
544
543
  mapping: Mapping<Registration>,
545
544
  configuration: EmailRegistrationConfiguration,
546
- ): Effect.fn.Return<EmailRegistrationAuthority<Registration>, never, LifecycleHooks> {
545
+ ): Effect.fn.Return<
546
+ EmailRegistrationAuthority<Registration>,
547
+ never,
548
+ LifecycleHooks | CurrentEmailSql
549
+ > {
550
+ const database = yield* CurrentEmailSql;
547
551
  const hooks = yield* LifecycleHooks;
548
552
 
549
553
  return {