@yielded/auth-persistence 0.1.0-beta.25 → 0.1.0-beta.26

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 (481) hide show
  1. package/README.md +6 -8
  2. package/dist/Adapter.d.mts +47 -33
  3. package/dist/Adapter.mjs +36 -23
  4. package/dist/OAuthPersistence.d.mts +35 -51
  5. package/dist/OAuthPersistence.mjs +60 -68
  6. package/dist/OAuthPersistence.mjs.map +1 -1
  7. package/dist/index.d.mts +2 -2
  8. package/dist/index.mjs +2 -2
  9. package/dist/internal/browser-login.d.mts +1 -1
  10. package/dist/internal/browser-login.mjs +29 -9
  11. package/dist/internal/browser-login.mjs.map +1 -1
  12. package/dist/internal/configuration.d.mts +13 -8
  13. package/dist/internal/configuration.mjs.map +1 -1
  14. package/dist/internal/crypto.d.mts +1 -0
  15. package/dist/internal/crypto.mjs +1 -1
  16. package/dist/internal/d1-planning.mjs +8 -0
  17. package/dist/internal/d1-planning.mjs.map +1 -0
  18. package/dist/internal/email-native-state.mjs +135 -0
  19. package/dist/internal/email-native-state.mjs.map +1 -0
  20. package/dist/internal/email-native.d.mts +17 -0
  21. package/dist/internal/email-native.mjs +245 -0
  22. package/dist/internal/email-native.mjs.map +1 -0
  23. package/dist/internal/email-policy.mjs +92 -0
  24. package/dist/internal/email-policy.mjs.map +1 -0
  25. package/dist/internal/email-registration-native.d.mts +38 -0
  26. package/dist/internal/email-registration-native.mjs +171 -0
  27. package/dist/internal/email-registration-native.mjs.map +1 -0
  28. package/dist/internal/models/email-model.d.mts +40 -104
  29. package/dist/internal/models/email-model.mjs +3 -5
  30. package/dist/internal/models/email-model.mjs.map +1 -1
  31. package/dist/internal/models/oauth-connected-model.d.mts +44 -213
  32. package/dist/internal/models/oauth-connected-model.mjs +6 -14
  33. package/dist/internal/models/oauth-connected-model.mjs.map +1 -1
  34. package/dist/internal/models/oauth-model.d.mts +95 -244
  35. package/dist/internal/models/oauth-model.mjs +28 -22
  36. package/dist/internal/models/oauth-model.mjs.map +1 -1
  37. package/dist/internal/models/passkey-model.d.mts +11 -147
  38. package/dist/internal/models/passkey-model.mjs +5 -24
  39. package/dist/internal/models/passkey-model.mjs.map +1 -1
  40. package/dist/internal/models/passkey-registration-ceremony-model.d.mts +5 -39
  41. package/dist/internal/models/passkey-write-model.d.mts +17 -75
  42. package/dist/internal/models/passkey-write-model.mjs +1 -7
  43. package/dist/internal/models/passkey-write-model.mjs.map +1 -1
  44. package/dist/internal/models/password-model.d.mts +14 -81
  45. package/dist/internal/models/password-model.mjs +1 -4
  46. package/dist/internal/models/password-model.mjs.map +1 -1
  47. package/dist/internal/models/phone-model.d.mts +86 -0
  48. package/dist/internal/models/phone-model.mjs +10 -0
  49. package/dist/internal/models/phone-model.mjs.map +1 -0
  50. package/dist/internal/models/proof-model.d.mts +43 -272
  51. package/dist/internal/models/proof-model.mjs +2 -10
  52. package/dist/internal/models/proof-model.mjs.map +1 -1
  53. package/dist/internal/models/session-model.d.mts +74 -93
  54. package/dist/internal/models/session-model.mjs +3 -11
  55. package/dist/internal/models/session-model.mjs.map +1 -1
  56. package/dist/internal/models/step-up-model.d.mts +12 -50
  57. package/dist/internal/models/step-up-model.mjs +2 -4
  58. package/dist/internal/models/step-up-model.mjs.map +1 -1
  59. package/dist/internal/models/totp-model.d.mts +76 -0
  60. package/dist/internal/models/totp-model.mjs +10 -0
  61. package/dist/internal/models/totp-model.mjs.map +1 -0
  62. package/dist/internal/native-sql-table.d.mts +21 -4
  63. package/dist/internal/native-sql-table.mjs +9 -5
  64. package/dist/internal/native-sql-table.mjs.map +1 -1
  65. package/dist/internal/oauth/native-accounts.d.mts +17 -0
  66. package/dist/internal/oauth/native-accounts.mjs +290 -0
  67. package/dist/internal/oauth/native-accounts.mjs.map +1 -0
  68. package/dist/internal/oauth/native-connected-state.d.mts +11 -0
  69. package/dist/internal/oauth/native-connected-state.mjs +146 -0
  70. package/dist/internal/oauth/native-connected-state.mjs.map +1 -0
  71. package/dist/internal/oauth/native-connected.d.mts +15 -0
  72. package/dist/internal/oauth/native-connected.mjs +462 -0
  73. package/dist/internal/oauth/native-connected.mjs.map +1 -0
  74. package/dist/internal/oauth/native-flow.mjs +138 -0
  75. package/dist/internal/oauth/native-flow.mjs.map +1 -0
  76. package/dist/internal/oauth/native-layers.d.mts +24 -0
  77. package/dist/internal/oauth/native-layers.mjs +13 -0
  78. package/dist/internal/oauth/native-layers.mjs.map +1 -0
  79. package/dist/internal/oauth/native-mutation.mjs +122 -0
  80. package/dist/internal/oauth/native-mutation.mjs.map +1 -0
  81. package/dist/internal/oauth/native-registration.d.mts +24 -0
  82. package/dist/internal/oauth/native-registration.mjs +328 -0
  83. package/dist/internal/oauth/native-registration.mjs.map +1 -0
  84. package/dist/internal/oauth/native-revocations.d.mts +17 -0
  85. package/dist/internal/oauth/native-revocations.mjs +106 -0
  86. package/dist/internal/oauth/native-revocations.mjs.map +1 -0
  87. package/dist/internal/oauth/native-sign-in.d.mts +17 -0
  88. package/dist/internal/oauth/native-sign-in.mjs +50 -0
  89. package/dist/internal/oauth/native-sign-in.mjs.map +1 -0
  90. package/dist/internal/oauth/native-state.d.mts +10 -0
  91. package/dist/internal/oauth/native-state.mjs +214 -0
  92. package/dist/internal/oauth/native-state.mjs.map +1 -0
  93. package/dist/internal/oauth/state.d.mts +10 -0
  94. package/dist/internal/oauth/state.mjs +3 -27
  95. package/dist/internal/oauth/state.mjs.map +1 -1
  96. package/dist/internal/passkey-actions.mjs +55 -0
  97. package/dist/internal/passkey-actions.mjs.map +1 -0
  98. package/dist/internal/passkey-inputs.mjs +73 -0
  99. package/dist/internal/passkey-inputs.mjs.map +1 -0
  100. package/dist/internal/passkey-managed.mjs +224 -0
  101. package/dist/internal/passkey-managed.mjs.map +1 -0
  102. package/dist/internal/passkey-native-ceremony.d.mts +35 -0
  103. package/dist/internal/passkey-native-ceremony.mjs +38 -0
  104. package/dist/internal/passkey-native-ceremony.mjs.map +1 -0
  105. package/dist/internal/passkey-native-flow.mjs +91 -0
  106. package/dist/internal/passkey-native-flow.mjs.map +1 -0
  107. package/dist/internal/passkey-native-registration.d.mts +10 -0
  108. package/dist/internal/passkey-native-registration.mjs +114 -0
  109. package/dist/internal/passkey-native-registration.mjs.map +1 -0
  110. package/dist/internal/passkey-native-state.d.mts +15 -0
  111. package/dist/internal/passkey-native-state.mjs +186 -0
  112. package/dist/internal/passkey-native-state.mjs.map +1 -0
  113. package/dist/internal/passkey-native-write.d.mts +82 -0
  114. package/dist/internal/passkey-native-write.mjs +330 -0
  115. package/dist/internal/passkey-native-write.mjs.map +1 -0
  116. package/dist/internal/passkey-native.d.mts +835 -0
  117. package/dist/internal/passkey-native.mjs +175 -0
  118. package/dist/internal/passkey-native.mjs.map +1 -0
  119. package/dist/internal/passkey-policy.mjs +115 -0
  120. package/dist/internal/passkey-policy.mjs.map +1 -0
  121. package/dist/internal/password-credentials.mjs +38 -9
  122. package/dist/internal/password-credentials.mjs.map +1 -1
  123. package/dist/internal/password-native.d.mts +14 -0
  124. package/dist/internal/password-native.mjs +292 -0
  125. package/dist/internal/password-native.mjs.map +1 -0
  126. package/dist/internal/password-policy.mjs +93 -0
  127. package/dist/internal/password-policy.mjs.map +1 -0
  128. package/dist/internal/password-registration-native.d.mts +22 -0
  129. package/dist/internal/password-registration-native.mjs +142 -0
  130. package/dist/internal/password-registration-native.mjs.map +1 -0
  131. package/dist/internal/persistence.d.mts +6 -19
  132. package/dist/internal/persistence.mjs +199 -166
  133. package/dist/internal/persistence.mjs.map +1 -1
  134. package/dist/internal/phone-composed.mjs +79 -0
  135. package/dist/internal/phone-composed.mjs.map +1 -0
  136. package/dist/internal/phone-native.d.mts +15 -0
  137. package/dist/internal/phone-native.mjs +354 -0
  138. package/dist/internal/phone-native.mjs.map +1 -0
  139. package/dist/internal/proof-native.d.mts +15 -0
  140. package/dist/internal/proof-native.mjs +289 -0
  141. package/dist/internal/proof-native.mjs.map +1 -0
  142. package/dist/internal/registration.mjs +50 -60
  143. package/dist/internal/registration.mjs.map +1 -1
  144. package/dist/internal/session-native-authority.d.mts +15 -0
  145. package/dist/internal/session-native-authority.mjs +91 -0
  146. package/dist/internal/session-native-authority.mjs.map +1 -0
  147. package/dist/internal/session-native-cleanup.d.mts +14 -0
  148. package/dist/internal/session-native-cleanup.mjs +48 -0
  149. package/dist/internal/session-native-cleanup.mjs.map +1 -0
  150. package/dist/internal/session-native-login.d.mts +15 -0
  151. package/dist/internal/session-native-login.mjs +87 -0
  152. package/dist/internal/session-native-login.mjs.map +1 -0
  153. package/dist/internal/session-native-pending-read.mjs +42 -0
  154. package/dist/internal/session-native-pending-read.mjs.map +1 -0
  155. package/dist/internal/session-native-pending.mjs +134 -0
  156. package/dist/internal/session-native-pending.mjs.map +1 -0
  157. package/dist/internal/session-native-record.mjs +79 -0
  158. package/dist/internal/session-native-record.mjs.map +1 -0
  159. package/dist/internal/session-native-state.mjs +130 -0
  160. package/dist/internal/session-native-state.mjs.map +1 -0
  161. package/dist/internal/session-native-stateful.d.mts +16 -0
  162. package/dist/internal/session-native-stateful.mjs +225 -0
  163. package/dist/internal/session-native-stateful.mjs.map +1 -0
  164. package/dist/internal/session-native-step-up.d.mts +15 -0
  165. package/dist/internal/session-native-step-up.mjs +212 -0
  166. package/dist/internal/session-native-step-up.mjs.map +1 -0
  167. package/dist/internal/session-native-validity.d.mts +15 -0
  168. package/dist/internal/session-native-validity.mjs +97 -0
  169. package/dist/internal/session-native-validity.mjs.map +1 -0
  170. package/dist/internal/session-policy.mjs +29 -0
  171. package/dist/internal/session-policy.mjs.map +1 -0
  172. package/dist/internal/sql-authority.d.mts +16 -0
  173. package/dist/internal/sql-authority.mjs +32 -0
  174. package/dist/internal/sql-authority.mjs.map +1 -0
  175. package/dist/internal/sql-change.mjs +21 -0
  176. package/dist/internal/sql-change.mjs.map +1 -0
  177. package/dist/internal/sql-cleanup.mjs +35 -0
  178. package/dist/internal/sql-cleanup.mjs.map +1 -0
  179. package/dist/internal/sql-commit.d.mts +72 -0
  180. package/dist/internal/sql-commit.mjs +176 -0
  181. package/dist/internal/sql-commit.mjs.map +1 -0
  182. package/dist/internal/sql-expression.d.mts +17 -0
  183. package/dist/internal/sql-expression.mjs +49 -0
  184. package/dist/internal/sql-expression.mjs.map +1 -0
  185. package/dist/internal/sql-oauth-connected-model.d.mts +7 -23
  186. package/dist/internal/sql-oauth-model.d.mts +27 -52
  187. package/dist/internal/sql-oauth-model.mjs +3 -4
  188. package/dist/internal/sql-oauth-model.mjs.map +1 -1
  189. package/dist/internal/sql-persistence.mjs +5 -9
  190. package/dist/internal/sql-persistence.mjs.map +1 -1
  191. package/dist/internal/sql-storage-validation.mjs +1 -2
  192. package/dist/internal/sql-storage-validation.mjs.map +1 -1
  193. package/dist/internal/sql-table.d.mts +3 -16
  194. package/dist/internal/sql-table.mjs +21 -42
  195. package/dist/internal/sql-table.mjs.map +1 -1
  196. package/dist/internal/standalone.mjs +2 -3
  197. package/dist/internal/standalone.mjs.map +1 -1
  198. package/dist/internal/step-up-state.mjs +5 -8
  199. package/dist/internal/step-up-state.mjs.map +1 -1
  200. package/dist/internal/storage-clock.mjs +44 -0
  201. package/dist/internal/storage-clock.mjs.map +1 -0
  202. package/dist/internal/storage-mapping.d.mts +11 -8
  203. package/dist/internal/storage-mapping.mjs +88 -302
  204. package/dist/internal/storage-mapping.mjs.map +1 -1
  205. package/dist/internal/storage-plans.mjs +15 -73
  206. package/dist/internal/storage-plans.mjs.map +1 -1
  207. package/dist/internal/storage-tables.d.mts +37 -520
  208. package/dist/internal/storage-tables.mjs +31 -211
  209. package/dist/internal/storage-tables.mjs.map +1 -1
  210. package/dist/internal/storage-validation.d.mts +1 -6
  211. package/dist/internal/storage-validation.mjs +1 -42
  212. package/dist/internal/storage-validation.mjs.map +1 -1
  213. package/dist/internal/table-model.d.mts +21 -0
  214. package/dist/internal/totp-native.d.mts +15 -0
  215. package/dist/internal/totp-native.mjs +401 -0
  216. package/dist/internal/totp-native.mjs.map +1 -0
  217. package/package.json +1 -1
  218. package/src/Adapter.ts +143 -199
  219. package/src/OAuthPersistence.ts +128 -271
  220. package/src/index.ts +1 -1
  221. package/src/internal/browser-login.ts +54 -24
  222. package/src/internal/configuration.ts +16 -31
  223. package/src/internal/d1-planning.ts +7 -0
  224. package/src/internal/email-native-state.ts +247 -0
  225. package/src/internal/email-native.ts +514 -0
  226. package/src/internal/email-policy.ts +235 -0
  227. package/src/internal/email-registration-native.ts +386 -0
  228. package/src/internal/models/email-model.ts +76 -214
  229. package/src/internal/models/oauth-connected-model.ts +50 -288
  230. package/src/internal/models/oauth-model.ts +147 -368
  231. package/src/internal/models/passkey-model.ts +11 -208
  232. package/src/internal/models/passkey-registration-ceremony-model.ts +6 -60
  233. package/src/internal/models/passkey-write-model.ts +14 -95
  234. package/src/internal/models/password-model.ts +26 -147
  235. package/src/internal/models/phone-model.ts +110 -0
  236. package/src/internal/models/proof-model.ts +48 -404
  237. package/src/internal/models/session-model.ts +102 -200
  238. package/src/internal/models/step-up-model.ts +17 -96
  239. package/src/internal/models/totp-model.ts +82 -0
  240. package/src/internal/native-sql-table.ts +32 -11
  241. package/src/internal/oauth/native-accounts.ts +576 -0
  242. package/src/internal/oauth/native-connected-state.ts +288 -0
  243. package/src/internal/oauth/native-connected.ts +888 -0
  244. package/src/internal/oauth/native-flow.ts +253 -0
  245. package/src/internal/oauth/native-layers.ts +83 -0
  246. package/src/internal/oauth/native-mutation.ts +222 -0
  247. package/src/internal/oauth/native-registration.ts +545 -0
  248. package/src/internal/oauth/native-revocations.ts +190 -0
  249. package/src/internal/oauth/native-sign-in.ts +111 -0
  250. package/src/internal/oauth/native-state.ts +346 -0
  251. package/src/internal/oauth/state.ts +2 -70
  252. package/src/internal/passkey-actions.ts +70 -0
  253. package/src/internal/passkey-inputs.ts +56 -0
  254. package/src/internal/passkey-managed.ts +360 -0
  255. package/src/internal/passkey-native-ceremony.ts +66 -0
  256. package/src/internal/passkey-native-flow.ts +140 -0
  257. package/src/internal/passkey-native-registration.ts +221 -0
  258. package/src/internal/passkey-native-state.ts +335 -0
  259. package/src/internal/passkey-native-write.ts +611 -0
  260. package/src/internal/passkey-native.ts +372 -0
  261. package/src/internal/passkey-policy.ts +246 -0
  262. package/src/internal/password-credentials.ts +52 -10
  263. package/src/internal/password-native.ts +571 -0
  264. package/src/internal/password-policy.ts +307 -0
  265. package/src/internal/password-registration-native.ts +322 -0
  266. package/src/internal/persistence.ts +336 -290
  267. package/src/internal/phone-composed.ts +86 -0
  268. package/src/internal/phone-native.ts +659 -0
  269. package/src/internal/proof-native.ts +448 -0
  270. package/src/internal/registration.ts +96 -143
  271. package/src/internal/session-native-authority.ts +247 -0
  272. package/src/internal/session-native-cleanup.ts +65 -0
  273. package/src/internal/session-native-login.ts +205 -0
  274. package/src/internal/session-native-pending-read.ts +68 -0
  275. package/src/internal/session-native-pending.ts +223 -0
  276. package/src/internal/session-native-record.ts +141 -0
  277. package/src/internal/session-native-state.ts +259 -0
  278. package/src/internal/session-native-stateful.ts +512 -0
  279. package/src/internal/session-native-step-up.ts +450 -0
  280. package/src/internal/session-native-validity.ts +208 -0
  281. package/src/internal/session-policy.ts +59 -0
  282. package/src/internal/sql-authority.ts +56 -0
  283. package/src/internal/sql-change.ts +38 -0
  284. package/src/internal/sql-cleanup.ts +56 -0
  285. package/src/internal/sql-commit.ts +435 -0
  286. package/src/internal/sql-expression.ts +94 -0
  287. package/src/internal/sql-metadata.ts +100 -0
  288. package/src/internal/sql-oauth-connected-model.ts +6 -95
  289. package/src/internal/sql-oauth-model.ts +31 -134
  290. package/src/internal/sql-persistence.ts +2 -6
  291. package/src/internal/sql-storage-validation.ts +1 -2
  292. package/src/internal/sql-table.ts +19 -52
  293. package/src/internal/standalone.ts +2 -11
  294. package/src/internal/step-up-state.ts +4 -17
  295. package/src/internal/storage-clock.ts +58 -0
  296. package/src/internal/storage-mapping.ts +125 -340
  297. package/src/internal/storage-plans.ts +14 -80
  298. package/src/internal/storage-tables.ts +28 -212
  299. package/src/internal/storage-validation.ts +0 -58
  300. package/src/internal/table-model.ts +24 -0
  301. package/src/internal/totp-native.ts +701 -0
  302. package/dist/internal/PasswordPreparedPostconditions.d.mts +0 -22
  303. package/dist/internal/PasswordPreparedPostconditions.mjs +0 -12
  304. package/dist/internal/PasswordPreparedPostconditions.mjs.map +0 -1
  305. package/dist/internal/authority-snapshot.mjs +0 -53
  306. package/dist/internal/authority-snapshot.mjs.map +0 -1
  307. package/dist/internal/email-kernel.d.mts +0 -276
  308. package/dist/internal/email-kernel.mjs +0 -497
  309. package/dist/internal/email-kernel.mjs.map +0 -1
  310. package/dist/internal/models/passkey-registration-ceremony-model.mjs +0 -18
  311. package/dist/internal/models/passkey-registration-ceremony-model.mjs.map +0 -1
  312. package/dist/internal/oauth/accounts.d.mts +0 -8
  313. package/dist/internal/oauth/accounts.mjs +0 -379
  314. package/dist/internal/oauth/accounts.mjs.map +0 -1
  315. package/dist/internal/oauth/connected-access.d.mts +0 -9
  316. package/dist/internal/oauth/connected-access.mjs +0 -229
  317. package/dist/internal/oauth/connected-access.mjs.map +0 -1
  318. package/dist/internal/oauth/connected-collection.d.mts +0 -7
  319. package/dist/internal/oauth/connected-collection.mjs +0 -214
  320. package/dist/internal/oauth/connected-collection.mjs.map +0 -1
  321. package/dist/internal/oauth/connected-custody.d.mts +0 -6
  322. package/dist/internal/oauth/connected-custody.mjs +0 -165
  323. package/dist/internal/oauth/connected-custody.mjs.map +0 -1
  324. package/dist/internal/oauth/connected-flow.d.mts +0 -7
  325. package/dist/internal/oauth/connected-flow.mjs +0 -324
  326. package/dist/internal/oauth/connected-flow.mjs.map +0 -1
  327. package/dist/internal/oauth/connected-input.mjs +0 -122
  328. package/dist/internal/oauth/connected-input.mjs.map +0 -1
  329. package/dist/internal/oauth/connected-keys.d.mts +0 -2
  330. package/dist/internal/oauth/connected-keys.mjs +0 -22
  331. package/dist/internal/oauth/connected-keys.mjs.map +0 -1
  332. package/dist/internal/oauth/connected-maintenance.d.mts +0 -9
  333. package/dist/internal/oauth/connected-maintenance.mjs +0 -226
  334. package/dist/internal/oauth/connected-maintenance.mjs.map +0 -1
  335. package/dist/internal/oauth/connected-management.d.mts +0 -9
  336. package/dist/internal/oauth/connected-management.mjs +0 -243
  337. package/dist/internal/oauth/connected-management.mjs.map +0 -1
  338. package/dist/internal/oauth/connected-reference.mjs +0 -63
  339. package/dist/internal/oauth/connected-reference.mjs.map +0 -1
  340. package/dist/internal/oauth/connected-settlement.d.mts +0 -8
  341. package/dist/internal/oauth/connected-settlement.mjs +0 -141
  342. package/dist/internal/oauth/connected-settlement.mjs.map +0 -1
  343. package/dist/internal/oauth/connected-sign-in.d.mts +0 -10
  344. package/dist/internal/oauth/connected-sign-in.mjs +0 -281
  345. package/dist/internal/oauth/connected-sign-in.mjs.map +0 -1
  346. package/dist/internal/oauth/connected-state.d.mts +0 -14
  347. package/dist/internal/oauth/connected-state.mjs +0 -469
  348. package/dist/internal/oauth/connected-state.mjs.map +0 -1
  349. package/dist/internal/oauth/connected-target.d.mts +0 -21
  350. package/dist/internal/oauth/connected-target.mjs +0 -117
  351. package/dist/internal/oauth/connected-target.mjs.map +0 -1
  352. package/dist/internal/oauth/flow.d.mts +0 -5
  353. package/dist/internal/oauth/flow.mjs +0 -279
  354. package/dist/internal/oauth/flow.mjs.map +0 -1
  355. package/dist/internal/oauth/input.mjs +0 -127
  356. package/dist/internal/oauth/input.mjs.map +0 -1
  357. package/dist/internal/oauth/owner.d.mts +0 -10
  358. package/dist/internal/oauth/owner.mjs +0 -10
  359. package/dist/internal/oauth/owner.mjs.map +0 -1
  360. package/dist/internal/oauth/query-compiler.d.mts +0 -7
  361. package/dist/internal/oauth/query-compiler.mjs +0 -9
  362. package/dist/internal/oauth/query-compiler.mjs.map +0 -1
  363. package/dist/internal/oauth/registration.d.mts +0 -7
  364. package/dist/internal/oauth/registration.mjs +0 -393
  365. package/dist/internal/oauth/registration.mjs.map +0 -1
  366. package/dist/internal/oauth/target.d.mts +0 -31
  367. package/dist/internal/oauth/target.mjs +0 -273
  368. package/dist/internal/oauth/target.mjs.map +0 -1
  369. package/dist/internal/oauth-kernel.d.mts +0 -1423
  370. package/dist/internal/oauth-kernel.mjs +0 -187
  371. package/dist/internal/oauth-kernel.mjs.map +0 -1
  372. package/dist/internal/passkey/admission.d.mts +0 -6
  373. package/dist/internal/passkey/admission.mjs +0 -220
  374. package/dist/internal/passkey/admission.mjs.map +0 -1
  375. package/dist/internal/passkey/credentials.d.mts +0 -14
  376. package/dist/internal/passkey/credentials.mjs +0 -249
  377. package/dist/internal/passkey/credentials.mjs.map +0 -1
  378. package/dist/internal/passkey/enrollment.mjs +0 -138
  379. package/dist/internal/passkey/enrollment.mjs.map +0 -1
  380. package/dist/internal/passkey/flow.d.mts +0 -21
  381. package/dist/internal/passkey/flow.mjs +0 -452
  382. package/dist/internal/passkey/flow.mjs.map +0 -1
  383. package/dist/internal/passkey/management.mjs +0 -231
  384. package/dist/internal/passkey/management.mjs.map +0 -1
  385. package/dist/internal/passkey/registration-ceremony.d.mts +0 -9
  386. package/dist/internal/passkey/registration-ceremony.mjs +0 -129
  387. package/dist/internal/passkey/registration-ceremony.mjs.map +0 -1
  388. package/dist/internal/passkey/registration-custody.d.mts +0 -2
  389. package/dist/internal/passkey/registration-custody.mjs +0 -52
  390. package/dist/internal/passkey/registration-custody.mjs.map +0 -1
  391. package/dist/internal/passkey/registration-write.mjs +0 -211
  392. package/dist/internal/passkey/registration-write.mjs.map +0 -1
  393. package/dist/internal/passkey/state.d.mts +0 -10
  394. package/dist/internal/passkey/state.mjs +0 -234
  395. package/dist/internal/passkey/state.mjs.map +0 -1
  396. package/dist/internal/passkey/target.d.mts +0 -20
  397. package/dist/internal/passkey/target.mjs +0 -200
  398. package/dist/internal/passkey/target.mjs.map +0 -1
  399. package/dist/internal/passkey/write-state.d.mts +0 -17
  400. package/dist/internal/passkey/write-state.mjs +0 -354
  401. package/dist/internal/passkey/write-state.mjs.map +0 -1
  402. package/dist/internal/passkey/write-target.mjs +0 -192
  403. package/dist/internal/passkey/write-target.mjs.map +0 -1
  404. package/dist/internal/passkey-kernel.d.mts +0 -6045
  405. package/dist/internal/passkey-kernel.mjs +0 -49
  406. package/dist/internal/passkey-kernel.mjs.map +0 -1
  407. package/dist/internal/passkeys.d.mts +0 -7
  408. package/dist/internal/passkeys.mjs +0 -387
  409. package/dist/internal/passkeys.mjs.map +0 -1
  410. package/dist/internal/password-credentials.d.mts +0 -11
  411. package/dist/internal/password-kernel.d.mts +0 -278
  412. package/dist/internal/password-kernel.mjs +0 -508
  413. package/dist/internal/password-kernel.mjs.map +0 -1
  414. package/dist/internal/phone-kernel.d.mts +0 -162
  415. package/dist/internal/phone-kernel.mjs +0 -437
  416. package/dist/internal/phone-kernel.mjs.map +0 -1
  417. package/dist/internal/proof-kernel.d.mts +0 -94
  418. package/dist/internal/proof-kernel.mjs +0 -624
  419. package/dist/internal/proof-kernel.mjs.map +0 -1
  420. package/dist/internal/query-operations.d.mts +0 -68
  421. package/dist/internal/session-kernel.d.mts +0 -62
  422. package/dist/internal/session-kernel.mjs +0 -820
  423. package/dist/internal/session-kernel.mjs.map +0 -1
  424. package/dist/internal/sql-oauth-connected-model.mjs +0 -7
  425. package/dist/internal/sql-oauth-connected-model.mjs.map +0 -1
  426. package/dist/internal/sql-query.d.mts +0 -12
  427. package/dist/internal/sql-query.mjs +0 -206
  428. package/dist/internal/sql-query.mjs.map +0 -1
  429. package/dist/internal/step-up-state.d.mts +0 -49
  430. package/dist/internal/transaction-execution-kernel.d.mts +0 -37
  431. package/dist/internal/transaction-execution-kernel.mjs +0 -120
  432. package/dist/internal/transaction-execution-kernel.mjs.map +0 -1
  433. package/dist/internal/transaction-kernel.d.mts +0 -81
  434. package/dist/internal/transaction-kernel.mjs +0 -264
  435. package/dist/internal/transaction-kernel.mjs.map +0 -1
  436. package/src/internal/PasswordPreparedPostconditions.ts +0 -30
  437. package/src/internal/authority-snapshot.ts +0 -91
  438. package/src/internal/email-kernel.ts +0 -1556
  439. package/src/internal/oauth/accounts.ts +0 -839
  440. package/src/internal/oauth/connected-access.ts +0 -388
  441. package/src/internal/oauth/connected-collection.ts +0 -345
  442. package/src/internal/oauth/connected-custody.ts +0 -308
  443. package/src/internal/oauth/connected-flow.ts +0 -562
  444. package/src/internal/oauth/connected-input.ts +0 -147
  445. package/src/internal/oauth/connected-keys.ts +0 -31
  446. package/src/internal/oauth/connected-maintenance.ts +0 -379
  447. package/src/internal/oauth/connected-management.ts +0 -391
  448. package/src/internal/oauth/connected-reference.ts +0 -135
  449. package/src/internal/oauth/connected-settlement.ts +0 -278
  450. package/src/internal/oauth/connected-sign-in.ts +0 -472
  451. package/src/internal/oauth/connected-state.ts +0 -924
  452. package/src/internal/oauth/connected-target.ts +0 -307
  453. package/src/internal/oauth/flow.ts +0 -505
  454. package/src/internal/oauth/input.ts +0 -201
  455. package/src/internal/oauth/owner.ts +0 -22
  456. package/src/internal/oauth/query-compiler.ts +0 -15
  457. package/src/internal/oauth/registration.ts +0 -676
  458. package/src/internal/oauth/target.ts +0 -803
  459. package/src/internal/oauth-kernel.ts +0 -294
  460. package/src/internal/passkey/admission.ts +0 -368
  461. package/src/internal/passkey/credentials.ts +0 -511
  462. package/src/internal/passkey/enrollment.ts +0 -326
  463. package/src/internal/passkey/flow.ts +0 -1062
  464. package/src/internal/passkey/management.ts +0 -426
  465. package/src/internal/passkey/registration-ceremony.ts +0 -283
  466. package/src/internal/passkey/registration-custody.ts +0 -91
  467. package/src/internal/passkey/registration-write.ts +0 -426
  468. package/src/internal/passkey/state.ts +0 -351
  469. package/src/internal/passkey/target.ts +0 -598
  470. package/src/internal/passkey/write-state.ts +0 -692
  471. package/src/internal/passkey/write-target.ts +0 -450
  472. package/src/internal/passkey-kernel.ts +0 -112
  473. package/src/internal/passkeys.ts +0 -652
  474. package/src/internal/password-kernel.ts +0 -1523
  475. package/src/internal/phone-kernel.ts +0 -872
  476. package/src/internal/proof-kernel.ts +0 -1992
  477. package/src/internal/query-operations.ts +0 -91
  478. package/src/internal/session-kernel.ts +0 -2406
  479. package/src/internal/sql-query.ts +0 -304
  480. package/src/internal/transaction-execution-kernel.ts +0 -335
  481. package/src/internal/transaction-kernel.ts +0 -603
