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