@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,888 @@
1
+ import type { LifecycleHooks, CommitJournal, PreparedCommit } from "@yielded/auth/Hooks";
2
+ import * as M from "@yielded/auth/OAuth";
3
+ import { Crypto, Effect, Option, Schema } from "effect";
4
+ import * as Base64Url from "effect/encoding/Base64Url";
5
+ import type { SqlClient } from "effect/sql/SqlClient";
6
+ import type { Fragment } from "effect/sql/Statement";
7
+
8
+ import type { NativeSqlTables, SqlTable } from "../native-sql-table";
9
+ import { makeConditionalSqlInsert } from "../session-native-record";
10
+ import { exactSqlText, executeSqlChange } from "../sql-change";
11
+ import { cleanupSqlRows } from "../sql-cleanup";
12
+ import { makeSqlCommitExecutor, SqlBatchCommit, CurrentSqlCommit } from "../sql-commit";
13
+ import {
14
+ connectedSummary,
15
+ makeOAuthNativeConnectedState,
16
+ type OAuthNativeConnectedMapping,
17
+ validConnectedMetadata,
18
+ } from "./native-connected-state";
19
+ import { makeOAuthNativeFlow } from "./native-flow";
20
+ import { prepareOAuthNative } from "./native-sign-in";
21
+ import {
22
+ invariant,
23
+ oauthIdentityKey,
24
+ sameIdentity,
25
+ sameRevision,
26
+ storage,
27
+ unavailable,
28
+ } from "./state";
29
+
30
+ export const makeNativeOAuthConnectedServices = Effect.fnUntraced(function* (
31
+ tables: NativeSqlTables,
32
+ mapping: OAuthNativeConnectedMapping,
33
+ batch?: SqlBatchCommit["Service"],
34
+ ): Effect.fn.Return<
35
+ { readonly oauthConnectedPersistence: M.OAuthConnectedPersistence["Service"] },
36
+ M.OAuthUnavailable,
37
+ SqlClient | LifecycleHooks | Crypto.Crypto
38
+ > {
39
+ const conditionalInsert = yield* makeConditionalSqlInsert();
40
+ const executor = yield* makeSqlCommitExecutor(unavailable);
41
+ const crypto = yield* Crypto.Crypto;
42
+ const external = yield* Effect.serviceOption(CurrentSqlCommit);
43
+ const planned = batch !== undefined && Option.isSome(external);
44
+ const state = yield* makeOAuthNativeConnectedState(tables, mapping, batch !== undefined);
45
+
46
+ const flow = yield* makeOAuthNativeFlow(
47
+ tables,
48
+ mapping,
49
+ M.OAuthConnectedFlow,
50
+ "connect",
51
+ (value) => value.context.revision.subjectId,
52
+ batch !== undefined,
53
+ );
54
+
55
+ const { sql, now, grant } = state;
56
+ const g = mapping.grant;
57
+ const mysql = sql.onDialectOrElse({ mysql: () => true, orElse: () => false });
58
+
59
+ const run = <A, E, R>(
60
+ effect: Effect.Effect<A, E, R>,
61
+ mode: "transaction" | "statement" = "transaction",
62
+ ) => {
63
+ const work = Effect.provideService(effect, Crypto.Crypto, crypto);
64
+
65
+ return batch === undefined
66
+ ? executor.run(work, mode)
67
+ : executor.batch(work).pipe(Effect.provideService(SqlBatchCommit, batch));
68
+ };
69
+
70
+ const atomic = <A, E, R>(
71
+ effect: Effect.Effect<A, E, R>,
72
+ mode: "transaction" | "statement" = "statement",
73
+ ) =>
74
+ planned
75
+ ? run(effect)
76
+ : executor.run(Effect.provideService(effect, Crypto.Crypto, crypto), mode);
77
+
78
+ const refreshMiss = <A>(
79
+ key: M.OAuthConnectedGrantKey,
80
+ nativeId: unknown,
81
+ encoded: string,
82
+ required: Fragment,
83
+ upper: number,
84
+ prepare: (
85
+ decision: typeof M.OAuthConnectedRefreshDecision.Type,
86
+ journal: CommitJournal,
87
+ ) => PreparedCommit<A>,
88
+ ) =>
89
+ Effect.gen(function* () {
90
+ const rows =
91
+ yield* sql`select ${grant.column(g.state)} as state,${now} as instant from ${grant.name} where ${state.key(key, nativeId)} and ${state.exact(g.snapshot, encoded)} and ${required} limit 2`;
92
+
93
+ invariant(rows.length <= 1);
94
+ const row = rows[0];
95
+
96
+ return yield* prepareOAuthNative(
97
+ row === undefined
98
+ ? { _tag: "Rejected" }
99
+ : row.state === "Refreshing"
100
+ ? { _tag: "Busy" }
101
+ : row.state !== "Active" || Number(row.instant) >= upper
102
+ ? { _tag: "ReauthorizationRequired" }
103
+ : { _tag: "Busy" },
104
+ prepare,
105
+ );
106
+ });
107
+
108
+ const read = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
109
+ executor.read(Effect.provideService(effect, Crypto.Crypto, crypto));
110
+
111
+ const sameConfiguration = (
112
+ left: M.OAuthConnectedConfiguration,
113
+ right: M.OAuthConnectedConfiguration,
114
+ ) =>
115
+ storage(M.OAuthConnectedConfiguration).encode(left) ===
116
+ storage(M.OAuthConnectedConfiguration).encode(right);
117
+
118
+ const policy = (input: Parameters<typeof mapping.policy.condition>[0]) =>
119
+ tables.expression(mapping.policy.condition(input));
120
+
121
+ const present = (
122
+ key: M.OAuthConnectedGrantKey,
123
+ nativeId: unknown,
124
+ encoded: string,
125
+ extra?: Fragment,
126
+ ) =>
127
+ sql`exists(select 1 from ${grant.name} where ${state.key(key, nativeId)} and ${state.exact(g.snapshot, encoded)} ${extra === undefined ? sql`` : sql`and ${extra}`})`;
128
+
129
+ const referenced = (identityKey: string, nativeId: unknown) =>
130
+ sql.or([
131
+ sql`exists(select 1 from ${grant.name} where ${state.exact(g.identityKey, identityKey)} and ${grant.column(g.subjectId)} = ${grant.value(g.subjectId, nativeId)})`,
132
+ ...(mapping.revocation.mode === "provider"
133
+ ? (() => {
134
+ const j = mapping.revocation.job;
135
+ const job = tables(j.table);
136
+
137
+ return [
138
+ sql`exists(select 1 from ${job.name} where ${exactSqlText(sql, job.column(j.identityKey), job.value(j.identityKey, identityKey))} and ${job.column(j.subjectId)} = ${job.value(j.subjectId, nativeId)})`,
139
+ ];
140
+ })()
141
+ : []),
142
+ tables.expression(mapping.otherReferences({ identityKey, subjectId: nativeId })),
143
+ ]);
144
+
145
+ const service: M.OAuthConnectedPersistence["Service"] = {
146
+ read: (input) =>
147
+ read(
148
+ Effect.suspend(() =>
149
+ state.readJoined(M.snapshotOAuthSync(M.OAuthConnectedReadInput, input)),
150
+ ),
151
+ ),
152
+ issue: (input, prepare) =>
153
+ run(
154
+ Effect.gen(function* () {
155
+ const value = M.snapshotOAuthSync(M.OAuthConnectedFlow, input);
156
+
157
+ return yield* prepareOAuthNative(
158
+ (yield* flow.issue(value)) ? { _tag: "Issued", flow: value } : { _tag: "Rejected" },
159
+ prepare,
160
+ );
161
+ }),
162
+ flow.mysql ? "transaction" : "statement",
163
+ ),
164
+ consume: (input, prepare) =>
165
+ run(
166
+ Effect.gen(function* () {
167
+ const consumed = yield* flow.consume(M.snapshotOAuthSync(M.OAuthConnectedAccess, input));
168
+
169
+ return yield* prepareOAuthNative(
170
+ consumed === undefined ? { _tag: "Rejected" } : { _tag: "Consumed", flow: consumed },
171
+ prepare,
172
+ );
173
+ }),
174
+ flow.mysql ? "transaction" : "statement",
175
+ ),
176
+ settle: (original, prepare) =>
177
+ run(
178
+ Effect.gen(function* () {
179
+ const input = M.snapshotOAuthSync(M.OAuthConnectedSettlement, original);
180
+ const token = input.grant.context;
181
+ const captured = yield* state.captureSubject(token.subjectId, batch === undefined);
182
+
183
+ const revision =
184
+ input._tag === "Connect" ? input.flow.context.revision : input.credential.revision;
185
+
186
+ const current =
187
+ captured === undefined ||
188
+ captured.securityRevision !== revision.securityRevision ||
189
+ revision.subjectId !== token.subjectId
190
+ ? undefined
191
+ : { ...captured, revision };
192
+
193
+ const rejected = () => prepareOAuthNative({ _tag: "Rejected" } as const, prepare);
194
+
195
+ if (
196
+ current === undefined ||
197
+ !validConnectedMetadata(token, current.now) ||
198
+ current.now >= token.metadata.useUntilMillis
199
+ )
200
+ return yield* rejected();
201
+ const context = input.flow.context;
202
+
203
+ if (
204
+ token.moduleId !== context.moduleId ||
205
+ token.identity.provider !== context.provider ||
206
+ token.identity.issuer !== context.issuer ||
207
+ current.now >= context.expiresAtMillis ||
208
+ token.metadata.obtainedAtMillis < context.issuedAtMillis
209
+ )
210
+ return yield* rejected();
211
+ let authorization: Fragment;
212
+ let previous: M.OAuthConnectedTarget | undefined;
213
+ let deadline = Math.min(context.expiresAtMillis, token.metadata.useUntilMillis);
214
+
215
+ if (input._tag === "Connect") {
216
+ const c = input.flow.context;
217
+
218
+ if (
219
+ !sameRevision(current.revision, c.revision) ||
220
+ token.grantId !== c.grantId ||
221
+ !sameConfiguration(
222
+ token.configuration,
223
+ M.snapshotOAuthSync(M.OAuthConnectedConfiguration, c),
224
+ )
225
+ )
226
+ return yield* rejected();
227
+ deadline = Math.min(deadline, input.authorization.validUntilMillis);
228
+ authorization = policy({
229
+ subjectId: current.nativeId,
230
+ revision: current.revision,
231
+ kind: "action",
232
+ operation: "settle",
233
+ authorization: input.authorization,
234
+ grant: token,
235
+ });
236
+ previous = c.reconnect;
237
+ } else {
238
+ if (
239
+ mapping.credential === undefined ||
240
+ !sameRevision(current.revision, input.credential.revision) ||
241
+ input.credential.moduleId !== token.moduleId ||
242
+ !sameIdentity(input.credential.identity, token.identity)
243
+ )
244
+ return yield* rejected();
245
+ const c = mapping.credential;
246
+ const credential = tables(c.table);
247
+ const identityKey = yield* oauthIdentityKey(token.identity);
248
+
249
+ authorization = sql.and([
250
+ policy({
251
+ subjectId: current.nativeId,
252
+ revision: current.revision,
253
+ kind: "sign-in",
254
+ credential: input.credential,
255
+ grant: token,
256
+ }),
257
+ sql`exists(select 1 from ${credential.name} where ${credential.column(c.subjectId)} = ${credential.value(c.subjectId, current.nativeId)} and ${exactSqlText(sql, credential.column(c.moduleId), credential.value(c.moduleId, token.moduleId))} and ${exactSqlText(sql, credential.column(c.identityKey), credential.value(c.identityKey, identityKey))} and ${exactSqlText(sql, credential.column(c.credentialId), credential.value(c.credentialId, input.credential.credentialId))} and ${exactSqlText(sql, credential.column(c.credentialRevision), credential.value(c.credentialRevision, input.credential.credentialRevision))} and ${tables.expression(c.activeCondition)})`,
258
+ ]);
259
+ previous = input.previous;
260
+ const profile = context.access;
261
+
262
+ if (
263
+ profile === undefined ||
264
+ !sameConfiguration(
265
+ token.configuration,
266
+ M.snapshotOAuthSync(M.OAuthConnectedConfiguration, { ...context, profile }),
267
+ )
268
+ )
269
+ return yield* rejected();
270
+ }
271
+
272
+ const required = sql.and([
273
+ state.authorityCondition(current.nativeId, current.revision),
274
+ authorization,
275
+ sql`${now} < ${deadline}`,
276
+ ]);
277
+
278
+ const key = {
279
+ moduleId: token.moduleId,
280
+ subjectId: token.subjectId,
281
+ grantId: token.grantId,
282
+ };
283
+
284
+ if (
285
+ previous !== undefined &&
286
+ (previous.grantId !== token.grantId ||
287
+ !sameIdentity(token.identity, previous.identity) ||
288
+ !sameConfiguration(token.configuration, previous.configuration) ||
289
+ token.grantVersion === previous.grantVersion)
290
+ )
291
+ return yield* rejected();
292
+
293
+ const identityKey =
294
+ input._tag === "SignIn" || previous !== undefined
295
+ ? yield* oauthIdentityKey(token.identity)
296
+ : yield* state.ensureOwnership(token.identity, current.nativeId);
297
+
298
+ if (identityKey === undefined)
299
+ return yield* prepareOAuthNative({ _tag: "Conflict" }, prepare);
300
+ const owner = sql`exists(select 1 from ${state.ownership.name} where ${state.ownerCondition(identityKey, current.nativeId)})`;
301
+ const values = state.values(input.grant, current.nativeId, identityKey);
302
+
303
+ const changed = yield* state.change(
304
+ previous === undefined
305
+ ? conditionalInsert(grant, values, sql`${required} and ${owner}`)
306
+ : sql`${grant.update(values)} where ${state.key(key, current.nativeId)} and ${state.exact(g.grantVersion, previous.grantVersion)} and ${state.exact(g.identityKey, identityKey)} and ${state.exact(g.profileKey, previous.configuration.profile.key)} ${input._tag === "SignIn" ? sql`and ${state.exact(g.tokenVersion, previous.tokenVersion)}` : sql``} and ${required} and ${owner}`,
307
+ );
308
+
309
+ if (changed !== 1) {
310
+ // A fresh connection may have inserted ownership in this transaction.
311
+ // Roll it back together with a lost grant predicate.
312
+ invariant(input._tag !== "Connect" || previous !== undefined);
313
+
314
+ return yield* rejected();
315
+ }
316
+ if (Option.isSome(external))
317
+ yield* state.finish(
318
+ "oauth-connected-grant",
319
+ sql.and([
320
+ required,
321
+ present(
322
+ key,
323
+ current.nativeId,
324
+ state.stored.encode(input.grant),
325
+ state.exact(g.state, "Active"),
326
+ ),
327
+ sql`exists(select 1 from ${state.ownership.name} where ${state.ownerCondition(identityKey, current.nativeId)})`,
328
+ ]),
329
+ );
330
+
331
+ return yield* prepareOAuthNative({ _tag: "Connected", grant: input.grant }, prepare);
332
+ }),
333
+ ),
334
+ list: (original) =>
335
+ read(
336
+ Effect.gen(function* () {
337
+ const authorization = M.snapshotOAuthSync(
338
+ M.OAuthConnectedUseAuthorization,
339
+ original.authorization,
340
+ );
341
+
342
+ const input = M.snapshotOAuthSync(M.OAuthConnectedList, {
343
+ limit: original.limit,
344
+ ...(original.cursor === undefined ? {} : { cursor: original.cursor }),
345
+ });
346
+
347
+ const nativeId = yield* mapping.subjectId.toNative(authorization.revision.subjectId);
348
+ const required = state.use(nativeId, authorization, "metadata");
349
+
350
+ if (required === undefined) return { items: [] };
351
+
352
+ const rows =
353
+ yield* sql`select ${grant.column(g.summary)} as summary, ${grant.column(g.state)} as state from ${grant.name}
354
+ where ${state.exact(g.moduleId, authorization.moduleId)} and ${grant.column(g.subjectId)} = ${grant.value(g.subjectId, nativeId)} and ${required}
355
+ ${input.cursor === undefined ? sql`` : sql`and ${grant.column(g.grantId)} > ${grant.value(g.grantId, input.cursor)}`}
356
+ order by ${grant.column(g.grantId)} limit ${input.limit}`;
357
+
358
+ const items = yield* Effect.forEach(rows, (row) =>
359
+ Effect.gen(function* () {
360
+ invariant(typeof row.summary === "string");
361
+
362
+ return M.snapshotOAuthSync(M.OAuthConnectedSummary, {
363
+ ...state.summary.decode(row.summary),
364
+ status: yield* Schema.decodeUnknownEffect(
365
+ M.OAuthConnectedGrantSnapshot.fields.state,
366
+ )(row.state),
367
+ });
368
+ }),
369
+ );
370
+
371
+ return {
372
+ items,
373
+ ...(items.length === input.limit ? { cursor: items[items.length - 1]!.grantId } : {}),
374
+ };
375
+ }),
376
+ ),
377
+ disconnect: (original, prepare) =>
378
+ run(
379
+ Effect.gen(function* () {
380
+ const key = M.snapshotOAuthSync(M.OAuthConnectedGrantKey, original.key);
381
+
382
+ const version = M.snapshotOAuthSync(
383
+ M.OAuthConnectedTarget.fields.grantVersion,
384
+ original.grantVersion,
385
+ );
386
+
387
+ const authorization = M.snapshotOAuthSync(
388
+ M.OAuthConnectedActionAuthorization,
389
+ original.authorization,
390
+ );
391
+
392
+ const captured = yield* state.captureSubject(key.subjectId, batch === undefined);
393
+ const revision = authorization.challenge.revision;
394
+
395
+ const current =
396
+ captured === undefined ||
397
+ revision.subjectId !== key.subjectId ||
398
+ captured.securityRevision !== revision.securityRevision
399
+ ? undefined
400
+ : { ...captured, revision };
401
+
402
+ const rejected = () => prepareOAuthNative({ _tag: "Rejected" } as const, prepare);
403
+
404
+ if (
405
+ current === undefined ||
406
+ !sameRevision(current.revision, authorization.challenge.revision)
407
+ )
408
+ return yield* rejected();
409
+ const old = yield* state.readGrant(key, current.nativeId, batch === undefined);
410
+
411
+ if (old === undefined || old.value.context.grantVersion !== version)
412
+ return yield* rejected();
413
+
414
+ const required = sql.and([
415
+ state.authorityCondition(current.nativeId, current.revision),
416
+ sql`${now} < ${authorization.validUntilMillis}`,
417
+ policy({
418
+ subjectId: current.nativeId,
419
+ revision: current.revision,
420
+ kind: "action",
421
+ operation: "disconnect",
422
+ authorization,
423
+ grant: old.value.context,
424
+ }),
425
+ ]);
426
+
427
+ let remoteRevocation: "Pending" | "Unsupported" = "Unsupported";
428
+ const final = [];
429
+
430
+ // The locked snapshot is also the provider job payload; never enqueue
431
+ // caller ciphertext or delete a different grant revision.
432
+ const removed = yield* state.change(
433
+ sql`delete from ${grant.name} where ${state.key(key, current.nativeId)} and ${state.exact(g.grantVersion, version)} and ${state.exact(g.snapshot, old.encoded)} and ${required}`,
434
+ );
435
+
436
+ if (removed !== 1) return yield* rejected();
437
+
438
+ if (
439
+ mapping.revocation.mode === "provider" &&
440
+ old.value.context.configuration.profile.revocation === "provider"
441
+ ) {
442
+ const j = mapping.revocation.job;
443
+ const job = tables(j.table);
444
+
445
+ const jobId = yield* Schema.decodeEffect(M.OAuthClaimId)(
446
+ Base64Url.encode(yield* crypto.randomBytes(32)),
447
+ );
448
+
449
+ const retained = M.snapshotOAuthSync(M.OAuthConnectedRevocationJob, {
450
+ jobId,
451
+ grant: old.value,
452
+ });
453
+
454
+ const encoded = storage(M.OAuthConnectedRevocationJob).encode(retained);
455
+
456
+ invariant(
457
+ Number.isSafeInteger(mapping.revocation.retentionMillis) &&
458
+ mapping.revocation.retentionMillis >= 120000,
459
+ );
460
+ invariant(
461
+ (yield* state.change(
462
+ job.insert({
463
+ ...j.encodeInsert({ job: retained, subjectId: current.nativeId }),
464
+ [j.jobId]: jobId,
465
+ [j.moduleId]: key.moduleId,
466
+ [j.subjectId]: current.nativeId,
467
+ [j.identityKey]: old.identityKey,
468
+ [j.snapshot]: encoded,
469
+ [j.state]: "Pending",
470
+ [j.claimId]: null,
471
+ [j.claimedAt]: null,
472
+ [j.claimExpiresAt]: null,
473
+ [j.retentionUntil]: mapping.clock.encodeInstant(
474
+ current.now + mapping.revocation.retentionMillis,
475
+ ),
476
+ }),
477
+ )) === 1,
478
+ );
479
+ final.push(
480
+ sql`exists(select 1 from ${job.name} where ${exactSqlText(sql, job.column(j.jobId), job.value(j.jobId, jobId))} and ${exactSqlText(sql, job.column(j.snapshot), job.value(j.snapshot, encoded))})`,
481
+ );
482
+ remoteRevocation = "Pending";
483
+ }
484
+ yield* state.releaseOwnership(
485
+ old.identityKey,
486
+ current.nativeId,
487
+ referenced(old.identityKey, current.nativeId),
488
+ );
489
+ if (Option.isSome(external))
490
+ yield* state.finish(
491
+ "oauth-connected-disconnected",
492
+ sql.and([
493
+ required,
494
+ sql`not exists(select 1 from ${grant.name} where ${state.key(key, current.nativeId)})`,
495
+ ...final,
496
+ ]),
497
+ );
498
+
499
+ return yield* prepareOAuthNative(
500
+ { _tag: "Disconnected", grantId: key.grantId, remoteRevocation },
501
+ prepare,
502
+ );
503
+ }),
504
+ ),
505
+ claimRefresh: (original, prepare) =>
506
+ atomic(
507
+ Effect.gen(function* () {
508
+ const stored = M.snapshotOAuthSync(M.OAuthConnectedStoredGrant, original.grant);
509
+ const token = stored.context;
510
+
511
+ const key = {
512
+ moduleId: token.moduleId,
513
+ subjectId: token.subjectId,
514
+ grantId: token.grantId,
515
+ };
516
+
517
+ const nativeId = yield* mapping.subjectId.toNative(token.subjectId);
518
+
519
+ const authorization = M.snapshotOAuthSync(
520
+ M.OAuthConnectedUseAuthorization,
521
+ original.authorization,
522
+ );
523
+
524
+ const rejected = () => prepareOAuthNative({ _tag: "Rejected" } as const, prepare);
525
+ const required = state.use(nativeId, authorization, "use", token);
526
+
527
+ if (required === undefined) return yield* rejected();
528
+ if (
529
+ token.configuration.profile.refresh === "unsupported" ||
530
+ token.metadata.refreshUseUntilMillis === undefined
531
+ )
532
+ return yield* prepareOAuthNative({ _tag: "ReauthorizationRequired" }, prepare);
533
+ invariant(
534
+ Number.isSafeInteger(original.lifetimeMillis) &&
535
+ original.lifetimeMillis >= 1000 &&
536
+ original.lifetimeMillis <= 300000 &&
537
+ original.nextTokenVersion !== token.tokenVersion &&
538
+ validConnectedMetadata(token, token.metadata.obtainedAtMillis),
539
+ );
540
+ const encoded = state.stored.encode(stored);
541
+
542
+ const upper = Math.min(
543
+ token.metadata.refreshUseUntilMillis,
544
+ authorization.expiresAtMillis,
545
+ );
546
+
547
+ const due =
548
+ token.metadata.useUntilMillis - token.configuration.profile.refreshAheadMillis;
549
+
550
+ const base = sql.and([
551
+ state.key(key, nativeId),
552
+ state.exact(g.grantVersion, token.grantVersion),
553
+ state.exact(g.tokenVersion, token.tokenVersion),
554
+ state.exact(g.snapshot, encoded),
555
+ state.exact(g.state, "Active"),
556
+ sql`${grant.column(g.refreshClaimId)} is null`,
557
+ required,
558
+ sql`${now} >= ${token.metadata.obtainedAtMillis} and ${now} >= ${due} and ${now} < ${upper}`,
559
+ ]);
560
+
561
+ let claimedAtMillis: number, claimExpiresAtMillis: number;
562
+
563
+ if (planned || mysql) {
564
+ // A fixed batch cannot return its future clock sample. Its planned
565
+ // sample is written exactly and guarded by the original horizon.
566
+ const clock = yield* sql`select ${now} as instant`;
567
+
568
+ claimedAtMillis = Number(clock[0]?.instant);
569
+ invariant(Number.isSafeInteger(claimedAtMillis));
570
+ claimExpiresAtMillis = Math.min(claimedAtMillis + original.lifetimeMillis, upper);
571
+ if (claimedAtMillis >= upper)
572
+ return yield* prepareOAuthNative({ _tag: "ReauthorizationRequired" }, prepare);
573
+ const statement = sql`${grant.update({ [g.state]: "Refreshing", [g.refreshClaimId]: original.claimId, [g.refreshNextTokenVersion]: original.nextTokenVersion, [g.refreshClaimedAt]: mapping.clock.encodeInstant(claimedAtMillis), [g.refreshClaimExpiresAt]: mapping.clock.encodeInstant(claimExpiresAtMillis) })} where ${base} and ${now} >= ${claimedAtMillis} and ${now} < ${claimExpiresAtMillis}`;
574
+
575
+ const changed = planned
576
+ ? yield* state.change(statement)
577
+ : yield* executeSqlChange(sql, statement);
578
+
579
+ if (changed !== 1)
580
+ return yield* refreshMiss(key, nativeId, encoded, required, upper, prepare);
581
+ } else {
582
+ const sample = sql`(select instant from refresh_clock)`;
583
+ const deadline = sql`case when ${sample} + ${original.lifetimeMillis} < ${upper} then ${sample} + ${original.lifetimeMillis} else ${upper} end`;
584
+ const statement = sql`with refresh_clock as materialized (select ${now} as instant) ${grant.update({ [g.state]: "Refreshing", [g.refreshClaimId]: original.claimId, [g.refreshNextTokenVersion]: original.nextTokenVersion, [g.refreshClaimedAt]: tables.expression(mapping.clock.fromMillis(sample)), [g.refreshClaimExpiresAt]: tables.expression(mapping.clock.fromMillis(deadline)) })} where ${base} and ${sample} >= ${due} and ${sample} >= ${token.metadata.obtainedAtMillis} and ${sample} < ${upper} returning ${grant.fields("claimed_")}`;
585
+ const rows = yield* statement;
586
+
587
+ if (rows.length === 0)
588
+ return yield* refreshMiss(key, nativeId, encoded, required, upper, prepare);
589
+ invariant(rows.length === 1);
590
+ const row = grant.decode(rows[0]!, "claimed_");
591
+
592
+ invariant(
593
+ row[g.snapshot] === encoded &&
594
+ row[g.refreshClaimId] === original.claimId &&
595
+ row[g.refreshNextTokenVersion] === original.nextTokenVersion,
596
+ );
597
+ claimedAtMillis = mapping.clock.decodeInstant(row[g.refreshClaimedAt]);
598
+ claimExpiresAtMillis = mapping.clock.decodeInstant(row[g.refreshClaimExpiresAt]);
599
+ }
600
+
601
+ const claim = M.snapshotOAuthSync(M.OAuthConnectedRefreshClaim, {
602
+ grant: stored,
603
+ claimId: original.claimId,
604
+ nextTokenVersion: original.nextTokenVersion,
605
+ claimedAtMillis,
606
+ claimExpiresAtMillis,
607
+ });
608
+
609
+ if (Option.isSome(external))
610
+ yield* state.finish(
611
+ "oauth-refresh-claim",
612
+ sql.and([
613
+ required,
614
+ sql`${now} < ${claimExpiresAtMillis}`,
615
+ present(
616
+ key,
617
+ nativeId,
618
+ encoded,
619
+ sql.and([
620
+ state.exact(g.state, "Refreshing"),
621
+ state.exact(g.refreshClaimId, claim.claimId),
622
+ state.exact(g.refreshNextTokenVersion, claim.nextTokenVersion),
623
+ sql`${tables.expression(mapping.clock.toMillis(grant.column(g.refreshClaimedAt)))} = ${claimedAtMillis}`,
624
+ sql`${tables.expression(mapping.clock.toMillis(grant.column(g.refreshClaimExpiresAt)))} = ${claimExpiresAtMillis}`,
625
+ ]),
626
+ ),
627
+ ]),
628
+ );
629
+
630
+ return yield* prepareOAuthNative({ _tag: "Claimed", claim }, prepare);
631
+ }),
632
+ mysql ? "transaction" : "statement",
633
+ ),
634
+ settleRefresh: (original, prepare) =>
635
+ atomic(
636
+ Effect.gen(function* () {
637
+ const claim = M.snapshotOAuthSync(M.OAuthConnectedRefreshClaim, original.claim);
638
+
639
+ const authorization = M.snapshotOAuthSync(
640
+ M.OAuthConnectedUseAuthorization,
641
+ original.authorization,
642
+ );
643
+
644
+ const outcome = M.snapshotOAuthSync(M.OAuthConnectedRefreshOutcome, original.outcome);
645
+ const token = claim.grant.context;
646
+
647
+ const key = {
648
+ moduleId: token.moduleId,
649
+ subjectId: token.subjectId,
650
+ grantId: token.grantId,
651
+ };
652
+
653
+ const nativeId = yield* mapping.subjectId.toNative(token.subjectId);
654
+ const required = state.use(nativeId, authorization, "use", token);
655
+
656
+ if (required === undefined)
657
+ return yield* prepareOAuthNative({ _tag: "Rejected" }, prepare);
658
+ let deadline = Math.min(claim.claimExpiresAtMillis, authorization.expiresAtMillis);
659
+ let lower = claim.claimedAtMillis;
660
+ let values: Readonly<Record<string, unknown>>;
661
+ let encoded = state.stored.encode(claim.grant);
662
+
663
+ if (outcome._tag === "Refreshed") {
664
+ const next = outcome.grant.context;
665
+
666
+ invariant(
667
+ next.moduleId === token.moduleId &&
668
+ next.subjectId === token.subjectId &&
669
+ next.grantId === token.grantId &&
670
+ next.grantVersion === token.grantVersion &&
671
+ next.tokenVersion === claim.nextTokenVersion &&
672
+ sameIdentity(next.identity, token.identity) &&
673
+ sameConfiguration(next.configuration, token.configuration) &&
674
+ next.metadata.obtainedAtMillis >= claim.claimedAtMillis &&
675
+ validConnectedMetadata(next, next.metadata.obtainedAtMillis) &&
676
+ (next.metadata.refreshUseUntilMillis === undefined ||
677
+ (token.metadata.refreshUseUntilMillis !== undefined &&
678
+ next.metadata.refreshUseUntilMillis <= token.metadata.refreshUseUntilMillis)),
679
+ );
680
+ deadline = Math.min(deadline, next.metadata.useUntilMillis);
681
+ lower = next.metadata.obtainedAtMillis;
682
+ values = state.values(outcome.grant, nativeId, yield* oauthIdentityKey(token.identity));
683
+ encoded = state.stored.encode(outcome.grant);
684
+ } else
685
+ values = {
686
+ [g.state]: "ReauthorizationRequired",
687
+ [g.refreshClaimId]: null,
688
+ [g.refreshNextTokenVersion]: null,
689
+ [g.refreshClaimedAt]: null,
690
+ [g.refreshClaimExpiresAt]: null,
691
+ [g.summary]: state.summary.encode({
692
+ ...connectedSummary(token),
693
+ status: "ReauthorizationRequired",
694
+ }),
695
+ };
696
+
697
+ const target = sql.and([
698
+ state.key(key, nativeId),
699
+ state.exact(g.grantVersion, token.grantVersion),
700
+ state.exact(g.tokenVersion, token.tokenVersion),
701
+ state.exact(g.snapshot, state.stored.encode(claim.grant)),
702
+ state.exact(g.state, "Refreshing"),
703
+ state.exact(g.refreshClaimId, claim.claimId),
704
+ state.exact(g.refreshNextTokenVersion, claim.nextTokenVersion),
705
+ sql`${tables.expression(mapping.clock.toMillis(grant.column(g.refreshClaimedAt)))} = ${claim.claimedAtMillis}`,
706
+ sql`${tables.expression(mapping.clock.toMillis(grant.column(g.refreshClaimExpiresAt)))} = ${claim.claimExpiresAtMillis}`,
707
+ required,
708
+ sql`${now} >= ${lower} and ${now} < ${deadline}`,
709
+ ]);
710
+
711
+ const statement = sql`${grant.update(values)} where ${target}`;
712
+
713
+ const changed = planned
714
+ ? yield* state.change(statement)
715
+ : yield* executeSqlChange(sql, statement);
716
+
717
+ if (changed !== 1) return yield* prepareOAuthNative({ _tag: "Rejected" }, prepare);
718
+ if (Option.isSome(external))
719
+ yield* state.finish(
720
+ "oauth-refresh-settled",
721
+ sql.and([
722
+ required,
723
+ sql`${now} < ${deadline}`,
724
+ present(
725
+ key,
726
+ nativeId,
727
+ encoded,
728
+ state.exact(
729
+ g.state,
730
+ outcome._tag === "Refreshed" ? "Active" : "ReauthorizationRequired",
731
+ ),
732
+ ),
733
+ ]),
734
+ );
735
+
736
+ return yield* prepareOAuthNative(outcome, prepare);
737
+ }),
738
+ ),
739
+ cleanup: (original, prepare) =>
740
+ run(
741
+ Effect.gen(function* () {
742
+ const input = M.snapshotOAuthSync(M.OAuthCleanupInput, original);
743
+ let removed = 0;
744
+
745
+ // Expired rows own the public limit. Releasing their now-unreferenced
746
+ // ownership is bounded ancillary teardown in this same commit.
747
+ const candidates: Array<{
748
+ table: SqlTable;
749
+ keys: readonly [string, ...string[]];
750
+ due: Fragment;
751
+ order: ReadonlyArray<Fragment>;
752
+ key: Fragment;
753
+ identityKey: string;
754
+ nativeId: unknown;
755
+ }> = [];
756
+
757
+ if (removed < input.limit) {
758
+ const due = sql.and([
759
+ state.exact(g.moduleId, input.moduleId),
760
+ sql`${tables.expression(mapping.clock.toMillis(grant.column(g.expiresAt)))} <= ${now}`,
761
+ ]);
762
+
763
+ const rows =
764
+ yield* sql`select ${grant.fields("due_")} from ${grant.name} where ${due} order by ${grant.column(g.expiresAt)}, ${grant.column(g.grantId)} limit ${input.limit - removed}`;
765
+
766
+ for (const raw of rows) {
767
+ const row = grant.decode(raw, "due_"),
768
+ nativeId = row[g.subjectId];
769
+
770
+ const value = yield* state.decode(row, nativeId);
771
+
772
+ candidates.push({
773
+ table: grant,
774
+ keys: [g.moduleId, g.grantId],
775
+ due,
776
+ order: [grant.column(g.expiresAt), grant.column(g.grantId)],
777
+ key: state.key(
778
+ {
779
+ moduleId: input.moduleId,
780
+ subjectId: value.value.context.subjectId,
781
+ grantId: value.value.context.grantId,
782
+ },
783
+ nativeId,
784
+ ),
785
+ identityKey: value.identityKey,
786
+ nativeId,
787
+ });
788
+ }
789
+ }
790
+ if (removed + candidates.length < input.limit && mapping.revocation.mode === "provider") {
791
+ const j = mapping.revocation.job,
792
+ job = tables(j.table);
793
+
794
+ const due = sql.and([
795
+ exactSqlText(sql, job.column(j.moduleId), job.value(j.moduleId, input.moduleId)),
796
+ sql`${tables.expression(mapping.clock.toMillis(job.column(j.retentionUntil)))} <= ${now}`,
797
+ ]);
798
+
799
+ const rows =
800
+ yield* sql`select ${job.fields("job_")} from ${job.name} where ${due} order by ${job.column(j.retentionUntil)}, ${job.column(j.jobId)} limit ${input.limit - removed - candidates.length}`;
801
+
802
+ for (const raw of rows) {
803
+ const row = job.decode(raw, "job_");
804
+
805
+ candidates.push({
806
+ table: job,
807
+ keys: [j.jobId],
808
+ due,
809
+ order: [job.column(j.retentionUntil), job.column(j.jobId)],
810
+ key: exactSqlText(sql, job.column(j.jobId), job.value(j.jobId, row[j.jobId])),
811
+ identityKey: yield* Schema.decodeUnknownEffect(Schema.String)(row[j.identityKey]),
812
+ nativeId: row[j.subjectId],
813
+ });
814
+ }
815
+ }
816
+ const owners = new Map<string, unknown>();
817
+
818
+ for (const candidate of candidates) {
819
+ const logical = yield* mapping.subjectId.toSubject(candidate.nativeId);
820
+
821
+ invariant(
822
+ mapping.subjectId.equals(
823
+ candidate.nativeId,
824
+ yield* mapping.subjectId.toNative(logical),
825
+ ),
826
+ );
827
+ owners.set(logical, candidate.nativeId);
828
+ }
829
+ // Collect the complete bounded owner set before locking; every cleanup
830
+ // invocation takes these subject locks in the same physical order.
831
+ if (
832
+ owners.size > 0 &&
833
+ batch === undefined &&
834
+ !sql.onDialectOrElse({ sqlite: () => true, orElse: () => false })
835
+ ) {
836
+ const s = mapping.subject,
837
+ subject = state.subject;
838
+
839
+ yield* sql`select ${subject.column(s.id)} from ${subject.name} where ${sql.or([...owners.values()].map((nativeId) => sql`${subject.column(s.id)} = ${subject.value(s.id, nativeId)}`))} order by ${subject.column(s.id)} for update`;
840
+ }
841
+ // Small fixed groups bound driver parameters even for codecs and
842
+ // application reference predicates. No cleanup statement is per row.
843
+ for (let start = 0; start < candidates.length;) {
844
+ const first = candidates[start]!;
845
+
846
+ const selected = candidates
847
+ .slice(start, start + 8)
848
+ .filter((candidate) => candidate.table === first.table);
849
+
850
+ start += selected.length;
851
+
852
+ const result = yield* cleanupSqlRows(
853
+ [
854
+ {
855
+ table: first.table,
856
+ keys: first.keys,
857
+ due: sql.and([first.due, sql.or(selected.map((candidate) => candidate.key))]),
858
+ order: first.order,
859
+ },
860
+ ],
861
+ selected.length,
862
+ batch !== undefined,
863
+ );
864
+
865
+ removed += result.removed;
866
+
867
+ const release = sql.or(
868
+ selected.map((candidate) =>
869
+ sql.and([
870
+ state.ownerCondition(candidate.identityKey, candidate.nativeId),
871
+ sql`not (${referenced(candidate.identityKey, candidate.nativeId)})`,
872
+ ]),
873
+ ),
874
+ );
875
+
876
+ yield* state.execute(sql`delete from ${state.ownership.name} where ${release}`);
877
+ }
878
+
879
+ if (removed < input.limit)
880
+ removed += (yield* flow.cleanup(input.moduleId, input.limit - removed)).removed;
881
+
882
+ return yield* prepareOAuthNative({ removed, hasMore: removed === input.limit }, prepare);
883
+ }),
884
+ ),
885
+ };
886
+
887
+ return { oauthConnectedPersistence: service };
888
+ });