@yielded/auth-persistence 0.1.0-beta.7

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