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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (481) hide show
  1. package/README.md +6 -8
  2. package/dist/Adapter.d.mts +47 -33
  3. package/dist/Adapter.mjs +36 -23
  4. package/dist/OAuthPersistence.d.mts +35 -51
  5. package/dist/OAuthPersistence.mjs +60 -68
  6. package/dist/OAuthPersistence.mjs.map +1 -1
  7. package/dist/index.d.mts +2 -2
  8. package/dist/index.mjs +2 -2
  9. package/dist/internal/browser-login.d.mts +1 -1
  10. package/dist/internal/browser-login.mjs +29 -9
  11. package/dist/internal/browser-login.mjs.map +1 -1
  12. package/dist/internal/configuration.d.mts +13 -8
  13. package/dist/internal/configuration.mjs.map +1 -1
  14. package/dist/internal/crypto.d.mts +1 -0
  15. package/dist/internal/crypto.mjs +1 -1
  16. package/dist/internal/d1-planning.mjs +8 -0
  17. package/dist/internal/d1-planning.mjs.map +1 -0
  18. package/dist/internal/email-native-state.mjs +135 -0
  19. package/dist/internal/email-native-state.mjs.map +1 -0
  20. package/dist/internal/email-native.d.mts +17 -0
  21. package/dist/internal/email-native.mjs +245 -0
  22. package/dist/internal/email-native.mjs.map +1 -0
  23. package/dist/internal/email-policy.mjs +92 -0
  24. package/dist/internal/email-policy.mjs.map +1 -0
  25. package/dist/internal/email-registration-native.d.mts +38 -0
  26. package/dist/internal/email-registration-native.mjs +171 -0
  27. package/dist/internal/email-registration-native.mjs.map +1 -0
  28. package/dist/internal/models/email-model.d.mts +40 -104
  29. package/dist/internal/models/email-model.mjs +3 -5
  30. package/dist/internal/models/email-model.mjs.map +1 -1
  31. package/dist/internal/models/oauth-connected-model.d.mts +44 -213
  32. package/dist/internal/models/oauth-connected-model.mjs +6 -14
  33. package/dist/internal/models/oauth-connected-model.mjs.map +1 -1
  34. package/dist/internal/models/oauth-model.d.mts +95 -244
  35. package/dist/internal/models/oauth-model.mjs +28 -22
  36. package/dist/internal/models/oauth-model.mjs.map +1 -1
  37. package/dist/internal/models/passkey-model.d.mts +11 -147
  38. package/dist/internal/models/passkey-model.mjs +5 -24
  39. package/dist/internal/models/passkey-model.mjs.map +1 -1
  40. package/dist/internal/models/passkey-registration-ceremony-model.d.mts +5 -39
  41. package/dist/internal/models/passkey-write-model.d.mts +17 -75
  42. package/dist/internal/models/passkey-write-model.mjs +1 -7
  43. package/dist/internal/models/passkey-write-model.mjs.map +1 -1
  44. package/dist/internal/models/password-model.d.mts +16 -82
  45. package/dist/internal/models/password-model.mjs +1 -4
  46. package/dist/internal/models/password-model.mjs.map +1 -1
  47. package/dist/internal/models/phone-model.d.mts +86 -0
  48. package/dist/internal/models/phone-model.mjs +10 -0
  49. package/dist/internal/models/phone-model.mjs.map +1 -0
  50. package/dist/internal/models/proof-model.d.mts +43 -272
  51. package/dist/internal/models/proof-model.mjs +2 -10
  52. package/dist/internal/models/proof-model.mjs.map +1 -1
  53. package/dist/internal/models/session-model.d.mts +74 -93
  54. package/dist/internal/models/session-model.mjs +3 -11
  55. package/dist/internal/models/session-model.mjs.map +1 -1
  56. package/dist/internal/models/step-up-model.d.mts +12 -50
  57. package/dist/internal/models/step-up-model.mjs +2 -4
  58. package/dist/internal/models/step-up-model.mjs.map +1 -1
  59. package/dist/internal/models/totp-model.d.mts +76 -0
  60. package/dist/internal/models/totp-model.mjs +10 -0
  61. package/dist/internal/models/totp-model.mjs.map +1 -0
  62. package/dist/internal/native-sql-table.d.mts +21 -4
  63. package/dist/internal/native-sql-table.mjs +9 -5
  64. package/dist/internal/native-sql-table.mjs.map +1 -1
  65. package/dist/internal/oauth/native-accounts.d.mts +17 -0
  66. package/dist/internal/oauth/native-accounts.mjs +290 -0
  67. package/dist/internal/oauth/native-accounts.mjs.map +1 -0
  68. package/dist/internal/oauth/native-connected-state.d.mts +11 -0
  69. package/dist/internal/oauth/native-connected-state.mjs +146 -0
  70. package/dist/internal/oauth/native-connected-state.mjs.map +1 -0
  71. package/dist/internal/oauth/native-connected.d.mts +15 -0
  72. package/dist/internal/oauth/native-connected.mjs +462 -0
  73. package/dist/internal/oauth/native-connected.mjs.map +1 -0
  74. package/dist/internal/oauth/native-flow.mjs +138 -0
  75. package/dist/internal/oauth/native-flow.mjs.map +1 -0
  76. package/dist/internal/oauth/native-layers.d.mts +24 -0
  77. package/dist/internal/oauth/native-layers.mjs +13 -0
  78. package/dist/internal/oauth/native-layers.mjs.map +1 -0
  79. package/dist/internal/oauth/native-mutation.mjs +122 -0
  80. package/dist/internal/oauth/native-mutation.mjs.map +1 -0
  81. package/dist/internal/oauth/native-registration.d.mts +24 -0
  82. package/dist/internal/oauth/native-registration.mjs +328 -0
  83. package/dist/internal/oauth/native-registration.mjs.map +1 -0
  84. package/dist/internal/oauth/native-revocations.d.mts +17 -0
  85. package/dist/internal/oauth/native-revocations.mjs +106 -0
  86. package/dist/internal/oauth/native-revocations.mjs.map +1 -0
  87. package/dist/internal/oauth/native-sign-in.d.mts +17 -0
  88. package/dist/internal/oauth/native-sign-in.mjs +50 -0
  89. package/dist/internal/oauth/native-sign-in.mjs.map +1 -0
  90. package/dist/internal/oauth/native-state.d.mts +10 -0
  91. package/dist/internal/oauth/native-state.mjs +214 -0
  92. package/dist/internal/oauth/native-state.mjs.map +1 -0
  93. package/dist/internal/oauth/state.d.mts +10 -0
  94. package/dist/internal/oauth/state.mjs +3 -27
  95. package/dist/internal/oauth/state.mjs.map +1 -1
  96. package/dist/internal/passkey-actions.mjs +55 -0
  97. package/dist/internal/passkey-actions.mjs.map +1 -0
  98. package/dist/internal/passkey-inputs.mjs +73 -0
  99. package/dist/internal/passkey-inputs.mjs.map +1 -0
  100. package/dist/internal/passkey-managed.mjs +224 -0
  101. package/dist/internal/passkey-managed.mjs.map +1 -0
  102. package/dist/internal/passkey-native-ceremony.d.mts +35 -0
  103. package/dist/internal/passkey-native-ceremony.mjs +38 -0
  104. package/dist/internal/passkey-native-ceremony.mjs.map +1 -0
  105. package/dist/internal/passkey-native-flow.mjs +91 -0
  106. package/dist/internal/passkey-native-flow.mjs.map +1 -0
  107. package/dist/internal/passkey-native-registration.d.mts +10 -0
  108. package/dist/internal/passkey-native-registration.mjs +114 -0
  109. package/dist/internal/passkey-native-registration.mjs.map +1 -0
  110. package/dist/internal/passkey-native-state.d.mts +15 -0
  111. package/dist/internal/passkey-native-state.mjs +186 -0
  112. package/dist/internal/passkey-native-state.mjs.map +1 -0
  113. package/dist/internal/passkey-native-write.d.mts +82 -0
  114. package/dist/internal/passkey-native-write.mjs +330 -0
  115. package/dist/internal/passkey-native-write.mjs.map +1 -0
  116. package/dist/internal/passkey-native.d.mts +835 -0
  117. package/dist/internal/passkey-native.mjs +175 -0
  118. package/dist/internal/passkey-native.mjs.map +1 -0
  119. package/dist/internal/passkey-policy.mjs +115 -0
  120. package/dist/internal/passkey-policy.mjs.map +1 -0
  121. package/dist/internal/password-credentials.mjs +38 -9
  122. package/dist/internal/password-credentials.mjs.map +1 -1
  123. package/dist/internal/password-native.d.mts +14 -0
  124. package/dist/internal/password-native.mjs +292 -0
  125. package/dist/internal/password-native.mjs.map +1 -0
  126. package/dist/internal/password-policy.mjs +93 -0
  127. package/dist/internal/password-policy.mjs.map +1 -0
  128. package/dist/internal/password-registration-native.d.mts +22 -0
  129. package/dist/internal/password-registration-native.mjs +142 -0
  130. package/dist/internal/password-registration-native.mjs.map +1 -0
  131. package/dist/internal/persistence.d.mts +6 -19
  132. package/dist/internal/persistence.mjs +199 -166
  133. package/dist/internal/persistence.mjs.map +1 -1
  134. package/dist/internal/phone-composed.mjs +79 -0
  135. package/dist/internal/phone-composed.mjs.map +1 -0
  136. package/dist/internal/phone-native.d.mts +15 -0
  137. package/dist/internal/phone-native.mjs +354 -0
  138. package/dist/internal/phone-native.mjs.map +1 -0
  139. package/dist/internal/proof-native.d.mts +15 -0
  140. package/dist/internal/proof-native.mjs +289 -0
  141. package/dist/internal/proof-native.mjs.map +1 -0
  142. package/dist/internal/registration.mjs +50 -60
  143. package/dist/internal/registration.mjs.map +1 -1
  144. package/dist/internal/session-native-authority.d.mts +15 -0
  145. package/dist/internal/session-native-authority.mjs +91 -0
  146. package/dist/internal/session-native-authority.mjs.map +1 -0
  147. package/dist/internal/session-native-cleanup.d.mts +14 -0
  148. package/dist/internal/session-native-cleanup.mjs +48 -0
  149. package/dist/internal/session-native-cleanup.mjs.map +1 -0
  150. package/dist/internal/session-native-login.d.mts +15 -0
  151. package/dist/internal/session-native-login.mjs +87 -0
  152. package/dist/internal/session-native-login.mjs.map +1 -0
  153. package/dist/internal/session-native-pending-read.mjs +42 -0
  154. package/dist/internal/session-native-pending-read.mjs.map +1 -0
  155. package/dist/internal/session-native-pending.mjs +134 -0
  156. package/dist/internal/session-native-pending.mjs.map +1 -0
  157. package/dist/internal/session-native-record.mjs +79 -0
  158. package/dist/internal/session-native-record.mjs.map +1 -0
  159. package/dist/internal/session-native-state.mjs +130 -0
  160. package/dist/internal/session-native-state.mjs.map +1 -0
  161. package/dist/internal/session-native-stateful.d.mts +16 -0
  162. package/dist/internal/session-native-stateful.mjs +225 -0
  163. package/dist/internal/session-native-stateful.mjs.map +1 -0
  164. package/dist/internal/session-native-step-up.d.mts +15 -0
  165. package/dist/internal/session-native-step-up.mjs +212 -0
  166. package/dist/internal/session-native-step-up.mjs.map +1 -0
  167. package/dist/internal/session-native-validity.d.mts +15 -0
  168. package/dist/internal/session-native-validity.mjs +97 -0
  169. package/dist/internal/session-native-validity.mjs.map +1 -0
  170. package/dist/internal/session-policy.mjs +29 -0
  171. package/dist/internal/session-policy.mjs.map +1 -0
  172. package/dist/internal/sql-authority.d.mts +16 -0
  173. package/dist/internal/sql-authority.mjs +32 -0
  174. package/dist/internal/sql-authority.mjs.map +1 -0
  175. package/dist/internal/sql-change.mjs +21 -0
  176. package/dist/internal/sql-change.mjs.map +1 -0
  177. package/dist/internal/sql-cleanup.mjs +35 -0
  178. package/dist/internal/sql-cleanup.mjs.map +1 -0
  179. package/dist/internal/sql-commit.d.mts +72 -0
  180. package/dist/internal/sql-commit.mjs +176 -0
  181. package/dist/internal/sql-commit.mjs.map +1 -0
  182. package/dist/internal/sql-expression.d.mts +17 -0
  183. package/dist/internal/sql-expression.mjs +49 -0
  184. package/dist/internal/sql-expression.mjs.map +1 -0
  185. package/dist/internal/sql-oauth-connected-model.d.mts +7 -23
  186. package/dist/internal/sql-oauth-model.d.mts +27 -52
  187. package/dist/internal/sql-oauth-model.mjs +3 -4
  188. package/dist/internal/sql-oauth-model.mjs.map +1 -1
  189. package/dist/internal/sql-persistence.mjs +5 -9
  190. package/dist/internal/sql-persistence.mjs.map +1 -1
  191. package/dist/internal/sql-storage-validation.mjs +1 -2
  192. package/dist/internal/sql-storage-validation.mjs.map +1 -1
  193. package/dist/internal/sql-table.d.mts +3 -16
  194. package/dist/internal/sql-table.mjs +21 -42
  195. package/dist/internal/sql-table.mjs.map +1 -1
  196. package/dist/internal/standalone.mjs +2 -3
  197. package/dist/internal/standalone.mjs.map +1 -1
  198. package/dist/internal/step-up-state.mjs +5 -8
  199. package/dist/internal/step-up-state.mjs.map +1 -1
  200. package/dist/internal/storage-clock.mjs +44 -0
  201. package/dist/internal/storage-clock.mjs.map +1 -0
  202. package/dist/internal/storage-mapping.d.mts +11 -8
  203. package/dist/internal/storage-mapping.mjs +88 -302
  204. package/dist/internal/storage-mapping.mjs.map +1 -1
  205. package/dist/internal/storage-plans.mjs +15 -73
  206. package/dist/internal/storage-plans.mjs.map +1 -1
  207. package/dist/internal/storage-tables.d.mts +37 -520
  208. package/dist/internal/storage-tables.mjs +31 -211
  209. package/dist/internal/storage-tables.mjs.map +1 -1
  210. package/dist/internal/storage-validation.d.mts +1 -6
  211. package/dist/internal/storage-validation.mjs +1 -42
  212. package/dist/internal/storage-validation.mjs.map +1 -1
  213. package/dist/internal/table-model.d.mts +21 -0
  214. package/dist/internal/totp-native.d.mts +15 -0
  215. package/dist/internal/totp-native.mjs +401 -0
  216. package/dist/internal/totp-native.mjs.map +1 -0
  217. package/package.json +1 -1
  218. package/src/Adapter.ts +143 -199
  219. package/src/OAuthPersistence.ts +128 -271
  220. package/src/index.ts +1 -1
  221. package/src/internal/browser-login.ts +54 -24
  222. package/src/internal/configuration.ts +16 -31
  223. package/src/internal/d1-planning.ts +7 -0
  224. package/src/internal/email-native-state.ts +247 -0
  225. package/src/internal/email-native.ts +514 -0
  226. package/src/internal/email-policy.ts +235 -0
  227. package/src/internal/email-registration-native.ts +386 -0
  228. package/src/internal/models/email-model.ts +76 -214
  229. package/src/internal/models/oauth-connected-model.ts +50 -288
  230. package/src/internal/models/oauth-model.ts +147 -368
  231. package/src/internal/models/passkey-model.ts +11 -208
  232. package/src/internal/models/passkey-registration-ceremony-model.ts +6 -60
  233. package/src/internal/models/passkey-write-model.ts +14 -95
  234. package/src/internal/models/password-model.ts +28 -148
  235. package/src/internal/models/phone-model.ts +110 -0
  236. package/src/internal/models/proof-model.ts +48 -404
  237. package/src/internal/models/session-model.ts +102 -200
  238. package/src/internal/models/step-up-model.ts +17 -96
  239. package/src/internal/models/totp-model.ts +82 -0
  240. package/src/internal/native-sql-table.ts +32 -11
  241. package/src/internal/oauth/native-accounts.ts +576 -0
  242. package/src/internal/oauth/native-connected-state.ts +288 -0
  243. package/src/internal/oauth/native-connected.ts +888 -0
  244. package/src/internal/oauth/native-flow.ts +253 -0
  245. package/src/internal/oauth/native-layers.ts +83 -0
  246. package/src/internal/oauth/native-mutation.ts +222 -0
  247. package/src/internal/oauth/native-registration.ts +545 -0
  248. package/src/internal/oauth/native-revocations.ts +190 -0
  249. package/src/internal/oauth/native-sign-in.ts +111 -0
  250. package/src/internal/oauth/native-state.ts +346 -0
  251. package/src/internal/oauth/state.ts +2 -70
  252. package/src/internal/passkey-actions.ts +70 -0
  253. package/src/internal/passkey-inputs.ts +56 -0
  254. package/src/internal/passkey-managed.ts +360 -0
  255. package/src/internal/passkey-native-ceremony.ts +66 -0
  256. package/src/internal/passkey-native-flow.ts +140 -0
  257. package/src/internal/passkey-native-registration.ts +221 -0
  258. package/src/internal/passkey-native-state.ts +335 -0
  259. package/src/internal/passkey-native-write.ts +611 -0
  260. package/src/internal/passkey-native.ts +372 -0
  261. package/src/internal/passkey-policy.ts +246 -0
  262. package/src/internal/password-credentials.ts +52 -10
  263. package/src/internal/password-native.ts +571 -0
  264. package/src/internal/password-policy.ts +307 -0
  265. package/src/internal/password-registration-native.ts +322 -0
  266. package/src/internal/persistence.ts +336 -290
  267. package/src/internal/phone-composed.ts +86 -0
  268. package/src/internal/phone-native.ts +659 -0
  269. package/src/internal/proof-native.ts +448 -0
  270. package/src/internal/registration.ts +96 -143
  271. package/src/internal/session-native-authority.ts +247 -0
  272. package/src/internal/session-native-cleanup.ts +65 -0
  273. package/src/internal/session-native-login.ts +205 -0
  274. package/src/internal/session-native-pending-read.ts +68 -0
  275. package/src/internal/session-native-pending.ts +223 -0
  276. package/src/internal/session-native-record.ts +141 -0
  277. package/src/internal/session-native-state.ts +259 -0
  278. package/src/internal/session-native-stateful.ts +512 -0
  279. package/src/internal/session-native-step-up.ts +450 -0
  280. package/src/internal/session-native-validity.ts +208 -0
  281. package/src/internal/session-policy.ts +59 -0
  282. package/src/internal/sql-authority.ts +56 -0
  283. package/src/internal/sql-change.ts +38 -0
  284. package/src/internal/sql-cleanup.ts +56 -0
  285. package/src/internal/sql-commit.ts +435 -0
  286. package/src/internal/sql-expression.ts +94 -0
  287. package/src/internal/sql-metadata.ts +100 -0
  288. package/src/internal/sql-oauth-connected-model.ts +6 -95
  289. package/src/internal/sql-oauth-model.ts +31 -134
  290. package/src/internal/sql-persistence.ts +2 -6
  291. package/src/internal/sql-storage-validation.ts +1 -2
  292. package/src/internal/sql-table.ts +19 -52
  293. package/src/internal/standalone.ts +2 -11
  294. package/src/internal/step-up-state.ts +4 -17
  295. package/src/internal/storage-clock.ts +58 -0
  296. package/src/internal/storage-mapping.ts +125 -340
  297. package/src/internal/storage-plans.ts +14 -80
  298. package/src/internal/storage-tables.ts +28 -212
  299. package/src/internal/storage-validation.ts +0 -58
  300. package/src/internal/table-model.ts +24 -0
  301. package/src/internal/totp-native.ts +701 -0
  302. package/dist/internal/PasswordPreparedPostconditions.d.mts +0 -22
  303. package/dist/internal/PasswordPreparedPostconditions.mjs +0 -12
  304. package/dist/internal/PasswordPreparedPostconditions.mjs.map +0 -1
  305. package/dist/internal/authority-snapshot.mjs +0 -53
  306. package/dist/internal/authority-snapshot.mjs.map +0 -1
  307. package/dist/internal/email-kernel.d.mts +0 -276
  308. package/dist/internal/email-kernel.mjs +0 -497
  309. package/dist/internal/email-kernel.mjs.map +0 -1
  310. package/dist/internal/models/passkey-registration-ceremony-model.mjs +0 -18
  311. package/dist/internal/models/passkey-registration-ceremony-model.mjs.map +0 -1
  312. package/dist/internal/oauth/accounts.d.mts +0 -8
  313. package/dist/internal/oauth/accounts.mjs +0 -379
  314. package/dist/internal/oauth/accounts.mjs.map +0 -1
  315. package/dist/internal/oauth/connected-access.d.mts +0 -9
  316. package/dist/internal/oauth/connected-access.mjs +0 -229
  317. package/dist/internal/oauth/connected-access.mjs.map +0 -1
  318. package/dist/internal/oauth/connected-collection.d.mts +0 -7
  319. package/dist/internal/oauth/connected-collection.mjs +0 -214
  320. package/dist/internal/oauth/connected-collection.mjs.map +0 -1
  321. package/dist/internal/oauth/connected-custody.d.mts +0 -6
  322. package/dist/internal/oauth/connected-custody.mjs +0 -165
  323. package/dist/internal/oauth/connected-custody.mjs.map +0 -1
  324. package/dist/internal/oauth/connected-flow.d.mts +0 -7
  325. package/dist/internal/oauth/connected-flow.mjs +0 -324
  326. package/dist/internal/oauth/connected-flow.mjs.map +0 -1
  327. package/dist/internal/oauth/connected-input.mjs +0 -122
  328. package/dist/internal/oauth/connected-input.mjs.map +0 -1
  329. package/dist/internal/oauth/connected-keys.d.mts +0 -2
  330. package/dist/internal/oauth/connected-keys.mjs +0 -22
  331. package/dist/internal/oauth/connected-keys.mjs.map +0 -1
  332. package/dist/internal/oauth/connected-maintenance.d.mts +0 -9
  333. package/dist/internal/oauth/connected-maintenance.mjs +0 -226
  334. package/dist/internal/oauth/connected-maintenance.mjs.map +0 -1
  335. package/dist/internal/oauth/connected-management.d.mts +0 -9
  336. package/dist/internal/oauth/connected-management.mjs +0 -243
  337. package/dist/internal/oauth/connected-management.mjs.map +0 -1
  338. package/dist/internal/oauth/connected-reference.mjs +0 -63
  339. package/dist/internal/oauth/connected-reference.mjs.map +0 -1
  340. package/dist/internal/oauth/connected-settlement.d.mts +0 -8
  341. package/dist/internal/oauth/connected-settlement.mjs +0 -141
  342. package/dist/internal/oauth/connected-settlement.mjs.map +0 -1
  343. package/dist/internal/oauth/connected-sign-in.d.mts +0 -10
  344. package/dist/internal/oauth/connected-sign-in.mjs +0 -281
  345. package/dist/internal/oauth/connected-sign-in.mjs.map +0 -1
  346. package/dist/internal/oauth/connected-state.d.mts +0 -14
  347. package/dist/internal/oauth/connected-state.mjs +0 -469
  348. package/dist/internal/oauth/connected-state.mjs.map +0 -1
  349. package/dist/internal/oauth/connected-target.d.mts +0 -21
  350. package/dist/internal/oauth/connected-target.mjs +0 -117
  351. package/dist/internal/oauth/connected-target.mjs.map +0 -1
  352. package/dist/internal/oauth/flow.d.mts +0 -5
  353. package/dist/internal/oauth/flow.mjs +0 -279
  354. package/dist/internal/oauth/flow.mjs.map +0 -1
  355. package/dist/internal/oauth/input.mjs +0 -127
  356. package/dist/internal/oauth/input.mjs.map +0 -1
  357. package/dist/internal/oauth/owner.d.mts +0 -10
  358. package/dist/internal/oauth/owner.mjs +0 -10
  359. package/dist/internal/oauth/owner.mjs.map +0 -1
  360. package/dist/internal/oauth/query-compiler.d.mts +0 -7
  361. package/dist/internal/oauth/query-compiler.mjs +0 -9
  362. package/dist/internal/oauth/query-compiler.mjs.map +0 -1
  363. package/dist/internal/oauth/registration.d.mts +0 -7
  364. package/dist/internal/oauth/registration.mjs +0 -393
  365. package/dist/internal/oauth/registration.mjs.map +0 -1
  366. package/dist/internal/oauth/target.d.mts +0 -31
  367. package/dist/internal/oauth/target.mjs +0 -273
  368. package/dist/internal/oauth/target.mjs.map +0 -1
  369. package/dist/internal/oauth-kernel.d.mts +0 -1423
  370. package/dist/internal/oauth-kernel.mjs +0 -187
  371. package/dist/internal/oauth-kernel.mjs.map +0 -1
  372. package/dist/internal/passkey/admission.d.mts +0 -6
  373. package/dist/internal/passkey/admission.mjs +0 -220
  374. package/dist/internal/passkey/admission.mjs.map +0 -1
  375. package/dist/internal/passkey/credentials.d.mts +0 -14
  376. package/dist/internal/passkey/credentials.mjs +0 -249
  377. package/dist/internal/passkey/credentials.mjs.map +0 -1
  378. package/dist/internal/passkey/enrollment.mjs +0 -138
  379. package/dist/internal/passkey/enrollment.mjs.map +0 -1
  380. package/dist/internal/passkey/flow.d.mts +0 -21
  381. package/dist/internal/passkey/flow.mjs +0 -452
  382. package/dist/internal/passkey/flow.mjs.map +0 -1
  383. package/dist/internal/passkey/management.mjs +0 -231
  384. package/dist/internal/passkey/management.mjs.map +0 -1
  385. package/dist/internal/passkey/registration-ceremony.d.mts +0 -9
  386. package/dist/internal/passkey/registration-ceremony.mjs +0 -129
  387. package/dist/internal/passkey/registration-ceremony.mjs.map +0 -1
  388. package/dist/internal/passkey/registration-custody.d.mts +0 -2
  389. package/dist/internal/passkey/registration-custody.mjs +0 -52
  390. package/dist/internal/passkey/registration-custody.mjs.map +0 -1
  391. package/dist/internal/passkey/registration-write.mjs +0 -211
  392. package/dist/internal/passkey/registration-write.mjs.map +0 -1
  393. package/dist/internal/passkey/state.d.mts +0 -10
  394. package/dist/internal/passkey/state.mjs +0 -234
  395. package/dist/internal/passkey/state.mjs.map +0 -1
  396. package/dist/internal/passkey/target.d.mts +0 -20
  397. package/dist/internal/passkey/target.mjs +0 -200
  398. package/dist/internal/passkey/target.mjs.map +0 -1
  399. package/dist/internal/passkey/write-state.d.mts +0 -17
  400. package/dist/internal/passkey/write-state.mjs +0 -346
  401. package/dist/internal/passkey/write-state.mjs.map +0 -1
  402. package/dist/internal/passkey/write-target.mjs +0 -192
  403. package/dist/internal/passkey/write-target.mjs.map +0 -1
  404. package/dist/internal/passkey-kernel.d.mts +0 -6045
  405. package/dist/internal/passkey-kernel.mjs +0 -49
  406. package/dist/internal/passkey-kernel.mjs.map +0 -1
  407. package/dist/internal/passkeys.d.mts +0 -7
  408. package/dist/internal/passkeys.mjs +0 -387
  409. package/dist/internal/passkeys.mjs.map +0 -1
  410. package/dist/internal/password-credentials.d.mts +0 -11
  411. package/dist/internal/password-kernel.d.mts +0 -278
  412. package/dist/internal/password-kernel.mjs +0 -508
  413. package/dist/internal/password-kernel.mjs.map +0 -1
  414. package/dist/internal/phone-kernel.d.mts +0 -162
  415. package/dist/internal/phone-kernel.mjs +0 -437
  416. package/dist/internal/phone-kernel.mjs.map +0 -1
  417. package/dist/internal/proof-kernel.d.mts +0 -94
  418. package/dist/internal/proof-kernel.mjs +0 -624
  419. package/dist/internal/proof-kernel.mjs.map +0 -1
  420. package/dist/internal/query-operations.d.mts +0 -68
  421. package/dist/internal/session-kernel.d.mts +0 -62
  422. package/dist/internal/session-kernel.mjs +0 -820
  423. package/dist/internal/session-kernel.mjs.map +0 -1
  424. package/dist/internal/sql-oauth-connected-model.mjs +0 -7
  425. package/dist/internal/sql-oauth-connected-model.mjs.map +0 -1
  426. package/dist/internal/sql-query.d.mts +0 -12
  427. package/dist/internal/sql-query.mjs +0 -206
  428. package/dist/internal/sql-query.mjs.map +0 -1
  429. package/dist/internal/step-up-state.d.mts +0 -49
  430. package/dist/internal/transaction-execution-kernel.d.mts +0 -37
  431. package/dist/internal/transaction-execution-kernel.mjs +0 -120
  432. package/dist/internal/transaction-execution-kernel.mjs.map +0 -1
  433. package/dist/internal/transaction-kernel.d.mts +0 -81
  434. package/dist/internal/transaction-kernel.mjs +0 -264
  435. package/dist/internal/transaction-kernel.mjs.map +0 -1
  436. package/src/internal/PasswordPreparedPostconditions.ts +0 -30
  437. package/src/internal/authority-snapshot.ts +0 -91
  438. package/src/internal/email-kernel.ts +0 -1555
  439. package/src/internal/oauth/accounts.ts +0 -838
  440. package/src/internal/oauth/connected-access.ts +0 -388
  441. package/src/internal/oauth/connected-collection.ts +0 -345
  442. package/src/internal/oauth/connected-custody.ts +0 -308
  443. package/src/internal/oauth/connected-flow.ts +0 -562
  444. package/src/internal/oauth/connected-input.ts +0 -147
  445. package/src/internal/oauth/connected-keys.ts +0 -31
  446. package/src/internal/oauth/connected-maintenance.ts +0 -379
  447. package/src/internal/oauth/connected-management.ts +0 -391
  448. package/src/internal/oauth/connected-reference.ts +0 -135
  449. package/src/internal/oauth/connected-settlement.ts +0 -278
  450. package/src/internal/oauth/connected-sign-in.ts +0 -472
  451. package/src/internal/oauth/connected-state.ts +0 -924
  452. package/src/internal/oauth/connected-target.ts +0 -307
  453. package/src/internal/oauth/flow.ts +0 -505
  454. package/src/internal/oauth/input.ts +0 -201
  455. package/src/internal/oauth/owner.ts +0 -22
  456. package/src/internal/oauth/query-compiler.ts +0 -15
  457. package/src/internal/oauth/registration.ts +0 -676
  458. package/src/internal/oauth/target.ts +0 -803
  459. package/src/internal/oauth-kernel.ts +0 -294
  460. package/src/internal/passkey/admission.ts +0 -368
  461. package/src/internal/passkey/credentials.ts +0 -511
  462. package/src/internal/passkey/enrollment.ts +0 -326
  463. package/src/internal/passkey/flow.ts +0 -1062
  464. package/src/internal/passkey/management.ts +0 -426
  465. package/src/internal/passkey/registration-ceremony.ts +0 -283
  466. package/src/internal/passkey/registration-custody.ts +0 -91
  467. package/src/internal/passkey/registration-write.ts +0 -426
  468. package/src/internal/passkey/state.ts +0 -351
  469. package/src/internal/passkey/target.ts +0 -598
  470. package/src/internal/passkey/write-state.ts +0 -678
  471. package/src/internal/passkey/write-target.ts +0 -450
  472. package/src/internal/passkey-kernel.ts +0 -112
  473. package/src/internal/passkeys.ts +0 -652
  474. package/src/internal/password-kernel.ts +0 -1522
  475. package/src/internal/phone-kernel.ts +0 -872
  476. package/src/internal/proof-kernel.ts +0 -1992
  477. package/src/internal/query-operations.ts +0 -91
  478. package/src/internal/session-kernel.ts +0 -2406
  479. package/src/internal/sql-query.ts +0 -304
  480. package/src/internal/transaction-execution-kernel.ts +0 -335
  481. package/src/internal/transaction-kernel.ts +0 -603
