@yielded/auth-persistence-drizzle 0.1.0-beta.25 → 0.1.0-beta.27

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 (383) hide show
  1. package/README.md +4 -2
  2. package/dist/D1.d.mts +495 -1151
  3. package/dist/D1.mjs +41 -19
  4. package/dist/D1.mjs.map +1 -1
  5. package/dist/Libsql.d.mts +385 -1996
  6. package/dist/Libsql.mjs +43 -47
  7. package/dist/Libsql.mjs.map +1 -1
  8. package/dist/Mysql2.d.mts +397 -1743
  9. package/dist/Mysql2.mjs +35 -41
  10. package/dist/Mysql2.mjs.map +1 -1
  11. package/dist/Pglite.d.mts +397 -1743
  12. package/dist/Pglite.mjs +42 -31
  13. package/dist/Pglite.mjs.map +1 -1
  14. package/dist/Postgres.d.mts +397 -1743
  15. package/dist/Postgres.mjs +42 -31
  16. package/dist/Postgres.mjs.map +1 -1
  17. package/dist/SqliteBun.d.mts +385 -1992
  18. package/dist/SqliteBun.mjs +43 -43
  19. package/dist/SqliteBun.mjs.map +1 -1
  20. package/dist/SqliteDo.d.mts +385 -1991
  21. package/dist/SqliteDo.mjs +42 -41
  22. package/dist/SqliteDo.mjs.map +1 -1
  23. package/dist/SqliteNode.d.mts +385 -1992
  24. package/dist/SqliteNode.mjs +43 -43
  25. package/dist/SqliteNode.mjs.map +1 -1
  26. package/dist/SqliteWasm.d.mts +385 -1992
  27. package/dist/SqliteWasm.mjs +43 -43
  28. package/dist/SqliteWasm.mjs.map +1 -1
  29. package/dist/drizzle/d1-identity.mjs +2 -2
  30. package/dist/drizzle/d1-identity.mjs.map +1 -1
  31. package/dist/drizzle/driver-types.d.mts +15 -0
  32. package/dist/drizzle/email-drivers.mjs +32 -0
  33. package/dist/drizzle/email-drivers.mjs.map +1 -0
  34. package/dist/drizzle/email-model.d.mts +9 -13
  35. package/dist/drizzle/email-target.d.mts +10 -11
  36. package/dist/drizzle/email-target.mjs +33 -70
  37. package/dist/drizzle/email-target.mjs.map +1 -1
  38. package/dist/drizzle/model.d.mts +1 -10
  39. package/dist/drizzle/model.mjs +1 -2
  40. package/dist/drizzle/model.mjs.map +1 -1
  41. package/dist/drizzle/mysql-identity.mjs +3 -6
  42. package/dist/drizzle/mysql-identity.mjs.map +1 -1
  43. package/dist/drizzle/native-clock.d.mts +9 -0
  44. package/dist/drizzle/native-clock.mjs +18 -0
  45. package/dist/drizzle/native-clock.mjs.map +1 -0
  46. package/dist/drizzle/native-database.d.mts +46 -0
  47. package/dist/drizzle/native-database.mjs +6 -5
  48. package/dist/drizzle/native-database.mjs.map +1 -1
  49. package/dist/drizzle/native-sql-table.mjs +13 -5
  50. package/dist/drizzle/native-sql-table.mjs.map +1 -1
  51. package/dist/drizzle/native-target.d.mts +6 -0
  52. package/dist/drizzle/native-target.mjs +44 -0
  53. package/dist/drizzle/native-target.mjs.map +1 -0
  54. package/dist/drizzle/oauth-connected-drivers.mjs +4 -56
  55. package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
  56. package/dist/drizzle/oauth-connected-model.d.mts +5 -22
  57. package/dist/drizzle/oauth-connected-model.mjs +1 -7
  58. package/dist/drizzle/oauth-connected-reference.d.mts +5 -7
  59. package/dist/drizzle/oauth-connected-reference.mjs +11 -3
  60. package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
  61. package/dist/drizzle/oauth-drivers.mjs +1 -2
  62. package/dist/drizzle/oauth-drivers.mjs.map +1 -1
  63. package/dist/drizzle/oauth-model.d.mts +11 -37
  64. package/dist/drizzle/oauth-model.mjs +3 -4
  65. package/dist/drizzle/oauth-model.mjs.map +1 -1
  66. package/dist/drizzle/oauth-proxy.d.mts +1 -1
  67. package/dist/drizzle/oauth-proxy.mjs +1 -1
  68. package/dist/drizzle/oauth-target.d.mts +9 -6
  69. package/dist/drizzle/oauth-target.mjs +47 -15
  70. package/dist/drizzle/oauth-target.mjs.map +1 -1
  71. package/dist/drizzle/passkey/target.d.mts +14 -0
  72. package/dist/drizzle/passkey/target.mjs +52 -0
  73. package/dist/drizzle/passkey/target.mjs.map +1 -0
  74. package/dist/drizzle/passkey/write-target.d.mts +11 -0
  75. package/dist/drizzle/passkey/write-target.mjs +28 -0
  76. package/dist/drizzle/passkey/write-target.mjs.map +1 -0
  77. package/dist/drizzle/passkey-drivers.mjs +2 -4
  78. package/dist/drizzle/passkey-drivers.mjs.map +1 -1
  79. package/dist/drizzle/passkey-model.d.mts +5 -26
  80. package/dist/drizzle/passkey-model.mjs +2 -8
  81. package/dist/drizzle/passkey-registration-ceremony-model.d.mts +3 -6
  82. package/dist/drizzle/passkey-write-drivers.mjs +2 -3
  83. package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
  84. package/dist/drizzle/passkey-write-model.d.mts +7 -9
  85. package/dist/drizzle/passkey-write-model.mjs +1 -3
  86. package/dist/drizzle/passkey-write-model.mjs.map +1 -1
  87. package/dist/drizzle/password-drivers.mjs +31 -0
  88. package/dist/drizzle/password-drivers.mjs.map +1 -0
  89. package/dist/drizzle/password-model.d.mts +7 -10
  90. package/dist/drizzle/password-target.d.mts +7 -8
  91. package/dist/drizzle/password-target.mjs +23 -68
  92. package/dist/drizzle/password-target.mjs.map +1 -1
  93. package/dist/drizzle/pg-identity.mjs +3 -6
  94. package/dist/drizzle/pg-identity.mjs.map +1 -1
  95. package/dist/drizzle/phone-drivers.mjs +24 -0
  96. package/dist/drizzle/phone-drivers.mjs.map +1 -0
  97. package/dist/drizzle/phone-model.d.mts +13 -104
  98. package/dist/drizzle/phone-model.mjs +5 -33
  99. package/dist/drizzle/phone-model.mjs.map +1 -1
  100. package/dist/drizzle/phone-target.mjs +22 -171
  101. package/dist/drizzle/phone-target.mjs.map +1 -1
  102. package/dist/drizzle/proof-drivers.mjs +24 -0
  103. package/dist/drizzle/proof-drivers.mjs.map +1 -0
  104. package/dist/drizzle/proof-model.d.mts +7 -15
  105. package/dist/drizzle/proof-target.d.mts +5 -5
  106. package/dist/drizzle/proof-target.mjs +14 -28
  107. package/dist/drizzle/proof-target.mjs.map +1 -1
  108. package/dist/drizzle/session-drivers.mjs +97 -0
  109. package/dist/drizzle/session-drivers.mjs.map +1 -0
  110. package/dist/drizzle/session-model.d.mts +11 -22
  111. package/dist/drizzle/sqlite-do-database.d.mts +3 -3
  112. package/dist/drizzle/sqlite-do-database.mjs +6 -1
  113. package/dist/drizzle/sqlite-do-database.mjs.map +1 -1
  114. package/dist/drizzle/sqlite-identity.mjs +3 -5
  115. package/dist/drizzle/sqlite-identity.mjs.map +1 -1
  116. package/dist/drizzle/step-up-model.d.mts +2 -5
  117. package/dist/drizzle/storage-validation.mjs +2 -1
  118. package/dist/drizzle/storage-validation.mjs.map +1 -1
  119. package/dist/drizzle/totp-model.d.mts +7 -74
  120. package/dist/drizzle/totp-model.mjs +1 -5
  121. package/dist/drizzle/totp-model.mjs.map +1 -1
  122. package/dist/drizzle/totp-target.mjs +39 -75
  123. package/dist/drizzle/totp-target.mjs.map +1 -1
  124. package/dist/drizzle/transaction-handle.mjs +13 -0
  125. package/dist/drizzle/transaction-handle.mjs.map +1 -0
  126. package/dist/drizzle/transaction-mysql.mjs +43 -12
  127. package/dist/drizzle/transaction-mysql.mjs.map +1 -1
  128. package/dist/index.d.mts +17 -22
  129. package/dist/index.mjs +10 -16
  130. package/dist/internal/drizzle-postgres.mjs +4 -6
  131. package/dist/internal/drizzle-postgres.mjs.map +1 -1
  132. package/dist/internal/drizzle-sqlite.mjs +4 -6
  133. package/dist/internal/drizzle-sqlite.mjs.map +1 -1
  134. package/package.json +1 -1
  135. package/src/D1.ts +77 -74
  136. package/src/Libsql.ts +65 -105
  137. package/src/Mysql2.ts +52 -87
  138. package/src/Pglite.ts +74 -81
  139. package/src/Postgres.ts +74 -81
  140. package/src/SqliteBun.ts +65 -113
  141. package/src/SqliteDo.ts +58 -106
  142. package/src/SqliteNode.ts +65 -113
  143. package/src/SqliteWasm.ts +65 -113
  144. package/src/drizzle/d1-identity.ts +2 -2
  145. package/src/drizzle/driver-types.ts +26 -0
  146. package/src/drizzle/email-drivers.ts +320 -0
  147. package/src/drizzle/email-model.ts +24 -78
  148. package/src/drizzle/email-target.ts +118 -211
  149. package/src/drizzle/model.ts +0 -2
  150. package/src/drizzle/mysql-identity.ts +4 -24
  151. package/src/drizzle/native-clock.ts +21 -0
  152. package/src/drizzle/native-database.ts +59 -18
  153. package/src/drizzle/native-sql-table.ts +104 -87
  154. package/src/drizzle/native-target.ts +120 -0
  155. package/src/drizzle/oauth-connected-drivers.ts +24 -233
  156. package/src/drizzle/oauth-connected-model.ts +3 -93
  157. package/src/drizzle/oauth-connected-reference.ts +16 -25
  158. package/src/drizzle/oauth-drivers.ts +58 -99
  159. package/src/drizzle/oauth-model.ts +27 -132
  160. package/src/drizzle/oauth-target.ts +250 -33
  161. package/src/drizzle/passkey/target.ts +205 -0
  162. package/src/drizzle/passkey/write-target.ts +91 -0
  163. package/src/drizzle/passkey-drivers.ts +35 -133
  164. package/src/drizzle/passkey-model.ts +3 -81
  165. package/src/drizzle/passkey-registration-ceremony-model.ts +5 -25
  166. package/src/drizzle/passkey-write-drivers.ts +32 -102
  167. package/src/drizzle/passkey-write-model.ts +10 -44
  168. package/src/drizzle/password-drivers.ts +286 -0
  169. package/src/drizzle/password-model.ts +10 -44
  170. package/src/drizzle/password-target.ts +85 -239
  171. package/src/drizzle/pg-identity.ts +4 -19
  172. package/src/drizzle/phone-drivers.ts +142 -0
  173. package/src/drizzle/phone-model.ts +22 -162
  174. package/src/drizzle/phone-target.ts +51 -493
  175. package/src/drizzle/proof-drivers.ts +123 -0
  176. package/src/drizzle/proof-model.ts +12 -123
  177. package/src/drizzle/proof-target.ts +38 -102
  178. package/src/drizzle/session-drivers.ts +696 -0
  179. package/src/drizzle/session-model.ts +54 -118
  180. package/src/drizzle/sqlite-do-database.ts +8 -0
  181. package/src/drizzle/sqlite-identity.ts +4 -22
  182. package/src/drizzle/step-up-model.ts +13 -37
  183. package/src/drizzle/storage-validation.ts +2 -1
  184. package/src/drizzle/totp-model.ts +20 -77
  185. package/src/drizzle/totp-target.ts +121 -261
  186. package/src/drizzle/transaction-handle.ts +41 -0
  187. package/src/drizzle/transaction-mysql.ts +91 -26
  188. package/src/index.ts +7 -122
  189. package/src/internal/drizzle-postgres.ts +4 -7
  190. package/src/internal/drizzle-sqlite.ts +4 -7
  191. package/dist/drizzle/crypto.mjs +0 -11
  192. package/dist/drizzle/crypto.mjs.map +0 -1
  193. package/dist/drizzle/d1-emails.d.mts +0 -62
  194. package/dist/drizzle/d1-emails.mjs +0 -626
  195. package/dist/drizzle/d1-emails.mjs.map +0 -1
  196. package/dist/drizzle/d1-generated-statement.mjs +0 -79
  197. package/dist/drizzle/d1-generated-statement.mjs.map +0 -1
  198. package/dist/drizzle/d1-oauth.d.mts +0 -331
  199. package/dist/drizzle/d1-oauth.mjs +0 -79
  200. package/dist/drizzle/d1-oauth.mjs.map +0 -1
  201. package/dist/drizzle/d1-passkey.d.mts +0 -37
  202. package/dist/drizzle/d1-passkey.mjs +0 -98
  203. package/dist/drizzle/d1-passkey.mjs.map +0 -1
  204. package/dist/drizzle/d1-password-prepared.d.mts +0 -25
  205. package/dist/drizzle/d1-password-prepared.mjs +0 -473
  206. package/dist/drizzle/d1-password-prepared.mjs.map +0 -1
  207. package/dist/drizzle/d1-passwords.d.mts +0 -70
  208. package/dist/drizzle/d1-passwords.mjs +0 -808
  209. package/dist/drizzle/d1-passwords.mjs.map +0 -1
  210. package/dist/drizzle/d1-phone.d.mts +0 -23
  211. package/dist/drizzle/d1-phone.mjs +0 -33
  212. package/dist/drizzle/d1-phone.mjs.map +0 -1
  213. package/dist/drizzle/d1-planning.d.mts +0 -11
  214. package/dist/drizzle/d1-planning.mjs +0 -43
  215. package/dist/drizzle/d1-planning.mjs.map +0 -1
  216. package/dist/drizzle/d1-proofs.d.mts +0 -80
  217. package/dist/drizzle/d1-proofs.mjs +0 -842
  218. package/dist/drizzle/d1-proofs.mjs.map +0 -1
  219. package/dist/drizzle/d1-sessions.d.mts +0 -68
  220. package/dist/drizzle/d1-sessions.mjs +0 -987
  221. package/dist/drizzle/d1-sessions.mjs.map +0 -1
  222. package/dist/drizzle/d1-totp.d.mts +0 -23
  223. package/dist/drizzle/d1-totp.mjs +0 -30
  224. package/dist/drizzle/d1-totp.mjs.map +0 -1
  225. package/dist/drizzle/email-registration.d.mts +0 -33
  226. package/dist/drizzle/email-registration.mjs +0 -281
  227. package/dist/drizzle/email-registration.mjs.map +0 -1
  228. package/dist/drizzle/email-sql.d.mts +0 -1
  229. package/dist/drizzle/email-sql.mjs +0 -9
  230. package/dist/drizzle/email-sql.mjs.map +0 -1
  231. package/dist/drizzle/mysql-emails.d.mts +0 -71
  232. package/dist/drizzle/mysql-emails.mjs +0 -43
  233. package/dist/drizzle/mysql-emails.mjs.map +0 -1
  234. package/dist/drizzle/mysql-password-prepared.d.mts +0 -30
  235. package/dist/drizzle/mysql-password-prepared.mjs +0 -21
  236. package/dist/drizzle/mysql-password-prepared.mjs.map +0 -1
  237. package/dist/drizzle/mysql-passwords.d.mts +0 -71
  238. package/dist/drizzle/mysql-passwords.mjs +0 -43
  239. package/dist/drizzle/mysql-passwords.mjs.map +0 -1
  240. package/dist/drizzle/mysql-proofs.d.mts +0 -75
  241. package/dist/drizzle/mysql-proofs.mjs +0 -28
  242. package/dist/drizzle/mysql-proofs.mjs.map +0 -1
  243. package/dist/drizzle/mysql-sessions.d.mts +0 -92
  244. package/dist/drizzle/mysql-sessions.mjs +0 -58
  245. package/dist/drizzle/mysql-sessions.mjs.map +0 -1
  246. package/dist/drizzle/oauth-connected-model.mjs.map +0 -1
  247. package/dist/drizzle/oauth-connected-target.d.mts +0 -6
  248. package/dist/drizzle/oauth-connected-target.mjs +0 -12
  249. package/dist/drizzle/oauth-connected-target.mjs.map +0 -1
  250. package/dist/drizzle/oauth-kernel.mjs +0 -11
  251. package/dist/drizzle/oauth-kernel.mjs.map +0 -1
  252. package/dist/drizzle/oauth-mysql.mjs +0 -8
  253. package/dist/drizzle/oauth-mysql.mjs.map +0 -1
  254. package/dist/drizzle/passkey-kernel.mjs +0 -8
  255. package/dist/drizzle/passkey-kernel.mjs.map +0 -1
  256. package/dist/drizzle/passkey-model.mjs.map +0 -1
  257. package/dist/drizzle/passkey-registration-ceremony-model.mjs +0 -2
  258. package/dist/drizzle/passkey-state.mjs +0 -7
  259. package/dist/drizzle/passkey-state.mjs.map +0 -1
  260. package/dist/drizzle/passkey-target.d.mts +0 -2
  261. package/dist/drizzle/passkey-target.mjs +0 -7
  262. package/dist/drizzle/passkey-target.mjs.map +0 -1
  263. package/dist/drizzle/passkey-write-target.d.mts +0 -5
  264. package/dist/drizzle/passkey-write-target.mjs +0 -7
  265. package/dist/drizzle/passkey-write-target.mjs.map +0 -1
  266. package/dist/drizzle/password-prepared-model.d.mts +0 -92
  267. package/dist/drizzle/password-prepared-model.mjs +0 -11
  268. package/dist/drizzle/password-prepared-model.mjs.map +0 -1
  269. package/dist/drizzle/password-prepared-sql.mjs +0 -395
  270. package/dist/drizzle/password-prepared-sql.mjs.map +0 -1
  271. package/dist/drizzle/password-prepared-state.mjs +0 -104
  272. package/dist/drizzle/password-prepared-state.mjs.map +0 -1
  273. package/dist/drizzle/password-prepared-target.d.mts +0 -13
  274. package/dist/drizzle/password-prepared-target.mjs +0 -62
  275. package/dist/drizzle/password-prepared-target.mjs.map +0 -1
  276. package/dist/drizzle/password-registration.d.mts +0 -7
  277. package/dist/drizzle/password-registration.mjs +0 -137
  278. package/dist/drizzle/password-registration.mjs.map +0 -1
  279. package/dist/drizzle/password-sql.d.mts +0 -1
  280. package/dist/drizzle/password-sql.mjs +0 -10
  281. package/dist/drizzle/password-sql.mjs.map +0 -1
  282. package/dist/drizzle/pg-emails.d.mts +0 -72
  283. package/dist/drizzle/pg-emails.mjs +0 -43
  284. package/dist/drizzle/pg-emails.mjs.map +0 -1
  285. package/dist/drizzle/pg-password-prepared.d.mts +0 -31
  286. package/dist/drizzle/pg-password-prepared.mjs +0 -21
  287. package/dist/drizzle/pg-password-prepared.mjs.map +0 -1
  288. package/dist/drizzle/pg-passwords.d.mts +0 -72
  289. package/dist/drizzle/pg-passwords.mjs +0 -43
  290. package/dist/drizzle/pg-passwords.mjs.map +0 -1
  291. package/dist/drizzle/pg-proofs.d.mts +0 -76
  292. package/dist/drizzle/pg-proofs.mjs +0 -27
  293. package/dist/drizzle/pg-proofs.mjs.map +0 -1
  294. package/dist/drizzle/pg-sessions.d.mts +0 -93
  295. package/dist/drizzle/pg-sessions.mjs +0 -58
  296. package/dist/drizzle/pg-sessions.mjs.map +0 -1
  297. package/dist/drizzle/phone-state.mjs +0 -14
  298. package/dist/drizzle/phone-state.mjs.map +0 -1
  299. package/dist/drizzle/phone-target.d.mts +0 -15
  300. package/dist/drizzle/proof-sql.d.mts +0 -1
  301. package/dist/drizzle/proof-sql.mjs +0 -8
  302. package/dist/drizzle/proof-sql.mjs.map +0 -1
  303. package/dist/drizzle/query-operations.mjs +0 -31
  304. package/dist/drizzle/query-operations.mjs.map +0 -1
  305. package/dist/drizzle/session-sql.d.mts +0 -1
  306. package/dist/drizzle/session-sql.mjs +0 -9
  307. package/dist/drizzle/session-sql.mjs.map +0 -1
  308. package/dist/drizzle/session-target.d.mts +0 -30
  309. package/dist/drizzle/session-target.mjs +0 -49
  310. package/dist/drizzle/session-target.mjs.map +0 -1
  311. package/dist/drizzle/sqlite-emails.mjs +0 -50
  312. package/dist/drizzle/sqlite-emails.mjs.map +0 -1
  313. package/dist/drizzle/sqlite-password-prepared.mjs +0 -26
  314. package/dist/drizzle/sqlite-password-prepared.mjs.map +0 -1
  315. package/dist/drizzle/sqlite-passwords.mjs +0 -54
  316. package/dist/drizzle/sqlite-passwords.mjs.map +0 -1
  317. package/dist/drizzle/sqlite-proofs.mjs +0 -34
  318. package/dist/drizzle/sqlite-proofs.mjs.map +0 -1
  319. package/dist/drizzle/sqlite-sessions.mjs +0 -79
  320. package/dist/drizzle/sqlite-sessions.mjs.map +0 -1
  321. package/dist/drizzle/standalone-guard.d.mts +0 -2
  322. package/dist/drizzle/standalone-guard.mjs +0 -21
  323. package/dist/drizzle/standalone-guard.mjs.map +0 -1
  324. package/dist/drizzle/totp-state.d.mts +0 -37
  325. package/dist/drizzle/totp-state.mjs +0 -287
  326. package/dist/drizzle/totp-state.mjs.map +0 -1
  327. package/dist/drizzle/totp-target.d.mts +0 -15
  328. package/dist/drizzle/transaction-execution.d.mts +0 -2
  329. package/dist/drizzle/transaction-execution.mjs +0 -11
  330. package/dist/drizzle/transaction-execution.mjs.map +0 -1
  331. package/dist/drizzle/transaction-owner.d.mts +0 -1
  332. package/dist/drizzle/transaction-owner.mjs +0 -8
  333. package/dist/drizzle/transaction-owner.mjs.map +0 -1
  334. package/src/drizzle/crypto.ts +0 -14
  335. package/src/drizzle/d1-emails.ts +0 -1945
  336. package/src/drizzle/d1-generated-statement.ts +0 -129
  337. package/src/drizzle/d1-oauth.ts +0 -360
  338. package/src/drizzle/d1-passkey.ts +0 -383
  339. package/src/drizzle/d1-password-prepared.ts +0 -1266
  340. package/src/drizzle/d1-passwords.ts +0 -2061
  341. package/src/drizzle/d1-phone.ts +0 -103
  342. package/src/drizzle/d1-planning.ts +0 -104
  343. package/src/drizzle/d1-proofs.ts +0 -2354
  344. package/src/drizzle/d1-sessions.ts +0 -2940
  345. package/src/drizzle/d1-totp.ts +0 -88
  346. package/src/drizzle/email-registration.ts +0 -850
  347. package/src/drizzle/email-sql.ts +0 -25
  348. package/src/drizzle/mysql-emails.ts +0 -343
  349. package/src/drizzle/mysql-password-prepared.ts +0 -198
  350. package/src/drizzle/mysql-passwords.ts +0 -343
  351. package/src/drizzle/mysql-proofs.ts +0 -196
  352. package/src/drizzle/mysql-sessions.ts +0 -780
  353. package/src/drizzle/oauth-connected-target.ts +0 -21
  354. package/src/drizzle/oauth-kernel.ts +0 -10
  355. package/src/drizzle/oauth-mysql.ts +0 -10
  356. package/src/drizzle/passkey-kernel.ts +0 -4
  357. package/src/drizzle/passkey-state.ts +0 -3
  358. package/src/drizzle/passkey-target.ts +0 -23
  359. package/src/drizzle/passkey-write-target.ts +0 -9
  360. package/src/drizzle/password-prepared-model.ts +0 -241
  361. package/src/drizzle/password-prepared-sql.ts +0 -1202
  362. package/src/drizzle/password-prepared-state.ts +0 -231
  363. package/src/drizzle/password-prepared-target.ts +0 -169
  364. package/src/drizzle/password-registration.ts +0 -369
  365. package/src/drizzle/password-sql.ts +0 -16
  366. package/src/drizzle/pg-emails.ts +0 -343
  367. package/src/drizzle/pg-password-prepared.ts +0 -199
  368. package/src/drizzle/pg-passwords.ts +0 -342
  369. package/src/drizzle/pg-proofs.ts +0 -206
  370. package/src/drizzle/pg-sessions.ts +0 -789
  371. package/src/drizzle/phone-state.ts +0 -21
  372. package/src/drizzle/proof-sql.ts +0 -10
  373. package/src/drizzle/query-operations.ts +0 -49
  374. package/src/drizzle/session-sql.ts +0 -15
  375. package/src/drizzle/session-target.ts +0 -337
  376. package/src/drizzle/sqlite-emails.ts +0 -393
  377. package/src/drizzle/sqlite-password-prepared.ts +0 -230
  378. package/src/drizzle/sqlite-passwords.ts +0 -497
  379. package/src/drizzle/sqlite-proofs.ts +0 -229
  380. package/src/drizzle/sqlite-sessions.ts +0 -1013
  381. package/src/drizzle/totp-state.ts +0 -525
  382. package/src/drizzle/transaction-execution.ts +0 -13
  383. package/src/drizzle/transaction-owner.ts +0 -11
