@yielded/auth-persistence-drizzle 0.1.0-beta.23 → 0.1.0-beta.25

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 (189) hide show
  1. package/README.md +3 -0
  2. package/dist/D1.d.mts +9 -9
  3. package/dist/D1.mjs +2 -1
  4. package/dist/D1.mjs.map +1 -1
  5. package/dist/Libsql.d.mts +48 -64
  6. package/dist/Libsql.mjs +2 -1
  7. package/dist/Libsql.mjs.map +1 -1
  8. package/dist/Mysql2.d.mts +26 -27
  9. package/dist/Pglite.d.mts +28 -28
  10. package/dist/Pglite.mjs +2 -1
  11. package/dist/Pglite.mjs.map +1 -1
  12. package/dist/Postgres.d.mts +29 -29
  13. package/dist/Postgres.mjs +2 -1
  14. package/dist/Postgres.mjs.map +1 -1
  15. package/dist/SqliteBun.d.mts +49 -65
  16. package/dist/SqliteBun.mjs +2 -1
  17. package/dist/SqliteBun.mjs.map +1 -1
  18. package/dist/SqliteDo.d.mts +47 -63
  19. package/dist/SqliteDo.mjs +2 -1
  20. package/dist/SqliteDo.mjs.map +1 -1
  21. package/dist/SqliteNode.d.mts +51 -67
  22. package/dist/SqliteNode.mjs +2 -1
  23. package/dist/SqliteNode.mjs.map +1 -1
  24. package/dist/SqliteWasm.d.mts +47 -63
  25. package/dist/SqliteWasm.mjs +2 -1
  26. package/dist/SqliteWasm.mjs.map +1 -1
  27. package/dist/drizzle/crypto.mjs +1 -1
  28. package/dist/drizzle/d1-emails.d.mts +1 -1
  29. package/dist/drizzle/d1-oauth.d.mts +15 -15
  30. package/dist/drizzle/d1-passkey.d.mts +1 -1
  31. package/dist/drizzle/d1-password-prepared.d.mts +4 -4
  32. package/dist/drizzle/d1-password-prepared.mjs +1 -1
  33. package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
  34. package/dist/drizzle/d1-passwords.d.mts +17 -33
  35. package/dist/drizzle/d1-passwords.mjs +57 -199
  36. package/dist/drizzle/d1-passwords.mjs.map +1 -1
  37. package/dist/drizzle/d1-phone.d.mts +1 -1
  38. package/dist/drizzle/d1-proofs.d.mts +1 -1
  39. package/dist/drizzle/d1-sessions.d.mts +2 -2
  40. package/dist/drizzle/d1-sessions.mjs +11 -6
  41. package/dist/drizzle/d1-sessions.mjs.map +1 -1
  42. package/dist/drizzle/d1-totp.d.mts +1 -1
  43. package/dist/drizzle/mysql-password-prepared.d.mts +5 -5
  44. package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
  45. package/dist/drizzle/mysql-passwords.d.mts +16 -32
  46. package/dist/drizzle/mysql-passwords.mjs.map +1 -1
  47. package/dist/drizzle/mysql-sessions.d.mts +1 -1
  48. package/dist/drizzle/native-sql-table.mjs +26 -1
  49. package/dist/drizzle/native-sql-table.mjs.map +1 -1
  50. package/dist/drizzle/oauth-connected-model.d.mts +20 -281
  51. package/dist/drizzle/oauth-connected-model.mjs +3 -17
  52. package/dist/drizzle/oauth-connected-model.mjs.map +1 -1
  53. package/dist/drizzle/oauth-connected-reference.d.mts +1 -3
  54. package/dist/drizzle/oauth-connected-reference.mjs +4 -53
  55. package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
  56. package/dist/drizzle/oauth-connected-target.d.mts +3 -990
  57. package/dist/drizzle/oauth-connected-target.mjs +8 -92
  58. package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
  59. package/dist/drizzle/oauth-kernel.mjs +11 -0
  60. package/dist/drizzle/oauth-kernel.mjs.map +1 -0
  61. package/dist/drizzle/oauth-model.d.mts +35 -438
  62. package/dist/drizzle/oauth-model.mjs +6 -44
  63. package/dist/drizzle/oauth-model.mjs.map +1 -1
  64. package/dist/drizzle/oauth-mysql.mjs +2 -2
  65. package/dist/drizzle/oauth-mysql.mjs.map +1 -1
  66. package/dist/drizzle/oauth-proxy.d.mts +10 -0
  67. package/dist/drizzle/oauth-proxy.mjs +54 -0
  68. package/dist/drizzle/oauth-proxy.mjs.map +1 -0
  69. package/dist/drizzle/oauth-target.d.mts +6 -107
  70. package/dist/drizzle/oauth-target.mjs +15 -245
  71. package/dist/drizzle/oauth-target.mjs.map +1 -1
  72. package/dist/drizzle/password-model.d.mts +5 -6
  73. package/dist/drizzle/password-prepared-model.d.mts +5 -5
  74. package/dist/drizzle/password-prepared-model.mjs.map +1 -1
  75. package/dist/drizzle/password-prepared-sql.mjs +1 -1
  76. package/dist/drizzle/password-prepared-sql.mjs.map +1 -1
  77. package/dist/drizzle/password-prepared-state.mjs +1 -1
  78. package/dist/drizzle/pg-password-prepared.d.mts +5 -5
  79. package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
  80. package/dist/drizzle/pg-passwords.d.mts +16 -32
  81. package/dist/drizzle/pg-passwords.mjs.map +1 -1
  82. package/dist/drizzle/pg-sessions.d.mts +1 -1
  83. package/dist/drizzle/phone-target.d.mts +1 -1
  84. package/dist/drizzle/phone-target.mjs +1 -1
  85. package/dist/drizzle/query-operations.mjs +3 -1
  86. package/dist/drizzle/query-operations.mjs.map +1 -1
  87. package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
  88. package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
  89. package/dist/drizzle/storage-validation.mjs +10 -185
  90. package/dist/drizzle/storage-validation.mjs.map +1 -1
  91. package/dist/drizzle/totp-target.d.mts +2 -2
  92. package/dist/drizzle/totp-target.mjs +2 -2
  93. package/dist/drizzle/transaction-execution.d.mts +2 -2
  94. package/dist/drizzle/transaction-owner.d.mts +1 -2
  95. package/dist/index.d.mts +3 -2
  96. package/dist/internal/drizzle-postgres-oauth-proxy.d.mts +138 -0
  97. package/dist/internal/drizzle-postgres-oauth-proxy.mjs +29 -0
  98. package/dist/internal/drizzle-postgres-oauth-proxy.mjs.map +1 -0
  99. package/dist/internal/drizzle-sqlite-oauth-proxy.d.mts +146 -0
  100. package/dist/internal/drizzle-sqlite-oauth-proxy.mjs +29 -0
  101. package/dist/internal/drizzle-sqlite-oauth-proxy.mjs.map +1 -0
  102. package/package.json +1 -1
  103. package/src/D1.ts +2 -0
  104. package/src/Libsql.ts +2 -0
  105. package/src/Pglite.ts +2 -0
  106. package/src/Postgres.ts +2 -0
  107. package/src/SqliteBun.ts +2 -0
  108. package/src/SqliteDo.ts +2 -0
  109. package/src/SqliteNode.ts +2 -0
  110. package/src/SqliteWasm.ts +2 -0
  111. package/src/drizzle/d1-password-prepared.ts +4 -6
  112. package/src/drizzle/d1-passwords.ts +125 -459
  113. package/src/drizzle/d1-sessions.ts +21 -6
  114. package/src/drizzle/mysql-password-prepared.ts +4 -8
  115. package/src/drizzle/mysql-passwords.ts +5 -10
  116. package/src/drizzle/native-sql-table.ts +30 -0
  117. package/src/drizzle/oauth-connected-model.ts +97 -315
  118. package/src/drizzle/oauth-connected-reference.ts +13 -93
  119. package/src/drizzle/oauth-connected-target.ts +14 -271
  120. package/src/drizzle/oauth-kernel.ts +10 -0
  121. package/src/drizzle/oauth-model.ts +188 -541
  122. package/src/drizzle/oauth-mysql.ts +2 -2
  123. package/src/drizzle/oauth-proxy.ts +101 -0
  124. package/src/drizzle/oauth-target.ts +33 -737
  125. package/src/drizzle/password-model.ts +0 -13
  126. package/src/drizzle/password-prepared-model.ts +0 -6
  127. package/src/drizzle/password-prepared-sql.ts +2 -1
  128. package/src/drizzle/pg-password-prepared.ts +4 -8
  129. package/src/drizzle/pg-passwords.ts +5 -10
  130. package/src/drizzle/query-operations.ts +4 -0
  131. package/src/drizzle/sqlite-password-prepared.ts +4 -8
  132. package/src/drizzle/sqlite-passwords.ts +7 -14
  133. package/src/drizzle/storage-validation.ts +13 -214
  134. package/src/index.ts +2 -4
  135. package/src/internal/drizzle-postgres-oauth-proxy.ts +37 -0
  136. package/src/internal/drizzle-sqlite-oauth-proxy.ts +44 -0
  137. package/dist/_virtual/_rolldown/runtime.mjs +0 -13
  138. package/dist/drizzle/oauth-accounts.mjs +0 -359
  139. package/dist/drizzle/oauth-accounts.mjs.map +0 -1
  140. package/dist/drizzle/oauth-connected-access.mjs +0 -212
  141. package/dist/drizzle/oauth-connected-access.mjs.map +0 -1
  142. package/dist/drizzle/oauth-connected-collection.mjs +0 -202
  143. package/dist/drizzle/oauth-connected-collection.mjs.map +0 -1
  144. package/dist/drizzle/oauth-connected-custody.mjs +0 -147
  145. package/dist/drizzle/oauth-connected-custody.mjs.map +0 -1
  146. package/dist/drizzle/oauth-connected-flow.mjs +0 -297
  147. package/dist/drizzle/oauth-connected-flow.mjs.map +0 -1
  148. package/dist/drizzle/oauth-connected-input.mjs +0 -122
  149. package/dist/drizzle/oauth-connected-input.mjs.map +0 -1
  150. package/dist/drizzle/oauth-connected-maintenance.mjs +0 -214
  151. package/dist/drizzle/oauth-connected-maintenance.mjs.map +0 -1
  152. package/dist/drizzle/oauth-connected-management.mjs +0 -229
  153. package/dist/drizzle/oauth-connected-management.mjs.map +0 -1
  154. package/dist/drizzle/oauth-connected-settlement.mjs +0 -128
  155. package/dist/drizzle/oauth-connected-settlement.mjs.map +0 -1
  156. package/dist/drizzle/oauth-connected-sign-in.mjs +0 -265
  157. package/dist/drizzle/oauth-connected-sign-in.mjs.map +0 -1
  158. package/dist/drizzle/oauth-connected-state.d.mts +0 -2062
  159. package/dist/drizzle/oauth-connected-state.mjs +0 -430
  160. package/dist/drizzle/oauth-connected-state.mjs.map +0 -1
  161. package/dist/drizzle/oauth-flow.d.mts +0 -22
  162. package/dist/drizzle/oauth-flow.mjs +0 -253
  163. package/dist/drizzle/oauth-flow.mjs.map +0 -1
  164. package/dist/drizzle/oauth-input.mjs +0 -127
  165. package/dist/drizzle/oauth-input.mjs.map +0 -1
  166. package/dist/drizzle/oauth-owner.d.mts +0 -10
  167. package/dist/drizzle/oauth-owner.mjs +0 -10
  168. package/dist/drizzle/oauth-owner.mjs.map +0 -1
  169. package/dist/drizzle/oauth-registration.d.mts +0 -5
  170. package/dist/drizzle/oauth-registration.mjs +0 -374
  171. package/dist/drizzle/oauth-registration.mjs.map +0 -1
  172. package/dist/drizzle/oauth-state.mjs +0 -107
  173. package/dist/drizzle/oauth-state.mjs.map +0 -1
  174. package/src/drizzle/oauth-accounts.ts +0 -805
  175. package/src/drizzle/oauth-connected-access.ts +0 -361
  176. package/src/drizzle/oauth-connected-collection.ts +0 -324
  177. package/src/drizzle/oauth-connected-custody.ts +0 -279
  178. package/src/drizzle/oauth-connected-flow.ts +0 -529
  179. package/src/drizzle/oauth-connected-input.ts +0 -147
  180. package/src/drizzle/oauth-connected-maintenance.ts +0 -346
  181. package/src/drizzle/oauth-connected-management.ts +0 -365
  182. package/src/drizzle/oauth-connected-settlement.ts +0 -251
  183. package/src/drizzle/oauth-connected-sign-in.ts +0 -443
  184. package/src/drizzle/oauth-connected-state.ts +0 -872
  185. package/src/drizzle/oauth-flow.ts +0 -462
  186. package/src/drizzle/oauth-input.ts +0 -201
  187. package/src/drizzle/oauth-owner.ts +0 -29
  188. package/src/drizzle/oauth-registration.ts +0 -640
  189. package/src/drizzle/oauth-state.ts +0 -218
