@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
@@ -1,1523 +0,0 @@
1
- import {
2
- coordinateCommit,
3
- CurrentCommitJournal,
4
- hasCommitScope,
5
- type CommitJournal,
6
- type PreparedCommit,
7
- LifecycleHooks,
8
- HookConfigurationError,
9
- } from "@yielded/auth/Hooks";
10
- import type { LoginIdentifier } from "@yielded/auth/Identity";
11
- import {
12
- PasswordUnavailable,
13
- PasswordPersistence,
14
- type PasswordMutationInput,
15
- snapshotPasswordCredential,
16
- snapshotPasswordRequirement,
17
- snapshotPasswordRevision,
18
- type PasswordAction,
19
- type PasswordMutationDecision,
20
- } from "@yielded/auth/Password";
21
- import { reportPersistenceFailure } from "@yielded/auth/Persistence";
22
- import {
23
- type ProofCompletionPlan,
24
- type ProofCompletionInput,
25
- ProofUnavailable,
26
- } from "@yielded/auth/Proofs";
27
- import {
28
- snapshotAuthenticationEvidence,
29
- type AuthenticationEvidence,
30
- type AuthenticationRequirement,
31
- type SecurityRevision,
32
- } from "@yielded/auth/Sessions";
33
- import { Cause, Context, DateTime, Effect, Option, Redacted, Schema } from "effect";
34
- import type { SqlClient } from "effect/sql/SqlClient";
35
- import type * as SqlError from "effect/sql/SqlError";
36
-
37
- import { PersistenceMappingError } from "./mapping-error";
38
- import {
39
- type AnyPasswordPersistenceMapping,
40
- requiredPasswordConstraints,
41
- } from "./models/password-model";
42
- import { makeNativeSqlTables, sqlMapping, type NativeSqlTables } from "./native-sql-table";
43
- import {
44
- makePasswordCredentials,
45
- samePasswordCredentialSnapshot as sameCredentialSnapshot,
46
- } from "./password-credentials";
47
- import {
48
- CurrentPasswordPreparedTransaction,
49
- PasswordPreparedPostconditions,
50
- } from "./PasswordPreparedPostconditions";
51
- import {
52
- CurrentProofSql,
53
- type ProofSqlConfiguration,
54
- type ProofSqlDatabase,
55
- type makeProofKernel,
56
- } from "./proof-kernel";
57
- /* oxlint-disable no-explicit-any -- existing storage kernels erase foreign table shapes; domain errors remain typed. */
58
- import type { QueryFailure } from "./query-operations";
59
- import type { QueryOperations, SqlFragment, SqlColumn } from "./query-operations";
60
- import { NativeDatabase } from "./transaction-kernel";
61
-
62
- type AdapterFailure = QueryFailure | PersistenceMappingError | SqlError.SqlError;
63
-
64
- export interface PasswordSqlQuery<A = ReadonlyArray<any>> extends Effect.Effect<A, AdapterFailure> {
65
- readonly getSQL: () => ReturnType<QueryOperations["sql"]>;
66
- readonly from: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
67
- readonly where: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
68
- readonly limit: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
69
- readonly orderBy: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
70
- readonly for: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
71
- readonly set: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
72
- readonly values: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
73
- readonly returning: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
74
- readonly $returningId: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
75
- readonly onConflictDoNothing: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
76
- readonly onDuplicateKeyUpdate: (...args: ReadonlyArray<any>) => PasswordSqlQuery<A>;
77
- }
78
-
79
- export interface PasswordSqlDatabase {
80
- readonly select: (...args: ReadonlyArray<any>) => PasswordSqlQuery;
81
- readonly insert: (...args: ReadonlyArray<any>) => PasswordSqlQuery;
82
- readonly update: (...args: ReadonlyArray<any>) => PasswordSqlQuery;
83
- readonly delete: (...args: ReadonlyArray<any>) => PasswordSqlQuery;
84
- readonly transaction: <A, E, R>(
85
- body: (transaction: PasswordSqlDatabase) => Effect.Effect<A, E, R>,
86
- ) => Effect.Effect<A, E | SqlError.SqlError, R>;
87
- }
88
-
89
- export class CurrentPasswordSql extends Context.Service<CurrentPasswordSql, PasswordSqlDatabase>()(
90
- "effect-auth/CurrentPasswordSql",
91
- ) {}
92
-
93
- export interface PasswordSqlConfiguration {
94
- readonly mode: "interactive" | "synchronous";
95
- readonly locking: boolean;
96
- readonly standaloneGuard: Effect.Effect<void, PasswordUnavailable>;
97
- readonly coordinated?: boolean;
98
- readonly insertIfAbsent: (
99
- query: PasswordSqlQuery,
100
- selfKey: string,
101
- selfValue: unknown,
102
- ) => PasswordSqlQuery;
103
- readonly proof?: {
104
- readonly mapping: any;
105
- readonly configuration: ProofSqlConfiguration;
106
- };
107
- }
108
-
109
- type Database = PasswordSqlDatabase;
110
-
111
- export const makePasswordKernel = <
112
- Fragment extends SqlFragment = SqlFragment,
113
- Column extends SqlColumn = SqlColumn,
114
- >(
115
- operations: QueryOperations<Fragment, Column>,
116
- proofs: Pick<ReturnType<typeof makeProofKernel>, "completeProofPlanIn">,
117
- nativeTables: (client: SqlClient, database: object) => NativeSqlTables = (client) =>
118
- makeNativeSqlTables(client),
119
- ) => {
120
- type Mapping = AnyPasswordPersistenceMapping<Fragment>;
121
-
122
- const { and, eq, inArray, column, updateValues } = operations;
123
- const { completeProofPlanIn } = proofs;
124
- const unavailable = () => PasswordUnavailable.make({});
125
-
126
- const translateFailure = <A, E, R>(
127
- effect: Effect.Effect<A, E, R>,
128
- ): Effect.Effect<A, PasswordUnavailable, R> =>
129
- reportPersistenceFailure(
130
- effect,
131
- (error) =>
132
- Schema.is(PasswordUnavailable)(error) ||
133
- Schema.is(ProofUnavailable)(error) ||
134
- Schema.is(HookConfigurationError)(error),
135
- ).pipe(Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, () => unavailable()))));
136
-
137
- const nowMillis = DateTime.now.pipe(Effect.map(DateTime.toEpochMillis));
138
-
139
- const validConstraints = (mapping: Mapping) =>
140
- Object.entries(requiredPasswordConstraints).every(
141
- ([key, value]) =>
142
- mapping.constraints[key as keyof typeof requiredPasswordConstraints] === value,
143
- );
144
-
145
- const selectRows = (query: PasswordSqlQuery, locking: boolean) =>
146
- locking && typeof query.for === "function" ? query.for("update") : query;
147
-
148
- const subjectColumns = (mapping: Mapping) => ({
149
- id: column(mapping.subject.table, mapping.subject.id),
150
- status: column(mapping.subject.table, mapping.subject.status),
151
- securityRevision: column(mapping.subject.table, mapping.subject.securityRevision),
152
- });
153
-
154
- const identifierColumns = (mapping: Mapping) => ({
155
- namespace: column(mapping.identifier.table, mapping.identifier.namespace),
156
- value: column(mapping.identifier.table, mapping.identifier.value),
157
- subjectId: column(mapping.identifier.table, mapping.identifier.subjectId),
158
- verifiedAt: column(mapping.identifier.table, mapping.identifier.verifiedAt),
159
- bindingRevision: column(mapping.identifier.table, mapping.identifier.bindingRevision),
160
- });
161
-
162
- const credentialColumns = (mapping: Mapping) => ({
163
- moduleId: column(mapping.credential.table, mapping.credential.moduleId),
164
- subjectId: column(mapping.credential.table, mapping.credential.subjectId),
165
- credentialId: column(mapping.credential.table, mapping.credential.credentialId),
166
- credentialRevision: column(mapping.credential.table, mapping.credential.credentialRevision),
167
- verifierVersion: column(mapping.credential.table, mapping.credential.verifierVersion),
168
- verifier: column(mapping.credential.table, mapping.credential.verifier),
169
- normalization: column(mapping.credential.table, mapping.credential.normalization),
170
- });
171
-
172
- const authorityCredentialColumns = (mapping: Mapping) => ({
173
- subjectId: column(mapping.authorityCredential.table, mapping.authorityCredential.subjectId),
174
- credentialId: column(
175
- mapping.authorityCredential.table,
176
- mapping.authorityCredential.credentialId,
177
- ),
178
- revision: column(mapping.authorityCredential.table, mapping.authorityCredential.revision),
179
- });
180
-
181
- const commandColumns = (mapping: Mapping) => ({
182
- moduleId: column(mapping.command.table, mapping.command.moduleId),
183
- commandId: column(mapping.command.table, mapping.command.commandId),
184
- action: column(mapping.command.table, mapping.command.action),
185
- bindingDigest: column(mapping.command.table, mapping.command.bindingDigest),
186
- decision: column(mapping.command.table, mapping.command.decision),
187
- retentionUntil: column(mapping.command.table, mapping.command.retentionUntil),
188
- });
189
-
190
- const allocate = <A>(
191
- mode: PasswordSqlConfiguration["mode"],
192
- asyncValue: Effect.Effect<A, PersistenceMappingError> | undefined,
193
- syncValue: (() => A) | undefined,
194
- ): Effect.Effect<A, PasswordUnavailable | PersistenceMappingError> => {
195
- if (mode === "synchronous")
196
- return syncValue === undefined
197
- ? Effect.fail(unavailable())
198
- : Effect.try({
199
- try: syncValue,
200
- catch: (cause) => new PersistenceMappingError({ operation: "mapping", cause }),
201
- });
202
- if (asyncValue !== undefined) return asyncValue;
203
-
204
- return syncValue === undefined
205
- ? Effect.fail(unavailable())
206
- : Effect.try({
207
- try: syncValue,
208
- catch: (cause) => new PersistenceMappingError({ operation: "mapping", cause }),
209
- });
210
- };
211
-
212
- const allocateNextSecurityRevision = (
213
- mapping: Mapping,
214
- mode: PasswordSqlConfiguration["mode"],
215
- current: SecurityRevision,
216
- ) => {
217
- const asyncValue = mapping.subject.nextSecurityRevision?.(current);
218
-
219
- const syncValue =
220
- mapping.subject.nextSecurityRevisionSync === undefined
221
- ? undefined
222
- : () => mapping.subject.nextSecurityRevisionSync!(current);
223
-
224
- return allocate(
225
- mode,
226
- asyncValue ?? mapping.allocateRevision,
227
- syncValue ?? mapping.allocateRevisionSync,
228
- );
229
- };
230
-
231
- const sameIdentifier = (left: LoginIdentifier, right: LoginIdentifier) =>
232
- left.namespace === right.namespace && left.value === right.value;
233
-
234
- const evidenceSatisfiedAt = (
235
- evidence: AuthenticationEvidence,
236
- requirement: AuthenticationRequirement,
237
- now: number,
238
- ): boolean => {
239
- if (evidence.proofs.length > 64 || evidence.revision.credentials.length > 64) return false;
240
- const revisions = new Map<string, string>();
241
-
242
- for (const item of evidence.revision.credentials) {
243
- if (revisions.has(item.credentialId)) return false;
244
- revisions.set(item.credentialId, item.revision);
245
- }
246
- if (evidence.proofs.some((proof) => !revisions.has(proof.credentialId))) return false;
247
- if (evidence.proofs.some((proof) => now < DateTime.toEpochMillis(proof.verifiedAt)))
248
- return false;
249
-
250
- const eligible = evidence.proofs.filter((proof) => {
251
- const age = now - DateTime.toEpochMillis(proof.verifiedAt);
252
-
253
- return age >= 0 && age < requirement.maximumAgeMillis;
254
- });
255
-
256
- const factors = new Set(eligible.flatMap((proof) => proof.factors));
257
- const credentials = new Set(eligible.map((proof) => proof.credentialId));
258
-
259
- return requirement.alternatives.some(
260
- (alternative) =>
261
- alternative.factors.every((factor) => factors.has(factor)) &&
262
- credentials.size >= alternative.minimumCredentials &&
263
- eligible.some(
264
- (proof) =>
265
- (!alternative.userVerified || proof.userVerified) &&
266
- (!alternative.phishingResistant || proof.phishingResistant),
267
- ),
268
- );
269
- };
270
-
271
- const snapshotMutationInput = Effect.fn("DrizzlePassword.snapshotMutationInput")(function* (
272
- input: PasswordMutationInput,
273
- ) {
274
- const expectedRevision = snapshotPasswordRevision(input.expectedRevision);
275
-
276
- const evidence = yield* snapshotAuthenticationEvidence(input.authorization.evidence).pipe(
277
- Effect.mapError(unavailable),
278
- );
279
-
280
- const requirement = yield* snapshotPasswordRequirement(input.authorization.requirement);
281
-
282
- const credential =
283
- input.credential === undefined
284
- ? undefined
285
- : yield* snapshotPasswordCredential(input.credential);
286
-
287
- return Object.freeze({
288
- ...input,
289
- expectedRevision,
290
- replacement: Object.freeze({
291
- verifier: Redacted.make(Redacted.value(input.replacement.verifier)),
292
- normalization: input.replacement.normalization,
293
- }),
294
- invalidation: Object.freeze({ ...input.invalidation }),
295
- ...(credential === undefined ? {} : { credential }),
296
- authorization: Object.freeze({
297
- challenge: Object.freeze({
298
- ...input.authorization.challenge,
299
- revision: snapshotPasswordRevision(input.authorization.challenge.revision),
300
- }),
301
- evidence,
302
- requirement,
303
- }),
304
- });
305
- });
306
-
307
- const lockSubject = Effect.fn("DrizzlePassword.lockSubject")(function* (
308
- mapping: Mapping,
309
- subjectId: string,
310
- locking: boolean,
311
- ) {
312
- const database = yield* CurrentPasswordSql;
313
-
314
- const nativeSubjectId = yield* mapping.subjectId.toNative(subjectId as any);
315
- const c = subjectColumns(mapping);
316
-
317
- const rows = yield* selectRows(
318
- database.select().from(mapping.subject.table).where(eq(c.id, nativeSubjectId)).limit(1),
319
- locking,
320
- );
321
-
322
- return { nativeSubjectId, row: rows[0] };
323
- });
324
-
325
- const lockIdentifier = Effect.fn("Drizzle.lockIdentifier")(function* (
326
- mapping: Mapping,
327
- identifier: LoginIdentifier,
328
- locking: boolean,
329
- ) {
330
- const database = yield* CurrentPasswordSql;
331
-
332
- const c = identifierColumns(mapping);
333
-
334
- return yield* selectRows(
335
- database
336
- .select()
337
- .from(mapping.identifier.table)
338
- .where(and(eq(c.namespace, identifier.namespace), eq(c.value, identifier.value)))
339
- .limit(1),
340
- locking,
341
- );
342
- });
343
-
344
- const readPasswordCredential = Effect.fn("Drizzle.readPasswordCredential")(function* (
345
- mapping: Mapping,
346
- moduleId: string,
347
- nativeSubjectId: unknown,
348
- locking: boolean,
349
- ) {
350
- const database = yield* CurrentPasswordSql;
351
-
352
- const c = credentialColumns(mapping);
353
-
354
- return yield* selectRows(
355
- database
356
- .select()
357
- .from(mapping.credential.table)
358
- .where(and(eq(c.moduleId, moduleId), eq(c.subjectId, nativeSubjectId)))
359
- .limit(1),
360
- locking,
361
- );
362
- });
363
-
364
- const resolveCredential = Effect.fn("DrizzlePassword.resolveCredential")(function* (
365
- mapping: Mapping,
366
- moduleId: string,
367
- identifier: LoginIdentifier,
368
- requestedSubjectId: string | undefined,
369
- locking: boolean,
370
- ) {
371
- const database = yield* CurrentPasswordSql;
372
-
373
- // The unlocked lookup only discovers the prospective subject. The canonical
374
- // protected order starts with the subject and then rechecks the identifier.
375
- const discovered = (yield* lockIdentifier(mapping, identifier, false))[0];
376
-
377
- if (discovered === undefined || !mapping.identifier.isCurrent(discovered)) return undefined;
378
- const discoveredNative = discovered[mapping.identifier.subjectId];
379
-
380
- const subjectRows = yield* selectRows(
381
- database
382
- .select()
383
- .from(mapping.subject.table)
384
- .where(eq(subjectColumns(mapping).id, discoveredNative))
385
- .limit(1),
386
- locking,
387
- );
388
-
389
- const subject = subjectRows[0];
390
-
391
- if (subject === undefined || !mapping.subject.isActiveStatus(subject[mapping.subject.status]))
392
- return undefined;
393
- const identifiers = yield* lockIdentifier(mapping, identifier, locking);
394
- const identifierRow = identifiers[0];
395
-
396
- if (
397
- identifierRow === undefined ||
398
- !mapping.identifier.isCurrent(identifierRow) ||
399
- !mapping.subjectId.equals(discoveredNative, identifierRow[mapping.identifier.subjectId])
400
- )
401
- return undefined;
402
- const subjectId = yield* mapping.subjectId.toSubject(discoveredNative);
403
-
404
- if (requestedSubjectId !== undefined && requestedSubjectId !== subjectId) return undefined;
405
- const credentials = yield* readPasswordCredential(mapping, moduleId, discoveredNative, locking);
406
- const credential = credentials[0];
407
-
408
- if (credential === undefined)
409
- return { nativeSubjectId: discoveredNative, subject, identifier: identifierRow };
410
-
411
- const snapshot = yield* mapping.credential
412
- .decode({ moduleId, subject, identifier: identifierRow, credential })
413
- .pipe(Effect.flatMap(snapshotPasswordCredential));
414
-
415
- return {
416
- nativeSubjectId: discoveredNative,
417
- subject,
418
- identifier: identifierRow,
419
- credential,
420
- snapshot,
421
- };
422
- });
423
-
424
- const owned = <A, E, R>(
425
- database: Database,
426
- mapping: Mapping,
427
- configuration: PasswordSqlConfiguration,
428
- body: Effect.Effect<A, E, R>,
429
- ) => {
430
- if (!validConstraints(mapping)) return Effect.fail(unavailable());
431
-
432
- const run = coordinateCommit(
433
- () =>
434
- database.transaction((transaction) =>
435
- body.pipe(
436
- Effect.provideService(CurrentPasswordSql, transaction),
437
- Effect.provideService(CurrentProofSql, transaction as unknown as ProofSqlDatabase),
438
- ),
439
- ),
440
- { mode: configuration.mode },
441
- ).pipe(Effect.map((result) => result.value));
442
-
443
- return configuration.coordinated !== true
444
- ? Effect.gen(function* () {
445
- if (yield* hasCommitScope) return yield* unavailable();
446
- yield* configuration.standaloneGuard;
447
-
448
- return yield* run;
449
- })
450
- : run;
451
- };
452
-
453
- // A coordinator that accepts postconditions re-runs this check against its
454
- // current transaction after application work, before commit.
455
- const registerFinal = Effect.fnUntraced(function* <E>(
456
- check: Effect.Effect<boolean, E, CurrentPasswordSql>,
457
- ) {
458
- const postconditions = yield* Effect.serviceOption(PasswordPreparedPostconditions);
459
-
460
- if (Option.isNone(postconditions)) return;
461
-
462
- const postcondition = Effect.gen(function* () {
463
- const transaction = yield* CurrentPasswordPreparedTransaction;
464
-
465
- if (!(yield* check.pipe(Effect.provideService(CurrentPasswordSql, transaction))))
466
- return yield* unavailable();
467
- }).pipe(translateFailure);
468
-
469
- if (!postconditions.value.register(postcondition)) return yield* unavailable();
470
- });
471
-
472
- const safeRead = <A, E, R>(
473
- database: Database,
474
- configuration: PasswordSqlConfiguration,
475
- body: Effect.Effect<A, E, R>,
476
- ) =>
477
- Effect.gen(function* () {
478
- if (configuration.coordinated !== true) {
479
- if (yield* hasCommitScope) return yield* unavailable();
480
- yield* configuration.standaloneGuard;
481
- }
482
-
483
- return yield* database.transaction((transaction) =>
484
- body.pipe(
485
- Effect.provideService(CurrentPasswordSql, transaction),
486
- Effect.provideService(CurrentProofSql, transaction as unknown as ProofSqlDatabase),
487
- ),
488
- );
489
- });
490
-
491
- const proofCompletionMatchesPassword = (
492
- input: PasswordMutationInput & { readonly completion: ProofCompletionPlan },
493
- ) => {
494
- const completion = input.completion.input;
495
- const binding = completion.binding;
496
-
497
- if (
498
- completion.moduleId !== `${input.moduleId}/reset` ||
499
- completion.purpose !== "password-reset" ||
500
- binding._tag !== "Subject" ||
501
- input.credential === undefined ||
502
- binding.revision.subjectId !== input.expectedRevision.subjectId ||
503
- binding.revision.securityRevision !== input.expectedRevision.securityRevision ||
504
- !sameIdentifier(binding.identifier, input.credential.identifier)
505
- )
506
- return false;
507
-
508
- const expected = [...input.expectedRevision.credentials].sort((left, right) =>
509
- left.credentialId.localeCompare(right.credentialId),
510
- );
511
-
512
- const actual = [...binding.revision.credentials].sort((left, right) =>
513
- left.credentialId.localeCompare(right.credentialId),
514
- );
515
-
516
- return (
517
- expected.length === actual.length &&
518
- expected.every(
519
- (item, index) =>
520
- item.credentialId === actual[index]!.credentialId &&
521
- item.revision === actual[index]!.revision,
522
- )
523
- );
524
- };
525
-
526
- const probeProofCompletion = Effect.fn("Drizzle.probeProofCompletion")(function* (
527
- configuration: PasswordSqlConfiguration,
528
- input: ProofCompletionInput,
529
- ) {
530
- const database = yield* CurrentPasswordSql;
531
-
532
- if (configuration.proof === undefined) return yield* Effect.fail(unavailable());
533
- const validProbe = { _tag: "PasswordProofCompletionValid" } as const;
534
-
535
- const plan: ProofCompletionPlan = {
536
- input,
537
- prepare: (decision, journal, project) => journal.prepare(project(decision)),
538
- };
539
-
540
- const probe = coordinateCommit(
541
- () =>
542
- database.transaction((transaction) =>
543
- completeProofPlanIn(
544
- configuration.proof!.mapping,
545
- configuration.proof!.configuration,
546
- plan,
547
- Effect.fail(validProbe),
548
- () => false,
549
- ).pipe(
550
- Effect.provideService(CurrentProofSql, transaction as unknown as ProofSqlDatabase),
551
- ),
552
- ),
553
- { mode: configuration.mode },
554
- );
555
-
556
- if (configuration.coordinated === true || (yield* hasCommitScope)) return yield* unavailable();
557
- yield* configuration.standaloneGuard;
558
-
559
- return yield* probe.pipe(
560
- Effect.as(false),
561
- Effect.catchCause((cause) => {
562
- const reason = cause.reasons[0];
563
-
564
- return cause.reasons.length === 1 &&
565
- reason !== undefined &&
566
- Cause.isFailReason(reason) &&
567
- reason.error === validProbe
568
- ? Effect.succeed(true)
569
- : Effect.failCause(cause);
570
- }),
571
- );
572
- });
573
-
574
- const validateMutationAuthority = Effect.fn("DrizzlePassword.validateMutationAuthority")(
575
- function* (
576
- mapping: Mapping,
577
- configuration: PasswordSqlConfiguration,
578
- input: PasswordMutationInput,
579
- action: PasswordAction,
580
- ) {
581
- const database = yield* CurrentPasswordSql;
582
-
583
- const locked = yield* lockSubject(
584
- mapping,
585
- input.expectedRevision.subjectId,
586
- configuration.locking,
587
- );
588
-
589
- const row = locked.row;
590
-
591
- if (
592
- row === undefined ||
593
- !mapping.subject.isActiveStatus(row[mapping.subject.status]) ||
594
- row[mapping.subject.securityRevision] !== input.expectedRevision.securityRevision
595
- )
596
- return undefined;
597
- if (
598
- input.authorization.challenge.moduleId !== input.moduleId ||
599
- input.authorization.challenge.action !== action ||
600
- input.authorization.challenge.commandId !== input.commandId ||
601
- input.authorization.challenge.revision.subjectId !== input.expectedRevision.subjectId ||
602
- input.authorization.challenge.revision.securityRevision !==
603
- input.expectedRevision.securityRevision ||
604
- (input.authorization.evidence.flowId as string) !== (input.commandId as string) ||
605
- input.authorization.evidence.bindingDigest !==
606
- input.authorization.challenge.bindingDigest ||
607
- input.authorization.evidence.revision.subjectId !== input.expectedRevision.subjectId ||
608
- input.authorization.evidence.revision.securityRevision !==
609
- input.expectedRevision.securityRevision ||
610
- (action === "add-password" &&
611
- (input.credential !== undefined ||
612
- input.authorization.challenge.targetCredentialId !== undefined))
613
- )
614
- return undefined;
615
- if (
616
- input.expectedRevision.credentials.some(
617
- (expected) =>
618
- !input.authorization.evidence.revision.credentials.some(
619
- (actual) =>
620
- actual.credentialId === expected.credentialId &&
621
- actual.revision === expected.revision,
622
- ),
623
- )
624
- )
625
- return undefined;
626
- if (input.credential !== undefined) {
627
- const identifier = (yield* lockIdentifier(
628
- mapping,
629
- input.credential.identifier,
630
- configuration.locking,
631
- ))[0];
632
-
633
- if (
634
- identifier === undefined ||
635
- !mapping.identifier.isCurrent(identifier) ||
636
- !mapping.subjectId.equals(
637
- identifier[mapping.identifier.subjectId],
638
- locked.nativeSubjectId,
639
- ) ||
640
- identifier[mapping.identifier.bindingRevision] !==
641
- input.credential.identifierBindingRevision
642
- )
643
- return undefined;
644
- }
645
-
646
- const allExpected = [
647
- ...input.expectedRevision.credentials,
648
- ...input.authorization.evidence.revision.credentials,
649
- ];
650
-
651
- const expected = new Map(allExpected.map((item) => [item.credentialId, item]));
652
-
653
- const ac = authorityCredentialColumns(mapping);
654
-
655
- const credentialRows =
656
- expected.size === 0
657
- ? []
658
- : yield* selectRows(
659
- database
660
- .select()
661
- .from(mapping.authorityCredential.table)
662
- .where(
663
- and(
664
- eq(ac.subjectId, locked.nativeSubjectId),
665
- inArray(ac.credentialId, [...expected.keys()]),
666
- ),
667
- )
668
- .orderBy(ac.credentialId),
669
- configuration.locking,
670
- );
671
-
672
- if (credentialRows.length !== expected.size) return undefined;
673
- // Database collation need not match JavaScript locale ordering.
674
- for (const actual of credentialRows) {
675
- const wanted = expected.get(actual[mapping.authorityCredential.credentialId]);
676
-
677
- if (
678
- wanted === undefined ||
679
- actual[mapping.authorityCredential.revision] !== wanted.revision ||
680
- (mapping.authorityCredential.status !== undefined &&
681
- mapping.authorityCredential.isActiveStatus?.(
682
- actual[mapping.authorityCredential.status],
683
- ) !== true)
684
- )
685
- return undefined;
686
- expected.delete(wanted.credentialId);
687
- }
688
- if (expected.size !== 0) return undefined;
689
- if (input.credential !== undefined) {
690
- const identifier = (yield* lockIdentifier(mapping, input.credential.identifier, false))[0];
691
-
692
- const credential = (yield* readPasswordCredential(
693
- mapping,
694
- input.moduleId,
695
- locked.nativeSubjectId,
696
- configuration.locking,
697
- ))[0];
698
-
699
- if (identifier === undefined || credential === undefined) return undefined;
700
-
701
- const snapshot = yield* mapping.credential.decode({
702
- moduleId: input.moduleId,
703
- subject: row,
704
- identifier,
705
- credential,
706
- });
707
-
708
- if (!sameCredentialSnapshot(snapshot, input.credential)) return undefined;
709
- }
710
- const currentRequirement = yield* mapping.subject.decodeActionRequirement(row, action);
711
- const now = yield* nowMillis;
712
-
713
- if (
714
- !evidenceSatisfiedAt(input.authorization.evidence, input.authorization.requirement, now) ||
715
- !evidenceSatisfiedAt(input.authorization.evidence, currentRequirement, now)
716
- )
717
- return undefined;
718
- if (
719
- (input.invalidation.existingSessions === "immediate" ||
720
- input.invalidation.existingSessions === "cache-expiry") &&
721
- mapping.sessionInvalidation !== "same-authority-immediate"
722
- )
723
- return undefined;
724
-
725
- return { ...locked, now };
726
- },
727
- );
728
-
729
- const commandExists = Effect.fn("Drizzle.commandExists")(function* (
730
- mapping: Mapping,
731
- moduleId: string,
732
- commandId: string,
733
- locking: boolean,
734
- ) {
735
- const database = yield* CurrentPasswordSql;
736
-
737
- const c = commandColumns(mapping);
738
-
739
- return yield* selectRows(
740
- database
741
- .select()
742
- .from(mapping.command.table)
743
- .where(and(eq(c.moduleId, moduleId), eq(c.commandId, commandId)))
744
- .limit(1),
745
- locking,
746
- );
747
- });
748
-
749
- const insertCommand = Effect.fn("Drizzle.insertCommand")(function* (
750
- mapping: Mapping,
751
- input: PasswordMutationInput,
752
- action: PasswordAction,
753
- now: number,
754
- ) {
755
- const database = yield* CurrentPasswordSql;
756
-
757
- return yield* database.insert(mapping.command.table).values(
758
- mapping.command.encodeInsert({
759
- moduleId: input.moduleId,
760
- commandId: input.commandId,
761
- action,
762
- bindingDigest: input.authorization.challenge.bindingDigest,
763
- decision: "changed",
764
- retentionUntilMillis: now + mapping.commandRetentionMillis,
765
- }),
766
- );
767
- });
768
-
769
- const mutationPostconditions = Effect.fn("DrizzlePassword.mutationPostconditions")(function* (
770
- mapping: Mapping,
771
- input: PasswordMutationInput,
772
- nativeSubjectId: unknown,
773
- subject: any,
774
- authorityCredential: any,
775
- now: number,
776
- ) {
777
- if (
778
- subject === undefined ||
779
- !mapping.subject.isActiveStatus(subject[mapping.subject.status]) ||
780
- authorityCredential === undefined ||
781
- (mapping.authorityCredential.status !== undefined &&
782
- mapping.authorityCredential.isActiveStatus?.(
783
- authorityCredential[mapping.authorityCredential.status],
784
- ) !== true)
785
- )
786
- return false;
787
- if (input.credential !== undefined) {
788
- const identifier = (yield* lockIdentifier(mapping, input.credential.identifier, false))[0];
789
-
790
- if (
791
- identifier === undefined ||
792
- !mapping.identifier.isCurrent(identifier) ||
793
- !mapping.subjectId.equals(identifier[mapping.identifier.subjectId], nativeSubjectId) ||
794
- identifier[mapping.identifier.bindingRevision] !==
795
- input.credential.identifierBindingRevision
796
- )
797
- return false;
798
-
799
- const credential = (yield* readPasswordCredential(
800
- mapping,
801
- input.moduleId,
802
- nativeSubjectId,
803
- false,
804
- ))[0];
805
-
806
- if (credential === undefined) return false;
807
-
808
- const decoded = yield* mapping.credential.decode({
809
- moduleId: input.moduleId,
810
- subject,
811
- identifier,
812
- credential,
813
- });
814
-
815
- if (decoded.identifierVerifiedAtMillis !== input.credential.identifierVerifiedAtMillis)
816
- return false;
817
- }
818
- const rows = yield* commandExists(mapping, input.moduleId, input.commandId, false);
819
- const row = rows[0];
820
-
821
- return (
822
- rows.length === 1 &&
823
- row[mapping.command.action] === input.authorization.challenge.action &&
824
- row[mapping.command.bindingDigest] === input.authorization.challenge.bindingDigest &&
825
- row[mapping.command.decision] === "changed" &&
826
- (yield* mapping.decodeInstant(row[mapping.command.retentionUntil])) ===
827
- now + mapping.commandRetentionMillis
828
- );
829
- });
830
-
831
- const addPasswordIn = Effect.fn("DrizzlePassword.addPasswordIn")(function* (
832
- mapping: Mapping,
833
- configuration: PasswordSqlConfiguration,
834
- input: PasswordMutationInput,
835
- revisions: {
836
- readonly credentialId: string;
837
- readonly credentialRevision: SecurityRevision;
838
- readonly verifierVersion: SecurityRevision;
839
- readonly nextSecurityRevision: SecurityRevision;
840
- },
841
- commandNow?: number,
842
- ) {
843
- const database = yield* CurrentPasswordSql;
844
-
845
- const { credentialId, credentialRevision, verifierVersion, nextSecurityRevision } = revisions;
846
-
847
- const authority = yield* validateMutationAuthority(
848
- mapping,
849
- configuration,
850
- input,
851
- "add-password",
852
- );
853
-
854
- if (authority === undefined) return false;
855
- if ((yield* commandExists(mapping, input.moduleId, input.commandId, true)).length) return false;
856
- if (
857
- (yield* readPasswordCredential(mapping, input.moduleId, authority.nativeSubjectId, true))
858
- .length
859
- )
860
- return false;
861
-
862
- yield* database.insert(mapping.credential.table).values(
863
- mapping.credential.encodeInsert({
864
- moduleId: input.moduleId,
865
- subjectId: authority.nativeSubjectId,
866
- credentialId,
867
- credentialRevision,
868
- verifierVersion,
869
- replacement: input.replacement,
870
- }),
871
- );
872
- yield* database.insert(mapping.authorityCredential.table).values(
873
- mapping.authorityCredential.encodeInsert({
874
- subjectId: authority.nativeSubjectId,
875
- credentialId,
876
- revision: credentialRevision,
877
- }),
878
- );
879
- yield* database
880
- .update(mapping.subject.table)
881
- .set(updateValues([[mapping.subject.securityRevision, nextSecurityRevision]]))
882
- .where(
883
- and(
884
- eq(subjectColumns(mapping).id, authority.nativeSubjectId),
885
- eq(subjectColumns(mapping).securityRevision, input.expectedRevision.securityRevision),
886
- ),
887
- );
888
- yield* insertCommand(mapping, input, "add-password", commandNow ?? authority.now);
889
-
890
- const applied = checkMutationApplied(
891
- mapping,
892
- input,
893
- authority.nativeSubjectId,
894
- revisions,
895
- commandNow ?? authority.now,
896
- );
897
-
898
- if (!(yield* applied)) return yield* unavailable();
899
- yield* registerFinal(applied);
900
-
901
- return true;
902
- });
903
-
904
- const makeSqlPasswordPersistence = Effect.fn("makeSqlPasswordPersistence")(function* (
905
- mapping: Mapping,
906
- configuration: PasswordSqlConfiguration,
907
- ): Effect.fn.Return<
908
- PasswordPersistence["Service"],
909
- PasswordUnavailable,
910
- LifecycleHooks | CurrentPasswordSql | NativeDatabase
911
- > {
912
- const database = yield* CurrentPasswordSql;
913
-
914
- if (!configuration.coordinated)
915
- yield* (
916
- operations.validateStorage?.({
917
- ...mapping,
918
- proof: configuration.proof?.mapping,
919
- }) ?? Effect.void
920
- ).pipe(Effect.mapError(unavailable));
921
- const hooks = yield* LifecycleHooks;
922
-
923
- if (!validConstraints(mapping)) return yield* unavailable();
924
- const root = yield* NativeDatabase;
925
-
926
- const credentials = yield* makePasswordCredentials(
927
- yield* sqlMapping(() => nativeTables(root.$client.withoutTransforms(), root)).pipe(
928
- translateFailure,
929
- ),
930
- mapping,
931
- configuration,
932
- );
933
-
934
- return PasswordPersistence.of({
935
- ...credentials,
936
- readForSubject: (input) =>
937
- safeRead(
938
- database,
939
- configuration,
940
- Effect.gen(function* () {
941
- const transaction = yield* CurrentPasswordSql;
942
-
943
- const locked = yield* lockSubject(mapping, input.subjectId, false);
944
-
945
- if (
946
- locked.row === undefined ||
947
- !mapping.subject.isActiveStatus(locked.row[mapping.subject.status])
948
- )
949
- return Option.none();
950
-
951
- const credential = (yield* readPasswordCredential(
952
- mapping,
953
- input.moduleId,
954
- locked.nativeSubjectId,
955
- false,
956
- ))[0];
957
-
958
- if (credential === undefined) return Option.none();
959
- const ic = identifierColumns(mapping);
960
-
961
- const identifiers = yield* transaction
962
- .select()
963
- .from(mapping.identifier.table)
964
- .where(eq(ic.subjectId, locked.nativeSubjectId));
965
-
966
- const identifier = identifiers.find((row: any) => mapping.identifier.isCurrent(row));
967
-
968
- if (identifier === undefined) return Option.none();
969
-
970
- const snapshot = yield* mapping.credential
971
- .decode({
972
- moduleId: input.moduleId,
973
- subject: locked.row,
974
- identifier,
975
- credential,
976
- })
977
- .pipe(Effect.flatMap(snapshotPasswordCredential));
978
-
979
- return Option.some(snapshot);
980
- }),
981
- ).pipe(
982
- Effect.provideService(CurrentPasswordSql, database),
983
- Effect.provideService(LifecycleHooks, hooks),
984
- translateFailure,
985
- ),
986
- recoveryTarget: (input) =>
987
- safeRead(
988
- database,
989
- configuration,
990
- Effect.gen(function* () {
991
- const resolved = yield* resolveCredential(
992
- mapping,
993
- input.moduleId,
994
- input.identifier,
995
- undefined,
996
- false,
997
- );
998
-
999
- return resolved?.snapshot === undefined ||
1000
- resolved.snapshot.identifierVerifiedAtMillis === undefined
1001
- ? Option.none()
1002
- : Option.some(resolved.snapshot);
1003
- }),
1004
- ).pipe(
1005
- Effect.provideService(CurrentPasswordSql, database),
1006
- Effect.provideService(LifecycleHooks, hooks),
1007
- translateFailure,
1008
- ),
1009
- addIfAbsent: (uncaptured, prepare) =>
1010
- Effect.gen(function* () {
1011
- const input = yield* snapshotMutationInput(uncaptured);
1012
-
1013
- const credentialId = yield* allocate(
1014
- configuration.mode,
1015
- mapping.allocateCredentialId,
1016
- mapping.allocateCredentialIdSync,
1017
- );
1018
-
1019
- const credentialRevision = yield* allocate(
1020
- configuration.mode,
1021
- mapping.allocateRevision,
1022
- mapping.allocateRevisionSync,
1023
- );
1024
-
1025
- const verifierVersion = yield* allocate(
1026
- configuration.mode,
1027
- mapping.allocateRevision,
1028
- mapping.allocateRevisionSync,
1029
- );
1030
-
1031
- const nextSecurityRevision = yield* allocateNextSecurityRevision(
1032
- mapping,
1033
- configuration.mode,
1034
- input.expectedRevision.securityRevision,
1035
- );
1036
-
1037
- if (nextSecurityRevision === input.expectedRevision.securityRevision)
1038
- return yield* unavailable();
1039
-
1040
- return yield* owned(
1041
- database,
1042
- mapping,
1043
- configuration,
1044
- Effect.gen(function* () {
1045
- const journal = yield* CurrentCommitJournal;
1046
-
1047
- const changed = yield* addPasswordIn(mapping, configuration, input, {
1048
- credentialId,
1049
- credentialRevision,
1050
- verifierVersion,
1051
- nextSecurityRevision,
1052
- });
1053
-
1054
- return prepare(changed ? "changed" : "rejected", journal);
1055
- }),
1056
- );
1057
- }).pipe(
1058
- Effect.provideService(CurrentPasswordSql, database),
1059
- Effect.provideService(LifecycleHooks, hooks),
1060
- translateFailure,
1061
- ),
1062
- replaceIfCurrent: (uncaptured, prepare) =>
1063
- Effect.gen(function* () {
1064
- const input = yield* snapshotMutationInput(uncaptured);
1065
-
1066
- const credentialRevision = yield* allocate(
1067
- configuration.mode,
1068
- mapping.allocateRevision,
1069
- mapping.allocateRevisionSync,
1070
- );
1071
-
1072
- const verifierVersion = yield* allocate(
1073
- configuration.mode,
1074
- mapping.allocateRevision,
1075
- mapping.allocateRevisionSync,
1076
- );
1077
-
1078
- const nextSecurityRevision = yield* allocateNextSecurityRevision(
1079
- mapping,
1080
- configuration.mode,
1081
- input.expectedRevision.securityRevision,
1082
- );
1083
-
1084
- if (
1085
- nextSecurityRevision === input.expectedRevision.securityRevision ||
1086
- (input.credential !== undefined &&
1087
- credentialRevision === input.credential.credentialRevision)
1088
- )
1089
- return yield* unavailable();
1090
-
1091
- return yield* owned(
1092
- database,
1093
- mapping,
1094
- configuration,
1095
- Effect.gen(function* () {
1096
- return yield* replaceIn(
1097
- mapping,
1098
- configuration,
1099
- input,
1100
- "change-password",
1101
- { credentialRevision, verifierVersion, nextSecurityRevision },
1102
- prepare,
1103
- );
1104
- }),
1105
- );
1106
- }).pipe(
1107
- Effect.provideService(CurrentPasswordSql, database),
1108
- Effect.provideService(LifecycleHooks, hooks),
1109
- translateFailure,
1110
- ),
1111
- checkReset: (input) =>
1112
- (configuration.proof === undefined
1113
- ? Effect.fail(unavailable())
1114
- : Effect.gen(function* () {
1115
- if (
1116
- input.moduleId.length <= "/reset".length ||
1117
- !input.moduleId.endsWith("/reset") ||
1118
- input.purpose !== "password-reset" ||
1119
- input.binding._tag !== "Subject"
1120
- )
1121
- return false;
1122
- const binding = input.binding;
1123
- const passwordModuleId = input.moduleId.slice(0, -"/reset".length);
1124
-
1125
- const current = yield* safeRead(
1126
- database,
1127
- configuration,
1128
- Effect.gen(function* () {
1129
- const resolved = yield* resolveCredential(
1130
- mapping,
1131
- passwordModuleId,
1132
- binding.identifier,
1133
- binding.revision.subjectId,
1134
- false,
1135
- );
1136
-
1137
- return (
1138
- resolved?.snapshot !== undefined &&
1139
- resolved.snapshot.revision.securityRevision ===
1140
- binding.revision.securityRevision &&
1141
- binding.revision.credentials.every((item) =>
1142
- resolved.snapshot!.revision.credentials.some(
1143
- (actual) =>
1144
- actual.credentialId === item.credentialId &&
1145
- actual.revision === item.revision,
1146
- ),
1147
- )
1148
- );
1149
- }),
1150
- );
1151
-
1152
- return current ? yield* probeProofCompletion(configuration, input) : false;
1153
- })
1154
- ).pipe(
1155
- Effect.provideService(CurrentPasswordSql, database),
1156
- Effect.provideService(LifecycleHooks, hooks),
1157
- translateFailure,
1158
- ),
1159
- resetWithProof: (uncaptured, prepare) =>
1160
- (configuration.proof === undefined
1161
- ? Effect.fail(unavailable())
1162
- : Effect.gen(function* () {
1163
- const input = Object.freeze({
1164
- ...(yield* snapshotMutationInput(uncaptured)),
1165
- completion: uncaptured.completion,
1166
- });
1167
-
1168
- const credentialRevision = yield* allocate(
1169
- configuration.mode,
1170
- mapping.allocateRevision,
1171
- mapping.allocateRevisionSync,
1172
- );
1173
-
1174
- const verifierVersion = yield* allocate(
1175
- configuration.mode,
1176
- mapping.allocateRevision,
1177
- mapping.allocateRevisionSync,
1178
- );
1179
-
1180
- const nextSecurityRevision = yield* allocateNextSecurityRevision(
1181
- mapping,
1182
- configuration.mode,
1183
- input.expectedRevision.securityRevision,
1184
- );
1185
-
1186
- if (
1187
- nextSecurityRevision === input.expectedRevision.securityRevision ||
1188
- (input.credential !== undefined &&
1189
- credentialRevision === input.credential.credentialRevision)
1190
- )
1191
- return yield* unavailable();
1192
-
1193
- return yield* owned(
1194
- database,
1195
- mapping,
1196
- configuration,
1197
- Effect.gen(function* () {
1198
- const journal = yield* CurrentCommitJournal;
1199
-
1200
- if (!proofCompletionMatchesPassword(input)) return prepare("rejected", journal);
1201
-
1202
- const authority = yield* validateMutationAuthority(
1203
- mapping,
1204
- configuration,
1205
- input,
1206
- "reset-password",
1207
- );
1208
-
1209
- if (authority === undefined) return prepare("rejected", journal);
1210
- if ((yield* commandExists(mapping, input.moduleId, input.commandId, true)).length)
1211
- return prepare("rejected", journal);
1212
-
1213
- const current = yield* currentExpectedCredential(
1214
- mapping,
1215
- input,
1216
- authority.nativeSubjectId,
1217
- );
1218
-
1219
- if (!current) return prepare("rejected", journal);
1220
- let passwordReceipt: PreparedCommit<any> | undefined;
1221
-
1222
- yield* completeProofPlanIn(
1223
- configuration.proof!.mapping,
1224
- configuration.proof!.configuration,
1225
- input.completion,
1226
- Effect.gen(function* () {
1227
- const revisions = {
1228
- credentialRevision,
1229
- verifierVersion,
1230
- nextSecurityRevision,
1231
- };
1232
-
1233
- const applied = yield* writeReplacement(
1234
- mapping,
1235
- input,
1236
- authority.nativeSubjectId,
1237
- revisions,
1238
- authority.now,
1239
- );
1240
-
1241
- if (applied)
1242
- yield* registerReplacement(
1243
- mapping,
1244
- input,
1245
- authority.nativeSubjectId,
1246
- revisions,
1247
- authority.now,
1248
- );
1249
-
1250
- return applied;
1251
- }),
1252
- (decision) => {
1253
- passwordReceipt = prepare(
1254
- decision === "completed" ? "changed" : "rejected",
1255
- journal,
1256
- );
1257
-
1258
- return decision;
1259
- },
1260
- );
1261
-
1262
- return passwordReceipt ?? prepare("rejected", journal);
1263
- }),
1264
- );
1265
- })
1266
- ).pipe(
1267
- Effect.provideService(CurrentPasswordSql, database),
1268
- Effect.provideService(LifecycleHooks, hooks),
1269
- translateFailure,
1270
- ),
1271
- });
1272
- });
1273
-
1274
- const currentExpectedCredential = Effect.fn("DrizzlePassword.currentExpectedCredential")(
1275
- function* (mapping: Mapping, input: PasswordMutationInput, nativeSubjectId: unknown) {
1276
- if (input.credential === undefined) return false;
1277
-
1278
- const row = (yield* readPasswordCredential(
1279
- mapping,
1280
- input.moduleId,
1281
- nativeSubjectId,
1282
- true,
1283
- ))[0];
1284
-
1285
- if (row === undefined) return false;
1286
-
1287
- return (
1288
- row[mapping.credential.credentialId] === input.credential.credentialId &&
1289
- row[mapping.credential.credentialRevision] === input.credential.credentialRevision &&
1290
- row[mapping.credential.verifierVersion] === input.credential.verifierVersion &&
1291
- row[mapping.credential.verifier] === Redacted.value(input.credential.verifier) &&
1292
- row[mapping.credential.normalization] === input.credential.normalization &&
1293
- input.authorization.challenge.targetCredentialId === input.credential.credentialId
1294
- );
1295
- },
1296
- );
1297
-
1298
- const checkMutationApplied = Effect.fn("DrizzlePassword.checkMutationApplied")(function* (
1299
- mapping: Mapping,
1300
- input: PasswordMutationInput,
1301
- nativeSubjectId: unknown,
1302
- revisions: {
1303
- readonly credentialId: string;
1304
- readonly credentialRevision: SecurityRevision;
1305
- readonly verifierVersion: SecurityRevision;
1306
- readonly nextSecurityRevision: SecurityRevision;
1307
- },
1308
- now: number,
1309
- ) {
1310
- const database = yield* CurrentPasswordSql;
1311
-
1312
- const c = credentialColumns(mapping),
1313
- s = subjectColumns(mapping);
1314
-
1315
- const credential = (yield* database
1316
- .select()
1317
- .from(mapping.credential.table)
1318
- .where(
1319
- and(
1320
- eq(c.moduleId, input.moduleId),
1321
- eq(c.subjectId, nativeSubjectId),
1322
- eq(c.credentialId, revisions.credentialId),
1323
- eq(c.credentialRevision, revisions.credentialRevision),
1324
- eq(c.verifierVersion, revisions.verifierVersion),
1325
- eq(c.verifier, Redacted.value(input.replacement.verifier)),
1326
- eq(c.normalization, input.replacement.normalization),
1327
- ),
1328
- )
1329
- .limit(1))[0];
1330
-
1331
- const subject = (yield* database
1332
- .select()
1333
- .from(mapping.subject.table)
1334
- .where(and(eq(s.id, nativeSubjectId), eq(s.securityRevision, revisions.nextSecurityRevision)))
1335
- .limit(1))[0];
1336
-
1337
- const authorityCredential = (yield* database
1338
- .select()
1339
- .from(mapping.authorityCredential.table)
1340
- .where(
1341
- and(
1342
- eq(authorityCredentialColumns(mapping).subjectId, nativeSubjectId),
1343
- eq(authorityCredentialColumns(mapping).credentialId, revisions.credentialId),
1344
- eq(authorityCredentialColumns(mapping).revision, revisions.credentialRevision),
1345
- ),
1346
- )
1347
- .limit(1))[0];
1348
-
1349
- // SQL equality follows column collation; compare the persisted values exactly.
1350
- return (
1351
- credential !== undefined &&
1352
- credential[mapping.credential.credentialId] === revisions.credentialId &&
1353
- credential[mapping.credential.credentialRevision] === revisions.credentialRevision &&
1354
- credential[mapping.credential.verifierVersion] === revisions.verifierVersion &&
1355
- credential[mapping.credential.verifier] === Redacted.value(input.replacement.verifier) &&
1356
- credential[mapping.credential.normalization] === input.replacement.normalization &&
1357
- (yield* mutationPostconditions(
1358
- mapping,
1359
- input,
1360
- nativeSubjectId,
1361
- subject,
1362
- authorityCredential,
1363
- now,
1364
- ))
1365
- );
1366
- });
1367
-
1368
- const writeReplacement = Effect.fn("DrizzlePassword.writeReplacement")(function* (
1369
- mapping: Mapping,
1370
- input: PasswordMutationInput,
1371
- nativeSubjectId: unknown,
1372
- revisions: {
1373
- readonly credentialRevision: SecurityRevision;
1374
- readonly verifierVersion: SecurityRevision;
1375
- readonly nextSecurityRevision: SecurityRevision;
1376
- },
1377
- now: number,
1378
- ) {
1379
- const database = yield* CurrentPasswordSql;
1380
-
1381
- const c = credentialColumns(mapping);
1382
- const s = subjectColumns(mapping);
1383
-
1384
- yield* database
1385
- .update(mapping.credential.table)
1386
- .set(
1387
- mapping.credential.encodeReplacement({
1388
- replacement: input.replacement,
1389
- credentialRevision: revisions.credentialRevision,
1390
- verifierVersion: revisions.verifierVersion,
1391
- }),
1392
- )
1393
- .where(
1394
- and(
1395
- eq(c.moduleId, input.moduleId),
1396
- eq(c.subjectId, nativeSubjectId),
1397
- eq(c.credentialId, input.credential!.credentialId),
1398
- eq(c.credentialRevision, input.credential!.credentialRevision),
1399
- eq(c.verifierVersion, input.credential!.verifierVersion),
1400
- eq(c.verifier, Redacted.value(input.credential!.verifier)),
1401
- eq(c.normalization, input.credential!.normalization),
1402
- ),
1403
- );
1404
- yield* database
1405
- .update(mapping.subject.table)
1406
- .set(updateValues([[mapping.subject.securityRevision, revisions.nextSecurityRevision]]))
1407
- .where(
1408
- and(
1409
- eq(s.id, nativeSubjectId),
1410
- eq(s.securityRevision, input.expectedRevision.securityRevision),
1411
- ),
1412
- );
1413
- yield* database
1414
- .update(mapping.authorityCredential.table)
1415
- .set(mapping.authorityCredential.encodeRevision(revisions.credentialRevision))
1416
- .where(
1417
- and(
1418
- eq(authorityCredentialColumns(mapping).subjectId, nativeSubjectId),
1419
- eq(authorityCredentialColumns(mapping).credentialId, input.credential!.credentialId),
1420
- eq(authorityCredentialColumns(mapping).revision, input.credential!.credentialRevision),
1421
- ),
1422
- );
1423
- yield* insertCommand(mapping, input, input.authorization.challenge.action, now);
1424
-
1425
- return yield* checkMutationApplied(
1426
- mapping,
1427
- input,
1428
- nativeSubjectId,
1429
- {
1430
- ...revisions,
1431
- credentialId: input.credential!.credentialId,
1432
- },
1433
- now,
1434
- );
1435
- });
1436
-
1437
- const registerReplacement = (
1438
- mapping: Mapping,
1439
- input: PasswordMutationInput,
1440
- nativeSubjectId: unknown,
1441
- revisions: {
1442
- readonly credentialRevision: SecurityRevision;
1443
- readonly verifierVersion: SecurityRevision;
1444
- readonly nextSecurityRevision: SecurityRevision;
1445
- },
1446
- now: number,
1447
- ) =>
1448
- registerFinal(
1449
- checkMutationApplied(
1450
- mapping,
1451
- input,
1452
- nativeSubjectId,
1453
- { ...revisions, credentialId: input.credential!.credentialId },
1454
- now,
1455
- ),
1456
- );
1457
-
1458
- const replaceIn = Effect.fn("Drizzle.replaceIn")(function* <A>(
1459
- mapping: Mapping,
1460
- configuration: PasswordSqlConfiguration,
1461
- input: PasswordMutationInput,
1462
- action: PasswordAction,
1463
- revisions: {
1464
- readonly credentialRevision: SecurityRevision;
1465
- readonly verifierVersion: SecurityRevision;
1466
- readonly nextSecurityRevision: SecurityRevision;
1467
- },
1468
- prepare: (value: PasswordMutationDecision, journal: CommitJournal) => PreparedCommit<A>,
1469
- ) {
1470
- const journal = yield* CurrentCommitJournal;
1471
-
1472
- const authority = yield* validateMutationAuthority(mapping, configuration, input, action);
1473
-
1474
- if (authority === undefined) return prepare("rejected", journal);
1475
- if ((yield* commandExists(mapping, input.moduleId, input.commandId, true)).length)
1476
- return prepare("rejected", journal);
1477
- if (!(yield* currentExpectedCredential(mapping, input, authority.nativeSubjectId)))
1478
- return prepare("rejected", journal);
1479
- const prepared = prepare("changed", journal);
1480
-
1481
- if (
1482
- !(yield* writeReplacement(
1483
- mapping,
1484
- input,
1485
- authority.nativeSubjectId,
1486
- revisions,
1487
- authority.now,
1488
- ))
1489
- )
1490
- return yield* unavailable();
1491
- yield* registerReplacement(mapping, input, authority.nativeSubjectId, revisions, authority.now);
1492
-
1493
- return prepared;
1494
- });
1495
-
1496
- /** Internal bound-owner primitives; deliberately not re-exported by driver modules. */
1497
- const passwordSqlKernel = {
1498
- allocate,
1499
- allocateNextSecurityRevision,
1500
- owned,
1501
- safeRead,
1502
- snapshotMutationInput,
1503
- lockSubject,
1504
- lockIdentifier,
1505
- readPasswordCredential,
1506
- resolveCredential,
1507
- validateMutationAuthority,
1508
- currentExpectedCredential,
1509
- commandExists,
1510
- addPasswordIn,
1511
- checkMutationApplied,
1512
- writeReplacement,
1513
- evidenceSatisfiedAt,
1514
- sameCredentialSnapshot,
1515
- subjectColumns,
1516
- identifierColumns,
1517
- credentialColumns,
1518
- authorityCredentialColumns,
1519
- proofCompletionMatchesPassword,
1520
- };
1521
-
1522
- return { makeSqlPasswordPersistence, passwordSqlKernel };
1523
- };