@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
@@ -8,13 +8,13 @@ import { CurrentD1PlanningDatabase, makeD1Owner } from "./d1-planning.mjs";
8
8
  import { nativeDatabase } from "./native-database.mjs";
9
9
  import { compileD1ProofCompletionPlan } from "./d1-proofs.mjs";
10
10
  import { NativeDatabase, requireStandalone, samePasswordCredentialSnapshot } from "@yielded/auth-persistence/Adapter";
11
- import { and, eq, inArray, lte, sql } from "drizzle-orm";
11
+ import { and, eq, getTableColumns, inArray, sql } from "drizzle-orm";
12
12
  import { Cause, Context, DateTime, Effect, Option, Predicate, Redacted, Schema } from "effect";
13
13
  import { CurrentCommitJournal, HookConfigurationError, LifecycleHooks, coordinateCommit, hasCommitScope } from "@yielded/auth/Hooks";
14
14
  import { AuthenticationEvidence, AuthenticationRequirement, snapshotAuthenticationEvidence } from "@yielded/auth/Sessions";
15
15
  import { reportPersistenceFailure } from "@yielded/auth/Persistence";
16
16
  import { ProofUnavailable } from "@yielded/auth/Proofs";
17
- import { PasswordPersistence, PasswordUnavailable, snapshotPasswordCredential, snapshotPasswordRequirement, snapshotPasswordRevision } from "@yielded/auth/Password";
17
+ import { EncodedPasswordHash, PasswordPersistence, PasswordUnavailable, snapshotPasswordCredential, snapshotPasswordRequirement, snapshotPasswordRevision } from "@yielded/auth/Password";
18
18
  //#region src/drizzle/d1-passwords.ts
19
19
  const unavailable = () => PasswordUnavailable.make({});
20
20
  const everyFailureMatches = (cause, classify) => classify !== void 0 && cause.reasons.length > 0 && cause.reasons.every((reason) => Cause.isFailReason(reason) && classify(Cause.fail(reason.error)));
@@ -60,10 +60,6 @@ const readEngineNowMillis = Effect.fn("Drizzle.readEngineNowMillis")(function* (
60
60
  return Number.isFinite(value) ? Effect.succeed(value) : Effect.fail(unavailable());
61
61
  }));
62
62
  });