@@ -1,987 +0,0 @@
1
- import { PersistenceMappingError as PersistenceMappingError$1, column, isMappedConstraintConflict, updateValues } from "./model.mjs";
2
- import { compactD1GeneratedStatement } from "./d1-generated-statement.mjs";
3
- import { validateDrizzleStorage } from "./storage-validation.mjs";
4
- import { Database } from "./d1-database.mjs";
5
- import { D1BatchStatements } from "./D1BatchStatements.mjs";
6
- import { CurrentD1PlanningDatabase, makeD1Owner } from "./d1-planning.mjs";
7
- import { nativeDatabase } from "./native-database.mjs";
8
- import { NativeDatabase, decodeStepUpIntent, encodeStepUpIntent, stepUpIntentLive, validateStepUpPlan } from "@yielded/auth-persistence/Adapter";
9
- import { and, eq, getTableColumns, gt, inArray, not, or, sql } from "drizzle-orm";
10
- import { Cause, Context, Data, DateTime, Effect, Schema } from "effect";
11
- import { CurrentCommitJournal, LifecycleHooks, coordinateCommit, hasCommitScope } from "@yielded/auth/Hooks";
12
- import { AuthenticationAuthority, AuthenticationCapture, PendingAuthenticationInvalid, SessionConflict, SessionInvalid, SessionMetadata, SessionStepUpInvalid, SessionUnavailable, StaleAuthentication, assessAuthentication, pendingAuthenticationContext, snapshotPendingAuthenticationContext, snapshotSessionAuthenticationProvenance } from "@yielded/auth/Sessions";
13
- import { reportPersistenceFailure } from "@yielded/auth/Persistence";
14
- //#region src/drizzle/d1-sessions.ts
15
- var CurrentD1SessionBatch = class extends Context.Service()("effect-auth/drizzle/CurrentD1SessionBatch") {};
16
- var D1BatchFailure = class extends Data.TaggedError("D1BatchFailure") {};
17
- const unavailable = () => SessionUnavailable.make({});
18
- const stale = () => StaleAuthentication.make({});
19
- const invalidPending = () => PendingAuthenticationInvalid.make({});
20
- const invalidSession = () => SessionInvalid.make({});
21
- const mapFailureCause = (effect, map) => Effect.catchCause(effect, (cause) => Effect.failCause(Cause.map(cause, map)));
22
- const isD1DomainError = (error) => {
23
- const tag = typeof error === "object" && error !== null ? Reflect.get(error, "_tag") : void 0;
24
- return tag === "SessionStepUpInvalid" || tag === "PendingAuthenticationInvalid" || tag === "SessionConflict" || tag === "SessionInvalid" || tag === "SessionUnavailable" || tag === "StaleAuthentication";
25
- };
26
- const normalizeD1Failure = (effect, isExpected) => reportPersistenceFailure(effect, isExpected).pipe(Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, (error) => isD1DomainError(error) ? error : unavailable()))));
27
- const terminalD1 = (effect) => normalizeD1Failure(effect, isD1DomainError);
28
- const containsFailure = (failure, predicate) => {
29
- const seen = /* @__PURE__ */ new Set();
30
- const pending = [failure];
31
- for (let inspected = 0; inspected < 24 && pending.length > 0; inspected++) {
32
- const current = pending.shift();
33
- if (current === void 0 || current === null || seen.has(current)) continue;
34
- seen.add(current);
35
- if (predicate(current)) return true;
36
- if (Cause.isCause(current)) {
37
- for (const reason of current.reasons) if (Cause.isFailReason(reason)) pending.push(reason.error);
38
- else if (Cause.isDieReason(reason)) pending.push(reason.defect);
39
- continue;
40
- }
41
- if (typeof current !== "object") continue;
42
- const wrapped = current;
43
- if (wrapped.cause !== void 0) pending.push(wrapped.cause);
44
- if (wrapped.reason !== void 0) pending.push(wrapped.reason);
45
- if (wrapped.message !== void 0) pending.push(wrapped.message);
46
- }
47
- return false;
48
- };
49
- const isGuardFailure = (failure) => containsFailure(failure, (value) => typeof value === "string" && value.includes("effect-auth-session-guard"));
50
- const recoverBatchFailure = (failure) => {
51
- const { cause, mutation } = failure;
52
- const onlyFailures = cause.reasons.length > 0 && cause.reasons.every(Cause.isFailReason);
53
- if (mutation === void 0) return Effect.failCause(cause);
54
- if (onlyFailures && mutation.isConstraintConflict !== void 0 && cause.reasons.every((reason) => Cause.isFailReason(reason) && isMappedConstraintConflict(mutation.isConstraintConflict, reason.error))) return Effect.fail(SessionConflict.make({}));
55
- if (onlyFailures && mutation.recoverGuard !== void 0 && cause.reasons.every((reason) => Cause.isFailReason(reason) && isGuardFailure(reason.error))) return mutation.recoverGuard;
56
- return Effect.failCause(cause);
57
- };
58
- const splitD1BatchFailure = (cause) => {
59
- const marker = cause.reasons.find((reason) => Cause.isFailReason(reason) && reason.error instanceof D1BatchFailure);
60
- if (marker === void 0 || !Cause.isFailReason(marker)) return void 0;
61
- const remaining = Cause.fromReasons(cause.reasons.filter((reason) => reason !== marker));
62
- return {
63
- failure: marker.error,
64
- remaining
65
- };
66
- };
67
- const recoverD1BatchCause = (cause) => {
68
- const split = splitD1BatchFailure(cause);
69
- if (split === void 0) return Effect.failCause(cause);
70
- return recoverBatchFailure(split.failure).pipe(Effect.catchCause((recovered) => Effect.failCause(Cause.combine(recovered, split.remaining))));
71
- };
72
- const recoverCoordinatedD1BatchCause = (cause) => {
73
- const split = splitD1BatchFailure(cause);
74
- if (split === void 0) return Effect.failCause(cause);
75
- return terminalD1(recoverBatchFailure(split.failure)).pipe(Effect.catchCause((recovered) => Effect.failCause(Cause.combine(recovered, split.remaining))));
76
- };
77
- const statement = (query) => Effect.map(CurrentD1PlanningDatabase, (database) => {
78
- const rendered = query.toSQL();
79
- return compactD1GeneratedStatement(database.$client, database.$client.unsafe(rendered.sql, rendered.params), unavailable);
80
- });
81
- const assertion = (condition) => Effect.gen(function* () {
82
- const database = yield* CurrentD1PlanningDatabase;
83
- return yield* statement(database.select({ ok: sql`case when ${condition} then 1 else json_extract('[]', '$[effect-auth-session-guard]') end`.as("ok") }).from(sql`(select 1)`));
84
- });
85
- const conditionMatches = (condition) => Effect.flatMap(CurrentD1PlanningDatabase, (database) => database.select({ ok: sql`1` }).from(sql`(select 1)`).where(condition).limit(1).pipe(Effect.map((rows) => rows.length > 0)));
86
- function runPlanned(plan, isConstraintConflict, recoverGuard) {
87
- const planned = plan.pipe(Effect.map((value) => ({
88
- ...value,
89
- ...isConstraintConflict === void 0 ? {} : { isConstraintConflict },
90
- ...recoverGuard === void 0 ? {} : { recoverGuard }
91
- })));
92
- const execution = Effect.gen(function* () {
93
- const batch = yield* Effect.serviceOption(CurrentD1SessionBatch);
94
- if (batch._tag === "Some") {
95
- const owned = batch.value;
96
- return (yield* coordinateCommit(() => Effect.gen(function* () {
97
- yield* owned.owner.check;
98
- const journal = yield* CurrentCommitJournal;
99
- const value = yield* planned;
100
- yield* owned.owner.check;
101
- const guarded = {
102
- ...value,
103
- journalGuard: journal.prepare(void 0)
104
- };
105
- yield* owned.append(guarded);
106
- return guarded.receipt;
107
- }), { mode: "batch" })).value;
108
- }
109
- const database = yield* CurrentD1PlanningDatabase;
110
- return (yield* coordinateCommit(() => Effect.gen(function* () {
111
- const prepared = yield* planned;
112
- yield* database.$client.batch(prepared.statements).pipe(Effect.catchCause((cause) => Effect.fail(new D1BatchFailure({
113
- cause,
114
- mutation: prepared
115
- }))));
116
- return prepared.receipt;
117
- }), { mode: "batch" })).value;
118
- });
119
- return normalizeD1Failure(execution.pipe(Effect.catchCause(recoverD1BatchCause)), isD1DomainError);
120
- }
121
- const subjectColumns = (mapping) => ({
122
- id: column(mapping.subject.table, mapping.subject.id),
123
- status: column(mapping.subject.table, mapping.subject.status),
124
- revision: column(mapping.subject.table, mapping.subject.securityRevision)
125
- });
126
- const credentialColumns = (mapping) => ({
127
- subjectId: column(mapping.credential.table, mapping.credential.subjectId),
128
- id: column(mapping.credential.table, mapping.credential.credentialId),
129
- revision: column(mapping.credential.table, mapping.credential.revision),
130
- ...mapping.credential.status === void 0 ? {} : { status: column(mapping.credential.table, mapping.credential.status) }
131
- });
132
- const flowColumns = (mapping) => ({
133
- flowId: column(mapping.flow.table, mapping.flow.flowId),
134
- subjectId: column(mapping.flow.table, mapping.flow.subjectId),
135
- state: column(mapping.flow.table, mapping.flow.state),
136
- pendingDigest: column(mapping.flow.table, mapping.flow.pendingDigest),
137
- dedupUntil: column(mapping.flow.table, mapping.flow.dedupUntil)
138
- });
139
- const hasActiveFlow = Effect.fn("D1Session.hasActiveFlow")(function* (mapping, flowId) {
140
- const database = yield* CurrentD1PlanningDatabase;
141
- const f = flowColumns(mapping);
142
- return yield* database.select({ flowId: f.flowId }).from(mapping.flow.table).where(and(eq(f.flowId, flowId), gt(f.dedupUntil, mapping.d1.engineNow))).limit(1).pipe(Effect.map((rows) => rows.length > 0));
143
- });
144
- const recoverFlowOrStale = (mapping, flowId) => hasActiveFlow(mapping, flowId).pipe(Effect.flatMap((active) => Effect.fail(active ? SessionConflict.make({}) : StaleAuthentication.make({}))));
145
- const pendingColumns = (mapping) => ({
146
- digest: column(mapping.pending.table, mapping.pending.digest),
147
- version: column(mapping.pending.table, mapping.pending.version),
148
- flowId: column(mapping.pending.table, mapping.pending.flowId),
149
- subjectId: column(mapping.pending.table, mapping.pending.subjectId),
150
- bindingDigest: column(mapping.pending.table, mapping.pending.bindingDigest),
151
- expiresAt: column(mapping.pending.table, mapping.pending.expiresAt),
152
- attemptLimit: column(mapping.pending.table, mapping.pending.attemptLimit),
153
- failedAttempts: column(mapping.pending.table, mapping.pending.failedAttempts),
154
- consumed: column(mapping.pending.table, mapping.pending.consumed)
155
- });
156
- const sessionColumns = (mapping) => ({
157
- sessionId: column(mapping.session.table, mapping.session.sessionId),
158
- subjectId: column(mapping.session.table, mapping.session.subjectId),
159
- digest: column(mapping.session.table, mapping.session.digest),
160
- version: column(mapping.session.table, mapping.session.version),
161
- securityRevision: column(mapping.session.table, mapping.session.securityRevision),
162
- issuedAt: column(mapping.session.table, mapping.session.issuedAt),
163
- expiresAt: column(mapping.session.table, mapping.session.expiresAt),
164
- absoluteExpiresAt: column(mapping.session.table, mapping.session.absoluteExpiresAt)
165
- });
166
- const captureDetails = Effect.fn("DrizzleD1Session.captureDetails")(function* (mapping, subjectId, credentialIds) {
167
- const database = yield* CurrentD1PlanningDatabase;
168
- const requested = [...new Set(credentialIds)].sort();
169
- if (requested.length !== credentialIds.length) return yield* stale();
170
- const nativeSubjectId = yield* mapping.subjectId.toNative(subjectId);
171
- const sc = subjectColumns(mapping);
172
- const cc = credentialColumns(mapping);
173
- const rows = yield* requested.length === 0 ? database.select({ subject: getTableColumns(mapping.subject.table) }).from(mapping.subject.table).where(eq(sc.id, nativeSubjectId)).limit(1).pipe(Effect.map((selected) => selected.map((row) => ({
174
- subject: row.subject,
175
- credential: void 0
176
- })))) : database.select({
177
- subject: getTableColumns(mapping.subject.table),
178
- credential: getTableColumns(mapping.credential.table)
179
- }).from(mapping.subject.table).innerJoin(mapping.credential.table, and(eq(cc.subjectId, sc.id), inArray(cc.id, requested))).where(eq(sc.id, nativeSubjectId));
180
- const subject = rows[0]?.subject;
181
- if (subject === void 0 || !mapping.subject.isActiveStatus(subject[mapping.subject.status])) return yield* stale();
182
- const credentials = rows.flatMap((row) => row.credential === void 0 || row.credential === null ? [] : [row.credential]);
183
- if (credentials.length !== requested.length || credentials.some((row) => mapping.credential.status !== void 0 && mapping.credential.isActiveStatus?.(row[mapping.credential.status]) !== true)) return yield* stale();
184
- return {
185
- subject,
186
- revision: {
187
- subjectId,
188
- securityRevision: subject[mapping.subject.securityRevision],
189
- credentials: credentials.map((row) => ({
190
- credentialId: row[mapping.credential.credentialId],
191
- revision: row[mapping.credential.revision]
192
- })).sort((a, b) => a.credentialId.localeCompare(b.credentialId))
193
- }
194
- };
195
- });
196
- const capture = Effect.fn("DrizzleD1Session.capture")(function* (mapping, subjectId, credentialIds) {
197
- const details = yield* captureDetails(mapping, subjectId, credentialIds);
198
- const requirement = yield* mapping.subject.decodeRequirement(details.subject);
199
- return yield* Schema.decodeEffect(AuthenticationCapture)({
200
- revision: details.revision,
201
- requirement
202
- });
203
- });
204
- const requirement = Effect.fn("DrizzleD1Session.requirement")(function* (mapping, evidence) {
205
- const current = yield* captureDetails(mapping, evidence.revision.subjectId, evidence.revision.credentials.map((item) => item.credentialId));
206
- const expected = new Map(evidence.revision.credentials.map((item) => [item.credentialId, item.revision]));
207
- if (current.revision.securityRevision !== evidence.revision.securityRevision || current.revision.credentials.some((item) => expected.get(item.credentialId) !== item.revision)) return yield* stale();
208
- return yield* mapping.subject.decodeRequirement(current.subject);
209
- });
210
- const authorityCondition = (mapping, nativeSubjectId, evidence) => {
211
- const sc = subjectColumns(mapping);
212
- const cc = credentialColumns(mapping);
213
- const subject = sql`exists(select 1 from ${mapping.subject.table} where ${sc.id} = ${sql.param(nativeSubjectId, sc.id)} and ${sc.status} = ${sql.param(mapping.d1.activeSubjectStatusValue, sc.status)} and ${sc.revision} = ${sql.param(evidence.revision.securityRevision, sc.revision)})`;
214
- const credentials = evidence.revision.credentials.map((item) => sql`exists(select 1 from ${mapping.credential.table} where ${cc.subjectId} = ${sql.param(nativeSubjectId, cc.subjectId)} and ${cc.id} = ${sql.param(item.credentialId, cc.id)} and ${cc.revision} = ${sql.param(item.revision, cc.revision)}${mapping.credential.status === void 0 ? sql`` : sql` and ${cc.status} = ${sql.param(mapping.d1.activeCredentialStatusValue, cc.status)}`})`);
215
- return and(subject, ...credentials);
216
- };
217
- const subjectRevisionCondition = (mapping, nativeSubjectId, revision) => {
218
- const sc = subjectColumns(mapping);
219
- return sql`exists(select 1 from ${mapping.subject.table} where ${sc.id} = ${sql.param(nativeSubjectId, sc.id)} and ${sc.status} = ${sql.param(mapping.d1.activeSubjectStatusValue, sc.status)} and ${sc.revision} = ${sql.param(revision, sc.revision)})`;
220
- };
221
- /** Engine-time counterpart of assessAuthentication. Complete transitions must
222
- * satisfy an entire alternative; incomplete pending flows need one eligible proof. */
223
- const freshnessCondition = (mapping, evidence, requirement, complete) => {
224
- const fresh = evidence.proofs.map((proof) => {
225
- const verified = DateTime.toEpochMillis(proof.verifiedAt);
226
- return and(sql`${mapping.d1.engineNowMillis} >= ${verified}`, sql`${mapping.d1.engineNowMillis} - ${verified} < ${requirement.maximumAgeMillis}`);
227
- });
228
- const any = (conditions) => conditions.length === 0 ? sql`false` : or(...conditions);
229
- const notFuture = evidence.proofs.map((proof) => sql`${mapping.d1.engineNowMillis} >= ${DateTime.toEpochMillis(proof.verifiedAt)}`);
230
- if (!complete) return and(...notFuture, any(fresh));
231
- const byCredential = /* @__PURE__ */ new Map();
232
- evidence.proofs.forEach((proof, index) => {
233
- const previous = byCredential.get(proof.credentialId) ?? [];
234
- previous.push(fresh[index]);
235
- byCredential.set(proof.credentialId, previous);
236
- });
237
- const credentialCount = sql.join([...byCredential.values()].map((proofs) => sql`case when ${any(proofs)} then 1 else 0 end`), sql` + `);
238
- const alternatives = requirement.alternatives.map((alternative) => and(...alternative.factors.map((factor) => any(fresh.filter((_, index) => evidence.proofs[index].factors.includes(factor)))), sql`(${credentialCount}) >= ${alternative.minimumCredentials}`, any(fresh.filter((_, index) => (!alternative.userVerified || evidence.proofs[index].userVerified) && (!alternative.phishingResistant || evidence.proofs[index].phishingResistant)))));
239
- return and(...notFuture, any(alternatives));
240
- };
241
- const allocate = (asynchronous, synchronous) => asynchronous !== void 0 ? asynchronous : synchronous === void 0 ? Effect.fail(unavailable()) : Effect.try({
242
- try: synchronous,
243
- catch: (cause) => PersistenceMappingError$1.make({
244
- operation: "allocate",
245
- cause
246
- })
247
- });
248
- const sameOriginalRevision = (completed, original) => {
249
- const current = new Map(completed.revision.credentials.map((item) => [item.credentialId, item.revision]));
250
- return completed.flowId === original.flowId && completed.bindingDigest === original.bindingDigest && completed.revision.subjectId === original.revision.subjectId && completed.revision.securityRevision === original.revision.securityRevision && original.revision.credentials.every((item) => current.get(item.credentialId) === item.revision) && original.proofs.every((expected) => completed.proofs.some((proof) => proof.method === expected.method && proof.credentialId === expected.credentialId && proof.userVerified === expected.userVerified && proof.phishingResistant === expected.phishingResistant && DateTime.toEpochMillis(proof.verifiedAt) === DateTime.toEpochMillis(expected.verifiedAt) && proof.factors.length === expected.factors.length && proof.factors.every((factor, index) => factor === expected.factors[index])));
251
- };
252
- const readPendingWith = Effect.fn("D1Session.readPendingWith")(function* (mapping, digest, projection) {
253
- const row = (yield* (yield* CurrentD1PlanningDatabase).select().from(mapping.pending.table).where(eq(pendingColumns(mapping).digest, digest)).limit(1))[0];
254
- if (row === void 0) return void 0;
255
- return yield* (projection === "context" ? mapping.pending.decodeContext : mapping.pending.decode)(row);
256
- });
257
- const readPending = (mapping, digest) => readPendingWith(mapping, digest, "record");
258
- const pendingCondition = (mapping, input, nativeSubjectId) => {
259
- const p = pendingColumns(mapping);
260
- const f = flowColumns(mapping);
261
- return and(sql`exists(select 1 from ${mapping.pending.table} where ${p.digest} = ${sql.param(input.digest, p.digest)} and ${p.version} = ${sql.param(input.version, p.version)} and ${p.flowId} = ${sql.param(input.flowId, p.flowId)} and ${p.subjectId} = ${sql.param(nativeSubjectId, p.subjectId)} and ${p.bindingDigest} = ${sql.param(input.bindingDigest, p.bindingDigest)} and ${p.consumed} = ${sql.param(false, p.consumed)} and ${p.failedAttempts} < ${p.attemptLimit} and ${p.expiresAt} > ${mapping.d1.engineNow})`, sql`exists(select 1 from ${mapping.flow.table} where ${f.flowId} = ${sql.param(input.flowId, f.flowId)} and ${f.subjectId} = ${sql.param(nativeSubjectId, f.subjectId)} and ${f.state} = ${sql.param(mapping.flow.pendingStateValue, f.state)} and ${f.pendingDigest} = ${sql.param(input.digest, f.pendingDigest)} and ${f.dedupUntil} > ${mapping.d1.engineNow})`);
262
- };
263
- const recoverPendingOrStale = (mapping, input, subjectId) => mapping.subjectId.toNative(subjectId).pipe(Effect.flatMap((nativeSubjectId) => conditionMatches(pendingCondition(mapping, input, nativeSubjectId))), Effect.flatMap((pendingIsCurrent) => Effect.fail(pendingIsCurrent ? StaleAuthentication.make({}) : PendingAuthenticationInvalid.make({}))));
264
- const consumePendingStatements = Effect.fn("D1Session.consumePendingStatements")(function* (mapping, input, absoluteExpiresAt) {
265
- const database = yield* CurrentD1PlanningDatabase;
266
- return [yield* statement(database.update(mapping.pending.table).set(updateValues([[mapping.pending.consumed, true]])).where(and(eq(pendingColumns(mapping).digest, input.digest), eq(pendingColumns(mapping).version, input.version)))), yield* statement(database.update(mapping.flow.table).set(updateValues([
267
- [mapping.flow.state, mapping.flow.establishedStateValue],
268
- [mapping.flow.pendingDigest, null],
269
- [mapping.flow.dedupUntil, mapping.flow.encodeInstant(absoluteExpiresAt)]
270
- ])).where(eq(flowColumns(mapping).flowId, input.flowId)))];
271
- });
272
- const makeD1AuthenticationAuthority = (mapping) => ({
273
- capture: (subjectId, credentialIds) => capture(mapping, subjectId, credentialIds).pipe(terminalD1),
274
- requirements: (evidence) => requirement(mapping, evidence).pipe(terminalD1),
275
- approve: (input, prepare) => runPlanned(Effect.gen(function* () {
276
- const journal = yield* CurrentCommitJournal;
277
- const policy = yield* requirement(mapping, input.evidence);
278
- if (!(yield* assessAuthentication(input.evidence, policy)).satisfied) return yield* stale();
279
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.evidence.revision.subjectId);
280
- let condition = and(authorityCondition(mapping, nativeSubjectId, input.evidence), freshnessCondition(mapping, input.evidence, policy, true), sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(input.expiresAt)}`, sql`${DateTime.toEpochMillis(input.expiresAt)} <= ${DateTime.toEpochMillis(input.absoluteExpiresAt)}`);
281
- const statements = [];
282
- if (input.pending !== void 0) {
283
- if (mapping.pending === void 0) return yield* invalidPending();
284
- const pendingMapping = {
285
- ...mapping,
286
- ...mapping.pending
287
- };
288
- const stored = yield* readPending(pendingMapping, input.pending.digest);
289
- if (stored === void 0 || !sameOriginalRevision(input.evidence, stored.evidence)) return yield* invalidPending();
290
- condition = and(condition, pendingCondition(pendingMapping, input.pending, nativeSubjectId));
291
- statements.push(...yield* consumePendingStatements(pendingMapping, input.pending, input.absoluteExpiresAt));
292
- }
293
- return {
294
- receipt: prepare(void 0, journal),
295
- statements: [yield* assertion(condition), ...statements]
296
- };
297
- }), void 0, Effect.suspend(() => input.pending === void 0 || mapping.pending === void 0 ? Effect.fail(stale()) : recoverPendingOrStale({
298
- ...mapping,
299
- ...mapping.pending
300
- }, input.pending, input.evidence.revision.subjectId)))
301
- });
302
- /** D1's last authoritative statement checks the original record version and
303
- * security state together. A later race is still rejected by final consumption. */
304
- const readAuthenticatedPending = Effect.fn("D1Session.readAuthenticatedPending")(function* (mapping, input, projection) {
305
- const record = yield* readPendingWith(mapping, input.digest, projection);
306
- if (record === void 0 || input.bindingDigest !== void 0 && record.evidence.bindingDigest !== input.bindingDigest) return yield* invalidPending();
307
- const policy = yield* mapFailureCause(requirement(mapping, record.evidence), (error) => error._tag === "StaleAuthentication" ? invalidPending() : error);
308
- yield* assessAuthentication(record.evidence, policy).pipe(Effect.mapError(() => invalidPending()));
309
- const nativeSubjectId = yield* mapping.subjectId.toNative(record.evidence.revision.subjectId);
310
- if (!(yield* conditionMatches(and(authorityCondition(mapping, nativeSubjectId, record.evidence), freshnessCondition(mapping, record.evidence, policy, false), pendingCondition(mapping, {
311
- digest: input.digest,
312
- bindingDigest: record.evidence.bindingDigest,
313
- flowId: record.evidence.flowId,
314
- version: record.version
315
- }, nativeSubjectId))))) return yield* invalidPending();
316
- return record;
317
- });
318
- const makeD1PendingAuthentication = (mapping) => ({
319
- create: (input, _now, prepare) => runPlanned(Effect.gen(function* () {
320
- const database = yield* CurrentD1PlanningDatabase;
321
- const journal = yield* CurrentCommitJournal;
322
- const policy = yield* requirement(mapping, input.evidence);
323
- yield* assessAuthentication(input.evidence, policy);
324
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.evidence.revision.subjectId);
325
- if (yield* hasActiveFlow(mapping, input.evidence.flowId)) return yield* SessionConflict.make({});
326
- const version = yield* allocate(mapping.pending.allocateVersion, mapping.pending.allocateVersionSync);
327
- const record = {
328
- ...input,
329
- version
330
- };
331
- const f = flowColumns(mapping);
332
- const condition = and(authorityCondition(mapping, nativeSubjectId, input.evidence), freshnessCondition(mapping, input.evidence, policy, false), sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(input.expiresAt)}`, not(sql`exists(select 1 from ${mapping.flow.table} where ${f.flowId} = ${sql.param(input.evidence.flowId, f.flowId)} and ${f.dedupUntil} > ${mapping.d1.engineNow})`));
333
- const cleanupPending = database.delete(mapping.pending.table).where(sql`${pendingColumns(mapping).flowId} in (select ${f.flowId} from ${mapping.flow.table} where ${f.flowId} = ${sql.param(input.evidence.flowId, f.flowId)} and ${f.dedupUntil} <= ${mapping.d1.engineNow})`);
334
- const cleanupFlow = database.delete(mapping.flow.table).where(and(eq(f.flowId, input.evidence.flowId), sql`${f.dedupUntil} <= ${mapping.d1.engineNow}`));
335
- const insertFlow = database.insert(mapping.flow.table).values(mapping.flow.encodePendingInsert({
336
- evidence: input.evidence,
337
- subjectId: nativeSubjectId,
338
- pendingDigest: input.digest,
339
- dedupUntil: input.expiresAt
340
- }));
341
- const insertPending = database.insert(mapping.pending.table).values(mapping.pending.encodeInsert(record, {
342
- subjectId: nativeSubjectId,
343
- failedAttempts: 0,
344
- consumed: false
345
- }));
346
- return {
347
- receipt: prepare(record, journal),
348
- statements: [
349
- yield* assertion(condition),
350
- yield* statement(cleanupPending),
351
- yield* statement(cleanupFlow),
352
- yield* statement(insertFlow),
353
- yield* statement(insertPending)
354
- ]
355
- };
356
- }), mapping.isConstraintConflict, recoverFlowOrStale(mapping, input.evidence.flowId)),
357
- context: (input) => readAuthenticatedPending(mapping, input, "context").pipe(Effect.flatMap(pendingAuthenticationContext), terminalD1),
358
- read: (input) => readAuthenticatedPending(mapping, input, "record").pipe(terminalD1),
359
- reject: (input, prepare) => runPlanned(Effect.gen(function* () {
360
- const database = yield* CurrentD1PlanningDatabase;
361
- const journal = yield* CurrentCommitJournal;
362
- const record = yield* readPendingWith(mapping, input.digest, "context");
363
- if (record === void 0) return {
364
- receipt: prepare({ _tag: "Rejected" }, journal),
365
- statements: [yield* assertion(sql`true`)]
366
- };
367
- const nativeSubjectId = yield* mapping.subjectId.toNative(record.evidence.revision.subjectId);
368
- const p = pendingColumns(mapping);
369
- const condition = and(authorityCondition(mapping, nativeSubjectId, record.evidence), eq(p.digest, input.digest), eq(p.bindingDigest, input.bindingDigest), eq(p.consumed, false), gt(p.expiresAt, mapping.d1.engineNow));
370
- const update = database.update(mapping.pending.table).set(updateValues([[mapping.pending.failedAttempts, sql`case when ${p.failedAttempts} < ${p.attemptLimit} then ${p.failedAttempts} + 1 else ${p.failedAttempts} end`]])).where(condition);
371
- return {
372
- receipt: prepare({ _tag: "Rejected" }, journal),
373
- statements: [yield* statement(update)]
374
- };
375
- }))
376
- });
377
- const makeD1StatefulSessions = (mapping) => {
378
- const s = sessionColumns(mapping);
379
- return {
380
- persistence: {
381
- establish: (input, prepare) => runPlanned(Effect.gen(function* () {
382
- const database = yield* CurrentD1PlanningDatabase;
383
- const journal = yield* CurrentCommitJournal;
384
- const policy = yield* requirement(mapping, input.evidence);
385
- const assessed = yield* assessAuthentication(input.evidence, policy);
386
- if (!assessed.satisfied) return yield* stale();
387
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.evidence.revision.subjectId);
388
- if (input.pending === void 0 && (input.fresh !== true || input.handoffSourceSessionId !== void 0) && (yield* hasActiveFlow(mapping, input.evidence.flowId))) return yield* SessionConflict.make({});
389
- const nativeSessionId = yield* allocate(mapping.session.allocateId, mapping.session.allocateIdSync);
390
- const sessionId = yield* mapping.sessionId.toSession(nativeSessionId);
391
- if (sessionId === input.handoffSourceSessionId) return yield* SessionConflict.make({});
392
- const version = yield* allocate(mapping.session.allocateVersion, mapping.session.allocateVersionSync);
393
- const record = {
394
- ...input.session,
395
- sessionId,
396
- version,
397
- subjectId: input.evidence.revision.subjectId,
398
- securityRevision: input.evidence.revision.securityRevision,
399
- assurance: input.handoffSourceSessionId === void 0 ? assessed.assurance : input.session.assurance,
400
- provenance: yield* snapshotSessionAuthenticationProvenance({ evidence: input.evidence }),
401
- issuedAt: DateTime.makeUnsafe(DateTime.toEpochMillis(input.session.issuedAt))
402
- };
403
- const commitCondition = and(authorityCondition(mapping, nativeSubjectId, input.evidence), freshnessCondition(mapping, input.evidence, policy, true), sql`${DateTime.toEpochMillis(record.issuedAt)} <= ${mapping.d1.engineNowMillis}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(record.expiresAt)}`, sql`${DateTime.toEpochMillis(record.expiresAt)} <= ${DateTime.toEpochMillis(record.absoluteExpiresAt)}`);
404
- let condition = commitCondition;
405
- const statements = [];
406
- if (input.pending === void 0 && (input.fresh !== true || input.handoffSourceSessionId !== void 0)) {
407
- const f = flowColumns(mapping);
408
- condition = and(condition, not(sql`exists(select 1 from ${mapping.flow.table} where ${f.flowId} = ${sql.param(input.evidence.flowId, f.flowId)} and ${f.dedupUntil} > ${mapping.d1.engineNow})`));
409
- if (mapping.pending !== void 0) statements.push(yield* statement(database.delete(mapping.pending.table).where(eq(column(mapping.pending.table, mapping.pending.flowId), input.evidence.flowId))));
410
- statements.push(yield* statement(database.delete(mapping.flow.table).where(eq(f.flowId, input.evidence.flowId))), yield* statement(database.insert(mapping.flow.table).values(mapping.flow.encodeEstablishedInsert({
411
- evidence: input.evidence,
412
- subjectId: nativeSubjectId,
413
- dedupUntil: record.absoluteExpiresAt
414
- }))));
415
- } else if (input.pending !== void 0) {
416
- if (mapping.pending === void 0) return yield* invalidPending();
417
- const stored = yield* readPending(mapping, input.pending.digest);
418
- if (stored === void 0 || !sameOriginalRevision(input.evidence, stored.evidence)) return yield* invalidPending();
419
- condition = and(condition, pendingCondition(mapping, input.pending, nativeSubjectId));
420
- statements.push(...yield* consumePendingStatements(mapping, input.pending, record.absoluteExpiresAt));
421
- }
422
- statements.push(yield* statement(database.insert(mapping.session.table).values(mapping.session.encodeInsert(record, {
423
- subjectId: nativeSubjectId,
424
- sessionId: nativeSessionId
425
- }))), yield* assertion(commitCondition));
426
- return {
427
- receipt: prepare(record, journal),
428
- statements: [yield* assertion(condition), ...statements]
429
- };
430
- }), mapping.isConstraintConflict, Effect.suspend(() => input.pending === void 0 ? input.fresh === true && input.handoffSourceSessionId === void 0 ? Effect.fail(stale()) : recoverFlowOrStale(mapping, input.evidence.flowId) : recoverPendingOrStale(mapping, input.pending, input.evidence.revision.subjectId))),
431
- verify: (input) => Effect.gen(function* () {
432
- const rows = yield* (yield* CurrentD1PlanningDatabase).select({ ...getTableColumns(mapping.session.table) }).from(mapping.session.table).innerJoin(mapping.subject.table, and(eq(s.subjectId, subjectColumns(mapping).id), eq(s.securityRevision, subjectColumns(mapping).revision), eq(subjectColumns(mapping).status, mapping.d1.activeSubjectStatusValue))).where(and(eq(s.digest, input.digest), gt(s.expiresAt, mapping.d1.engineNow), gt(s.absoluteExpiresAt, mapping.d1.engineNow))).limit(1);
433
- if (rows[0] === void 0) return yield* invalidSession();
434
- return yield* mapping.session.decode(rows[0]);
435
- }).pipe(terminalD1),
436
- rotate: (input, prepare) => runPlanned(Effect.gen(function* () {
437
- const database = yield* CurrentD1PlanningDatabase;
438
- const journal = yield* CurrentCommitJournal;
439
- const nativeSessionId = yield* mapping.sessionId.toNative(input.sessionId);
440
- const row = (yield* database.select().from(mapping.session.table).where(eq(s.sessionId, nativeSessionId)).limit(1))[0];
441
- if (row === void 0) return yield* SessionConflict.make({});
442
- const current = yield* mapping.session.decode(row);
443
- const nativeSubjectId = yield* mapping.subjectId.toNative(current.subjectId);
444
- const version = yield* allocate(mapping.session.allocateVersion, mapping.session.allocateVersionSync);
445
- const next = {
446
- ...current,
447
- digest: input.nextDigest,
448
- credentialVersion: input.nextCredentialVersion,
449
- version,
450
- issuedAt: DateTime.makeUnsafe(DateTime.toEpochMillis(input.now)),
451
- expiresAt: input.nextExpiresAt
452
- };
453
- const sessionCondition = and(eq(s.sessionId, nativeSessionId), eq(s.digest, input.expectedDigest), eq(s.version, input.expectedVersion), eq(s.securityRevision, input.expectedSecurityRevision), gt(s.expiresAt, mapping.d1.engineNow), gt(s.absoluteExpiresAt, mapping.d1.engineNow));
454
- const timeCondition = and(sql`${DateTime.toEpochMillis(next.issuedAt)} <= ${mapping.d1.engineNowMillis}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(input.nextExpiresAt)}`, sql`${DateTime.toEpochMillis(input.nextExpiresAt)} <= ${DateTime.toEpochMillis(current.absoluteExpiresAt)}`);
455
- const authority = subjectRevisionCondition(mapping, nativeSubjectId, input.expectedSecurityRevision);
456
- const assertionCondition = and(authority, sql`exists(select 1 from ${mapping.session.table} where ${sessionCondition})`, timeCondition);
457
- const update = database.update(mapping.session.table).set(mapping.session.encodeRotation(next)).where(and(authority, sessionCondition, timeCondition));
458
- return {
459
- receipt: prepare(next, journal),
460
- statements: [yield* assertion(assertionCondition), yield* statement(update)]
461
- };
462
- }), void 0, Effect.fail(SessionConflict.make({}))),
463
- revokeDigest: (digest, prepare) => runPlanned(Effect.gen(function* () {
464
- const database = yield* CurrentD1PlanningDatabase;
465
- const journal = yield* CurrentCommitJournal;
466
- const row = (yield* database.select().from(mapping.session.table).where(eq(s.digest, digest)).limit(1))[0];
467
- const statements = row === void 0 ? [yield* assertion(sql`true`)] : [yield* statement(database.delete(mapping.session.table).where(eq(s.digest, digest)))];
468
- return {
469
- receipt: prepare(row !== void 0, journal),
470
- statements
471
- };
472
- })),
473
- revoke: (input, prepare) => runPlanned(Effect.gen(function* () {
474
- const database = yield* CurrentD1PlanningDatabase;
475
- const journal = yield* CurrentCommitJournal;
476
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.subjectId);
477
- const nativeSessionId = yield* mapping.sessionId.toNative(input.sessionId);
478
- const condition = subjectRevisionCondition(mapping, nativeSubjectId, input.expectedSecurityRevision);
479
- const remove = database.delete(mapping.session.table).where(and(eq(s.subjectId, nativeSubjectId), eq(s.sessionId, nativeSessionId)));
480
- return {
481
- receipt: prepare(void 0, journal),
482
- statements: [yield* assertion(condition), yield* statement(remove)]
483
- };
484
- }), void 0, Effect.fail(stale())),
485
- revokeAll: (input, prepare) => runPlanned(Effect.gen(function* () {
486
- const database = yield* CurrentD1PlanningDatabase;
487
- const journal = yield* CurrentCommitJournal;
488
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.subjectId);
489
- const next = yield* allocate(mapping.subject.nextSecurityRevision?.(input.expectedSecurityRevision), mapping.subject.nextSecurityRevisionSync === void 0 ? void 0 : () => mapping.subject.nextSecurityRevisionSync(input.expectedSecurityRevision));
490
- const sc = subjectColumns(mapping);
491
- const condition = and(eq(sc.id, nativeSubjectId), eq(sc.status, mapping.d1.activeSubjectStatusValue), eq(sc.revision, input.expectedSecurityRevision));
492
- const updateSubject = database.update(mapping.subject.table).set(updateValues([[mapping.subject.securityRevision, next]])).where(condition);
493
- const removeSessions = database.delete(mapping.session.table).where(eq(s.subjectId, nativeSubjectId));
494
- return {
495
- receipt: prepare(void 0, journal),
496
- statements: [
497
- yield* assertion(sql`exists(select 1 from ${mapping.subject.table} where ${condition})`),
498
- yield* statement(updateSubject),
499
- yield* statement(removeSessions)
500
- ]
501
- };
502
- }), void 0, Effect.fail(stale()))
503
- },
504
- repository: { list: (input) => Effect.gen(function* () {
505
- const database = yield* CurrentD1PlanningDatabase;
506
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.subjectId);
507
- const cursor = input.cursor === void 0 ? void 0 : yield* mapping.sessionId.toNative(input.cursor);
508
- const rows = yield* database.select({ ...getTableColumns(mapping.session.table) }).from(mapping.session.table).innerJoin(mapping.subject.table, and(eq(s.subjectId, subjectColumns(mapping).id), eq(s.securityRevision, subjectColumns(mapping).revision), eq(subjectColumns(mapping).status, mapping.d1.activeSubjectStatusValue))).where(and(eq(s.subjectId, nativeSubjectId), gt(s.expiresAt, mapping.d1.engineNow), gt(s.absoluteExpiresAt, mapping.d1.engineNow), cursor === void 0 ? void 0 : gt(s.sessionId, cursor))).orderBy(s.sessionId).limit(input.limit + 1);
509
- const decoded = yield* Effect.forEach(rows, (row) => mapping.session.decode(row));
510
- const codec = Schema.toCodecJson(Schema.toType(SessionMetadata));
511
- const sessions = yield* Effect.forEach(decoded.slice(0, input.limit), (record) => Schema.encodeEffect(codec)(record).pipe(Effect.flatMap(Schema.decodeEffect(codec))));
512
- const nextCursor = decoded.length <= input.limit ? void 0 : sessions.at(-1)?.sessionId;
513
- return {
514
- sessions,
515
- ...nextCursor === void 0 ? {} : { nextCursor }
516
- };
517
- }).pipe(terminalD1) }
518
- };
519
- };
520
- const makeD1SignedValidity = (mapping) => {
521
- const sc = subjectColumns(mapping);
522
- const t = {
523
- subjectId: column(mapping.tombstone.table, mapping.tombstone.subjectId),
524
- sessionId: column(mapping.tombstone.table, mapping.tombstone.sessionId),
525
- absoluteExpiresAt: column(mapping.tombstone.table, mapping.tombstone.absoluteExpiresAt)
526
- };
527
- return {
528
- verify: (session, _now) => Effect.gen(function* () {
529
- const database = yield* CurrentD1PlanningDatabase;
530
- const nativeSubjectId = yield* mapping.subjectId.toNative(session.subjectId);
531
- const nativeSessionId = yield* mapping.sessionId.toNative(session.sessionId);
532
- if ((yield* database.select({ subjectId: sc.id }).from(mapping.subject.table).where(and(eq(sc.id, nativeSubjectId), eq(sc.status, mapping.d1.activeSubjectStatusValue), eq(sc.revision, session.securityRevision), sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(session.expiresAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(session.absoluteExpiresAt)}`, not(sql`exists(select 1 from ${mapping.tombstone.table} where ${t.subjectId} = ${sql.param(nativeSubjectId, t.subjectId)} and ${t.sessionId} = ${sql.param(nativeSessionId, t.sessionId)} and ${t.absoluteExpiresAt} > ${mapping.d1.engineNow})`))).limit(1)).length === 0) return yield* invalidSession();
533
- }).pipe(terminalD1),
534
- revoke: (input, prepare) => runPlanned(Effect.gen(function* () {
535
- const database = yield* CurrentD1PlanningDatabase;
536
- const journal = yield* CurrentCommitJournal;
537
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.subjectId);
538
- const nativeSessionId = yield* mapping.sessionId.toNative(input.sessionId);
539
- const condition = sql`exists(select 1 from ${mapping.subject.table} where ${sc.id} = ${sql.param(nativeSubjectId, sc.id)} and ${sc.status} = ${sql.param(mapping.d1.activeSubjectStatusValue, sc.status)} and ${sc.revision} = ${sql.param(input.expectedSecurityRevision, sc.revision)})`;
540
- const encodedExpiry = mapping.tombstone.encodeInstant(input.absoluteExpiresAt);
541
- const desiredExpiry = sql.param(encodedExpiry, t.absoluteExpiresAt);
542
- const write = database.insert(mapping.tombstone.table).values(mapping.tombstone.encodeInsert({
543
- subjectId: nativeSubjectId,
544
- sessionId: nativeSessionId,
545
- absoluteExpiresAt: input.absoluteExpiresAt
546
- })).onConflictDoUpdate({
547
- target: [t.subjectId, t.sessionId],
548
- set: updateValues([[mapping.tombstone.absoluteExpiresAt, sql`case when ${t.absoluteExpiresAt} < ${desiredExpiry} then ${desiredExpiry} else ${t.absoluteExpiresAt} end`]])
549
- });
550
- return {
551
- receipt: prepare(void 0, journal),
552
- statements: [yield* assertion(condition), yield* statement(write)]
553
- };
554
- }), void 0, Effect.fail(stale())),
555
- revokeAll: (input, prepare) => runPlanned(Effect.gen(function* () {
556
- const database = yield* CurrentD1PlanningDatabase;
557
- const journal = yield* CurrentCommitJournal;
558
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.subjectId);
559
- const next = yield* allocate(mapping.subject.nextSecurityRevision?.(input.expectedSecurityRevision), mapping.subject.nextSecurityRevisionSync === void 0 ? void 0 : () => mapping.subject.nextSecurityRevisionSync(input.expectedSecurityRevision));
560
- const condition = and(eq(sc.id, nativeSubjectId), eq(sc.status, mapping.d1.activeSubjectStatusValue), eq(sc.revision, input.expectedSecurityRevision));
561
- const updateSubject = database.update(mapping.subject.table).set(updateValues([[mapping.subject.securityRevision, next]])).where(condition);
562
- return {
563
- receipt: prepare(void 0, journal),
564
- statements: [yield* assertion(sql`exists(select 1 from ${mapping.subject.table} where ${condition})`), yield* statement(updateSubject)]
565
- };
566
- }), void 0, Effect.fail(stale()))
567
- };
568
- };
569
- const makeD1SessionServiceEffects = {
570
- authority: (mapping) => Effect.gen(function* () {
571
- const database = yield* CurrentD1PlanningDatabase;
572
- yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
573
- const hooks = yield* LifecycleHooks;
574
- const raw = makeD1AuthenticationAuthority(mapping);
575
- const run = (effect) => Effect.gen(function* () {
576
- if ((yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" || (yield* hasCommitScope)) return yield* unavailable();
577
- return yield* effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
578
- });
579
- return { authenticationAuthority: {
580
- capture: (subjectId, credentialIds) => run(raw.capture(subjectId, credentialIds)),
581
- requirements: (evidence) => run(raw.requirements(evidence)),
582
- approve: (input, prepare) => run(raw.approve(input, prepare))
583
- } };
584
- }),
585
- pending: (mapping) => Effect.gen(function* () {
586
- const database = yield* CurrentD1PlanningDatabase;
587
- yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
588
- const hooks = yield* LifecycleHooks;
589
- const raw = makeD1PendingAuthentication(mapping);
590
- const run = (effect) => Effect.gen(function* () {
591
- if ((yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" || (yield* hasCommitScope)) return yield* unavailable();
592
- return yield* effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
593
- });
594
- return { pendingAuthentication: {
595
- create: (input, now, prepare) => run(raw.create(input, now, prepare)),
596
- context: (input) => run(raw.context(input)),
597
- read: (input) => run(raw.read(input)),
598
- reject: (input, prepare) => run(raw.reject(input, prepare))
599
- } };
600
- }),
601
- stateful: (mapping) => Effect.gen(function* () {
602
- const database = yield* CurrentD1PlanningDatabase;
603
- yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
604
- const hooks = yield* LifecycleHooks;
605
- const raw = makeD1StatefulSessions(mapping);
606
- const run = (effect) => Effect.gen(function* () {
607
- if ((yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" || (yield* hasCommitScope)) return yield* unavailable();
608
- return yield* effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
609
- });
610
- return {
611
- statefulSessionPersistence: {
612
- establish: (input, prepare) => run(raw.persistence.establish(input, prepare)),
613
- verify: (input) => run(raw.persistence.verify(input)),
614
- rotate: (input, prepare) => run(raw.persistence.rotate(input, prepare)),
615
- revokeDigest: (digest, prepare) => run(raw.persistence.revokeDigest(digest, prepare)),
616
- revoke: (input, prepare) => run(raw.persistence.revoke(input, prepare)),
617
- revokeAll: (input, prepare) => run(raw.persistence.revokeAll(input, prepare))
618
- },
619
- sessionRepository: { list: (input) => run(raw.repository.list(input)) }
620
- };
621
- }),
622
- validity: (mapping) => Effect.gen(function* () {
623
- const database = yield* CurrentD1PlanningDatabase;
624
- yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
625
- const hooks = yield* LifecycleHooks;
626
- const raw = makeD1SignedValidity(mapping);
627
- const run = (effect) => Effect.gen(function* () {
628
- if ((yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" || (yield* hasCommitScope)) return yield* unavailable();
629
- return yield* effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
630
- });
631
- return { signedSessionValidity: {
632
- verify: (session, now) => run(raw.verify(session, now)),
633
- revoke: (input, prepare) => run(raw.revoke(input, prepare)),
634
- revokeAll: (input, prepare) => run(raw.revokeAll(input, prepare))
635
- } };
636
- })
637
- };
638
- /**
639
- * Owns one atomic D1 persistence transition together with any number of
640
- * application statements appended by `owner`. Keeping one persistence
641
- * transition makes a failed batch's domain guard recoverable without exposing
642
- * a prepared value. Compose additional transitions in later root batches.
643
- * Interruption or owner failure before `$client.batch` discards the journal;
644
- * the adapter performs no hidden retry and a retry must re-plan the whole owner.
645
- * Caller failures remain in the error channel. D1 batch/transport failures that
646
- * cannot be tied to this adapter's reserved guard become `SessionUnavailable`.
647
- */
648
- const coordinateD1SessionBatch = (database, mapping, make, owner) => Effect.gen(function* () {
649
- if (yield* hasCommitScope) return yield* unavailable();
650
- yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
651
- return (yield* coordinateCommit(() => Effect.gen(function* () {
652
- const statements = [];
653
- let mutation;
654
- const nativeCollector = D1BatchStatements.of({ append: (statement) => Effect.sync(() => statements.push(statement)) });
655
- const d1Owner = yield* makeD1Owner(unavailable()).pipe(Effect.provideService(D1BatchStatements, nativeCollector));
656
- let batch;
657
- const appendMutation = (input) => d1Owner.run(Effect.suspend(() => {
658
- if (mutation !== void 0) return Effect.fail(unavailable());
659
- mutation = input;
660
- statements.push(...input.statements);
661
- return Effect.void;
662
- }));
663
- batch = {
664
- owner: d1Owner,
665
- append: appendMutation
666
- };
667
- const services = yield* make(batch);
668
- const value = yield* d1Owner.close(Effect.provideService(owner(services, batch), D1BatchStatements, d1Owner.collector));
669
- if (mutation?.journalGuard !== void 0) {
670
- const status = yield* Effect.result(mutation.journalGuard.read);
671
- if (status._tag === "Success" || status.failure._tag !== "CommitPending") return yield* unavailable();
672
- }
673
- yield* database.$client.batch(statements).pipe(Effect.catchCause((cause) => Effect.fail(new D1BatchFailure({
674
- cause,
675
- ...mutation === void 0 ? {} : { mutation }
676
- }))));
677
- return value;
678
- }), { mode: "batch" }).pipe(Effect.catchCause(recoverCoordinatedD1BatchCause), Effect.provideService(CurrentD1PlanningDatabase, database))).value;
679
- });
680
- const makeD1AuthenticationAuthorityServices = (mapping) => makeD1SessionServiceEffects.authority(mapping).pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, Database), Effect.provideServiceEffect(NativeDatabase, nativeDatabase(Database)));
681
- const makeD1PendingAuthenticationServices = (mapping) => makeD1SessionServiceEffects.pending(mapping).pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, Database), Effect.provideServiceEffect(NativeDatabase, nativeDatabase(Database)));
682
- const makeD1StatefulSessionServices = (mapping) => makeD1SessionServiceEffects.stateful(mapping).pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, Database), Effect.provideServiceEffect(NativeDatabase, nativeDatabase(Database)));
683
- const makeD1SignedSessionValidityServices = (mapping) => makeD1SessionServiceEffects.validity(mapping).pipe(Effect.provideServiceEffect(CurrentD1PlanningDatabase, Database), Effect.provideServiceEffect(NativeDatabase, nativeDatabase(Database)));
684
- function coordinateD1AuthenticationAuthority(acquire, options, body) {
685
- return Effect.flatMap(nativeDatabase(acquire), (database) => coordinateD1SessionBatch(database, options.mapping, (batch) => Effect.gen(function* () {
686
- const hooks = yield* LifecycleHooks;
687
- const raw = makeD1AuthenticationAuthority(options.mapping);
688
- const run = (effect) => batch.owner.run(effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), Effect.provideService(CurrentD1SessionBatch, batch)));
689
- return { authenticationAuthority: {
690
- capture: (subjectId, credentialIds) => run(raw.capture(subjectId, credentialIds)),
691
- requirements: (evidence) => run(raw.requirements(evidence)),
692
- approve: (input, prepare) => run(raw.approve(input, prepare))
693
- } };
694
- }), (ownedServices, batch) => {
695
- const provided = Context.make(AuthenticationAuthority, ownedServices.authenticationAuthority).pipe(Context.add(D1BatchStatements, batch.owner.collector));
696
- return Effect.provideContext(body, provided);
697
- }).pipe(Effect.provideService(NativeDatabase, database)));
698
- }
699
- function coordinateD1PendingAuthentication(acquire, options, body) {
700
- return Effect.flatMap(nativeDatabase(acquire), (database) => coordinateD1SessionBatch(database, options.mapping, (batch) => Effect.gen(function* () {
701
- const hooks = yield* LifecycleHooks;
702
- const raw = makeD1PendingAuthentication(options.mapping);
703
- const run = (effect) => batch.owner.run(effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), Effect.provideService(CurrentD1SessionBatch, batch)));
704
- return { pendingAuthentication: {
705
- create: (input, now, prepare) => run(raw.create(input, now, prepare)),
706
- context: (input) => run(raw.context(input)),
707
- read: (input) => run(raw.read(input)),
708
- reject: (input, prepare) => run(raw.reject(input, prepare))
709
- } };
710
- }), (ownedServices, batch) => {
711
- const provided = Context.make(options.target, ownedServices.pendingAuthentication).pipe(Context.add(D1BatchStatements, batch.owner.collector));
712
- return Effect.provideContext(body, provided);
713
- }).pipe(Effect.provideService(NativeDatabase, database)));
714
- }
715
- function coordinateD1StatefulSessions(acquire, options, body) {
716
- return Effect.flatMap(nativeDatabase(acquire), (database) => coordinateD1SessionBatch(database, options.mapping, (batch) => Effect.gen(function* () {
717
- const hooks = yield* LifecycleHooks;
718
- const raw = makeD1StatefulSessions(options.mapping);
719
- const run = (effect) => batch.owner.run(effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), Effect.provideService(CurrentD1SessionBatch, batch)));
720
- return {
721
- statefulSessionPersistence: {
722
- establish: (input, prepare) => run(raw.persistence.establish(input, prepare)),
723
- verify: (input) => run(raw.persistence.verify(input)),
724
- rotate: (input, prepare) => run(raw.persistence.rotate(input, prepare)),
725
- revokeDigest: (digest, prepare) => run(raw.persistence.revokeDigest(digest, prepare)),
726
- revoke: (input, prepare) => run(raw.persistence.revoke(input, prepare)),
727
- revokeAll: (input, prepare) => run(raw.persistence.revokeAll(input, prepare))
728
- },
729
- sessionRepository: { list: (input) => run(raw.repository.list(input)) }
730
- };
731
- }), (ownedServices, batch) => {
732
- const provided = Context.make(options.persistence, ownedServices.statefulSessionPersistence).pipe(Context.add(options.repository, ownedServices.sessionRepository), Context.add(D1BatchStatements, batch.owner.collector));
733
- return Effect.provideContext(body, provided);
734
- }).pipe(Effect.provideService(NativeDatabase, database)));
735
- }
736
- function coordinateD1SignedSessionValidity(acquire, options, body) {
737
- return Effect.flatMap(nativeDatabase(acquire), (database) => coordinateD1SessionBatch(database, options.mapping, (batch) => Effect.gen(function* () {
738
- const hooks = yield* LifecycleHooks;
739
- const raw = makeD1SignedValidity(options.mapping);
740
- const run = (effect) => batch.owner.run(effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), Effect.provideService(CurrentD1SessionBatch, batch)));
741
- return { signedSessionValidity: {
742
- verify: (session, now) => run(raw.verify(session, now)),
743
- revoke: (input, prepare) => run(raw.revoke(input, prepare)),
744
- revokeAll: (input, prepare) => run(raw.revokeAll(input, prepare))
745
- } };
746
- }), (ownedServices, batch) => {
747
- const provided = Context.make(options.target, ownedServices.signedSessionValidity).pipe(Context.add(D1BatchStatements, batch.owner.collector));
748
- return Effect.provideContext(body, provided);
749
- }).pipe(Effect.provideService(NativeDatabase, database)));
750
- }
751
- const stepUpColumns = (mapping) => Object.fromEntries([
752
- "digest",
753
- "version",
754
- "flowId",
755
- "subjectId",
756
- "bindingDigest",
757
- "snapshot",
758
- "expiresAt",
759
- "attemptLimit",
760
- "failedAttempts",
761
- "consumed"
762
- ].map((key) => [key, column(mapping.intent.table, mapping.intent[key])]));
763
- const stepUpSourceCondition = (mapping, intent, nativeSubjectId, nativeSessionId, plan) => {
764
- const source = mapping.source;
765
- if (source.kind !== intent.sourceKind) return sql`false`;
766
- const time = and(sql`${mapping.d1.engineNowMillis} >= ${DateTime.toEpochMillis(intent.sourceAuthenticatedAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(intent.sourceExpiresAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(intent.sourceAbsoluteExpiresAt)}`);
767
- if (source.kind === "StatelessSigned") return time;
768
- if (source.kind === "StateAssistedSigned") {
769
- const t = source.tombstone, owner = column(t.table, t.subjectId), id = column(t.table, t.sessionId), expiry = column(t.table, t.absoluteExpiresAt);
770
- return and(time, not(sql`exists(select 1 from ${t.table} where ${owner}=${sql.param(nativeSubjectId, owner)} and ${id}=${sql.param(nativeSessionId, id)} and ${expiry}>${mapping.d1.engineNow})`));
771
- }
772
- const s = source.session, c = sessionColumns(source);
773
- const condition = and(eq(c.sessionId, nativeSessionId), eq(c.subjectId, nativeSubjectId), eq(c.securityRevision, intent.revision.securityRevision), eq(column(s.table, s.credentialVersion), intent.sourceCredentialVersion), eq(column(s.table, s.authenticatedAt), s.encodeInstant(intent.sourceAuthenticatedAt)), eq(c.expiresAt, s.encodeInstant(intent.sourceExpiresAt)), eq(c.absoluteExpiresAt, s.encodeInstant(intent.sourceAbsoluteExpiresAt)), gt(c.expiresAt, mapping.d1.engineNow), gt(c.absoluteExpiresAt, mapping.d1.engineNow), plan?.replacement._tag === "Stateful" ? eq(c.digest, plan.replacement.expectedDigest) : void 0, plan?.replacement._tag === "Stateful" ? eq(c.version, plan.replacement.expectedRowVersion) : void 0);
774
- return and(time, sql`exists(select 1 from ${s.table} where ${condition})`);
775
- };
776
- const stepUpRowCondition = (mapping, row, intent, nativeSubjectId) => {
777
- const c = stepUpColumns(mapping), m = mapping.intent;
778
- return and(eq(c.digest, intent.digest), eq(c.version, intent.version), eq(c.flowId, intent.flowId), eq(c.subjectId, nativeSubjectId), eq(c.bindingDigest, intent.bindingDigest), eq(c.snapshot, row[m.snapshot]), eq(c.expiresAt, m.encodeInstant(intent.expiresAt)), eq(c.attemptLimit, intent.attemptLimit), eq(c.consumed, false), eq(c.failedAttempts, row[m.failedAttempts]), sql`${c.failedAttempts} >= 0`, sql`${c.failedAttempts} < ${c.attemptLimit}`, gt(c.expiresAt, mapping.d1.engineNow));
779
- };
780
- const readD1StepUp = Effect.fn("DrizzleD1StepUp.read")(function* (mapping, digest) {
781
- const database = yield* CurrentD1PlanningDatabase;
782
- const m = mapping.intent, c = stepUpColumns(mapping);
783
- const row = (yield* database.select().from(m.table).where(eq(c.digest, digest)).limit(1))[0];
784
- if (row === void 0) return yield* SessionStepUpInvalid.make({});
785
- const intent = yield* decodeStepUpIntent(row[m.snapshot]);
786
- if (intent.digest !== digest || !stepUpIntentLive(intent, mapping.source.kind, yield* DateTime.now) || !Schema.is(Schema.Natural)(row[m.failedAttempts])) return yield* SessionStepUpInvalid.make({});
787
- const nativeSubjectId = yield* mapping.subjectId.toNative(intent.revision.subjectId);
788
- const nativeSessionId = mapping.source.kind === "StatelessSigned" ? void 0 : yield* mapping.source.sessionId.toNative(intent.sourceSessionId);
789
- const condition = and(authorityCondition(mapping, nativeSubjectId, intent), stepUpSourceCondition(mapping, intent, nativeSubjectId, nativeSessionId), sql`exists(select 1 from ${m.table} where ${stepUpRowCondition(mapping, row, intent, nativeSubjectId)})`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(intent.expiresAt)}`);
790
- if (!(yield* conditionMatches(condition))) return yield* SessionStepUpInvalid.make({});
791
- return {
792
- row,
793
- intent,
794
- nativeSubjectId,
795
- nativeSessionId
796
- };
797
- });
798
- const isD1StepUpRejectAbsence = (error) => typeof error === "object" && error !== null && Reflect.get(error, "_tag") === "SessionStepUpInvalid";
799
- const recoverD1StepUpRejectAbsence = (effect, rejected) => effect.pipe(Effect.catchCause((cause) => {
800
- if (cause.reasons.length > 0 && cause.reasons.every((reason) => Cause.isFailReason(reason) && isD1StepUpRejectAbsence(reason.error))) return Effect.succeed(rejected);
801
- return Effect.failCause(Cause.map(cause, (error) => isD1StepUpRejectAbsence(error) ? SessionUnavailable.make({}) : error));
802
- }));
803
- const makeD1SessionStepUp = (mapping) => {
804
- const m = mapping.intent, c = stepUpColumns(mapping);
805
- const recover = Effect.fail(SessionStepUpInvalid.make({}));
806
- return {
807
- create: (input, _now, prepare) => runPlanned(Effect.gen(function* () {
808
- const database = yield* CurrentD1PlanningDatabase;
809
- const journal = yield* CurrentCommitJournal;
810
- const version = yield* allocate(m.allocateVersion, m.allocateVersionSync), record = {
811
- ...input,
812
- version
813
- };
814
- if (!stepUpIntentLive(record, mapping.source.kind, yield* DateTime.now)) return yield* stale();
815
- const nativeSubjectId = yield* mapping.subjectId.toNative(input.revision.subjectId);
816
- const nativeSessionId = mapping.source.kind === "StatelessSigned" ? void 0 : yield* mapping.source.sessionId.toNative(input.sourceSessionId);
817
- if ((yield* database.select().from(m.table).where(or(eq(c.digest, input.digest), eq(c.flowId, input.flowId))).limit(1)).length > 0) return yield* SessionConflict.make({});
818
- const condition = and(authorityCondition(mapping, nativeSubjectId, record), stepUpSourceCondition(mapping, record, nativeSubjectId, nativeSessionId), sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(input.expiresAt)}`);
819
- if (!(yield* conditionMatches(condition))) return yield* stale();
820
- const snapshot = yield* encodeStepUpIntent(record);
821
- const values = {
822
- ...m.encodeInsert(record, { subjectId: nativeSubjectId }),
823
- ...updateValues([
824
- [m.digest, record.digest],
825
- [m.version, version],
826
- [m.flowId, record.flowId],
827
- [m.subjectId, nativeSubjectId],
828
- [m.bindingDigest, record.bindingDigest],
829
- [m.snapshot, snapshot],
830
- [m.expiresAt, m.encodeInstant(record.expiresAt)],
831
- [m.attemptLimit, record.attemptLimit],
832
- [m.failedAttempts, 0],
833
- [m.consumed, false]
834
- ])
835
- };
836
- const receipt = prepare(record, journal);
837
- const exact = and(eq(c.digest, record.digest), eq(c.version, version), eq(c.flowId, record.flowId), eq(c.subjectId, nativeSubjectId), eq(c.bindingDigest, record.bindingDigest), eq(c.snapshot, snapshot), eq(c.expiresAt, m.encodeInstant(record.expiresAt)), eq(c.attemptLimit, record.attemptLimit), eq(c.failedAttempts, 0), eq(c.consumed, false));
838
- return {
839
- receipt,
840
- statements: [
841
- yield* assertion(condition),
842
- yield* statement(database.insert(m.table).values(values)),
843
- yield* assertion(sql`changes() = 1`),
844
- yield* assertion(and(condition, sql`exists(select 1 from ${m.table} where ${exact})`))
845
- ]
846
- };
847
- }), mapping.isConstraintConflict, Effect.fail(stale())),
848
- context: (input) => mapFailureCause(readD1StepUp(mapping, input.digest).pipe(Effect.flatMap(({ intent }) => snapshotPendingAuthenticationContext({
849
- flowId: intent.flowId,
850
- bindingDigest: intent.bindingDigest,
851
- revision: intent.revision,
852
- expiresAtMillis: DateTime.toEpochMillis(intent.expiresAt)
853
- }))), (error) => error._tag === "PendingAuthenticationInvalid" ? unavailable() : error).pipe(terminalD1),
854
- read: (input) => readD1StepUp(mapping, input.digest).pipe(Effect.flatMap(({ intent }) => intent.bindingDigest === input.bindingDigest ? Effect.succeed(intent) : Effect.fail(SessionStepUpInvalid.make({}))), terminalD1),
855
- reject: (input, prepare) => runPlanned(Effect.gen(function* () {
856
- const database = yield* CurrentD1PlanningDatabase;
857
- const journal = yield* CurrentCommitJournal;
858
- const selected = yield* recoverD1StepUpRejectAbsence(readD1StepUp(mapping, input.digest).pipe(Effect.map((value) => ({
859
- _tag: "Found",
860
- value
861
- }))), { _tag: "Rejected" });
862
- if (selected._tag === "Rejected") return {
863
- receipt: prepare({ _tag: "Rejected" }, journal),
864
- statements: []
865
- };
866
- const { row, intent, nativeSubjectId, nativeSessionId } = selected.value;
867
- const condition = and(eq(c.digest, intent.digest), eq(c.version, intent.version), eq(c.snapshot, row[m.snapshot]), eq(c.subjectId, nativeSubjectId), eq(c.bindingDigest, intent.bindingDigest), eq(c.flowId, intent.flowId), eq(c.expiresAt, m.encodeInstant(intent.expiresAt)), eq(c.attemptLimit, intent.attemptLimit), eq(c.consumed, false), sql`${c.failedAttempts} >= 0`, sql`${c.failedAttempts} < ${c.attemptLimit}`, gt(c.expiresAt, mapping.d1.engineNow), authorityCondition(mapping, nativeSubjectId, intent), stepUpSourceCondition(mapping, intent, nativeSubjectId, nativeSessionId));
868
- const write = database.update(m.table).set(updateValues([[m.failedAttempts, sql`${c.failedAttempts} + 1`]])).where(condition);
869
- const settled = sql`changes() = 1 or not exists(select 1 from ${m.table} where ${condition})`;
870
- return {
871
- receipt: prepare({ _tag: "Rejected" }, journal),
872
- statements: [yield* statement(write), yield* assertion(settled)]
873
- };
874
- }), void 0, Effect.fail(unavailable())),
875
- complete: (plan, prepare) => runPlanned(Effect.gen(function* () {
876
- const database = yield* CurrentD1PlanningDatabase;
877
- const journal = yield* CurrentCommitJournal;
878
- yield* validateStepUpPlan(plan);
879
- const stored = yield* readD1StepUp(mapping, plan.intent.digest);
880
- if ((yield* encodeStepUpIntent(stored.intent)) !== (yield* encodeStepUpIntent(plan.intent))) return yield* SessionStepUpInvalid.make({});
881
- const base = yield* requirement(mapping, plan.evidence);
882
- if (!(yield* assessAuthentication(plan.evidence, base)).satisfied || !(yield* assessAuthentication(plan.evidence, stored.intent.requirement)).satisfied) return yield* stale();
883
- const { row, intent, nativeSubjectId, nativeSessionId } = stored, replacement = plan.replacement;
884
- const target = replacement.inspection.session;
885
- if (DateTime.toEpochMillis(target.expiresAt) > DateTime.toEpochMillis(intent.sourceAbsoluteExpiresAt)) return yield* SessionStepUpInvalid.make({});
886
- const live = and(authorityCondition(mapping, nativeSubjectId, plan.evidence), freshnessCondition(mapping, plan.evidence, base, true), freshnessCondition(mapping, plan.evidence, intent.requirement, true), sql`${mapping.d1.engineNowMillis} >= ${DateTime.toEpochMillis(intent.sourceAuthenticatedAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(intent.expiresAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(intent.sourceExpiresAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(intent.sourceAbsoluteExpiresAt)}`, sql`${mapping.d1.engineNowMillis} >= ${DateTime.toEpochMillis(target.issuedAt)}`, sql`${mapping.d1.engineNowMillis} < ${DateTime.toEpochMillis(target.expiresAt)}`);
887
- const source = stepUpSourceCondition(mapping, intent, nativeSubjectId, nativeSessionId, plan);
888
- const version = yield* allocate(m.allocateVersion, m.allocateVersionSync);
889
- if (version === intent.version) return yield* unavailable();
890
- const snapshot = yield* encodeStepUpIntent({
891
- ...intent,
892
- version
893
- });
894
- const consume = database.update(m.table).set(updateValues([
895
- [m.consumed, true],
896
- [m.version, version],
897
- [m.snapshot, snapshot]
898
- ])).where(and(stepUpRowCondition(mapping, row, intent, nativeSubjectId), live, source));
899
- const marker = sql`exists(select 1 from ${m.table} where ${c.digest}=${sql.param(intent.digest, c.digest)} and ${c.version}=${sql.param(version, c.version)} and ${c.snapshot}=${sql.param(snapshot, c.snapshot)} and ${c.consumed}=${sql.param(true, c.consumed)} and ${c.failedAttempts}=${row[m.failedAttempts]})`;
900
- const statements = [yield* statement(consume), yield* assertion(sql`changes() = 1`)];
901
- let post = sql`true`;
902
- if (replacement._tag === "Stateful") {
903
- if (mapping.source.kind !== "Stateful") return yield* SessionStepUpInvalid.make({});
904
- const s = mapping.source.session, sc = sessionColumns(mapping.source);
905
- const rowVersion = yield* allocate(s.allocateVersion, s.allocateVersionSync);
906
- const next = {
907
- ...target,
908
- provenance: replacement.inspection.provenance,
909
- credentialVersion: replacement.inspection.credentialVersion,
910
- digest: replacement.nextDigest,
911
- version: rowVersion
912
- };
913
- const rotation = {
914
- ...s.encodeRotation(next),
915
- ...updateValues([
916
- [s.version, rowVersion],
917
- [s.digest, next.digest],
918
- [s.credentialVersion, next.credentialVersion],
919
- [s.authenticatedAt, s.encodeInstant(target.assurance.authenticatedAt)],
920
- [s.issuedAt, s.encodeInstant(target.issuedAt)],
921
- [s.expiresAt, s.encodeInstant(target.expiresAt)],
922
- [s.absoluteExpiresAt, s.encodeInstant(target.absoluteExpiresAt)]
923
- ])
924
- };
925
- const write = database.update(s.table).set(rotation).where(and(eq(sc.sessionId, nativeSessionId), eq(sc.digest, replacement.expectedDigest), eq(sc.version, replacement.expectedRowVersion), marker, source, live));
926
- statements.push(yield* statement(write), yield* assertion(sql`changes() = 1`));
927
- const exact = and(eq(sc.sessionId, nativeSessionId), eq(sc.subjectId, nativeSubjectId), eq(sc.version, rowVersion), eq(sc.digest, next.digest), eq(sc.securityRevision, target.securityRevision), eq(column(s.table, s.credentialVersion), next.credentialVersion), eq(column(s.table, s.authenticatedAt), s.encodeInstant(target.assurance.authenticatedAt)), eq(sc.issuedAt, s.encodeInstant(target.issuedAt)), eq(sc.expiresAt, s.encodeInstant(target.expiresAt)), eq(sc.absoluteExpiresAt, s.encodeInstant(target.absoluteExpiresAt)));
928
- post = sql`exists(select 1 from ${s.table} where ${exact})`;
929
- } else if (replacement._tag === "StateAssistedSigned") {
930
- if (mapping.source.kind !== "StateAssistedSigned") return yield* SessionStepUpInvalid.make({});
931
- const t = mapping.source.tombstone, owner = column(t.table, t.subjectId), id = column(t.table, t.sessionId), expiry = column(t.table, t.absoluteExpiresAt);
932
- statements.push(yield* statement(database.delete(t.table).where(and(eq(owner, nativeSubjectId), eq(id, nativeSessionId), sql`${expiry} <= ${mapping.d1.engineNow}`, marker))));
933
- const values = t.encodeInsert({
934
- subjectId: nativeSubjectId,
935
- sessionId: nativeSessionId,
936
- absoluteExpiresAt: replacement.tombstoneUntil
937
- });
938
- statements.push(yield* statement(database.insert(t.table).values(values)), yield* assertion(sql`changes() = 1`));
939
- const exact = and(eq(owner, nativeSubjectId), eq(id, nativeSessionId), eq(expiry, t.encodeInstant(replacement.tombstoneUntil)));
940
- post = sql`exists(select 1 from ${t.table} where ${exact})`;
941
- }
942
- statements.push(yield* assertion(and(marker, post, live)));
943
- return {
944
- receipt: prepare(replacement.inspection, journal),
945
- statements
946
- };
947
- }), mapping.isConstraintConflict, recover)
948
- };
949
- };
950
- const makeD1SessionStepUpServices = Effect.fnUntraced(function* (mapping, target) {
951
- const database = yield* Database;
952
- yield* validateDrizzleStorage(mapping).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(Database)), Effect.mapError(unavailable));
953
- const hooks = yield* LifecycleHooks;
954
- const raw = makeD1SessionStepUp(mapping);
955
- const run = (effect) => Effect.gen(function* () {
956
- if ((yield* Effect.serviceOption(CurrentD1SessionBatch))._tag === "Some" || (yield* hasCommitScope)) return yield* unavailable();
957
- return yield* effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks));
958
- });
959
- return { sessionStepUpPersistence: target.of({
960
- create: (input, now, prepare) => run(raw.create(input, now, prepare)),
961
- context: (input) => run(raw.context(input)),
962
- read: (input) => run(raw.read(input)),
963
- reject: (input, prepare) => run(raw.reject(input, prepare)),
964
- complete: (plan, prepare) => run(raw.complete(plan, prepare))
965
- }) };
966
- });
967
- function coordinateD1SessionStepUp(acquire, options, body) {
968
- return Effect.flatMap(nativeDatabase(acquire), (database) => coordinateD1SessionBatch(database, options.mapping, (batch) => Effect.gen(function* () {
969
- const hooks = yield* LifecycleHooks;
970
- const raw = makeD1SessionStepUp(options.mapping);
971
- const run = (effect) => batch.owner.run(effect.pipe(Effect.provideService(CurrentD1PlanningDatabase, database), Effect.provideService(LifecycleHooks, hooks), Effect.provideService(CurrentD1SessionBatch, batch)));
972
- return { sessionStepUpPersistence: options.target.of({
973
- create: (input, now, prepare) => run(raw.create(input, now, prepare)),
974
- context: (input) => run(raw.context(input)),
975
- read: (input) => run(raw.read(input)),
976
- reject: (input, prepare) => run(raw.reject(input, prepare)),
977
- complete: (plan, prepare) => run(raw.complete(plan, prepare))
978
- }) };
979
- }), (ownedServices, batch) => {
980
- const provided = Context.make(options.target, ownedServices.sessionStepUpPersistence).pipe(Context.add(D1BatchStatements, batch.owner.collector));
981
- return Effect.provideContext(body, provided);
982
- }).pipe(Effect.provideService(NativeDatabase, database)));
983
- }
984
- //#endregion
985
- export { coordinateD1AuthenticationAuthority, coordinateD1PendingAuthentication, coordinateD1SessionBatch, coordinateD1SessionStepUp, coordinateD1SignedSessionValidity, coordinateD1StatefulSessions, makeD1AuthenticationAuthority, makeD1AuthenticationAuthorityServices, makeD1PendingAuthentication, makeD1PendingAuthenticationServices, makeD1SessionServiceEffects, makeD1SessionStepUp, makeD1SessionStepUpServices, makeD1SignedSessionValidityServices, makeD1SignedValidity, makeD1StatefulSessionServices, makeD1StatefulSessions };
986
-
987
- //# sourceMappingURL=d1-sessions.mjs.map