@@ -8,13 +8,14 @@ import {
8
8
  type PasswordCredentialSnapshot,
9
9
  } from "@yielded/auth/Password";
10
10
  import { reportPersistenceFailure } from "@yielded/auth/Persistence";
11
+ import { SecurityRevision } from "@yielded/auth/Sessions";
11
12
  import { Effect, Option, Redacted, Schema } from "effect";
13
+ import { SqlClient } from "effect/sql";
12
14
 
13
15
  import type { PersistenceMappingError } from "./mapping-error";
14
16
  import type { AnyPasswordPersistenceMapping } from "./models/password-model";
15
17
  import { sqlMapping, type SqlTable } from "./native-sql-table";
16
- import type { PasswordSqlConfiguration } from "./password-kernel";
17
- import { NativeDatabase } from "./transaction-kernel";
18
+ import type { PasswordWorkflowOptions } from "./password-policy";
18
19
 
19
20
  type Row = Readonly<Record<string, unknown>>;
20
21
  const unavailable = () => PasswordUnavailable.make({});
@@ -55,21 +56,22 @@ export const samePasswordCredentialSnapshot = (
55
56
  export const makePasswordCredentials = Effect.fnUntraced(function* (
56
57
  table: (table: object) => SqlTable,
57
58
  mapping: AnyPasswordPersistenceMapping,
58
- options: PasswordSqlConfiguration,
59
+ options: PasswordWorkflowOptions,
59
60
  ): Effect.fn.Return<
60
61
  Pick<PasswordPersistence["Service"], "findCredential" | "rehashIfCurrent">,
61
62
  PasswordUnavailable,
62
- NativeDatabase
63
+ SqlClient.SqlClient
63
64
  > {
64
- const sql = (yield* NativeDatabase).$client.withoutTransforms();
65
+ const sql = (yield* SqlClient.SqlClient).withoutTransforms();
65
66
  const parent = yield* Effect.serviceOption(CurrentCommitJournal);
66
67
 
67
- const [s, i, c] = yield* sqlMapping(
68
+ const [s, i, c, a] = yield* sqlMapping(
68
69
  () =>
69
70
  [
70
71
  table(mapping.subject.table),
71
72
  table(mapping.identifier.table),
72
73
  table(mapping.credential.table),
74
+ table(mapping.authorityCredential.table),
73
75
  ] as const,
74
76
  ).pipe(failure);
75
77
 
@@ -106,21 +108,26 @@ export const makePasswordCredentials = Effect.fnUntraced(function* (
106
108
  const subjectTable = s.as("password_subject");
107
109
  const identifierTable = i.as("password_identifier");
108
110
  const credentialTable = c.as("password_credential");
111
+ const authorityTable = a.as("password_authority");
112
+ const authority = mapping.authorityCredential;
109
113
 
110
114
  const rows = yield* sqlMapping(
111
115
  () =>
112
- sql<Row>`select ${subjectTable.fields("subject_")}, ${identifierTable.fields("identifier_")}, ${credentialTable.fields("credential_")}
116
+ sql<Row>`select ${subjectTable.fields("subject_")}, ${identifierTable.fields("identifier_")}, ${credentialTable.fields("credential_")}, ${authorityTable.fields("authority_")}
113
117
  from ${subjectTable.name}
114
118
  inner join ${identifierTable.name} on ${identifierTable.column(mapping.identifier.namespace)} = ${identifierTable.value(mapping.identifier.namespace, identifier.namespace)}
115
119
  and ${identifierTable.column(mapping.identifier.value)} = ${identifierTable.value(mapping.identifier.value, identifier.value)}
116
120
  and ${identifierTable.column(mapping.identifier.subjectId)} = ${identifierTable.value(mapping.identifier.subjectId, nativeId)}
117
121
  inner join ${credentialTable.name} on ${credentialTable.column(mapping.credential.moduleId)} = ${credentialTable.value(mapping.credential.moduleId, moduleId)}
118
122
  and ${credentialTable.column(mapping.credential.subjectId)} = ${credentialTable.value(mapping.credential.subjectId, nativeId)}
119
- where ${subjectTable.column(mapping.subject.id)} = ${subjectTable.value(mapping.subject.id, nativeId)}
123
+ left join ${authorityTable.name} on ${authorityTable.column(authority.subjectId)} = ${authorityTable.value(authority.subjectId, nativeId)}
124
+ ${authority.status === undefined || authority.d1ActiveStatusValue === undefined ? sql`` : sql`and ${authorityTable.column(authority.status)} = ${authorityTable.value(authority.status, authority.d1ActiveStatusValue)}`}
125
+ where ${subjectTable.column(mapping.subject.id)} = ${subjectTable.value(mapping.subject.id, nativeId)} order by ${authorityTable.column(authority.credentialId)} limit 4097
120
126
  `,
121
127
  ).pipe(Effect.flatten);
122
128
 
123
- if (rows.length !== 1) return undefined;
129
+ if (rows.length === 0) return undefined;
130
+ if (rows.length > 4096) return yield* unavailable();
124
131
 
125
132
  const [subject, identifierRow, credential] = yield* sqlMapping(
126
133
  () =>
@@ -147,7 +154,42 @@ export const makePasswordCredentials = Effect.fnUntraced(function* (
147
154
  mapping.credential.decode({ moduleId, subject, identifier: identifierRow, credential }),
148
155
  ).pipe(Effect.flatten, Effect.flatMap(snapshotPasswordCredential));
149
156
 
150
- return captured;
157
+ const factors = new Map<string, SecurityRevision>();
158
+
159
+ for (const row of rows) {
160
+ const factor = yield* sqlMapping(() => a.decode(row, "authority_"));
161
+
162
+ if (factor[authority.credentialId] === null || factor[authority.credentialId] === undefined)
163
+ continue;
164
+ if (!mapping.subjectId.equals(nativeId, factor[authority.subjectId]))
165
+ return yield* unavailable();
166
+ if (
167
+ authority.status !== undefined &&
168
+ authority.isActiveStatus?.(factor[authority.status]) !== true
169
+ )
170
+ continue;
171
+
172
+ const credentialId = yield* Schema.decodeUnknownEffect(Schema.String)(
173
+ factor[authority.credentialId],
174
+ );
175
+
176
+ const revision = yield* Schema.decodeUnknownEffect(SecurityRevision)(
177
+ factor[authority.revision],
178
+ );
179
+
180
+ if (factors.has(credentialId)) return yield* unavailable();
181
+ factors.set(credentialId, revision);
182
+ }
183
+ if (factors.size > 64 || factors.get(captured.credentialId) !== captured.credentialRevision)
184
+ return undefined;
185
+
186
+ return yield* snapshotPasswordCredential({
187
+ ...captured,
188
+ revision: {
189
+ ...captured.revision,
190
+ credentials: [...factors].map(([credentialId, revision]) => ({ credentialId, revision })),
191
+ },
192
+ });
151
193
  });
152
194
 
153
195
  return {
@@ -0,0 +1,571 @@
1
+ import { CurrentCommitJournal, type LifecycleHooks } from "@yielded/auth/Hooks";
2
+ import type { LoginIdentifier } from "@yielded/auth/Identity";
3
+ import * as P from "@yielded/auth/Password";
4
+ import { ProofRedemptionInput } from "@yielded/auth/Proofs";
5
+ import type { SubjectId } from "@yielded/auth/Schema";
6
+ import { SecurityRevision, type AuthenticationRequirement } from "@yielded/auth/Sessions";
7
+ import { DateTime, Effect, Option, Redacted, Schema, Crypto } from "effect";
8
+ import { SqlClient } from "effect/sql/SqlClient";
9
+ import type { Fragment } from "effect/sql/Statement";
10
+
11
+ import { sqlBatchAssertion } from "./d1-planning";
12
+ import { PersistenceMappingError } from "./mapping-error";
13
+ import type { AnyPasswordPersistenceMapping } from "./models/password-model";
14
+ import type { AnyProofPersistenceMapping } from "./models/proof-model";
15
+ import type { NativeSqlTables, SqlTable } from "./native-sql-table";
16
+ import { makePasswordCredentials, samePasswordCredentialSnapshot } from "./password-credentials";
17
+ import {
18
+ allocatePasswordNextSecurityRevision,
19
+ allocatePasswordValue,
20
+ passwordEvidenceSatisfiedAt,
21
+ passwordProofRedemptionMatches,
22
+ snapshotPasswordMutation,
23
+ validatePasswordMutation,
24
+ } from "./password-policy";
25
+ import { makeNativeProofStore } from "./proof-native";
26
+ import { exactSqlText, executeSqlChange } from "./sql-change";
27
+ import {
28
+ appendSqlBatchStatement,
29
+ CurrentSqlCommit,
30
+ makeSqlCommitExecutor,
31
+ registerSqlBatchPostcondition,
32
+ registerSqlCommitReceipt,
33
+ registerSqlPostcondition,
34
+ SqlBatchCommit,
35
+ } from "./sql-commit";
36
+ import { requireStandalone } from "./standalone";
37
+
38
+ const unavailable = () => P.PasswordUnavailable.make({});
39
+
40
+ const ensure: (condition: unknown) => asserts condition = (condition) => {
41
+ if (!condition) throw unavailable();
42
+ };
43
+
44
+ export const makeNativePasswordServices = Effect.fnUntraced(function* (
45
+ tables: NativeSqlTables,
46
+ mapping: AnyPasswordPersistenceMapping,
47
+ proofs?: AnyProofPersistenceMapping,
48
+ ): Effect.fn.Return<
49
+ { readonly passwordPersistence: P.PasswordPersistence["Service"] },
50
+ P.PasswordUnavailable,
51
+ SqlClient | LifecycleHooks | Crypto.Crypto | SqlBatchCommit
52
+ > {
53
+ const batch = yield* SqlBatchCommit;
54
+ const sql = (yield* SqlClient).withoutTransforms();
55
+ const executor = yield* makeSqlCommitExecutor(unavailable);
56
+ const crypto = yield* Crypto.Crypto;
57
+ const parent = yield* Effect.serviceOption(CurrentSqlCommit);
58
+
59
+ const s = mapping.subject,
60
+ i = mapping.identifier,
61
+ c = mapping.credential,
62
+ a = mapping.authorityCredential;
63
+
64
+ const subject = tables(s.table).as("password_subject");
65
+ const identifier = tables(i.table).as("password_identifier");
66
+ const credential = tables(c.table).as("password_credential");
67
+ const authority = tables(a.table).as("password_authority");
68
+
69
+ const rawSubject = tables(s.table),
70
+ rawPassword = tables(c.table),
71
+ rawAuthority = tables(a.table);
72
+
73
+ const now = tables.expression(mapping.clock.engineNowMillis);
74
+ const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });
75
+
76
+ const exact = (table: SqlTable, key: string, value: unknown) =>
77
+ exactSqlText(sql, table.column(key), table.value(key, value));
78
+
79
+ const subjectKey = (table: SqlTable, key: string, nativeId: unknown) =>
80
+ sql`${table.column(key)} = ${table.value(key, nativeId)}`;
81
+
82
+ const run = <A, E, R>(work: Effect.Effect<A, E, R>) =>
83
+ batch === undefined
84
+ ? executor.run(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))
85
+ : executor
86
+ .batch(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))
87
+ .pipe(Effect.provideService(SqlBatchCommit, batch));
88
+
89
+ const read = Effect.fnUntraced(function* (
90
+ moduleId: string,
91
+ subjectId: SubjectId,
92
+ wanted?: LoginIdentifier,
93
+ locked?: Record<string, unknown>,
94
+ ) {
95
+ const nativeId = yield* mapping.subjectId.toNative(subjectId);
96
+
97
+ // Without one wanted identifier, retired identifiers would multiply authority
98
+ // rows; read authority separately so the result grows linearly.
99
+ const joined = wanted !== undefined;
100
+
101
+ const rows =
102
+ yield* sql`select ${subject.fields("password_subject_")}, ${identifier.fields("password_identifier_")}, ${credential.fields("password_credential_")}${joined ? sql`, ${authority.fields("password_authority_")}` : sql``}, ${now} as engine_now
103
+ from ${subject.name}
104
+ left join ${identifier.name} on ${subjectKey(identifier, i.subjectId, nativeId)} ${wanted === undefined ? sql`` : sql`and ${exact(identifier, i.namespace, wanted.namespace)} and ${exact(identifier, i.value, wanted.value)}`}
105
+ left join ${credential.name} on ${subjectKey(credential, c.subjectId, nativeId)} and ${exact(credential, c.moduleId, moduleId)}
106
+ ${joined ? sql`left join ${authority.name} on ${subjectKey(authority, a.subjectId, nativeId)}` : sql``}
107
+ where ${subjectKey(subject, s.id, nativeId)} order by ${identifier.column(i.namespace)}, ${identifier.column(i.value)}${joined ? sql`, ${authority.column(a.credentialId)}` : sql``} limit 4097`;
108
+
109
+ const authorityRows = joined
110
+ ? rows
111
+ : yield* sql`select ${authority.fields("password_authority_")} from ${authority.name} where ${subjectKey(authority, a.subjectId, nativeId)} order by ${authority.column(a.credentialId)} limit 4097`;
112
+
113
+ ensure(rows.length <= 4096 && authorityRows.length <= 4096);
114
+ if (rows[0] === undefined) return undefined;
115
+ const subjectRow = subject.decode(rows[0], "password_subject_");
116
+ const decodedId = yield* mapping.subjectId.toSubject(subjectRow[s.id]);
117
+
118
+ ensure(
119
+ decodedId === subjectId &&
120
+ (locked === undefined || subjectRow[s.securityRevision] === locked[s.securityRevision]),
121
+ );
122
+ const password = credential.decode(rows[0], "password_credential_");
123
+ const passwordRow = password[c.credentialId] === null ? undefined : password;
124
+
125
+ const factors = new Map<
126
+ string,
127
+ {
128
+ readonly credentialId: string;
129
+ readonly revision: SecurityRevision;
130
+ readonly active: boolean;
131
+ }
132
+ >();
133
+
134
+ let identifierRow: Record<string, unknown> | undefined;
135
+
136
+ for (const row of authorityRows) {
137
+ const factor = authority.decode(row, "password_authority_");
138
+
139
+ if (
140
+ factor[a.credentialId] !== null &&
141
+ (a.status === undefined || a.isActiveStatus?.(factor[a.status]) === true)
142
+ ) {
143
+ ensure(mapping.subjectId.equals(factor[a.subjectId], nativeId));
144
+ const id = yield* Schema.decodeUnknownEffect(Schema.String)(factor[a.credentialId]);
145
+ const revision = yield* Schema.decodeUnknownEffect(SecurityRevision)(factor[a.revision]);
146
+ const old = factors.get(id);
147
+
148
+ ensure(old === undefined || old.revision === revision);
149
+ factors.set(id, { credentialId: id, revision, active: true });
150
+ }
151
+ }
152
+ for (const row of rows) {
153
+ const entry = identifier.decode(row, "password_identifier_");
154
+
155
+ if (
156
+ entry[i.namespace] !== null &&
157
+ mapping.subjectId.equals(entry[i.subjectId], nativeId) &&
158
+ mapping.identifier.isCurrent(entry)
159
+ )
160
+ identifierRow ??= entry;
161
+ }
162
+ ensure(factors.size <= 64);
163
+
164
+ const revision = {
165
+ subjectId,
166
+ securityRevision: yield* Schema.decodeUnknownEffect(SecurityRevision)(
167
+ subjectRow[s.securityRevision],
168
+ ),
169
+ credentials: [...factors.values()].map(({ credentialId, revision }) => ({
170
+ credentialId,
171
+ revision,
172
+ })),
173
+ };
174
+
175
+ const snapshot =
176
+ identifierRow === undefined || passwordRow === undefined
177
+ ? undefined
178
+ : yield* mapping.credential
179
+ .decode({
180
+ moduleId,
181
+ subject: subjectRow,
182
+ identifier: identifierRow,
183
+ credential: passwordRow,
184
+ })
185
+ .pipe(Effect.flatMap(P.snapshotPasswordCredential));
186
+
187
+ if (snapshot !== undefined)
188
+ ensure(
189
+ snapshot.revision.subjectId === subjectId &&
190
+ snapshot.credentialId === passwordRow?.[c.credentialId],
191
+ );
192
+
193
+ return {
194
+ nativeId,
195
+ subjectRow,
196
+ identifierRow,
197
+ passwordRow,
198
+ revision,
199
+ snapshot: snapshot === undefined ? undefined : { ...snapshot, revision },
200
+ now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0].engine_now)),
201
+ };
202
+ });
203
+
204
+ const prepare = <V, A>(value: V, project: P.PreparePasswordCommit<V, A>) =>
205
+ Effect.gen(function* () {
206
+ const journal = yield* CurrentCommitJournal;
207
+
208
+ const receipt = project(value, journal);
209
+
210
+ ensure(receipt?._tag === "PreparedCommit" && Effect.isEffect(receipt.read));
211
+ yield* registerSqlCommitReceipt(receipt);
212
+
213
+ return receipt;
214
+ });
215
+
216
+ const mutation = <A>(
217
+ original: P.PasswordMutationInput,
218
+ action: P.PasswordAction,
219
+ project: P.PreparePasswordCommit<P.PasswordMutationDecision, A>,
220
+ redemption?: Parameters<P.PasswordPersistence["Service"]["resetWithProof"]>[0]["redemption"],
221
+ ) =>
222
+ run(
223
+ Effect.gen(function* () {
224
+ const input = yield* snapshotPasswordMutation(original);
225
+ const nativeId = yield* mapping.subjectId.toNative(input.expectedRevision.subjectId);
226
+
227
+ const rows =
228
+ yield* sql`select ${rawSubject.fields("password_lock_")} from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} limit 2 ${batch === undefined ? lock : sql``}`;
229
+
230
+ if (rows.length === 0) return yield* prepare("rejected" as const, project);
231
+ ensure(rows.length === 1);
232
+ const locked = rawSubject.decode(rows[0]!, "password_lock_");
233
+
234
+ const state = yield* read(
235
+ input.moduleId,
236
+ input.expectedRevision.subjectId,
237
+ input.credential?.identifier,
238
+ locked,
239
+ );
240
+
241
+ if (state === undefined) return yield* prepare("rejected" as const, project);
242
+ const requirement = yield* s.decodeActionRequirement(state.subjectRow, action);
243
+
244
+ const valid = yield* validatePasswordMutation(
245
+ mapping,
246
+ input,
247
+ action,
248
+ {
249
+ subject: {
250
+ active: s.isActiveStatus(state.subjectRow[s.status]),
251
+ securityRevision: state.revision.securityRevision,
252
+ },
253
+ identifierCurrent: state.identifierRow !== undefined,
254
+ credentials: state.revision.credentials.map((entry) => ({ ...entry, active: true })),
255
+ snapshot: Effect.succeed(state.snapshot),
256
+ requirement: Effect.succeed(requirement),
257
+ },
258
+ state.now,
259
+ );
260
+
261
+ if (
262
+ valid === undefined ||
263
+ (action === "add-password"
264
+ ? state.passwordRow !== undefined
265
+ : state.snapshot === undefined ||
266
+ input.credential === undefined ||
267
+ !samePasswordCredentialSnapshot(state.snapshot, input.credential))
268
+ )
269
+ return yield* prepare("rejected" as const, project);
270
+ let proofValidity = sql`1 = 1`;
271
+
272
+ if (redemption !== undefined) {
273
+ if (proofs === undefined) return yield* unavailable();
274
+
275
+ const captured = {
276
+ ...redemption,
277
+ input: yield* Schema.decodeEffect(ProofRedemptionInput)(redemption.input),
278
+ };
279
+
280
+ if (!passwordProofRedemptionMatches({ ...input, redemption: captured }))
281
+ return yield* prepare("rejected" as const, project);
282
+ // Inherit the physical owner; application owners retain the exact consumed
283
+ // proof absence check after their callback.
284
+ const proof = yield* makeNativeProofStore(tables, proofs, batch !== undefined);
285
+ const redeemed = yield* proof.redeemLocked(captured.input);
286
+
287
+ const proofReceipt = captured.prepare(
288
+ redeemed.decision,
289
+ yield* CurrentCommitJournal,
290
+ (value) => value,
291
+ );
292
+
293
+ yield* registerSqlCommitReceipt(proofReceipt);
294
+ if (redeemed.decision === "rejected") return yield* prepare("rejected" as const, project);
295
+ proofValidity = redeemed.validUntil;
296
+ }
297
+ const mode = "interactive";
298
+
299
+ const credentialId =
300
+ input.credential?.credentialId ??
301
+ (yield* allocatePasswordValue(
302
+ mode,
303
+ mapping.allocateCredentialId,
304
+ mapping.allocateCredentialIdSync,
305
+ ));
306
+
307
+ const credentialRevision = yield* allocatePasswordValue(
308
+ mode,
309
+ mapping.allocateRevision,
310
+ mapping.allocateRevisionSync,
311
+ );
312
+
313
+ const verifierVersion = yield* allocatePasswordValue(
314
+ mode,
315
+ mapping.allocateRevision,
316
+ mapping.allocateRevisionSync,
317
+ );
318
+
319
+ const nextSecurityRevision = yield* allocatePasswordNextSecurityRevision(
320
+ mapping,
321
+ mode,
322
+ input.expectedRevision.securityRevision,
323
+ );
324
+
325
+ ensure(
326
+ nextSecurityRevision !== input.expectedRevision.securityRevision &&
327
+ credentialRevision !== input.credential?.credentialRevision &&
328
+ verifierVersion !== input.credential?.verifierVersion,
329
+ );
330
+
331
+ const freshUntil = (requirement: AuthenticationRequirement) => {
332
+ const deadlines = [
333
+ ...new Set(
334
+ input.authorization.evidence.proofs.map(
335
+ (proof) => DateTime.toEpochMillis(proof.verifiedAt) + requirement.maximumAgeMillis,
336
+ ),
337
+ ),
338
+ ]
339
+ .filter((time) => time > state.now)
340
+ .sort((a, b) => a - b);
341
+
342
+ return deadlines.find(
343
+ (time) => !passwordEvidenceSatisfiedAt(input.authorization.evidence, requirement, time),
344
+ );
345
+ };
346
+
347
+ const requestedDeadline = freshUntil(input.authorization.requirement),
348
+ currentDeadline = freshUntil(requirement);
349
+
350
+ ensure(requestedDeadline !== undefined && currentDeadline !== undefined);
351
+ const deadline = Math.min(requestedDeadline, currentDeadline);
352
+ const freshness = sql`${now} >= ${state.now} and ${now} < ${deadline} and ${proofValidity}`;
353
+
354
+ const stage = Effect.fnUntraced(function* (statement: Fragment) {
355
+ if (batch === undefined) ensure((yield* executeSqlChange(sql, statement)) === 1);
356
+ else {
357
+ yield* appendSqlBatchStatement(sql`${statement}`);
358
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));
359
+ }
360
+ });
361
+
362
+ if (batch !== undefined) {
363
+ if (
364
+ s.d1ActiveStatusValue === undefined ||
365
+ (a.status !== undefined && a.d1ActiveStatusValue === undefined)
366
+ )
367
+ return yield* unavailable();
368
+
369
+ const factors = state.revision.credentials.map(
370
+ (factor) =>
371
+ sql`exists(select 1 from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, factor.credentialId)} and ${exact(rawAuthority, a.revision, factor.revision)} ${a.status === undefined ? sql`` : sql`and ${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`})`,
372
+ );
373
+
374
+ const active =
375
+ a.status === undefined
376
+ ? sql`1 = 1`
377
+ : sql`${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`;
378
+
379
+ const condition = sql.and([
380
+ sql`exists(select 1 from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, input.expectedRevision.securityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, s.d1ActiveStatusValue)})`,
381
+ sql`(select count(*) from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${active}) = ${factors.length}`,
382
+ ...factors,
383
+ freshness,
384
+ ]);
385
+
386
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, condition));
387
+ if (input.credential !== undefined) {
388
+ if (i.d1CurrentCondition === undefined) return yield* unavailable();
389
+ yield* appendSqlBatchStatement(
390
+ sqlBatchAssertion(
391
+ sql,
392
+ sql`exists(select 1 from ${tables(i.table).name} where ${exact(tables(i.table), i.namespace, input.credential.identifier.namespace)} and ${exact(tables(i.table), i.value, input.credential.identifier.value)} and ${subjectKey(tables(i.table), i.subjectId, nativeId)} and ${tables.expression(i.d1CurrentCondition({ identifier: input.credential.identifier, nativeSubjectId: nativeId }))})`,
393
+ ),
394
+ );
395
+ }
396
+ }
397
+ const revisions = { credentialId, credentialRevision, verifierVersion };
398
+
399
+ if (input.credential === undefined) {
400
+ yield* stage(
401
+ sql`${rawPassword.insert(c.encodeInsert({ moduleId: input.moduleId, subjectId: nativeId, replacement: input.replacement, ...revisions }))}`,
402
+ );
403
+ yield* stage(
404
+ sql`${rawAuthority.insert(a.encodeInsert({ subjectId: nativeId, credentialId, revision: credentialRevision }))}`,
405
+ );
406
+ } else {
407
+ const old = input.credential;
408
+
409
+ yield* stage(
410
+ sql`${rawPassword.update(c.encodeReplacement({ replacement: input.replacement, credentialRevision, verifierVersion }))} where ${subjectKey(rawPassword, c.subjectId, nativeId)} and ${exact(rawPassword, c.moduleId, input.moduleId)} and ${exact(rawPassword, c.credentialId, old.credentialId)} and ${exact(rawPassword, c.credentialRevision, old.credentialRevision)} and ${exact(rawPassword, c.verifierVersion, old.verifierVersion)} and ${exact(rawPassword, c.verifier, Redacted.value(old.verifier))} and ${exact(rawPassword, c.normalization, old.normalization)} and ${freshness}`,
411
+ );
412
+ yield* stage(
413
+ sql`${rawAuthority.update(a.encodeRevision(credentialRevision))} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, old.credentialId)} and ${exact(rawAuthority, a.revision, old.credentialRevision)}`,
414
+ );
415
+ }
416
+
417
+ const expectedFactors = state.revision.credentials
418
+ .filter((factor) => factor.credentialId !== credentialId)
419
+ .concat({ credentialId, revision: credentialRevision });
420
+
421
+ const finalPassword = sql`exists(select 1 from ${rawPassword.name} where ${subjectKey(rawPassword, c.subjectId, nativeId)} and ${exact(rawPassword, c.moduleId, input.moduleId)} and ${exact(rawPassword, c.credentialId, credentialId)} and ${exact(rawPassword, c.credentialRevision, credentialRevision)} and ${exact(rawPassword, c.verifierVersion, verifierVersion)} and ${exact(rawPassword, c.verifier, Redacted.value(input.replacement.verifier))} and ${exact(rawPassword, c.normalization, input.replacement.normalization)})`;
422
+
423
+ const canGuardResult =
424
+ (a.status === undefined || a.d1ActiveStatusValue !== undefined) &&
425
+ (input.credential === undefined || i.d1CurrentCondition !== undefined);
426
+
427
+ let resultingState: Fragment | undefined;
428
+
429
+ if (canGuardResult) {
430
+ const active =
431
+ a.status === undefined
432
+ ? sql`1 = 1`
433
+ : sql`${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`;
434
+
435
+ const conditions: Array<Fragment> = [
436
+ finalPassword,
437
+ freshness,
438
+ sql`(select count(*) from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${active}) = ${expectedFactors.length}`,
439
+ ...expectedFactors.map(
440
+ (factor) =>
441
+ sql`exists(select 1 from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, factor.credentialId)} and ${exact(rawAuthority, a.revision, factor.revision)} and ${active})`,
442
+ ),
443
+ ];
444
+
445
+ if (input.credential !== undefined) {
446
+ const expected = input.credential;
447
+ const identifierTable = tables(i.table);
448
+
449
+ ensure(i.d1CurrentCondition !== undefined);
450
+ conditions.push(
451
+ sql`exists(select 1 from ${identifierTable.name} where ${exact(identifierTable, i.namespace, expected.identifier.namespace)} and ${exact(identifierTable, i.value, expected.identifier.value)} and ${subjectKey(identifierTable, i.subjectId, nativeId)} and ${tables.expression(i.d1CurrentCondition({ identifier: expected.identifier, nativeSubjectId: nativeId }))})`,
452
+ sql`exists(select 1 from ${identifierTable.name} where ${exact(identifierTable, i.namespace, expected.identifier.namespace)} and ${exact(identifierTable, i.value, expected.identifier.value)} and ${subjectKey(identifierTable, i.subjectId, nativeId)} and ${exact(identifierTable, i.bindingRevision, expected.identifierBindingRevision)} and ${expected.identifierVerifiedAtMillis === undefined ? sql`${identifierTable.column(i.verifiedAt)} is null` : sql`${identifierTable.column(i.verifiedAt)} = ${identifierTable.value(i.verifiedAt, mapping.clock.encodeInstant(expected.identifierVerifiedAtMillis))}`})`,
453
+ );
454
+ }
455
+ resultingState = sql.and(conditions);
456
+ }
457
+ yield* stage(
458
+ sql`${rawSubject.update({ [s.securityRevision]: nextSecurityRevision })} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, input.expectedRevision.securityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, locked[s.status])} and ${freshness} and ${resultingState ?? sql`1 = 1`}`,
459
+ );
460
+ if (batch !== undefined) {
461
+ ensure(resultingState !== undefined);
462
+ yield* registerSqlBatchPostcondition({
463
+ name: "password-replacement-authority",
464
+ statement: sqlBatchAssertion(
465
+ sql,
466
+ sql.and([
467
+ resultingState,
468
+ sql`exists(select 1 from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, nextSecurityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, s.d1ActiveStatusValue)})`,
469
+ ]),
470
+ ),
471
+ });
472
+ } else if (Option.isSome(parent) || resultingState === undefined)
473
+ yield* registerSqlPostcondition({
474
+ name: "password-replacement-authority",
475
+ check: Effect.gen(function* () {
476
+ const final = yield* read(
477
+ input.moduleId,
478
+ input.expectedRevision.subjectId,
479
+ input.credential?.identifier,
480
+ );
481
+
482
+ ensure(
483
+ final !== undefined &&
484
+ s.isActiveStatus(final.subjectRow[s.status]) &&
485
+ final.revision.securityRevision === nextSecurityRevision &&
486
+ final.revision.credentials.length === expectedFactors.length &&
487
+ expectedFactors.every((factor) =>
488
+ final.revision.credentials.some(
489
+ (entry) =>
490
+ entry.credentialId === factor.credentialId &&
491
+ entry.revision === factor.revision,
492
+ ),
493
+ ) &&
494
+ final.now >= state.now &&
495
+ final.now < deadline,
496
+ );
497
+ const password = final.passwordRow;
498
+
499
+ ensure(
500
+ password !== undefined &&
501
+ password[c.credentialId] === credentialId &&
502
+ password[c.credentialRevision] === credentialRevision &&
503
+ password[c.verifierVersion] === verifierVersion &&
504
+ password[c.verifier] === Redacted.value(input.replacement.verifier) &&
505
+ password[c.normalization] === input.replacement.normalization,
506
+ );
507
+ if (input.credential !== undefined)
508
+ ensure(
509
+ final.snapshot !== undefined &&
510
+ final.snapshot.identifierBindingRevision ===
511
+ input.credential.identifierBindingRevision &&
512
+ final.snapshot.identifierVerifiedAtMillis ===
513
+ input.credential.identifierVerifiedAtMillis,
514
+ );
515
+ }).pipe(
516
+ Effect.mapError((cause) =>
517
+ PersistenceMappingError.make({ operation: "decode", cause }),
518
+ ),
519
+ ),
520
+ });
521
+
522
+ return yield* prepare("changed" as const, project);
523
+ }),
524
+ );
525
+
526
+ const credentials = yield* makePasswordCredentials(tables, mapping, {
527
+ mode: "interactive",
528
+ locking: false,
529
+ coordinated: Option.isSome(parent),
530
+ standaloneGuard: requireStandalone(unavailable, sql.transactionService),
531
+ });
532
+
533
+ const passwordPersistence: P.PasswordPersistence["Service"] = {
534
+ ...credentials,
535
+ readForSubject: (input) =>
536
+ executor.read(
537
+ Effect.map(read(input.moduleId, input.subjectId), (state) =>
538
+ state === undefined || !s.isActiveStatus(state.subjectRow[s.status])
539
+ ? Option.none()
540
+ : Option.fromUndefinedOr(state.snapshot),
541
+ ),
542
+ ),
543
+ recoveryTarget: (input) =>
544
+ executor.read(
545
+ Effect.gen(function* () {
546
+ const rows =
547
+ yield* sql`select ${identifier.fields("password_recovery_")} from ${identifier.name} where ${exact(identifier, i.namespace, input.identifier.namespace)} and ${exact(identifier, i.value, input.identifier.value)} limit 2`;
548
+
549
+ if (rows.length === 0) return Option.none();
550
+ ensure(rows.length === 1);
551
+ const row = identifier.decode(rows[0]!, "password_recovery_");
552
+
553
+ if (!i.isCurrent(row)) return Option.none();
554
+ const subjectId = yield* mapping.subjectId.toSubject(row[i.subjectId]);
555
+ const state = yield* read(input.moduleId, subjectId, input.identifier);
556
+
557
+ return state === undefined ||
558
+ !s.isActiveStatus(state.subjectRow[s.status]) ||
559
+ state.snapshot?.identifierVerifiedAtMillis === undefined
560
+ ? Option.none()
561
+ : Option.some(state.snapshot);
562
+ }),
563
+ ),
564
+ addIfAbsent: (input, project) => mutation(input, "add-password", project),
565
+ replaceIfCurrent: (input, project) => mutation(input, "change-password", project),
566
+ resetWithProof: (input, project) =>
567
+ mutation(input, "reset-password", project, input.redemption),
568
+ };
569
+
570
+ return { passwordPersistence };
571
+ });