@@ -0,0 +1,59 @@
1
+ import type { AuthenticationEvidence } from "@yielded/auth/Sessions";
2
+ import { SessionUnavailable } from "@yielded/auth/Sessions";
3
+ import { DateTime, Effect } from "effect";
4
+
5
+ import { PersistenceMappingError } from "./mapping-error";
6
+
7
+ export const preservesRevision = (
8
+ completed: AuthenticationEvidence,
9
+ original: AuthenticationEvidence,
10
+ ): boolean => {
11
+ const current = new Map(
12
+ completed.revision.credentials.map((item) => [item.credentialId, item.revision]),
13
+ );
14
+
15
+ return (
16
+ completed.flowId === original.flowId &&
17
+ completed.bindingDigest === original.bindingDigest &&
18
+ completed.revision.subjectId === original.revision.subjectId &&
19
+ completed.revision.securityRevision === original.revision.securityRevision &&
20
+ original.revision.credentials.every(
21
+ (item) => current.get(item.credentialId) === item.revision,
22
+ ) &&
23
+ original.proofs.every((expected) =>
24
+ completed.proofs.some(
25
+ (proof) =>
26
+ proof.method === expected.method &&
27
+ proof.credentialId === expected.credentialId &&
28
+ proof.userVerified === expected.userVerified &&
29
+ proof.phishingResistant === expected.phishingResistant &&
30
+ DateTime.toEpochMillis(proof.verifiedAt) ===
31
+ DateTime.toEpochMillis(expected.verifiedAt) &&
32
+ proof.factors.length === expected.factors.length &&
33
+ proof.factors.every((factor, index) => factor === expected.factors[index]),
34
+ ),
35
+ )
36
+ );
37
+ };
38
+
39
+ export const allocateSessionValue = <A>(
40
+ mode: "interactive" | "synchronous" | "batch",
41
+ asynchronous: Effect.Effect<A, PersistenceMappingError> | undefined,
42
+ synchronous: (() => A) | undefined,
43
+ ): Effect.Effect<A, PersistenceMappingError | SessionUnavailable> => {
44
+ if (mode === "synchronous")
45
+ return synchronous === undefined
46
+ ? Effect.fail(SessionUnavailable.make({}))
47
+ : Effect.try({
48
+ try: synchronous,
49
+ catch: (cause) => PersistenceMappingError.make({ operation: "allocate", cause }),
50
+ });
51
+ if (asynchronous !== undefined) return asynchronous;
52
+
53
+ return synchronous === undefined
54
+ ? Effect.fail(SessionUnavailable.make({}))
55
+ : Effect.try({
56
+ try: synchronous,
57
+ catch: (cause) => PersistenceMappingError.make({ operation: "allocate", cause }),
58
+ });
59
+ };
@@ -0,0 +1,56 @@
1
+ import type { LifecycleHooks } from "@yielded/auth/Hooks";
2
+ import { SessionUnavailable, type AuthenticationAuthority } from "@yielded/auth/Sessions";
3
+ import { Effect } from "effect";
4
+ import { SqlClient } from "effect/sql";
5
+
6
+ import { PersistenceConfigurationError } from "./configuration";
7
+ import type { AuthenticationAuthorityMapping } from "./models/session-model";
8
+ import { makeNativeSqlTables } from "./native-sql-table";
9
+ import {
10
+ makeNativeAuthenticationAuthorityServices,
11
+ type NativeAuthenticationAuthorityMapping,
12
+ } from "./session-native-authority";
13
+ import { SqlBatchCommit } from "./sql-commit";
14
+ import { SqlExpression, compileSqlExpression } from "./sql-expression";
15
+ import type { SqlTableModel } from "./sql-oauth-model";
16
+ import { validateSqlStorage } from "./sql-storage-validation";
17
+
18
+ /** Direct SQL uses the same authority owner as the mapped Drizzle adapters. */
19
+ export const makeAuthenticationAuthorityServices = Effect.fnUntraced(function* <Claims, N>(
20
+ mapping: AuthenticationAuthorityMapping<
21
+ Claims,
22
+ SqlTableModel,
23
+ SqlTableModel,
24
+ SqlTableModel,
25
+ N,
26
+ SqlExpression
27
+ >,
28
+ ): Effect.fn.Return<
29
+ { readonly authenticationAuthority: AuthenticationAuthority["Service"] },
30
+ SessionUnavailable | PersistenceConfigurationError,
31
+ LifecycleHooks | SqlClient.SqlClient
32
+ > {
33
+ const sql = yield* SqlClient.SqlClient;
34
+
35
+ if (!sql.onDialectOrElse({ pg: () => true, sqlite: () => true, orElse: () => false }))
36
+ return yield* PersistenceConfigurationError.make({
37
+ reason: "Authentication authority requires PostgreSQL or SQLite",
38
+ });
39
+ yield* validateSqlStorage(mapping).pipe(Effect.mapError(() => SessionUnavailable.make({})));
40
+
41
+ // Erase mapped native ID callback variance, never decoded authentication data.
42
+ return yield* makeNativeAuthenticationAuthorityServices(makeNativeSqlTables(sql), {
43
+ ...mapping,
44
+ clock: {
45
+ ...mapping.clock,
46
+ toMillis: (value: unknown) =>
47
+ mapping.clock.toMillis(new SqlExpression((client) => compileSqlExpression(client, value))),
48
+ fromMillis: (value: unknown) =>
49
+ mapping.clock.fromMillis(
50
+ new SqlExpression((client) => compileSqlExpression(client, value)),
51
+ ),
52
+ },
53
+ } as unknown as NativeAuthenticationAuthorityMapping<Claims>).pipe(
54
+ Effect.provideService(SqlBatchCommit, undefined),
55
+ );
56
+ });
@@ -0,0 +1,38 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { SqlClient } from "effect/sql/SqlClient";
3
+ import type { SqlError } from "effect/sql/SqlError";
4
+ import { join, type Fragment } from "effect/sql/Statement";
5
+
6
+ /** Native row counts are the authority for conditional writes. MySQL exposes
7
+ * its result header; PostgreSQL and SQLite return one row for every match. */
8
+ export const executeSqlChange = (
9
+ sql: SqlClient,
10
+ query: Fragment,
11
+ ): Effect.Effect<number, SqlError | Schema.SchemaError> =>
12
+ sql.onDialectOrElse({
13
+ mysql: () =>
14
+ sql`${query}`.raw.pipe(
15
+ Effect.flatMap(Schema.decodeUnknownEffect(Schema.Struct({ affectedRows: Schema.Int }))),
16
+ Effect.map((result) => result.affectedRows),
17
+ ),
18
+ orElse: () => sql`${query} returning 1 as changed`.pipe(Effect.map((rows) => rows.length)),
19
+ });
20
+
21
+ /** Effect renders an empty OR as `1=1`; an empty set of alternatives matches nothing. */
22
+ export const anySqlCondition: (conditions: ReadonlyArray<Fragment>) => Fragment = join(
23
+ " OR ",
24
+ true,
25
+ "1 = 0",
26
+ );
27
+
28
+ /** Keep the indexed predicate and reject collation aliases of security tokens. */
29
+ export const exactSqlText = (sql: SqlClient, left: Fragment, right: Fragment) =>
30
+ sql.and([
31
+ sql`${left} = ${right}`,
32
+ sql.onDialectOrElse({
33
+ mysql: () => sql`binary ${left} = binary ${right}`,
34
+ pg: () =>
35
+ sql`convert_to(cast(${left} as text), 'UTF8') = convert_to(cast(${right} as text), 'UTF8')`,
36
+ orElse: () => sql`cast(${left} as blob) = cast(${right} as blob)`,
37
+ }),
38
+ ]);
@@ -0,0 +1,56 @@
1
+ import { CleanupLimit, CleanupResult } from "@yielded/auth/Persistence";
2
+ import { Effect, Schema } from "effect";
3
+ import { SqlClient } from "effect/sql/SqlClient";
4
+ import type { Fragment } from "effect/sql/Statement";
5
+
6
+ import { sqlBatchAssertion } from "./d1-planning";
7
+ import type { SqlTable } from "./native-sql-table";
8
+ import { executeSqlChange } from "./sql-change";
9
+ import { appendSqlBatchStatement } from "./sql-commit";
10
+
11
+ /** A mapped row key and its strategy-owned retention predicate are the entire
12
+ * cleanup authority. All tables share the same remaining row budget. */
13
+ export interface SqlCleanupTable {
14
+ readonly table: SqlTable;
15
+ readonly keys: readonly [string, ...string[]];
16
+ readonly due: Fragment;
17
+ readonly order: ReadonlyArray<Fragment>;
18
+ }
19
+
20
+ export const cleanupSqlRows = Effect.fnUntraced(function* (
21
+ candidates: ReadonlyArray<SqlCleanupTable>,
22
+ requested: CleanupLimit,
23
+ batch = false,
24
+ ) {
25
+ const limit = yield* Schema.decodeEffect(CleanupLimit)(requested);
26
+ const sql = (yield* SqlClient).withoutTransforms();
27
+ let removed = 0;
28
+
29
+ for (const candidate of candidates) {
30
+ const remaining = limit - removed;
31
+
32
+ if (remaining === 0) break;
33
+ const { table, keys, due } = candidate;
34
+ const aliases = keys.map((_, index) => sql.literal(`cleanup_key_${index}`));
35
+ const selection = sql`select ${sql.join(", ", false)(keys.map((key, index) => sql`${table.column(key)} as ${aliases[index]!}`))} from ${table.name} where ${due} order by ${sql.join(", ", false)(candidate.order.length === 0 ? keys.map(table.column) : candidate.order)} limit ${remaining}`;
36
+
37
+ // An uncorrelated IN selection materializes the bounded key set before
38
+ // deletion, including SQLite's self-table case and composite tombstone keys.
39
+ const rowKey =
40
+ keys.length === 1
41
+ ? table.column(keys[0])
42
+ : sql`(${sql.join(", ", false)(keys.map(table.column))})`;
43
+
44
+ const deletion = sql`delete from ${table.name} where ${due} and ${rowKey} in (select ${sql.join(", ", false)(aliases)} from (${selection}) as cleanup_candidates)`;
45
+
46
+ if (batch) {
47
+ const planned = (yield* sql`${selection}`).length;
48
+
49
+ yield* appendSqlBatchStatement(deletion);
50
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = ${planned}`));
51
+ removed += planned;
52
+ } else removed += yield* executeSqlChange(sql, deletion);
53
+ }
54
+
55
+ return yield* Schema.decodeEffect(CleanupResult)({ removed, hasMore: removed === limit });
56
+ });
@@ -0,0 +1,435 @@
1
+ import {
2
+ type CommitDiscarded,
3
+ type CommitPending,
4
+ type PreparedCommit,
5
+ CurrentCommitJournal,
6
+ LifecycleHooks,
7
+ coordinateCommit,
8
+ hasCommitScope,
9
+ } from "@yielded/auth/Hooks";
10
+ import { reportPersistenceFailure } from "@yielded/auth/Persistence";
11
+ import { Cause, Context, Data, Effect, Option, Predicate, Schema } from "effect";
12
+ import { SqlClient } from "effect/sql";
13
+ import type { SqlError } from "effect/sql/SqlError";
14
+ import type { Statement } from "effect/sql/Statement";
15
+
16
+ import type { PersistenceMappingError } from "./mapping-error";
17
+ import { requireStandalone } from "./standalone";
18
+
19
+ type SqlCommitError = PersistenceMappingError | Schema.SchemaError | SqlError;
20
+
21
+ export class SqlCommitOwnerError extends Schema.TaggedError<SqlCommitOwnerError>()(
22
+ "SqlCommitOwnerError",
23
+ {
24
+ reason: Schema.Literals([
25
+ "closed",
26
+ "different-client",
27
+ "poisoned",
28
+ "in-flight",
29
+ "invalid-receipt",
30
+ "invalid-mode",
31
+ "postcondition-requires-transaction",
32
+ "batch-required",
33
+ "empty-batch",
34
+ ]),
35
+ },
36
+ ) {}
37
+
38
+ /** Composition selects a D1 batch owner or explicitly supplies no batch owner. */
39
+ export class SqlBatchCommit extends Context.Service<
40
+ SqlBatchCommit,
41
+ | undefined
42
+ | {
43
+ readonly client: SqlClient.SqlClient;
44
+ readonly execute: (
45
+ statements: ReadonlyArray<Statement<unknown>>,
46
+ ) => Effect.Effect<void, SqlError>;
47
+ }
48
+ >()("@yielded/auth-persistence/SqlBatchCommit") {}
49
+
50
+ /** Platform ownership for databases requiring a transaction isolation policy. */
51
+ export class SqlNativeCommit extends Context.Service<
52
+ SqlNativeCommit,
53
+ {
54
+ readonly client: SqlClient.SqlClient;
55
+ readonly withTransaction: <A, E, R>(
56
+ effect: Effect.Effect<A, E, R>,
57
+ ) => Effect.Effect<A, E | SqlCommitError, R>;
58
+ }
59
+ >()("@yielded/auth-persistence/SqlNativeCommit") {}
60
+
61
+ type SqlCommitMode = "transaction" | "statement" | "batch";
62
+
63
+ interface SqlPostcondition {
64
+ readonly name: string;
65
+ readonly check: Effect.Effect<void, SqlCommitError, SqlClient.SqlClient>;
66
+ }
67
+
68
+ export interface SqlCommitScope {
69
+ readonly client: SqlClient.SqlClient;
70
+ readonly mode: SqlCommitMode;
71
+ readonly origin: "operation" | "application";
72
+ readonly postconditions: Array<
73
+ SqlPostcondition | { readonly name: string; readonly statement: Statement<unknown> }
74
+ >;
75
+ readonly receipts: Array<Effect.Effect<void, CommitPending | CommitDiscarded>>;
76
+ readonly statements: Array<Statement<unknown>>;
77
+ active: boolean;
78
+ poisoned: boolean;
79
+ inFlight: number;
80
+ }
81
+
82
+ export class CurrentSqlCommit extends Context.Service<CurrentSqlCommit, SqlCommitScope>()(
83
+ "@yielded/auth-persistence/CurrentSqlCommit",
84
+ ) {}
85
+
86
+ const closed = (): SqlCommitOwnerError => SqlCommitOwnerError.make({ reason: "closed" });
87
+
88
+ /** Explicit final checks run in the physical owner after application work.
89
+ * They resolve SqlClient there, rather than retaining a released savepoint.
90
+ */
91
+ export const registerSqlPostcondition = (
92
+ condition: SqlPostcondition,
93
+ ): Effect.Effect<void, SqlCommitOwnerError, CurrentSqlCommit> =>
94
+ Effect.flatMap(CurrentSqlCommit, (scope) => {
95
+ if (!scope.active) return Effect.fail(closed());
96
+ if (scope.mode !== "transaction")
97
+ return Effect.fail(
98
+ SqlCommitOwnerError.make({ reason: "postcondition-requires-transaction" }),
99
+ );
100
+
101
+ return Effect.sync(() => {
102
+ scope.postconditions.push(condition);
103
+ });
104
+ });
105
+
106
+ /** D1 checks final semantic predicates after all application batch statements. */
107
+ export const registerSqlBatchPostcondition = (condition: {
108
+ readonly name: string;
109
+ readonly statement: Statement<unknown>;
110
+ }): Effect.Effect<void, SqlCommitOwnerError, CurrentSqlCommit> =>
111
+ Effect.flatMap(CurrentSqlCommit, (scope) => {
112
+ if (!scope.active) return Effect.fail(closed());
113
+ if (scope.mode !== "batch")
114
+ return Effect.fail(SqlCommitOwnerError.make({ reason: "batch-required" }));
115
+
116
+ return Effect.sync(() => {
117
+ scope.postconditions.push(condition);
118
+ });
119
+ });
120
+
121
+ /** A caught rollback cannot leave a discarded receipt in a successful owner. A D1
122
+ * batch needs one physical statement even when the decision writes nothing. */
123
+ export const registerSqlCommitReceipt = <A>(
124
+ receipt: PreparedCommit<A>,
125
+ ): Effect.Effect<void, SqlCommitOwnerError, CurrentSqlCommit> =>
126
+ Effect.flatMap(CurrentSqlCommit, (scope) => {
127
+ if (!scope.active) return Effect.fail(closed());
128
+
129
+ return Effect.sync(() => {
130
+ if (scope.mode === "batch" && scope.statements.length === 0)
131
+ scope.statements.push(scope.client`select 1`);
132
+ scope.receipts.push(receipt.read.pipe(Effect.asVoid));
133
+ });
134
+ });
135
+
136
+ export const appendSqlBatchStatement = (
137
+ statement: Statement<unknown>,
138
+ ): Effect.Effect<void, SqlCommitOwnerError, CurrentSqlCommit> =>
139
+ Effect.flatMap(CurrentSqlCommit, (scope) => {
140
+ if (!scope.active) return Effect.fail(closed());
141
+ if (scope.mode !== "batch")
142
+ return Effect.fail(SqlCommitOwnerError.make({ reason: "batch-required" }));
143
+
144
+ return Effect.sync(() => {
145
+ scope.statements.push(statement);
146
+ });
147
+ });
148
+
149
+ type OwnedRequirements<R> = Exclude<
150
+ Exclude<Exclude<Exclude<R, CurrentSqlCommit>, CurrentCommitJournal>, SqlClient.SqlClient>,
151
+ LifecycleHooks
152
+ >;
153
+
154
+ export interface SqlCommitExecutor<Failure> {
155
+ readonly read: <A, E, R>(
156
+ effect: Effect.Effect<A, E, R>,
157
+ ) => Effect.Effect<A, Failure, Exclude<Exclude<R, SqlClient.SqlClient>, LifecycleHooks>>;
158
+ /** Session verification only: runs on the caller's transaction connection when
159
+ * one is ambient. Other reads reject ambient transactions before any result. */
160
+ readonly verify: <A, E, R>(
161
+ effect: Effect.Effect<A, E, R>,
162
+ ) => Effect.Effect<A, Failure, Exclude<Exclude<R, SqlClient.SqlClient>, LifecycleHooks>>;
163
+ /** Preserve expected operation failures without admitting application suffix work. */
164
+ readonly operation: <A, E, R>(
165
+ effect: Effect.Effect<A, E, R>,
166
+ mode?: "transaction" | "statement",
167
+ ) => Effect.Effect<A, E | Failure, OwnedRequirements<R>>;
168
+ readonly operationBatch: <A, E, R>(
169
+ effect: Effect.Effect<A, E, R>,
170
+ ) => Effect.Effect<A, E | Failure, OwnedRequirements<R> | SqlBatchCommit>;
171
+ readonly coordinate: <A, E, R>(
172
+ effect: Effect.Effect<A, E, R>,
173
+ mode?: "transaction" | "statement",
174
+ ) => Effect.Effect<A, E | Failure, OwnedRequirements<R>>;
175
+ readonly coordinateBatch: <A, E, R>(
176
+ effect: Effect.Effect<A, E, R>,
177
+ ) => Effect.Effect<A, E | Failure, OwnedRequirements<R> | SqlBatchCommit>;
178
+ readonly run: <A, E, R>(
179
+ effect: Effect.Effect<A, E, R>,
180
+ mode?: "transaction" | "statement",
181
+ ) => Effect.Effect<A, Failure, OwnedRequirements<R>>;
182
+ readonly batch: <A, E, R>(
183
+ effect: Effect.Effect<A, E, R>,
184
+ ) => Effect.Effect<A, Failure, OwnedRequirements<R> | SqlBatchCommit>;
185
+ }
186
+
187
+ /** Capture an executor where its service is constructed. Bound services cannot
188
+ * escape their owner, join another client, or silently start a second commit.
189
+ * Reads are advisory and never coordinate a commit. Statement mode is reserved
190
+ * for one atomic SQL mutation; authority mutations use transaction or batch mode.
191
+ */
192
+ export const makeSqlCommitExecutor = Effect.fnUntraced(function* <Failure>(
193
+ unavailable: () => Failure,
194
+ ): Effect.fn.Return<SqlCommitExecutor<Failure>, never, SqlClient.SqlClient | LifecycleHooks> {
195
+ const sql = yield* SqlClient.SqlClient;
196
+ const hooks = yield* LifecycleHooks;
197
+ const captured = yield* Effect.serviceOption(CurrentSqlCommit);
198
+ const native = yield* Effect.serviceOption(SqlNativeCommit);
199
+ const failure = unavailable();
200
+
201
+ const report = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
202
+ reportPersistenceFailure(
203
+ effect,
204
+ (error) =>
205
+ Object.is(error, failure) ||
206
+ Schema.is(SqlCommitOwnerError)(error) ||
207
+ (Predicate.hasProperty(failure, "_tag") &&
208
+ typeof failure._tag === "string" &&
209
+ Predicate.hasProperty(error, "_tag") &&
210
+ error._tag === failure._tag),
211
+ ).pipe(
212
+ Effect.mapError(() => failure),
213
+ Effect.catchCause((cause) =>
214
+ Cause.hasInterrupts(cause) ? Effect.failCause(cause) : Effect.fail(failure),
215
+ ),
216
+ );
217
+
218
+ const admit = Effect.gen(function* () {
219
+ if (Option.isSome(captured)) {
220
+ const scope = captured.value;
221
+ const current = yield* Effect.serviceOption(CurrentSqlCommit);
222
+
223
+ if (!scope.active || Option.isNone(current) || current.value !== scope)
224
+ return yield* closed();
225
+ if (scope.client.transactionService !== sql.transactionService)
226
+ return yield* SqlCommitOwnerError.make({ reason: "different-client" });
227
+ } else {
228
+ if (yield* hasCommitScope) return yield* Effect.fail(failure);
229
+ yield* requireStandalone(() => failure, sql.transactionService);
230
+ }
231
+ });
232
+
233
+ const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
234
+ effect.pipe(
235
+ Effect.provideService(SqlClient.SqlClient, sql),
236
+ Effect.provideService(LifecycleHooks, hooks),
237
+ );
238
+
239
+ const bound = <A, E, R>(scope: SqlCommitScope, effect: Effect.Effect<A, E, R>) =>
240
+ Effect.uninterruptibleMask((restore) =>
241
+ Effect.gen(function* () {
242
+ yield* admit;
243
+ const journal = yield* Effect.serviceOption(CurrentCommitJournal);
244
+
245
+ if (Option.isNone(journal)) return yield* closed();
246
+ scope.inFlight++;
247
+
248
+ return yield* restore(
249
+ effect.pipe(
250
+ Effect.provideService(CurrentSqlCommit, scope),
251
+ Effect.provideService(CurrentCommitJournal, journal.value),
252
+ ),
253
+ ).pipe(
254
+ Effect.flatMap((value) => admit.pipe(Effect.as(value))),
255
+ Effect.onExit((exit) =>
256
+ Effect.sync(() => {
257
+ scope.inFlight--;
258
+ if (exit._tag === "Failure") scope.poisoned = true;
259
+ }),
260
+ ),
261
+ );
262
+ }),
263
+ );
264
+
265
+ const finish = Effect.fnUntraced(function* (scope: SqlCommitScope) {
266
+ if (scope.poisoned) return yield* SqlCommitOwnerError.make({ reason: "poisoned" });
267
+ if (scope.inFlight !== 0) return yield* SqlCommitOwnerError.make({ reason: "in-flight" });
268
+
269
+ for (const condition of scope.postconditions) {
270
+ if ("statement" in condition) scope.statements.push(condition.statement);
271
+ else yield* condition.check;
272
+ }
273
+ for (const receipt of scope.receipts) {
274
+ const status = yield* Effect.result(receipt);
275
+
276
+ if (status._tag !== "Failure" || status.failure._tag !== "CommitPending")
277
+ return yield* SqlCommitOwnerError.make({ reason: "invalid-receipt" });
278
+ }
279
+ });
280
+
281
+ const owned = <A, E, R>(
282
+ effect: Effect.Effect<A, E, R>,
283
+ mode: SqlCommitMode,
284
+ origin: SqlCommitScope["origin"],
285
+ batch?: SqlBatchCommit["Service"],
286
+ ) => {
287
+ if (Option.isSome(captured)) {
288
+ const scope = captured.value;
289
+
290
+ if (mode !== scope.mode && !(mode === "statement" && scope.mode === "transaction"))
291
+ return Effect.fail(SqlCommitOwnerError.make({ reason: "invalid-mode" }));
292
+
293
+ return provide(bound(scope, effect));
294
+ }
295
+
296
+ const work = Effect.gen(function* () {
297
+ yield* admit;
298
+
299
+ const result = yield* coordinateCommit(() => {
300
+ const scope: SqlCommitScope = {
301
+ client: sql,
302
+ mode,
303
+ origin,
304
+ active: true,
305
+ poisoned: false,
306
+ inFlight: 0,
307
+ postconditions: [],
308
+ receipts: [],
309
+ statements: [],
310
+ };
311
+
312
+ const owner = Effect.gen(function* () {
313
+ const value = yield* effect.pipe(
314
+ Effect.provideService(CurrentSqlCommit, scope),
315
+ Effect.ensuring(
316
+ Effect.sync(() => {
317
+ scope.active = false;
318
+ }),
319
+ ),
320
+ );
321
+
322
+ yield* finish(scope);
323
+ if (mode === "batch") {
324
+ if (batch === undefined)
325
+ return yield* SqlCommitOwnerError.make({ reason: "batch-required" });
326
+ if (batch.client.transactionService !== sql.transactionService)
327
+ return yield* SqlCommitOwnerError.make({ reason: "different-client" });
328
+ if (scope.statements.length === 0)
329
+ return yield* SqlCommitOwnerError.make({ reason: "empty-batch" });
330
+
331
+ yield* batch.execute(scope.statements);
332
+ }
333
+
334
+ return value;
335
+ });
336
+
337
+ if (mode !== "transaction") return owner;
338
+ if (Option.isNone(native)) return sql.withTransaction(owner);
339
+ if (native.value.client.transactionService !== sql.transactionService)
340
+ return Effect.fail(SqlCommitOwnerError.make({ reason: "different-client" }));
341
+
342
+ return native.value.withTransaction(owner);
343
+ });
344
+
345
+ return result.value;
346
+ });
347
+
348
+ return provide(work);
349
+ };
350
+
351
+ const read = <A, E, R>(effect: Effect.Effect<A, E, R>) => {
352
+ if (Option.isSome(captured)) return provide(report(bound(captured.value, effect)));
353
+
354
+ return provide(report(admit.pipe(Effect.andThen(effect))));
355
+ };
356
+
357
+ const verify = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
358
+ Option.isSome(captured) ? read(effect) : provide(report(effect));
359
+
360
+ const coordinate = <A, E, R>(
361
+ effect: Effect.Effect<A, E, R>,
362
+ mode: SqlCommitMode,
363
+ origin: SqlCommitScope["origin"],
364
+ batch?: SqlBatchCommit["Service"],
365
+ ) => {
366
+ class ApplicationFailure extends Data.TaggedError("SqlCommitApplicationFailure")<{
367
+ readonly error: E;
368
+ }> {}
369
+ const wrapped = effect.pipe(Effect.mapError((error) => new ApplicationFailure({ error })));
370
+
371
+ return reportPersistenceFailure(
372
+ owned(wrapped, mode, origin, batch),
373
+ (error) => error instanceof ApplicationFailure || Schema.is(SqlCommitOwnerError)(error),
374
+ ).pipe(
375
+ Effect.catchCause((cause) =>
376
+ Effect.failCause(
377
+ Cause.fromReasons(
378
+ cause.reasons.map((reason): Cause.Reason<E | Failure> => {
379
+ if (Cause.isInterruptReason(reason)) return reason;
380
+ if (Cause.isFailReason(reason) && reason.error instanceof ApplicationFailure)
381
+ return Cause.makeFailReason(reason.error.error);
382
+
383
+ return Cause.makeFailReason(failure);
384
+ }),
385
+ ),
386
+ ),
387
+ ),
388
+ );
389
+ };
390
+
391
+ return {
392
+ read,
393
+ verify,
394
+ operation: <A, E, R>(
395
+ effect: Effect.Effect<A, E, R>,
396
+ mode: "transaction" | "statement" = "transaction",
397
+ ) => coordinate(effect, mode, "operation"),
398
+ operationBatch: <A, E, R>(effect: Effect.Effect<A, E, R>) =>
399
+ Effect.flatMap(SqlBatchCommit, (batch) => coordinate(effect, "batch", "operation", batch)),
400
+ coordinate: <A, E, R>(
401
+ effect: Effect.Effect<A, E, R>,
402
+ mode: "transaction" | "statement" = "transaction",
403
+ ) => coordinate(effect, mode, "application"),
404
+ coordinateBatch: <A, E, R>(effect: Effect.Effect<A, E, R>) =>
405
+ Effect.flatMap(SqlBatchCommit, (batch) => coordinate(effect, "batch", "application", batch)),
406
+ run: <A, E, R>(
407
+ effect: Effect.Effect<A, E, R>,
408
+ mode: "transaction" | "statement" = "transaction",
409
+ ): Effect.Effect<A, Failure, OwnedRequirements<R>> => report(owned(effect, mode, "operation")),
410
+ batch: <A, E, R>(effect: Effect.Effect<A, E, R>) =>
411
+ Effect.flatMap(SqlBatchCommit, (batch) => report(owned(effect, "batch", "operation", batch))),
412
+ };
413
+ });
414
+
415
+ /** Application statements join the same fixed batch and cannot escape it. */
416
+ export interface SqlBatchCollector {
417
+ readonly append: (statement: Statement<unknown>) => Effect.Effect<void, SqlCommitOwnerError>;
418
+ }
419
+
420
+ export const captureSqlBatchStatements: Effect.Effect<SqlBatchCollector, never, CurrentSqlCommit> =
421
+ Effect.map(CurrentSqlCommit, (scope) => ({
422
+ append: (statement: Statement<unknown>) =>
423
+ Effect.gen(function* () {
424
+ const current = yield* Effect.serviceOption(CurrentSqlCommit);
425
+
426
+ if (
427
+ !scope.active ||
428
+ scope.mode !== "batch" ||
429
+ Option.isNone(current) ||
430
+ current.value !== scope
431
+ )
432
+ return yield* closed();
433
+ scope.statements.push(statement);
434
+ }),
435
+ }));