63
- const driverValues = (values, entries) => ({
64
- ...values,
65
- ...Object.fromEntries(entries)
66
- });
67
63
  const allocate = (asyncValue, syncValue) => asyncValue !== void 0 ? asyncValue : syncValue === void 0 ? Effect.fail(unavailable()) : Effect.try({
68
64
  try: syncValue,
69
65
  catch: (cause) => new PersistenceMappingError$1({
@@ -99,23 +95,6 @@ const authorityColumns = (mapping) => ({
99
95
  revision: column(mapping.authorityCredential.table, mapping.authorityCredential.revision),
100
96
  status: mapping.authorityCredential.status === void 0 ? void 0 : column(mapping.authorityCredential.table, mapping.authorityCredential.status)
101
97
  });
102
- const attemptColumns = (mapping) => ({
103
- moduleId: column(mapping.attempt.table, mapping.attempt.moduleId),
104
- action: column(mapping.attempt.table, mapping.attempt.action),
105
- attemptId: column(mapping.attempt.table, mapping.attempt.attemptId),
106
- identifierNamespace: column(mapping.attempt.table, mapping.attempt.identifierNamespace),
107
- identifierValue: column(mapping.attempt.table, mapping.attempt.identifierValue),
108
- subjectId: column(mapping.attempt.table, mapping.attempt.subjectId),
109
- credentialId: column(mapping.attempt.table, mapping.attempt.credentialId),
110
- securityRevision: column(mapping.attempt.table, mapping.attempt.securityRevision),
111
- credentialRevision: column(mapping.attempt.table, mapping.attempt.credentialRevision),
112
- verifierVersion: column(mapping.attempt.table, mapping.attempt.verifierVersion),
113
- identifierBindingRevision: column(mapping.attempt.table, mapping.attempt.identifierBindingRevision),
114
- admittedAt: column(mapping.attempt.table, mapping.attempt.admittedAt),
115
- deadline: column(mapping.attempt.table, mapping.attempt.deadline),
116
- retentionUntil: column(mapping.attempt.table, mapping.attempt.retentionUntil),
117
- state: column(mapping.attempt.table, mapping.attempt.state)
118
- });
119
98
  const commandColumns = (mapping) => ({
120
99
  moduleId: column(mapping.command.table, mapping.command.moduleId),
121
100
  commandId: column(mapping.command.table, mapping.command.commandId),
@@ -281,7 +260,7 @@ const readAuthority = Effect.fn("DrizzleD1Password.readAuthority")(function* (ma
281
260
  const requirement = yield* mapping.subject.decodeActionRequirement(subject, action);
282
261
  const engineNow = yield* readEngineNowMillis(mapping);
283
262
  if (!evidenceSatisfiedAt(input.authorization.evidence, input.authorization.requirement, engineNow) || !evidenceSatisfiedAt(input.authorization.evidence, requirement, engineNow)) return void 0;
284
- if (input.invalidation.existingSessions === "immediate" && mapping.sessionInvalidation !== "same-authority-immediate") return void 0;
263
+ if ((input.invalidation.existingSessions === "immediate" || input.invalidation.existingSessions === "cache-expiry") && mapping.sessionInvalidation !== "same-authority-immediate") return void 0;
285
264
  const s = subjectColumns(mapping);
286
265
  const credentialConditions = expected.map((item) => sql`exists(select 1 from ${mapping.authorityCredential.table} where ${ac.subjectId} = ${sql.param(nativeSubjectId, ac.subjectId)} and ${ac.credentialId} = ${sql.param(item.credentialId, ac.credentialId)} and ${ac.revision} = ${sql.param(item.revision, ac.revision)}${ac.status === void 0 ? sql`` : sql` and ${ac.status} = ${sql.param(mapping.authorityCredential.d1ActiveStatusValue, ac.status)}`})`);
287
266
  return {
@@ -300,18 +279,6 @@ const credentialCurrentCondition = (mapping, input, nativeSubjectId) => {
300
279
  const c = credentialColumns(mapping);
301
280
  return input.credential === void 0 ? sql`false` : 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)})`;
302
281
  };
303
- const admittedSnapshotCondition = (mapping, resolved, moduleId) => {
304
- const snapshot = resolved?.snapshot;
305
- if (snapshot === void 0 || resolved === void 0) return sql`true`;
306
- const s = subjectColumns(mapping);
307
- const i = identifierColumns(mapping);
308
- const c = credentialColumns(mapping);
309
- const ac = authorityColumns(mapping);
310
- return and(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)})`, mapping.identifier.d1CurrentCondition({
311
- identifier: snapshot.identifier,
312
- nativeSubjectId: resolved.nativeSubjectId
313
- }), 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)}`})`, 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)})`, ...snapshot.revision.credentials.map((item) => 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 === void 0 ? sql`` : sql` and ${ac.status} = ${sql.param(mapping.authorityCredential.d1ActiveStatusValue, ac.status)}`})`));
314
- };
315
282
  const mutationStatements = Effect.fn(function* (mapping, input, nativeSubjectId, revisions, now) {
316
283
  const database = yield* CurrentD1PlanningDatabase;
317
284
  const c = credentialColumns(mapping);
@@ -394,132 +361,58 @@ const makePasswordPlans = (mapping, proofMapping) => {
394
361
  return yield* plan;
395
362
  });
396
363
  return {
397
- prepareAttempt: (uncaptured) => Effect.gen(function* () {
364
+ findCredential: (uncaptured) => Effect.gen(function* () {
398
365
  if (!validConstraints(mapping)) return yield* unavailable();
399
- const input = Object.freeze({
400
- ...uncaptured,
401
- identifier: Object.freeze({ ...uncaptured.identifier })
402
- });
403
- const resolved = yield* resolveCredential(mapping, input.moduleId, input.identifier, input.subjectId);
404
- const snapshot = resolved?.snapshot;
405
- const attemptId = yield* allocate(mapping.allocateAttemptId, mapping.allocateAttemptIdSync);
406
- let used = false;
407
- return Object.freeze({
408
- ...snapshot === void 0 ? {} : { credential: snapshot },
409
- claim: Effect.suspend(() => {
410
- if (used) return Effect.fail(unavailable());
411
- used = true;
412
- return Effect.void;
413
- }),
414
- admit: (prepare) => run(Effect.gen(function* () {
415
- const database = yield* CurrentD1PlanningDatabase;
416
- const journal = yield* CurrentCommitJournal;
417
- const now = yield* readEngineNowMillis(mapping);
418
- const marker = `effect-auth-password-guard:admit:${attemptId}`;
419
- const a = attemptColumns(mapping);
420
- const key = and(eq(a.moduleId, input.moduleId), eq(a.attemptId, attemptId));
421
- const current = admittedSnapshotCondition(mapping, resolved, input.moduleId);
422
- const record = {
423
- moduleId: input.moduleId,
424
- action: input.action,
425
- attemptId,
426
- identifier: input.identifier,
427
- ...snapshot === void 0 ? {} : {
428
- subjectId: snapshot.revision.subjectId,
429
- credentialId: snapshot.credentialId,
430
- securityRevision: snapshot.revision.securityRevision,
431
- credentialRevision: snapshot.credentialRevision,
432
- verifierVersion: snapshot.verifierVersion,
433
- identifierBindingRevision: snapshot.identifierBindingRevision
434
- },
435
- admittedAtMillis: now,
436
- deadlineMillis: now + input.attemptLifetimeMillis,
437
- retentionUntilMillis: now + input.attemptLifetimeMillis
438
- };
439
- const receipt = prepare({
440
- _tag: "Admitted",
441
- attemptId,
442
- ...snapshot === void 0 ? {} : { credential: snapshot }
443
- }, journal);
444
- const admitted = and(current, sql`exists(select 1 from ${mapping.attempt.table} where ${key} and ${a.state} = ${"pending"} and ${a.deadline} > ${mapping.d1.engineNow})`);
445
- return {
446
- receipt,
447
- statements: [
448
- yield* assertion(and(current, sql`not exists(select 1 from ${mapping.attempt.table} where ${key})`), marker),
449
- yield* statement(database.insert(mapping.attempt.table).values(driverValues(mapping.attempt.encodeInsert(record, {
450
- ...resolved?.nativeSubjectId === void 0 ? {} : { nativeSubjectId: resolved.nativeSubjectId },
451
- state: "pending"
452
- }), [
453
- [mapping.attempt.admittedAt, mapping.d1.engineNow],
454
- [mapping.attempt.deadline, mapping.d1.engineInstantPlus(input.attemptLifetimeMillis)],
455
- [mapping.attempt.retentionUntil, mapping.d1.engineInstantPlus(input.attemptLifetimeMillis)]
456
- ]))),
457
- yield* assertion(and(sql`changes() = 1`, admitted), marker)
458
- ],
459
- postconditions: [yield* assertion(admitted, marker)]
460
- };
461
- }))
462
- });
463
- }),
464
- settleAttempt: (uncaptured, prepare) => Effect.gen(function* () {
465
- const database = yield* CurrentD1PlanningDatabase;
466
- const captured = uncaptured.captured === void 0 ? void 0 : yield* snapshotPasswordCredential(uncaptured.captured);
467
366
  const input = {
468
367
  ...uncaptured,
469
- ...captured === void 0 ? {} : { captured }
368
+ identifier: { ...uncaptured.identifier }
470
369
  };
471
- return yield* run(Effect.gen(function* () {
472
- const journal = yield* CurrentCommitJournal;
473
- const a = attemptColumns(mapping);
474
- const row = (yield* database.select().from(mapping.attempt.table).where(and(eq(a.moduleId, input.moduleId), eq(a.attemptId, input.attemptId))).limit(1))[0];
475
- const engineNow = yield* readEngineNowMillis(mapping);
476
- const deadline = row === void 0 ? void 0 : yield* mapping.decodeInstant(row[mapping.attempt.deadline]);
477
- let resolved;
478
- let verified = false;
479
- if (row !== void 0 && row[mapping.attempt.state] === "pending" && input.outcome === "verified" && input.captured !== void 0 && deadline !== void 0 && deadline > engineNow) {
480
- resolved = yield* resolveCredential(mapping, input.moduleId, input.captured.identifier, input.captured.revision.subjectId);
481
- verified = input.captured.moduleId === input.moduleId && resolved?.snapshot !== void 0 && samePasswordCredentialSnapshot(resolved.snapshot, input.captured) && mapping.subjectId.equals(row[mapping.attempt.subjectId], resolved.nativeSubjectId) && row[mapping.attempt.identifierNamespace] === input.captured.identifier.namespace && row[mapping.attempt.identifierValue] === input.captured.identifier.value && row[mapping.attempt.credentialId] === input.captured.credentialId && row[mapping.attempt.securityRevision] === input.captured.revision.securityRevision && row[mapping.attempt.credentialRevision] === input.captured.credentialRevision && row[mapping.attempt.verifierVersion] === input.captured.verifierVersion && row[mapping.attempt.identifierBindingRevision] === input.captured.identifierBindingRevision;
482
- }
483
- const decision = verified ? "verified" : "rejected";
484
- const receipt = prepare(decision, journal);
485
- if (row === void 0 || row[mapping.attempt.state] !== "pending") return {
486
- receipt,
487
- statements: []
488
- };
489
- const marker = `effect-auth-password-guard:settle:${input.attemptId}`;
490
- const base = and(eq(a.moduleId, input.moduleId), eq(a.attemptId, input.attemptId), eq(a.state, "pending"));
491
- const attemptSnapshot = verified && resolved?.snapshot !== void 0 ? and(eq(a.action, row[mapping.attempt.action]), eq(a.subjectId, resolved.nativeSubjectId), eq(a.identifierNamespace, input.captured.identifier.namespace), eq(a.identifierValue, input.captured.identifier.value), eq(a.credentialId, input.captured.credentialId), eq(a.securityRevision, input.captured.revision.securityRevision), eq(a.credentialRevision, input.captured.credentialRevision), eq(a.verifierVersion, input.captured.verifierVersion), eq(a.identifierBindingRevision, input.captured.identifierBindingRevision), eq(a.deadline, row[mapping.attempt.deadline])) : sql`true`;
492
- const condition = verified ? and(base, attemptSnapshot, sql`${a.deadline} > ${mapping.d1.engineNow}`) : base;
493
- const statements = [yield* assertion(sql`exists(select 1 from ${mapping.attempt.table} where ${condition})`, marker), yield* statement(database.update(mapping.attempt.table).set(updateValues([[mapping.attempt.state, decision]])).where(condition))];
494
- let finalAuthority = sql`true`;
495
- if (verified && resolved?.snapshot !== void 0) {
496
- const captured = input.captured;
497
- const c = credentialColumns(mapping);
498
- finalAuthority = admittedSnapshotCondition(mapping, resolved, input.moduleId);
499
- statements.splice(1, 0, yield* assertion(finalAuthority, marker));
500
- if (input.rehash !== void 0 && input.rehash.expectedVersion === captured.verifierVersion && Redacted.value(input.rehash.expectedVerifier) === Redacted.value(captured.verifier)) {
501
- const nextVersion = yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync);
502
- statements.push(yield* assertion(sql`changes() = 1`, marker), yield* statement(database.update(mapping.credential.table).set(mapping.credential.encodeVerifier(input.rehash.nextVerifier, nextVersion)).where(and(eq(c.moduleId, input.moduleId), eq(c.subjectId, resolved.nativeSubjectId), eq(c.credentialId, captured.credentialId), eq(c.credentialRevision, captured.credentialRevision), eq(c.verifierVersion, input.rehash.expectedVersion), eq(c.verifier, Redacted.value(input.rehash.expectedVerifier))))));
503
- finalAuthority = admittedSnapshotCondition(mapping, {
504
- ...resolved,
505
- snapshot: {
506
- ...resolved.snapshot,
507
- verifierVersion: nextVersion,
508
- verifier: input.rehash.nextVerifier
509
- }
510
- }, input.moduleId);
511
- }
512
- }
513
- const settled = and(finalAuthority, 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``})`);
514
- statements.push(yield* assertion(and(sql`changes() = 1`, settled), marker));
515
- return {
516
- receipt,
517
- statements,
518
- postconditions: [yield* assertion(settled, marker)],
519
- retryable: (cause) => isGuardFailure(cause, marker)
520
- };
521
- }));
370
+ const database = yield* CurrentD1PlanningDatabase;
371
+ const identifierRow = (yield* readIdentifier(mapping, input.identifier))[0];
372
+ if (identifierRow === void 0 || !mapping.identifier.isCurrent(identifierRow)) return Option.none();
373
+ const nativeId = identifierRow[mapping.identifier.subjectId];
374
+ const sc = subjectColumns(mapping), ic = identifierColumns(mapping), cc = credentialColumns(mapping);
375
+ const rows = yield* database.select({
376
+ subject: getTableColumns(mapping.subject.table),
377
+ identifier: getTableColumns(mapping.identifier.table),
378
+ credential: getTableColumns(mapping.credential.table)
379
+ }).from(mapping.subject.table).innerJoin(mapping.identifier.table, and(eq(ic.namespace, input.identifier.namespace), eq(ic.value, input.identifier.value), eq(ic.subjectId, nativeId))).innerJoin(mapping.credential.table, and(eq(cc.moduleId, input.moduleId), eq(cc.subjectId, nativeId))).where(eq(sc.id, nativeId));
380
+ if (rows.length !== 1) return Option.none();
381
+ const row = rows[0];
382
+ if (!mapping.subject.isActiveStatus(row.subject[mapping.subject.status]) || !mapping.identifier.isCurrent(row.identifier) || !mapping.subjectId.equals(nativeId, row.subject[mapping.subject.id]) || !mapping.subjectId.equals(nativeId, row.identifier[mapping.identifier.subjectId]) || !mapping.subjectId.equals(nativeId, row.credential[mapping.credential.subjectId])) return Option.none();
383
+ const credential = yield* mapping.credential.decode({
384
+ moduleId: input.moduleId,
385
+ ...row
386
+ }).pipe(Effect.flatMap(snapshotPasswordCredential));
387
+ return input.subjectId !== void 0 && credential.revision.subjectId !== input.subjectId ? Option.none() : Option.some(credential);
522
388
  }),
389
+ rehashIfCurrent: (input) => run(Effect.gen(function* () {
390
+ const nextVerifier = Redacted.make(yield* Schema.decodeEffect(EncodedPasswordHash)(Redacted.value(input.nextVerifier)));
391
+ const credential = yield* snapshotPasswordCredential(input.credential);
392
+ const database = yield* CurrentD1PlanningDatabase;
393
+ const nativeId = yield* mapping.subjectId.toNative(credential.revision.subjectId);
394
+ const version = yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync);
395
+ if (version === credential.verifierVersion) return yield* unavailable();
396
+ const encoded = mapping.credential.encodeVerifier(nextVerifier, version);
397
+ const values = {
398
+ [mapping.credential.verifier]: encoded[mapping.credential.verifier],
399
+ [mapping.credential.verifierVersion]: encoded[mapping.credential.verifierVersion]
400
+ };
401
+ if (Object.values(values).some((value) => value === void 0)) return yield* unavailable();
402
+ const c = credentialColumns(mapping);
403
+ return {
404
+ receipt: void 0,
405
+ statements: [yield* statement(database.update(mapping.credential.table).set(values).where(and(eq(c.moduleId, credential.moduleId), eq(c.subjectId, nativeId), eq(c.credentialId, credential.credentialId), ...[
406
+ [c.moduleId, credential.moduleId],
407
+ [c.subjectId, nativeId],
408
+ [c.credentialId, credential.credentialId],
409
+ [c.credentialRevision, credential.credentialRevision],
410
+ [c.verifierVersion, credential.verifierVersion],
411
+ [c.verifier, Redacted.value(credential.verifier)],
412
+ [c.normalization, credential.normalization]
413
+ ].map(([column, value]) => typeof value === "string" ? sql`cast(${column} as blob) = cast(${sql.param(value, column)} as blob)` : eq(column, value)))))]
414
+ };
415
+ })),
523
416
  readForSubject: (input) => Effect.gen(function* () {
524
417
  const database = yield* CurrentD1PlanningDatabase;
525
418
  if (yield* hasCommitScope) return yield* unavailable();
@@ -581,10 +474,7 @@ const makePasswordPlans = (mapping, proofMapping) => {
581
474
  resetWithProof: (uncaptured, prepare) => proofMapping === void 0 ? Effect.fail(unavailable()) : Effect.flatMap(snapshotMutationInput(uncaptured), (captured) => replacementPlan(mapping, proofMapping, Object.freeze({
582
475
  ...captured,
583
476
  completion: uncaptured.completion
584
- }), prepare, "reset-password")),
585
- cleanupAttempts: (input, prepare) => run(Effect.gen(function* () {
586
- return yield* cleanupPlan(mapping, input, prepare);
587
- }))
477
+ }), prepare, "reset-password"))
588
478
  };
589
479
  };
590
480
  const compileReplacementMutation = Effect.fn("DrizzleD1Password.compileReplacementMutation")(function* (mapping, input, action, revisions) {
@@ -653,30 +543,6 @@ const replacementPlan = Effect.fn("Drizzle.replacementPlan")(function* (mapping,
653
543
  retryable: (cause) => isGuardFailure(cause, marker)
654
544
  };
655
545
  });
656
- const cleanupPlan = Effect.fn("Drizzle.cleanupPlan")(function* (mapping, input, prepare) {
657
- const database = yield* CurrentD1PlanningDatabase;
658
- const journal = yield* CurrentCommitJournal;
659
- const now = yield* readEngineNowMillis(mapping);
660
- const nativeNow = mapping.encodeInstant(now);
661
- const a = attemptColumns(mapping);
662
- const attempts = yield* database.select({ attemptId: a.attemptId }).from(mapping.attempt.table).where(and(eq(a.moduleId, input.moduleId), lte(a.retentionUntil, nativeNow))).limit(input.limit + 1);
663
- const selectedAttempts = attempts.slice(0, input.limit);
664
- const hasMore = attempts.length > selectedAttempts.length;
665
- const marker = `effect-auth-password-guard:cleanup:${input.moduleId}:${now}`;
666
- const statements = [];
667
- for (const row of selectedAttempts) {
668
- const condition = and(eq(a.moduleId, input.moduleId), eq(a.attemptId, row.attemptId), lte(a.retentionUntil, mapping.d1.engineNow));
669
- statements.push(yield* assertion(sql`exists(select 1 from ${mapping.attempt.table} where ${condition})`, marker), yield* statement(database.delete(mapping.attempt.table).where(condition)));
670
- }
671
- return {
672
- receipt: prepare({
673
- removed: selectedAttempts.length,
674
- hasMore
675
- }, journal),
676
- statements,
677
- retryable: (cause) => isGuardFailure(cause, marker)
678
- };
679
- });
680
546
  const makeD1PasswordPersistenceServices = Effect.fnUntraced(function* (mapping, proofMapping) {
681
547
  const database = yield* Database;
682
548
  yield* validateDrizzleStorage({
@@ -694,18 +560,14 @@ const makeD1PasswordPersistenceServices = Effect.fnUntraced(function* (mapping,
694
560
  return yield* executeStandalone(plan, 2);
695
561
  }).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
696
562
  return { passwordPersistence: {
697
- prepareAttempt: (input) => standalone.pipe(Effect.andThen(plans.prepareAttempt(input)), Effect.map((planned) => Object.freeze({
698
- ...planned.credential === void 0 ? {} : { credential: planned.credential },
699
- admit: (prepare) => planned.claim.pipe(Effect.andThen(run(planned.admit(prepare))), translateFailure)
700
- })), Effect.provideService(CurrentD1PlanningDatabase, database), translateFailure),
701
- settleAttempt: (input, prepare) => run(plans.settleAttempt(input, prepare)).pipe(translateFailure),
563
+ findCredential: (input) => standalone.pipe(Effect.andThen(plans.findCredential(input)), Effect.provideService(CurrentD1PlanningDatabase, database), translateFailure),
564
+ rehashIfCurrent: (input) => run(plans.rehashIfCurrent(input)).pipe(translateFailure),
702
565
  readForSubject: (input) => plans.readForSubject(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), translateFailure),
703
566
  recoveryTarget: (input) => plans.recoveryTarget(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), translateFailure),
704
567
  addIfAbsent: (input, prepare) => run(plans.addIfAbsent(input, prepare)).pipe(translateFailure),
705
568
  replaceIfCurrent: (input, prepare) => run(plans.replaceIfCurrent(input, prepare)).pipe(translateFailure),
706
569
  checkReset: (input) => plans.checkReset(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), translateFailure),
707
- resetWithProof: (input, prepare) => run(plans.resetWithProof(input, prepare)).pipe(translateFailure),
708
- cleanupAttempts: (input, prepare) => run(plans.cleanupAttempts(input, prepare)).pipe(translateFailure)
570
+ resetWithProof: (input, prepare) => run(plans.resetWithProof(input, prepare)).pipe(translateFailure)
709
571
  } };
710
572
  });
711
573
  /**
@@ -741,18 +603,14 @@ function coordinateD1PasswordPersistence(acquire, options, body) {
741
603
  return guarded.receipt;
742
604
  }), { mode: "batch" }).pipe(Effect.map((result) => result.value), Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
743
605
  const provided = Context.make(PasswordPersistence, {
744
- prepareAttempt: (input) => owner.run(plans.prepareAttempt(input).pipe(Effect.map((planned) => Object.freeze({
745
- ...planned.credential === void 0 ? {} : { credential: planned.credential },
746
- admit: (prepare) => owner.run(planned.claim.pipe(Effect.andThen(run(planned.admit(prepare))), translateFailure))
747
- })), Effect.provideService(CurrentD1PlanningDatabase, database), translateFailure)),
748
- settleAttempt: (input, prepare) => owner.run(run(plans.settleAttempt(input, prepare)).pipe(translateFailure)),
606
+ findCredential: (input) => owner.run(plans.findCredential(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), translateFailure)),
607
+ rehashIfCurrent: (input) => owner.run(run(plans.rehashIfCurrent(input)).pipe(translateFailure)),
749
608
  readForSubject: (input) => owner.run(plans.readForSubject(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), translateFailure)),
750
609
  recoveryTarget: (input) => owner.run(plans.recoveryTarget(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), translateFailure)),
751
610
  addIfAbsent: (input, prepare) => owner.run(run(plans.addIfAbsent(input, prepare)).pipe(translateFailure)),
752
611
  replaceIfCurrent: (input, prepare) => owner.run(run(plans.replaceIfCurrent(input, prepare)).pipe(translateFailure)),
753
612
  checkReset: (input) => owner.run(plans.checkReset(input).pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), translateFailure)),
754
- resetWithProof: (input, prepare) => owner.run(run(plans.resetWithProof(input, prepare)).pipe(translateFailure)),
755
- cleanupAttempts: (input, prepare) => owner.run(run(plans.cleanupAttempts(input, prepare)).pipe(translateFailure))
613
+ resetWithProof: (input, prepare) => owner.run(run(plans.resetWithProof(input, prepare)).pipe(translateFailure))
756
614
  }).pipe(Context.add(D1BatchStatements, owner.collector));
757
615
  const value = yield* owner.close(Effect.provideContext(body, provided));
758
616
  if (mutation?.journalGuard !== void 0) {