@@ -16,6 +16,7 @@ import {
16
16
  } from "@yielded/auth/Hooks";
17
17
  import type { LoginIdentifier } from "@yielded/auth/Identity";
18
18
  import {
19
+ EncodedPasswordHash,
19
20
  PasswordUnavailable,
20
21
  PasswordPersistence,
21
22
  type PasswordMutationInput,
@@ -24,11 +25,7 @@ import {
24
25
  snapshotPasswordRequirement,
25
26
  snapshotPasswordRevision,
26
27
  type PasswordAction,
27
- type PasswordAttemptDecision,
28
- type PasswordCredentialSnapshot,
29
28
  type PasswordMutationDecision,
30
- type PasswordAttemptPreparation,
31
- type PasswordAttemptAdmission,
32
29
  } from "@yielded/auth/Password";
33
30
  import { reportPersistenceFailure } from "@yielded/auth/Persistence";
34
31
  import {
@@ -43,7 +40,16 @@ import {
43
40
  AuthenticationRequirement,
44
41
  type SecurityRevision,
45
42
  } from "@yielded/auth/Sessions";
46
- import { and, eq, inArray, lte, sql, type AnyRelations, type SQL, type Table } from "drizzle-orm";
43
+ import {
44
+ and,
45
+ eq,
46
+ getTableColumns,
47
+ inArray,
48
+ sql,
49
+ type AnyRelations,
50
+ type SQL,
51
+ type Table,
52
+ } from "drizzle-orm";
47
53
  import type { EffectSQLiteD1Database } from "drizzle-orm/effect-d1";
48
54
  import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
49
55
  import { Cause, DateTime, Effect, Option, Predicate, Redacted, Schema, Context } from "effect";
@@ -59,7 +65,6 @@ import { nativeDatabase } from "./native-database";
59
65
  import {
60
66
  type AnyPasswordRegistrationMapping,
61
67
  type D1PasswordPersistenceMapping,
62
- type PasswordAttemptRecord,
63
68
  type PasswordRegistrationMapping,
64
69
  requiredPasswordConstraints,
65
70
  requiredPasswordRegistrationConstraints,
@@ -75,7 +80,7 @@ type PlanPrepare<Method extends (...args: any[]) => any, A> = (
75
80
  ) => PreparedCommit<A>;
76
81
 
77
82
  type Database = EffectSQLiteD1Database<AnyRelations> & { readonly $client: D1Client };
78
- type Mapping = D1PasswordPersistenceMapping<Table, Table, Table, Table, Table, Table, unknown>;
83
+ type Mapping = D1PasswordPersistenceMapping<Table, Table, Table, Table, Table, unknown>;
79
84
  type RegistrationMapping<Registration> = AnyPasswordRegistrationMapping<Registration>;
80
85
 
81
86
  interface Planned<A> {
@@ -189,11 +194,6 @@ const readEngineNowMillis = Effect.fn("Drizzle.readEngineNowMillis")(function* (
189
194
  );
190
195
  });
191
196
 
192
- const driverValues = (values: object, entries: ReadonlyArray<readonly [string, unknown]>) => ({
193
- ...values,
194
- ...Object.fromEntries(entries),
195
- });
196
-
197
197
  const allocate = <A>(
198
198
  asyncValue: Effect.Effect<A, PersistenceMappingError> | undefined,
199
199
  syncValue: (() => A) | undefined,
@@ -249,27 +249,6 @@ const authorityColumns = (mapping: Mapping) => ({
249
249
  : column(mapping.authorityCredential.table, mapping.authorityCredential.status),
250
250
  });
251
251
 
252
- const attemptColumns = (mapping: Mapping) => ({
253
- moduleId: column(mapping.attempt.table, mapping.attempt.moduleId),
254
- action: column(mapping.attempt.table, mapping.attempt.action),
255
- attemptId: column(mapping.attempt.table, mapping.attempt.attemptId),
256
- identifierNamespace: column(mapping.attempt.table, mapping.attempt.identifierNamespace),
257
- identifierValue: column(mapping.attempt.table, mapping.attempt.identifierValue),
258
- subjectId: column(mapping.attempt.table, mapping.attempt.subjectId),
259
- credentialId: column(mapping.attempt.table, mapping.attempt.credentialId),
260
- securityRevision: column(mapping.attempt.table, mapping.attempt.securityRevision),
261
- credentialRevision: column(mapping.attempt.table, mapping.attempt.credentialRevision),
262
- verifierVersion: column(mapping.attempt.table, mapping.attempt.verifierVersion),
263
- identifierBindingRevision: column(
264
- mapping.attempt.table,
265
- mapping.attempt.identifierBindingRevision,
266
- ),
267
- admittedAt: column(mapping.attempt.table, mapping.attempt.admittedAt),
268
- deadline: column(mapping.attempt.table, mapping.attempt.deadline),
269
- retentionUntil: column(mapping.attempt.table, mapping.attempt.retentionUntil),
270
- state: column(mapping.attempt.table, mapping.attempt.state),
271
- });
272
-
273
252
  const commandColumns = (mapping: Mapping) => ({
274
253
  moduleId: column(mapping.command.table, mapping.command.moduleId),
275
254
  commandId: column(mapping.command.table, mapping.command.commandId),
@@ -323,14 +302,6 @@ const readCredentialNative = Effect.fn("Drizzle.readCredentialNative")(function*
323
302
  .limit(1);
324
303
  });
325
304
 
326
- interface Resolved {
327
- readonly nativeSubjectId: unknown;
328
- readonly subject: any;
329
- readonly identifier: any;
330
- readonly credential?: any;
331
- readonly snapshot?: PasswordCredentialSnapshot;
332
- }
333
-
334
305
  const resolveCredential = Effect.fn("DrizzleD1Password.resolveCredential")(function* (
335
306
  mapping: Mapping,
336
307
  moduleId: string,
@@ -697,7 +668,8 @@ const readAuthority = Effect.fn("DrizzleD1Password.readAuthority")(function* (
697
668
  )
698
669
  return undefined;
699
670
  if (
700
- input.invalidation.existingSessions === "immediate" &&
671
+ (input.invalidation.existingSessions === "immediate" ||
672
+ input.invalidation.existingSessions === "cache-expiry") &&
701
673
  mapping.sessionInvalidation !== "same-authority-immediate"
702
674
  )
703
675
  return undefined;
@@ -741,34 +713,6 @@ const credentialCurrentCondition = (
741
713
  : sql`exists(select 1 from ${mapping.credential.table} where ${c.moduleId} = ${sql.param(input.moduleId, c.moduleId)} and ${c.subjectId} = ${sql.param(nativeSubjectId, c.subjectId)} and ${c.credentialId} = ${sql.param(input.credential.credentialId, c.credentialId)} and ${c.credentialRevision} = ${sql.param(input.credential.credentialRevision, c.credentialRevision)} and ${c.verifierVersion} = ${sql.param(input.credential.verifierVersion, c.verifierVersion)} and ${c.verifier} = ${sql.param(Redacted.value(input.credential.verifier), c.verifier)} and ${c.normalization} = ${sql.param(input.credential.normalization, c.normalization)})`;
742
714
  };
743
715
 
744
- const admittedSnapshotCondition = (
745
- mapping: Mapping,
746
- resolved: Resolved | undefined,
747
- moduleId: string,
748
- ) => {
749
- const snapshot = resolved?.snapshot;
750
-
751
- if (snapshot === undefined || resolved === undefined) return sql`true`;
752
- const s = subjectColumns(mapping);
753
- const i = identifierColumns(mapping);
754
- const c = credentialColumns(mapping);
755
- const ac = authorityColumns(mapping);
756
-
757
- return and(
758
- sql`exists(select 1 from ${mapping.subject.table} where ${s.id} = ${sql.param(resolved.nativeSubjectId, s.id)} and ${s.status} = ${sql.param(mapping.subject.d1ActiveStatusValue, s.status)} and ${s.securityRevision} = ${sql.param(snapshot.revision.securityRevision, s.securityRevision)})`,
759
- mapping.identifier.d1CurrentCondition({
760
- identifier: snapshot.identifier,
761
- nativeSubjectId: resolved.nativeSubjectId,
762
- }),
763
- sql`exists(select 1 from ${mapping.identifier.table} where ${i.namespace} = ${sql.param(snapshot.identifier.namespace, i.namespace)} and ${i.value} = ${sql.param(snapshot.identifier.value, i.value)} and ${i.subjectId} = ${sql.param(resolved.nativeSubjectId, i.subjectId)} and ${i.bindingRevision} = ${sql.param(snapshot.identifierBindingRevision, i.bindingRevision)} and ${Predicate.isNullish(resolved.identifier[mapping.identifier.verifiedAt]) ? sql`${i.verifiedAt} is null` : sql`${i.verifiedAt} = ${sql.param(resolved.identifier[mapping.identifier.verifiedAt], i.verifiedAt)}`})`,
764
- sql`exists(select 1 from ${mapping.credential.table} where ${c.moduleId} = ${sql.param(moduleId, c.moduleId)} and ${c.subjectId} = ${sql.param(resolved.nativeSubjectId, c.subjectId)} and ${c.credentialId} = ${sql.param(snapshot.credentialId, c.credentialId)} and ${c.credentialRevision} = ${sql.param(snapshot.credentialRevision, c.credentialRevision)} and ${c.verifierVersion} = ${sql.param(snapshot.verifierVersion, c.verifierVersion)} and ${c.verifier} = ${sql.param(Redacted.value(snapshot.verifier), c.verifier)} and ${c.normalization} = ${sql.param(snapshot.normalization, c.normalization)})`,
765
- ...snapshot.revision.credentials.map(
766
- (item) =>
767
- sql`exists(select 1 from ${mapping.authorityCredential.table} where ${ac.subjectId} = ${sql.param(resolved.nativeSubjectId, ac.subjectId)} and ${ac.credentialId} = ${sql.param(item.credentialId, ac.credentialId)} and ${ac.revision} = ${sql.param(item.revision, ac.revision)}${ac.status === undefined ? sql`` : sql` and ${ac.status} = ${sql.param(mapping.authorityCredential.d1ActiveStatusValue, ac.status)}`})`,
768
- ),
769
- )!;
770
- };
771
-
772
716
  const mutationStatements = Effect.fn(function* (
773
717
  mapping: Mapping,
774
718
  input: PasswordMutationInput,
@@ -993,312 +937,121 @@ const makePasswordPlans = (
993
937
  });
994
938
 
995
939
  return {
996
- prepareAttempt: (uncaptured: Parameters<PasswordPersistence["Service"]["prepareAttempt"]>[0]) =>
940
+ findCredential: (uncaptured: Parameters<PasswordPersistence["Service"]["findCredential"]>[0]) =>
997
941
  Effect.gen(function* () {
998
942
  if (!validConstraints(mapping)) return yield* unavailable();
943
+ const input = { ...uncaptured, identifier: { ...uncaptured.identifier } };
944
+ const database = yield* CurrentD1PlanningDatabase;
945
+ const identifierRow = (yield* readIdentifier(mapping, input.identifier))[0];
999
946
 
1000
- const input = Object.freeze({
1001
- ...uncaptured,
1002
- identifier: Object.freeze({ ...uncaptured.identifier }),
1003
- });
1004
-
1005
- const resolved = yield* resolveCredential(
1006
- mapping,
1007
- input.moduleId,
1008
- input.identifier,
1009
- input.subjectId,
1010
- );
1011
-
1012
- const snapshot = resolved?.snapshot;
1013
- const attemptId = yield* allocate(mapping.allocateAttemptId, mapping.allocateAttemptIdSync);
1014
- let used = false;
1015
-
1016
- return Object.freeze({
1017
- ...(snapshot === undefined ? {} : { credential: snapshot }),
1018
- // Claim outside execution: a definite batch rollback may replan other
1019
- // operations, but a prepared admission never consumes its limits twice.
1020
- claim: Effect.suspend(() => {
1021
- if (used) return Effect.fail(unavailable());
1022
- used = true;
1023
-
1024
- return Effect.void;
1025
- }),
1026
- admit: <A>(prepare: PreparePasswordCommit<PasswordAttemptAdmission, A>) =>
1027
- run(
1028
- Effect.gen(function* () {
1029
- const database = yield* CurrentD1PlanningDatabase;
1030
- const journal = yield* CurrentCommitJournal;
1031
- const now = yield* readEngineNowMillis(mapping);
1032
- const marker = `effect-auth-password-guard:admit:${attemptId}`;
1033
- const a = attemptColumns(mapping);
1034
- const key = and(eq(a.moduleId, input.moduleId), eq(a.attemptId, attemptId))!;
1035
- const current = admittedSnapshotCondition(mapping, resolved, input.moduleId);
1036
-
1037
- const record: PasswordAttemptRecord = {
1038
- moduleId: input.moduleId,
1039
- action: input.action,
1040
- attemptId,
1041
- identifier: input.identifier,
1042
- ...(snapshot === undefined
1043
- ? {}
1044
- : {
1045
- subjectId: snapshot.revision.subjectId,
1046
- credentialId: snapshot.credentialId,
1047
- securityRevision: snapshot.revision.securityRevision,
1048
- credentialRevision: snapshot.credentialRevision,
1049
- verifierVersion: snapshot.verifierVersion,
1050
- identifierBindingRevision: snapshot.identifierBindingRevision,
1051
- }),
1052
- admittedAtMillis: now,
1053
- deadlineMillis: now + input.attemptLifetimeMillis,
1054
- retentionUntilMillis: now + input.attemptLifetimeMillis,
1055
- };
1056
-
1057
- const receipt = prepare(
1058
- {
1059
- _tag: "Admitted",
1060
- attemptId,
1061
- ...(snapshot === undefined ? {} : { credential: snapshot }),
1062
- },
1063
- journal,
1064
- );
1065
-
1066
- const admitted = and(
1067
- current,
1068
- sql`exists(select 1 from ${mapping.attempt.table} where ${key} and ${a.state} = ${"pending"} and ${a.deadline} > ${mapping.d1.engineNow})`,
1069
- )!;
1070
-
1071
- const statements: Statement<any>[] = [
1072
- yield* assertion(
1073
- and(
1074
- current,
1075
- sql`not exists(select 1 from ${mapping.attempt.table} where ${key})`,
1076
- )!,
1077
- marker,
1078
- ),
1079
- yield* statement(
1080
- database.insert(mapping.attempt.table).values(
1081
- driverValues(
1082
- mapping.attempt.encodeInsert(record, {
1083
- ...(resolved?.nativeSubjectId === undefined
1084
- ? {}
1085
- : { nativeSubjectId: resolved.nativeSubjectId }),
1086
- state: "pending",
1087
- }),
1088
- [
1089
- [mapping.attempt.admittedAt, mapping.d1.engineNow],
1090
- [
1091
- mapping.attempt.deadline,
1092
- mapping.d1.engineInstantPlus(input.attemptLifetimeMillis),
1093
- ],
1094
- [
1095
- mapping.attempt.retentionUntil,
1096
- mapping.d1.engineInstantPlus(input.attemptLifetimeMillis),
1097
- ],
1098
- ],
1099
- ),
1100
- ),
1101
- ),
1102
- yield* assertion(and(sql`changes() = 1`, admitted)!, marker),
1103
- ];
1104
-
1105
- // A failed captured-snapshot guard cannot authorize refreshing the
1106
- // candidate after the strategy has consumed that subject's limit.
1107
- return {
1108
- receipt,
1109
- statements,
1110
- postconditions: [yield* assertion(admitted, marker)],
1111
- };
1112
- }),
947
+ if (identifierRow === undefined || !mapping.identifier.isCurrent(identifierRow))
948
+ return Option.none();
949
+ const nativeId = identifierRow[mapping.identifier.subjectId];
950
+
951
+ const sc = subjectColumns(mapping),
952
+ ic = identifierColumns(mapping),
953
+ cc = credentialColumns(mapping);
954
+
955
+ // Bind the same native ID through each column's codec, then inspect one coherent snapshot.
956
+ const rows = yield* database
957
+ .select({
958
+ subject: getTableColumns(mapping.subject.table),
959
+ identifier: getTableColumns(mapping.identifier.table),
960
+ credential: getTableColumns(mapping.credential.table),
961
+ })
962
+ .from(mapping.subject.table)
963
+ .innerJoin(
964
+ mapping.identifier.table,
965
+ and(
966
+ eq(ic.namespace, input.identifier.namespace),
967
+ eq(ic.value, input.identifier.value),
968
+ eq(ic.subjectId, nativeId),
1113
969
  ),
1114
- });
1115
- }),
1116
- settleAttempt: <A>(
1117
- uncaptured: Parameters<PasswordPersistence["Service"]["settleAttempt"]>[0],
1118
- prepare: PlanPrepare<PasswordPersistence["Service"]["settleAttempt"], A>,
1119
- ) =>
1120
- Effect.gen(function* () {
1121
- const database = yield* CurrentD1PlanningDatabase;
970
+ )
971
+ .innerJoin(
972
+ mapping.credential.table,
973
+ and(eq(cc.moduleId, input.moduleId), eq(cc.subjectId, nativeId)),
974
+ )
975
+ .where(eq(sc.id, nativeId));
1122
976
 
1123
- const captured =
1124
- uncaptured.captured === undefined
1125
- ? undefined
1126
- : yield* snapshotPasswordCredential(uncaptured.captured);
977
+ if (rows.length !== 1) return Option.none();
978
+ const row = rows[0]!;
1127
979
 
1128
- const input = { ...uncaptured, ...(captured === undefined ? {} : { captured }) };
980
+ if (
981
+ !mapping.subject.isActiveStatus(row.subject[mapping.subject.status]) ||
982
+ !mapping.identifier.isCurrent(row.identifier) ||
983
+ !mapping.subjectId.equals(nativeId, row.subject[mapping.subject.id]) ||
984
+ !mapping.subjectId.equals(nativeId, row.identifier[mapping.identifier.subjectId]) ||
985
+ !mapping.subjectId.equals(nativeId, row.credential[mapping.credential.subjectId])
986
+ )
987
+ return Option.none();
1129
988
 
1130
- return yield* run(
1131
- Effect.gen(function* () {
1132
- const journal = yield* CurrentCommitJournal;
989
+ const credential = yield* mapping.credential
990
+ .decode({ moduleId: input.moduleId, ...row })
991
+ .pipe(Effect.flatMap(snapshotPasswordCredential));
1133
992
 
1134
- const a = attemptColumns(mapping);
993
+ return input.subjectId !== undefined && credential.revision.subjectId !== input.subjectId
994
+ ? Option.none()
995
+ : Option.some(credential);
996
+ }),
997
+ rehashIfCurrent: (input: Parameters<PasswordPersistence["Service"]["rehashIfCurrent"]>[0]) =>
998
+ run(
999
+ Effect.gen(function* () {
1000
+ const nextVerifier = Redacted.make(
1001
+ yield* Schema.decodeEffect(EncodedPasswordHash)(Redacted.value(input.nextVerifier)),
1002
+ );
1135
1003
 
1136
- const rows = yield* database
1137
- .select()
1138
- .from(mapping.attempt.table)
1139
- .where(and(eq(a.moduleId, input.moduleId), eq(a.attemptId, input.attemptId)))
1140
- .limit(1);
1004
+ const credential = yield* snapshotPasswordCredential(input.credential);
1005
+ const database = yield* CurrentD1PlanningDatabase;
1006
+ const nativeId = yield* mapping.subjectId.toNative(credential.revision.subjectId);
1007
+ const version = yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync);
1141
1008
 
1142
- const row = rows[0];
1143
- const engineNow = yield* readEngineNowMillis(mapping);
1009
+ if (version === credential.verifierVersion) return yield* unavailable();
1010
+ const encoded = mapping.credential.encodeVerifier(nextVerifier, version);
1144
1011
 
1145
- const deadline =
1146
- row === undefined
1147
- ? undefined
1148
- : yield* mapping.decodeInstant(row[mapping.attempt.deadline]);
1012
+ const values = {
1013
+ [mapping.credential.verifier]: encoded[mapping.credential.verifier],
1014
+ [mapping.credential.verifierVersion]: encoded[mapping.credential.verifierVersion],
1015
+ };
1149
1016
 
1150
- let resolved: Resolved | undefined;
1151
- let verified = false;
1017
+ if (Object.values(values).some((value) => value === undefined))
1018
+ return yield* unavailable();
1019
+ const c = credentialColumns(mapping);
1152
1020
 
1153
- if (
1154
- row !== undefined &&
1155
- row[mapping.attempt.state] === "pending" &&
1156
- input.outcome === "verified" &&
1157
- input.captured !== undefined &&
1158
- deadline !== undefined &&
1159
- deadline > engineNow
1160
- ) {
1161
- resolved = yield* resolveCredential(
1162
- mapping,
1163
- input.moduleId,
1164
- input.captured.identifier,
1165
- input.captured.revision.subjectId,
1166
- );
1167
- verified =
1168
- input.captured.moduleId === input.moduleId &&
1169
- resolved?.snapshot !== undefined &&
1170
- sameSnapshot(resolved.snapshot, input.captured) &&
1171
- mapping.subjectId.equals(
1172
- row[mapping.attempt.subjectId],
1173
- resolved.nativeSubjectId,
1174
- ) &&
1175
- row[mapping.attempt.identifierNamespace] === input.captured.identifier.namespace &&
1176
- row[mapping.attempt.identifierValue] === input.captured.identifier.value &&
1177
- row[mapping.attempt.credentialId] === input.captured.credentialId &&
1178
- row[mapping.attempt.securityRevision] ===
1179
- input.captured.revision.securityRevision &&
1180
- row[mapping.attempt.credentialRevision] === input.captured.credentialRevision &&
1181
- row[mapping.attempt.verifierVersion] === input.captured.verifierVersion &&
1182
- row[mapping.attempt.identifierBindingRevision] ===
1183
- input.captured.identifierBindingRevision;
1184
- }
1185
- const decision: PasswordAttemptDecision = verified ? "verified" : "rejected";
1186
- const receipt = prepare(decision, journal);
1187
-
1188
- if (row === undefined || row[mapping.attempt.state] !== "pending")
1189
- return { receipt, statements: [] };
1190
- const marker = `effect-auth-password-guard:settle:${input.attemptId}`;
1191
-
1192
- const base = and(
1193
- eq(a.moduleId, input.moduleId),
1194
- eq(a.attemptId, input.attemptId),
1195
- eq(a.state, "pending"),
1196
- )!;
1197
-
1198
- const attemptSnapshot =
1199
- verified && resolved?.snapshot !== undefined
1200
- ? and(
1201
- eq(a.action, row[mapping.attempt.action]),
1202
- eq(a.subjectId, resolved.nativeSubjectId),
1203
- eq(a.identifierNamespace, input.captured!.identifier.namespace),
1204
- eq(a.identifierValue, input.captured!.identifier.value),
1205
- eq(a.credentialId, input.captured!.credentialId),
1206
- eq(a.securityRevision, input.captured!.revision.securityRevision),
1207
- eq(a.credentialRevision, input.captured!.credentialRevision),
1208
- eq(a.verifierVersion, input.captured!.verifierVersion),
1209
- eq(a.identifierBindingRevision, input.captured!.identifierBindingRevision),
1210
- eq(a.deadline, row[mapping.attempt.deadline]),
1211
- )!
1212
- : sql`true`;
1213
-
1214
- const condition = verified
1215
- ? and(base, attemptSnapshot, sql`${a.deadline} > ${mapping.d1.engineNow}`)!
1216
- : base;
1217
-
1218
- const statements: Statement<any>[] = [
1219
- yield* assertion(
1220
- sql`exists(select 1 from ${mapping.attempt.table} where ${condition})`,
1221
- marker,
1222
- ),
1021
+ return {
1022
+ receipt: undefined,
1023
+ statements: [
1223
1024
  yield* statement(
1224
1025
  database
1225
- .update(mapping.attempt.table)
1226
- .set(updateValues([[mapping.attempt.state, decision]]))
1227
- .where(condition),
1228
- ),
1229
- ];
1230
-
1231
- let finalAuthority = sql`true`;
1232
-
1233
- if (verified && resolved?.snapshot !== undefined) {
1234
- const captured = input.captured!;
1235
- const c = credentialColumns(mapping);
1236
-
1237
- finalAuthority = admittedSnapshotCondition(mapping, resolved, input.moduleId);
1238
-
1239
- statements.splice(1, 0, yield* assertion(finalAuthority, marker));
1240
- if (
1241
- input.rehash !== undefined &&
1242
- input.rehash.expectedVersion === captured.verifierVersion &&
1243
- Redacted.value(input.rehash.expectedVerifier) === Redacted.value(captured.verifier)
1244
- ) {
1245
- const nextVersion = yield* allocate(
1246
- mapping.allocateRevision,
1247
- mapping.allocateRevisionSync,
1248
- );
1249
-
1250
- statements.push(
1251
- yield* assertion(sql`changes() = 1`, marker),
1252
- yield* statement(
1253
- database
1254
- .update(mapping.credential.table)
1255
- .set(
1256
- mapping.credential.encodeVerifier(input.rehash.nextVerifier, nextVersion),
1257
- )
1258
- .where(
1259
- and(
1260
- eq(c.moduleId, input.moduleId),
1261
- eq(c.subjectId, resolved.nativeSubjectId),
1262
- eq(c.credentialId, captured.credentialId),
1263
- eq(c.credentialRevision, captured.credentialRevision),
1264
- eq(c.verifierVersion, input.rehash.expectedVersion),
1265
- eq(c.verifier, Redacted.value(input.rehash.expectedVerifier)),
1266
- ),
1026
+ .update(mapping.credential.table)
1027
+ .set(values)
1028
+ .where(
1029
+ and(
1030
+ eq(c.moduleId, credential.moduleId),
1031
+ eq(c.subjectId, nativeId),
1032
+ eq(c.credentialId, credential.credentialId),
1033
+ ...(
1034
+ [
1035
+ [c.moduleId, credential.moduleId],
1036
+ [c.subjectId, nativeId],
1037
+ [c.credentialId, credential.credentialId],
1038
+ [c.credentialRevision, credential.credentialRevision],
1039
+ [c.verifierVersion, credential.verifierVersion],
1040
+ [c.verifier, Redacted.value(credential.verifier)],
1041
+ [c.normalization, credential.normalization],
1042
+ ] as const
1043
+ ).map(([column, value]) =>
1044
+ typeof value === "string"
1045
+ ? sql`cast(${column} as blob) = cast(${sql.param(value, column)} as blob)`
1046
+ : eq(column, value),
1267
1047
  ),
1048
+ ),
1268
1049
  ),
1269
- );
1270
- finalAuthority = admittedSnapshotCondition(
1271
- mapping,
1272
- {
1273
- ...resolved,
1274
- snapshot: {
1275
- ...resolved.snapshot,
1276
- verifierVersion: nextVersion,
1277
- verifier: input.rehash.nextVerifier,
1278
- },
1279
- },
1280
- input.moduleId,
1281
- );
1282
- }
1283
- }
1284
-
1285
- const settled = and(
1286
- finalAuthority,
1287
- sql`exists(select 1 from ${mapping.attempt.table} where ${a.moduleId} = ${sql.param(input.moduleId, a.moduleId)} and ${a.attemptId} = ${sql.param(input.attemptId, a.attemptId)} and ${a.state} = ${sql.param(decision, a.state)} and ${attemptSnapshot}${verified ? sql` and ${a.deadline} > ${mapping.d1.engineNow}` : sql``})`,
1288
- )!;
1289
-
1290
- // Run after attempt/rehash triggers, before the batch can publish its journal.
1291
- statements.push(yield* assertion(and(sql`changes() = 1`, settled)!, marker));
1292
-
1293
- return {
1294
- receipt,
1295
- statements,
1296
- postconditions: [yield* assertion(settled, marker)],
1297
- retryable: (cause: unknown) => isGuardFailure(cause, marker),
1298
- };
1299
- }),
1300
- );
1301
- }),
1050
+ ),
1051
+ ],
1052
+ };
1053
+ }),
1054
+ ),
1302
1055
  readForSubject: (input: Parameters<PasswordPersistence["Service"]["readForSubject"]>[0]) =>
1303
1056
  Effect.gen(function* () {
1304
1057
  const database = yield* CurrentD1PlanningDatabase;
@@ -1456,15 +1209,6 @@ const makePasswordPlans = (
1456
1209
  "reset-password",
1457
1210
  ),
1458
1211
  ),
1459
- cleanupAttempts: <A>(
1460
- input: Parameters<PasswordPersistence["Service"]["cleanupAttempts"]>[0],
1461
- prepare: PlanPrepare<PasswordPersistence["Service"]["cleanupAttempts"], A>,
1462
- ) =>
1463
- run(
1464
- Effect.gen(function* () {
1465
- return yield* cleanupPlan(mapping, input, prepare);
1466
- }),
1467
- ),
1468
1212
  };
1469
1213
  };
1470
1214
 
@@ -1623,68 +1367,15 @@ const replacementPlan = Effect.fn("Drizzle.replacementPlan")(function* <A>(
1623
1367
  };
1624
1368
  });
1625
1369
 
1626
- const cleanupPlan = Effect.fn("Drizzle.cleanupPlan")(function* <A>(
1627
- mapping: Mapping,
1628
- input: { readonly moduleId: string; readonly limit: number },
1629
- prepare: PreparePasswordCommit<{ readonly removed: number; readonly hasMore: boolean }, A>,
1630
- ) {
1631
- const database = yield* CurrentD1PlanningDatabase;
1632
- const journal = yield* CurrentCommitJournal;
1633
-
1634
- const now = yield* readEngineNowMillis(mapping);
1635
- const nativeNow = mapping.encodeInstant(now);
1636
- const a = attemptColumns(mapping);
1637
-
1638
- const attempts = yield* database
1639
- .select({ attemptId: a.attemptId })
1640
- .from(mapping.attempt.table)
1641
- .where(and(eq(a.moduleId, input.moduleId), lte(a.retentionUntil, nativeNow)))
1642
- .limit(input.limit + 1);
1643
-
1644
- const selectedAttempts = attempts.slice(0, input.limit);
1645
- const hasMore = attempts.length > selectedAttempts.length;
1646
- const marker = `effect-auth-password-guard:cleanup:${input.moduleId}:${now}`;
1647
- const statements: Statement<any>[] = [];
1648
-
1649
- for (const row of selectedAttempts) {
1650
- const condition = and(
1651
- eq(a.moduleId, input.moduleId),
1652
- eq(a.attemptId, row.attemptId),
1653
- lte(a.retentionUntil, mapping.d1.engineNow),
1654
- )!;
1655
-
1656
- statements.push(
1657
- yield* assertion(
1658
- sql`exists(select 1 from ${mapping.attempt.table} where ${condition})`,
1659
- marker,
1660
- ),
1661
- yield* statement(database.delete(mapping.attempt.table).where(condition)),
1662
- );
1663
- }
1664
-
1665
- return {
1666
- receipt: prepare(
1667
- {
1668
- removed: selectedAttempts.length,
1669
- hasMore,
1670
- },
1671
- journal,
1672
- ),
1673
- statements,
1674
- retryable: (cause: unknown) => isGuardFailure(cause, marker),
1675
- };
1676
- });
1677
-
1678
1370
  export const makeD1PasswordPersistenceServices = Effect.fnUntraced(function* <
1679
1371
  S extends AnySQLiteTable,
1680
1372
  I extends AnySQLiteTable,
1681
1373
  C extends AnySQLiteTable,
1682
1374
  AC extends AnySQLiteTable,
1683
- A extends AnySQLiteTable,
1684
1375
  M extends AnySQLiteTable,
1685
1376
  NativeId,
1686
1377
  >(
1687
- mapping: D1PasswordPersistenceMapping<S, I, C, AC, A, M, NativeId>,
1378
+ mapping: D1PasswordPersistenceMapping<S, I, C, AC, M, NativeId>,
1688
1379
  proofMapping?: D1ProofPersistenceMapping<
1689
1380
  any,
1690
1381
  any,
@@ -1726,21 +1417,13 @@ export const makeD1PasswordPersistenceServices = Effect.fnUntraced(function* <
1726
1417
  );
1727
1418
 
1728
1419
  const service: PasswordPersistence["Service"] = {
1729
- prepareAttempt: (input) =>
1420
+ findCredential: (input) =>
1730
1421
  standalone.pipe(
1731
- Effect.andThen(plans.prepareAttempt(input)),
1732
- Effect.map((planned): PasswordAttemptPreparation =>
1733
- Object.freeze({
1734
- ...(planned.credential === undefined ? {} : { credential: planned.credential }),
1735
- admit: <A>(prepare: PreparePasswordCommit<PasswordAttemptAdmission, A>) =>
1736
- planned.claim.pipe(Effect.andThen(run(planned.admit(prepare))), translateFailure),
1737
- }),
1738
- ),
1422
+ Effect.andThen(plans.findCredential(input)),
1739
1423
  Effect.provideService(CurrentD1PlanningDatabase, database),
1740
1424
  translateFailure,
1741
1425
  ),
1742
- settleAttempt: (input, prepare) =>
1743
- run(plans.settleAttempt(input, prepare)).pipe(translateFailure),
1426
+ rehashIfCurrent: (input) => run(plans.rehashIfCurrent(input)).pipe(translateFailure),
1744
1427
  readForSubject: (input) =>
1745
1428
  plans
1746
1429
  .readForSubject(input)
@@ -1770,8 +1453,6 @@ export const makeD1PasswordPersistenceServices = Effect.fnUntraced(function* <
1770
1453
  ),
1771
1454
  resetWithProof: (input, prepare) =>
1772
1455
  run(plans.resetWithProof(input, prepare)).pipe(translateFailure),
1773
- cleanupAttempts: (input, prepare) =>
1774
- run(plans.cleanupAttempts(input, prepare)).pipe(translateFailure),
1775
1456
  };
1776
1457
 
1777
1458
  return { passwordPersistence: service };
@@ -1789,7 +1470,6 @@ export function coordinateD1PasswordPersistence<
1789
1470
  I extends AnySQLiteTable,
1790
1471
  C extends AnySQLiteTable,
1791
1472
  AC extends AnySQLiteTable,
1792
- At extends AnySQLiteTable,
1793
1473
  M extends AnySQLiteTable,
1794
1474
  NativeId,
1795
1475
  A,
@@ -1800,7 +1480,7 @@ export function coordinateD1PasswordPersistence<
1800
1480
  >(
1801
1481
  acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,
1802
1482
  options: {
1803
- readonly mapping: D1PasswordPersistenceMapping<S, I, C, AC, At, M, NativeId>;
1483
+ readonly mapping: D1PasswordPersistenceMapping<S, I, C, AC, M, NativeId>;
1804
1484
  readonly proofMapping?:
1805
1485
  | D1ProofPersistenceMapping<any, any, any, any, any, any, any, any, any, any, any, any>
1806
1486
  | undefined;
@@ -1864,29 +1544,17 @@ export function coordinateD1PasswordPersistence<
1864
1544
  );
1865
1545
 
1866
1546
  const service: PasswordPersistence["Service"] = {
1867
- prepareAttempt: (input) =>
1547
+ findCredential: (input) =>
1868
1548
  owner.run(
1869
- plans.prepareAttempt(input).pipe(
1870
- Effect.map((planned): PasswordAttemptPreparation =>
1871
- Object.freeze({
1872
- ...(planned.credential === undefined
1873
- ? {}
1874
- : { credential: planned.credential }),
1875
- admit: <A>(prepare: PreparePasswordCommit<PasswordAttemptAdmission, A>) =>
1876
- owner.run(
1877
- planned.claim.pipe(
1878
- Effect.andThen(run(planned.admit(prepare))),
1879
- translateFailure,
1880
- ),
1881
- ),
1882
- }),
1549
+ plans
1550
+ .findCredential(input)
1551
+ .pipe(
1552
+ Effect.provideService(CurrentD1PlanningDatabase, database),
1553
+ translateFailure,
1883
1554
  ),
1884
- Effect.provideService(CurrentD1PlanningDatabase, database),
1885
- translateFailure,
1886
- ),
1887
1555
  ),
1888
- settleAttempt: (input, prepare) =>
1889
- owner.run(run(plans.settleAttempt(input, prepare)).pipe(translateFailure)),
1556
+ rehashIfCurrent: (input) =>
1557
+ owner.run(run(plans.rehashIfCurrent(input)).pipe(translateFailure)),
1890
1558
  readForSubject: (input) =>
1891
1559
  owner.run(
1892
1560
  plans
@@ -1923,8 +1591,6 @@ export function coordinateD1PasswordPersistence<
1923
1591
  ),
1924
1592
  resetWithProof: (input, prepare) =>
1925
1593
  owner.run(run(plans.resetWithProof(input, prepare)).pipe(translateFailure)),
1926
- cleanupAttempts: (input, prepare) =>
1927
- owner.run(run(plans.cleanupAttempts(input, prepare)).pipe(translateFailure)),
1928
1594
  };
1929
1595
 
1930
1596
  const provided = Context.make(PasswordPersistence, service).pipe(