@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,289 @@
1
+ import { PersistenceMappingError } from "./mapping-error.mjs";
2
+ import { sqlBatchAssertion } from "./d1-planning.mjs";
3
+ import { exactSqlText, executeSqlChange } from "./sql-change.mjs";
4
+ import { CurrentSqlCommit, SqlBatchCommit, appendSqlBatchStatement, makeSqlCommitExecutor, registerSqlBatchPostcondition, registerSqlCommitReceipt, registerSqlPostcondition } from "./sql-commit.mjs";
5
+ import { cleanupSqlRows } from "./sql-cleanup.mjs";
6
+ import { Crypto, Effect, Option, Schema } from "effect";
7
+ import { CurrentCommitJournal } from "@yielded/auth/Hooks";
8
+ import * as P from "@yielded/auth/Proofs";
9
+ import { SqlClient } from "effect/sql/SqlClient";
10
+ import { Base64Url } from "effect/encoding";
11
+ //#region src/internal/proof-native.ts
12
+ const bindingJson = Schema.encodeSync(Schema.fromJsonString(P.ProofBinding));
13
+ const decodeBinding = Schema.decodeUnknownSync(Schema.fromJsonString(P.ProofBinding));
14
+ const unavailable = () => P.ProofUnavailable.make({});
15
+ const invariant = (condition) => {
16
+ if (!condition) throw PersistenceMappingError.make({
17
+ operation: "decode",
18
+ cause: "Invalid proof state"
19
+ });
20
+ };
21
+ /** Flow/context changes do not allocate new durable series. The hash bounds the
22
+ * indexed key; the complete canonical binding is still checked independently. */
23
+ const seriesKey = Effect.fnUntraced(function* (binding) {
24
+ const crypto = yield* Crypto.Crypto;
25
+ const tuple = Schema.encodeSync(Schema.fromJsonString(Schema.Array(Schema.NullOr(Schema.String))))([
26
+ "effect-auth/proof-series/v1",
27
+ binding.identifier.namespace,
28
+ binding.identifier.value,
29
+ binding._tag === "Identifier" ? null : binding.revision.subjectId
30
+ ]);
31
+ return Base64Url.encode(yield* crypto.digest("SHA-256", new TextEncoder().encode(tuple)));
32
+ });
33
+ /** Shared native statements. A protected mutation calls redeemLocked only after
34
+ * taking its subject lock; bare redemption calls lockSubject first. */
35
+ const makeNativeProofStore = Effect.fnUntraced(function* (tables, mapping, batch = false) {
36
+ const externalOwner = yield* Effect.serviceOption(CurrentSqlCommit);
37
+ const sql = (yield* SqlClient).withoutTransforms();
38
+ const crypto = yield* Crypto.Crypto;
39
+ const p = mapping.proof;
40
+ const proof = tables(p.table);
41
+ const subject = tables(mapping.subject.table);
42
+ const mysql = sql.onDialectOrElse({
43
+ mysql: () => true,
44
+ orElse: () => false
45
+ });
46
+ const locking = sql.onDialectOrElse({
47
+ sqlite: () => sql``,
48
+ orElse: () => sql`for update`
49
+ });
50
+ const rowLocks = !batch && sql.onDialectOrElse({
51
+ sqlite: () => false,
52
+ orElse: () => true
53
+ });
54
+ const now = tables.expression(mapping.clock.engineNowMillis);
55
+ const millis = (key) => tables.expression(mapping.clock.toMillis(proof.column(key)));
56
+ const instant = (value) => tables.expression(mapping.clock.fromMillis(sql`(${value})`));
57
+ const exact = (key, value) => exactSqlText(sql, proof.column(key), proof.value(key, value));
58
+ const series = Effect.fnUntraced(function* (input) {
59
+ const key = yield* seriesKey(input.binding).pipe(Effect.provideService(Crypto.Crypto, crypto));
60
+ return {
61
+ key,
62
+ predicate: sql.and([
63
+ exact(p.moduleId, input.moduleId),
64
+ exact(p.purpose, input.purpose),
65
+ exact(p.seriesKey, key)
66
+ ])
67
+ };
68
+ });
69
+ const decode = (row) => {
70
+ const value = proof.decode(row, "proof_");
71
+ return Schema.decodeUnknownSync(P.ProofRecord)({
72
+ moduleId: value[p.moduleId],
73
+ purpose: value[p.purpose],
74
+ proofId: value[p.proofId],
75
+ binding: decodeBinding(value[p.binding]),
76
+ verifier: {
77
+ keyId: value[p.verifierKeyId],
78
+ digest: value[p.verifierDigest]
79
+ },
80
+ issuedAtMillis: mapping.clock.decodeInstant(value[p.issuedAt]),
81
+ expiresAtMillis: mapping.clock.decodeInstant(value[p.expiresAt])
82
+ });
83
+ };
84
+ const clock = Effect.gen(function* () {
85
+ const rows = yield* sql`select ${now} as engine_now`;
86
+ return yield* Schema.decodeEffect(P.ProofInstant)(Number(rows[0]?.engine_now));
87
+ });
88
+ const lockSubject = Effect.fnUntraced(function* (binding) {
89
+ if (binding._tag === "Identifier") return true;
90
+ const nativeId = yield* mapping.subjectId.toNative(binding.revision.subjectId);
91
+ const condition = sql`${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, nativeId)}`;
92
+ const rows = yield* sql`select ${subject.fields("proof_subject_")} from ${subject.name} where ${condition} ${batch ? sql`` : locking}`;
93
+ if (rows.length === 0) return false;
94
+ invariant(rows.length === 1);
95
+ const value = subject.decode(rows[0], "proof_subject_");
96
+ const decoded = yield* mapping.subjectId.toSubject(value[mapping.subject.id]);
97
+ invariant(decoded === binding.revision.subjectId);
98
+ if (batch) yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`exists(select 1 from ${subject.name} where ${condition})`));
99
+ return true;
100
+ });
101
+ const issue = Effect.fnUntraced(function* (input) {
102
+ if (!input.eligible) return { _tag: "Suppressed" };
103
+ const record = yield* Schema.decodeEffect(P.ProofIssueRecord)(input.record);
104
+ invariant(Number.isSafeInteger(input.lifetimeMillis) && input.lifetimeMillis > 0 && Number.isSafeInteger(input.resendCooldownMillis) && input.resendCooldownMillis >= 0);
105
+ const key = yield* series(record);
106
+ const binding = bindingJson(record.binding);
107
+ const decisionNow = batch || mysql ? now : sql`(select instant from effect_auth_proof_clock)`;
108
+ const allowed = sql.and([sql`${millis(p.issuedAt)} + ${input.resendCooldownMillis} <= ${decisionNow}`, sql`(${millis(p.expiresAt)} <= ${decisionNow} or ${exact(p.binding, binding)})`]);
109
+ let sampled;
110
+ if (batch || mysql) {
111
+ const rows = yield* sql`select ${proof.fields("proof_")} from ${proof.name} where ${key.predicate} ${mysql ? locking : sql``}`;
112
+ sampled = yield* clock;
113
+ invariant(rows.length <= 1);
114
+ if (rows[0] !== void 0) {
115
+ const old = decode(rows[0]);
116
+ if (old.issuedAtMillis + input.resendCooldownMillis > sampled || old.expiresAtMillis > sampled && bindingJson(old.binding) !== binding) return { _tag: "Suppressed" };
117
+ }
118
+ }
119
+ const issuedAt = sampled === void 0 ? instant(decisionNow) : mapping.clock.encodeInstant(sampled);
120
+ const expiresAt = sampled === void 0 ? instant(sql`${decisionNow} + ${input.lifetimeMillis}`) : mapping.clock.encodeInstant(sampled + input.lifetimeMillis);
121
+ const values = {
122
+ ...p.encodeInsert({
123
+ record,
124
+ seriesKey: key.key
125
+ }),
126
+ [p.moduleId]: record.moduleId,
127
+ [p.purpose]: record.purpose,
128
+ [p.seriesKey]: key.key,
129
+ [p.proofId]: record.proofId,
130
+ [p.binding]: binding,
131
+ [p.verifierKeyId]: record.verifier.keyId,
132
+ [p.verifierDigest]: record.verifier.digest,
133
+ [p.issuedAt]: issuedAt,
134
+ [p.expiresAt]: expiresAt,
135
+ [p.failedAttempts]: 0
136
+ };
137
+ if (mysql) {
138
+ if ((yield* executeSqlChange(sql, sql`${proof.update(values)} where ${key.predicate} and ${allowed}`)) === 0) yield* sql`${proof.insert(values)}`;
139
+ invariant(sampled !== void 0);
140
+ return {
141
+ _tag: "Issued",
142
+ record: yield* Schema.decodeEffect(P.ProofRecord)({
143
+ ...record,
144
+ issuedAtMillis: sampled,
145
+ expiresAtMillis: sampled + input.lifetimeMillis
146
+ })
147
+ };
148
+ }
149
+ const replaced = [
150
+ p.proofId,
151
+ p.binding,
152
+ p.verifierKeyId,
153
+ p.verifierDigest,
154
+ p.issuedAt,
155
+ p.expiresAt,
156
+ p.failedAttempts
157
+ ];
158
+ const excluded = proof.as("excluded");
159
+ const upsert = sql`${proof.insert(values)} on conflict (${sql.join(", ", false)([
160
+ p.moduleId,
161
+ p.purpose,
162
+ p.seriesKey
163
+ ].map(proof.columnName))}) do update set ${sql.join(", ", false)(replaced.map((key) => sql`${proof.columnName(key)} = ${excluded.column(key)}`))} where ${allowed}`;
164
+ if (batch) {
165
+ invariant(sampled !== void 0);
166
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`${now} >= ${sampled} and ${now} < ${sampled + input.lifetimeMillis}`));
167
+ yield* appendSqlBatchStatement(upsert);
168
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));
169
+ return {
170
+ _tag: "Issued",
171
+ record: yield* Schema.decodeEffect(P.ProofRecord)({
172
+ ...record,
173
+ issuedAtMillis: sampled,
174
+ expiresAtMillis: sampled + input.lifetimeMillis
175
+ })
176
+ };
177
+ }
178
+ const rows = yield* sql`with effect_auth_proof_clock as materialized (select ${now} as instant) ${upsert} returning ${proof.fields("proof_")}`;
179
+ invariant(rows.length <= 1);
180
+ return rows[0] === void 0 ? { _tag: "Suppressed" } : {
181
+ _tag: "Issued",
182
+ record: decode(rows[0])
183
+ };
184
+ });
185
+ const redeemLocked = Effect.fnUntraced(function* (original) {
186
+ const input = yield* Schema.decodeEffect(P.ProofRedemptionInput)(original);
187
+ const key = yield* series(input);
188
+ const current = sql.and([
189
+ key.predicate,
190
+ exact(p.proofId, input.proofId),
191
+ exact(p.binding, bindingJson(input.binding)),
192
+ sql`${millis(p.issuedAt)} <= ${now}`,
193
+ sql`${millis(p.expiresAt)} > ${now}`,
194
+ sql`${proof.column(p.failedAttempts)} >= 0`,
195
+ sql`${proof.column(p.failedAttempts)} < ${input.maximumFailedAttempts}`
196
+ ]);
197
+ const valid = sql.and([current, input.candidate === void 0 ? sql`1 = 0` : sql.and([exact(p.verifierKeyId, input.candidate.keyId), exact(p.verifierDigest, input.candidate.digest)])]);
198
+ if (input.binding._tag === "Identifier" && rowLocks) yield* sql`select 1 from ${proof.name} where ${current} ${locking}`;
199
+ const deletion = sql`delete from ${proof.name} where ${valid}`;
200
+ const rows = batch || mysql ? yield* sql`select ${proof.fields("proof_")} from ${proof.name} where ${valid} ${mysql ? locking : sql``}` : yield* sql`${deletion} returning ${proof.fields("proof_")}`;
201
+ invariant(rows.length <= 1);
202
+ if (rows[0] === void 0) {
203
+ const failure = sql`${proof.update({ [p.failedAttempts]: sql`${proof.column(p.failedAttempts)} + 1` })} where ${current}`;
204
+ if (batch) {
205
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`not exists(select 1 from ${proof.name} where ${valid})`));
206
+ yield* appendSqlBatchStatement(failure);
207
+ } else yield* sql`${failure}`;
208
+ return { decision: "rejected" };
209
+ }
210
+ const consumed = decode(rows[0]);
211
+ if (mysql) invariant((yield* executeSqlChange(sql, deletion)) === 1);
212
+ if (batch) {
213
+ yield* appendSqlBatchStatement(deletion);
214
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));
215
+ }
216
+ const validUntil = sql`${now} >= ${consumed.issuedAtMillis} and ${now} < ${consumed.expiresAtMillis}`;
217
+ if (Option.isSome(externalOwner) && externalOwner.value.origin === "application") {
218
+ const absent = sql`not exists(select 1 from ${proof.name} where ${exact(p.moduleId, input.moduleId)} and ${exact(p.proofId, input.proofId)})`;
219
+ const condition = sql`${absent} and ${validUntil}`;
220
+ if (batch) yield* registerSqlBatchPostcondition({
221
+ name: "proof-redemption",
222
+ statement: sqlBatchAssertion(sql, condition)
223
+ });
224
+ else yield* registerSqlPostcondition({
225
+ name: "proof-redemption",
226
+ check: Effect.gen(function* () {
227
+ const rows = yield* sql`select 1 as valid where ${condition}`;
228
+ invariant(rows.length === 1);
229
+ })
230
+ });
231
+ }
232
+ return {
233
+ decision: "redeemed",
234
+ validUntil
235
+ };
236
+ });
237
+ const cancel = Effect.fnUntraced(function* (input) {
238
+ const key = yield* series(input);
239
+ const deletion = sql`delete from ${proof.name} where ${key.predicate} and ${exact(p.binding, bindingJson(input.binding))}`;
240
+ if (batch) yield* appendSqlBatchStatement(deletion);
241
+ else yield* sql`${deletion}`;
242
+ });
243
+ const cleanup = (input) => cleanupSqlRows([{
244
+ table: proof,
245
+ keys: [p.moduleId, p.proofId],
246
+ due: sql`${exact(p.moduleId, input.moduleId)} and ${millis(p.expiresAt)} <= ${now}`,
247
+ order: [proof.column(p.expiresAt), proof.column(p.proofId)]
248
+ }], input.limit, batch);
249
+ return {
250
+ issue,
251
+ lockSubject,
252
+ redeemLocked,
253
+ cancel,
254
+ cleanup,
255
+ mysql
256
+ };
257
+ });
258
+ const makeNativeProofServices = Effect.fnUntraced(function* (tables, mapping) {
259
+ const batch = yield* SqlBatchCommit;
260
+ const executor = yield* makeSqlCommitExecutor(unavailable);
261
+ const store = yield* makeNativeProofStore(tables, mapping, batch !== void 0);
262
+ const run = (effect, mode = "transaction") => batch === void 0 ? executor.run(effect, mode) : executor.batch(effect).pipe(Effect.provideService(SqlBatchCommit, batch));
263
+ const prepare = (value, project) => Effect.gen(function* () {
264
+ const receipt = project(value, yield* CurrentCommitJournal);
265
+ invariant(receipt?._tag === "PreparedCommit" && Effect.isEffect(receipt.read));
266
+ yield* registerSqlCommitReceipt(receipt);
267
+ return receipt;
268
+ });
269
+ return { proofPersistence: {
270
+ issue: (input, project) => run(Effect.gen(function* () {
271
+ return yield* prepare(yield* store.issue(input), project);
272
+ }), store.mysql ? "transaction" : "statement"),
273
+ redeem: (input, project) => run(Effect.gen(function* () {
274
+ const locked = yield* store.lockSubject(input.binding);
275
+ return yield* prepare(locked ? (yield* store.redeemLocked(input)).decision : "rejected", project);
276
+ })),
277
+ cancel: (input, project) => run(Effect.gen(function* () {
278
+ yield* store.cancel(input);
279
+ return yield* prepare(void 0, project);
280
+ }), "statement"),
281
+ cleanup: (input, project) => run(Effect.gen(function* () {
282
+ return yield* prepare(yield* store.cleanup(input), project);
283
+ }), "statement")
284
+ } };
285
+ });
286
+ //#endregion
287
+ export { makeNativeProofServices, makeNativeProofStore };
288
+
289
+ //# sourceMappingURL=proof-native.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-native.mjs","names":[],"sources":["../../src/internal/proof-native.ts"],"sourcesContent":["import { CurrentCommitJournal, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport * as P from \"@yielded/auth/Proofs\";\nimport { Crypto, Effect, Option, Schema, type PlatformError } from \"effect\";\nimport { Base64Url } from \"effect/encoding\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport { sqlBatchAssertion } from \"./d1-planning\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { exactSqlText, executeSqlChange } from \"./sql-change\";\nimport { cleanupSqlRows } from \"./sql-cleanup\";\nimport {\n appendSqlBatchStatement,\n CurrentSqlCommit,\n makeSqlCommitExecutor,\n registerSqlBatchPostcondition,\n registerSqlCommitReceipt,\n registerSqlPostcondition,\n SqlBatchCommit,\n type SqlCommitOwnerError,\n} from \"./sql-commit\";\n\nconst bindingJson = Schema.encodeSync(Schema.fromJsonString(P.ProofBinding));\nconst decodeBinding = Schema.decodeUnknownSync(Schema.fromJsonString(P.ProofBinding));\nconst unavailable = () => P.ProofUnavailable.make({});\n\nconst invariant: (condition: unknown) => asserts condition = (condition) => {\n if (!condition)\n throw PersistenceMappingError.make({ operation: \"decode\", cause: \"Invalid proof state\" });\n};\n\n/** Flow/context changes do not allocate new durable series. The hash bounds the\n * indexed key; the complete canonical binding is still checked independently. */\nconst seriesKey = Effect.fnUntraced(function* (binding: P.ProofBinding) {\n const crypto = yield* Crypto.Crypto;\n\n const tuple = Schema.encodeSync(\n Schema.fromJsonString(Schema.Array(Schema.NullOr(Schema.String))),\n )([\n \"effect-auth/proof-series/v1\",\n binding.identifier.namespace,\n binding.identifier.value,\n binding._tag === \"Identifier\" ? null : binding.revision.subjectId,\n ]);\n\n return Base64Url.encode(yield* crypto.digest(\"SHA-256\", new TextEncoder().encode(tuple)));\n});\n\n/** Shared native statements. A protected mutation calls redeemLocked only after\n * taking its subject lock; bare redemption calls lockSubject first. */\nexport const makeNativeProofStore = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyProofPersistenceMapping,\n batch = false,\n) {\n const externalOwner = yield* Effect.serviceOption(CurrentSqlCommit);\n const sql = (yield* SqlClient).withoutTransforms();\n const crypto = yield* Crypto.Crypto;\n const p = mapping.proof;\n const proof = tables(p.table);\n const subject = tables(mapping.subject.table);\n const mysql = sql.onDialectOrElse({ mysql: () => true, orElse: () => false });\n const locking = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n const rowLocks = !batch && sql.onDialectOrElse({ sqlite: () => false, orElse: () => true });\n const now = tables.expression(mapping.clock.engineNowMillis);\n const millis = (key: string) => tables.expression(mapping.clock.toMillis(proof.column(key)));\n const instant = (value: Fragment) => tables.expression(mapping.clock.fromMillis(sql`(${value})`));\n\n const exact = (key: string, value: unknown) =>\n exactSqlText(sql, proof.column(key), proof.value(key, value));\n\n const series = Effect.fnUntraced(function* (input: {\n readonly moduleId: string;\n readonly purpose: P.ProofPurpose;\n readonly binding: P.ProofBinding;\n }) {\n const key = yield* seriesKey(input.binding).pipe(Effect.provideService(Crypto.Crypto, crypto));\n\n return {\n key,\n predicate: sql.and([\n exact(p.moduleId, input.moduleId),\n exact(p.purpose, input.purpose),\n exact(p.seriesKey, key),\n ]),\n };\n });\n\n const decode = (row: Readonly<Record<string, unknown>>) => {\n const value = proof.decode(row, \"proof_\");\n\n return Schema.decodeUnknownSync(P.ProofRecord)({\n moduleId: value[p.moduleId],\n purpose: value[p.purpose],\n proofId: value[p.proofId],\n binding: decodeBinding(value[p.binding]),\n verifier: { keyId: value[p.verifierKeyId], digest: value[p.verifierDigest] },\n issuedAtMillis: mapping.clock.decodeInstant(value[p.issuedAt]),\n expiresAtMillis: mapping.clock.decodeInstant(value[p.expiresAt]),\n });\n };\n\n const clock = Effect.gen(function* () {\n const rows = yield* sql`select ${now} as engine_now`;\n\n return yield* Schema.decodeEffect(P.ProofInstant)(Number(rows[0]?.engine_now));\n });\n\n const lockSubject = Effect.fnUntraced(function* (binding: P.ProofBinding) {\n if (binding._tag === \"Identifier\") return true;\n const nativeId = yield* mapping.subjectId.toNative(binding.revision.subjectId);\n const condition = sql`${subject.column(mapping.subject.id)} = ${subject.value(mapping.subject.id, nativeId)}`;\n\n const rows =\n yield* sql`select ${subject.fields(\"proof_subject_\")} from ${subject.name} where ${condition} ${batch ? sql`` : locking}`;\n\n if (rows.length === 0) return false;\n invariant(rows.length === 1);\n const value = subject.decode(rows[0]!, \"proof_subject_\");\n const decoded = yield* mapping.subjectId.toSubject(value[mapping.subject.id]);\n\n invariant(decoded === binding.revision.subjectId);\n if (batch)\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(sql, sql`exists(select 1 from ${subject.name} where ${condition})`),\n );\n\n return true;\n });\n\n const issue = Effect.fnUntraced(function* (\n input: Parameters<P.ProofPersistence[\"Service\"][\"issue\"]>[0],\n ): Effect.fn.Return<\n P.ProofIssueDecision,\n | SqlError\n | Schema.SchemaError\n | PlatformError.PlatformError\n | PersistenceMappingError\n | SqlCommitOwnerError,\n CurrentSqlCommit\n > {\n if (!input.eligible) return { _tag: \"Suppressed\" };\n const record = yield* Schema.decodeEffect(P.ProofIssueRecord)(input.record);\n\n invariant(\n Number.isSafeInteger(input.lifetimeMillis) &&\n input.lifetimeMillis > 0 &&\n Number.isSafeInteger(input.resendCooldownMillis) &&\n input.resendCooldownMillis >= 0,\n );\n const key = yield* series(record);\n const binding = bindingJson(record.binding);\n // PostgreSQL's clock_timestamp is volatile. One materialized sample owns\n // both timestamps and this upsert's cooldown/expiry decision.\n const decisionNow = batch || mysql ? now : sql`(select instant from effect_auth_proof_clock)`;\n\n const allowed = sql.and([\n sql`${millis(p.issuedAt)} + ${input.resendCooldownMillis} <= ${decisionNow}`,\n sql`(${millis(p.expiresAt)} <= ${decisionNow} or ${exact(p.binding, binding)})`,\n ]);\n\n let sampled: number | undefined;\n\n if (batch || mysql) {\n const rows =\n yield* sql`select ${proof.fields(\"proof_\")} from ${proof.name} where ${key.predicate} ${mysql ? locking : sql``}`;\n\n sampled = yield* clock;\n invariant(rows.length <= 1);\n if (rows[0] !== undefined) {\n const old = decode(rows[0]);\n\n if (\n old.issuedAtMillis + input.resendCooldownMillis > sampled ||\n (old.expiresAtMillis > sampled && bindingJson(old.binding) !== binding)\n )\n return { _tag: \"Suppressed\" };\n }\n }\n\n const issuedAt =\n sampled === undefined ? instant(decisionNow) : mapping.clock.encodeInstant(sampled);\n\n const expiresAt =\n sampled === undefined\n ? instant(sql`${decisionNow} + ${input.lifetimeMillis}`)\n : mapping.clock.encodeInstant(sampled + input.lifetimeMillis);\n\n const values = {\n ...p.encodeInsert({ record, seriesKey: key.key }),\n [p.moduleId]: record.moduleId,\n [p.purpose]: record.purpose,\n [p.seriesKey]: key.key,\n [p.proofId]: record.proofId,\n [p.binding]: binding,\n [p.verifierKeyId]: record.verifier.keyId,\n [p.verifierDigest]: record.verifier.digest,\n [p.issuedAt]: issuedAt,\n [p.expiresAt]: expiresAt,\n [p.failedAttempts]: 0,\n };\n\n if (mysql) {\n const changed = yield* executeSqlChange(\n sql,\n sql`${proof.update(values)} where ${key.predicate} and ${allowed}`,\n );\n\n if (changed === 0) yield* sql`${proof.insert(values)}`;\n invariant(sampled !== undefined);\n\n return {\n _tag: \"Issued\",\n record: yield* Schema.decodeEffect(P.ProofRecord)({\n ...record,\n issuedAtMillis: sampled,\n expiresAtMillis: sampled! + input.lifetimeMillis,\n }),\n };\n }\n\n const replaced = [\n p.proofId,\n p.binding,\n p.verifierKeyId,\n p.verifierDigest,\n p.issuedAt,\n p.expiresAt,\n p.failedAttempts,\n ];\n\n const excluded = proof.as(\"excluded\");\n const upsert = sql`${proof.insert(values)} on conflict (${sql.join(\", \", false)([p.moduleId, p.purpose, p.seriesKey].map(proof.columnName))}) do update set ${sql.join(\", \", false)(replaced.map((key) => sql`${proof.columnName(key)} = ${excluded.column(key)}`))} where ${allowed}`;\n\n if (batch) {\n invariant(sampled !== undefined);\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`${now} >= ${sampled} and ${now} < ${sampled! + input.lifetimeMillis}`,\n ),\n );\n yield* appendSqlBatchStatement(upsert);\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));\n\n return {\n _tag: \"Issued\",\n record: yield* Schema.decodeEffect(P.ProofRecord)({\n ...record,\n issuedAtMillis: sampled,\n expiresAtMillis: sampled! + input.lifetimeMillis,\n }),\n };\n }\n\n const rows =\n yield* sql`with effect_auth_proof_clock as materialized (select ${now} as instant) ${upsert} returning ${proof.fields(\"proof_\")}`;\n\n invariant(rows.length <= 1);\n\n return rows[0] === undefined\n ? { _tag: \"Suppressed\" }\n : { _tag: \"Issued\", record: decode(rows[0]) };\n });\n\n const redeemLocked = Effect.fnUntraced(function* (original: P.ProofRedemptionInput) {\n const input = yield* Schema.decodeEffect(P.ProofRedemptionInput)(original);\n const key = yield* series(input);\n\n const current = sql.and([\n key.predicate,\n exact(p.proofId, input.proofId),\n exact(p.binding, bindingJson(input.binding)),\n sql`${millis(p.issuedAt)} <= ${now}`,\n sql`${millis(p.expiresAt)} > ${now}`,\n sql`${proof.column(p.failedAttempts)} >= 0`,\n sql`${proof.column(p.failedAttempts)} < ${input.maximumFailedAttempts}`,\n ]);\n\n const valid = sql.and([\n current,\n input.candidate === undefined\n ? sql`1 = 0`\n : sql.and([\n exact(p.verifierKeyId, input.candidate.keyId),\n exact(p.verifierDigest, input.candidate.digest),\n ]),\n ]);\n\n // No subject lock serializes an identifier-bound proof. Lock its row first so\n // concurrent wrong guesses cannot all compare before any of them is charged.\n if (input.binding._tag === \"Identifier\" && rowLocks)\n yield* sql`select 1 from ${proof.name} where ${current} ${locking}`;\n\n const deletion = sql`delete from ${proof.name} where ${valid}`;\n\n const rows =\n batch || mysql\n ? yield* sql`select ${proof.fields(\"proof_\")} from ${proof.name} where ${valid} ${mysql ? locking : sql``}`\n : yield* sql`${deletion} returning ${proof.fields(\"proof_\")}`;\n\n invariant(rows.length <= 1);\n if (rows[0] === undefined) {\n const failure = sql`${proof.update({ [p.failedAttempts]: sql`${proof.column(p.failedAttempts)} + 1` })} where ${current}`;\n\n if (batch) {\n // The planning miss never authorizes charging or accepting a replacement.\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(sql, sql`not exists(select 1 from ${proof.name} where ${valid})`),\n );\n yield* appendSqlBatchStatement(failure);\n } else yield* sql`${failure}`;\n\n return { decision: \"rejected\" as const };\n }\n const consumed = decode(rows[0]);\n\n if (mysql) invariant((yield* executeSqlChange(sql, deletion)) === 1);\n if (batch) {\n yield* appendSqlBatchStatement(deletion);\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));\n }\n const validUntil = sql`${now} >= ${consumed.issuedAtMillis} and ${now} < ${consumed.expiresAtMillis}`;\n\n if (Option.isSome(externalOwner) && externalOwner.value.origin === \"application\") {\n const absent = sql`not exists(select 1 from ${proof.name} where ${exact(p.moduleId, input.moduleId)} and ${exact(p.proofId, input.proofId)})`;\n const condition = sql`${absent} and ${validUntil}`;\n\n if (batch)\n yield* registerSqlBatchPostcondition({\n name: \"proof-redemption\",\n statement: sqlBatchAssertion(sql, condition),\n });\n else\n yield* registerSqlPostcondition({\n name: \"proof-redemption\",\n check: Effect.gen(function* () {\n const rows = yield* sql`select 1 as valid where ${condition}`;\n\n invariant(rows.length === 1);\n }),\n });\n }\n\n return { decision: \"redeemed\" as const, validUntil };\n });\n\n const cancel = Effect.fnUntraced(function* (\n input: Parameters<P.ProofPersistence[\"Service\"][\"cancel\"]>[0],\n ) {\n const key = yield* series(input);\n const deletion = sql`delete from ${proof.name} where ${key.predicate} and ${exact(p.binding, bindingJson(input.binding))}`;\n\n if (batch) yield* appendSqlBatchStatement(deletion);\n else yield* sql`${deletion}`;\n });\n\n const cleanup = (input: Parameters<P.ProofPersistence[\"Service\"][\"cleanup\"]>[0]) =>\n cleanupSqlRows(\n [\n {\n table: proof,\n keys: [p.moduleId, p.proofId],\n due: sql`${exact(p.moduleId, input.moduleId)} and ${millis(p.expiresAt)} <= ${now}`,\n order: [proof.column(p.expiresAt), proof.column(p.proofId)],\n },\n ],\n input.limit,\n batch,\n );\n\n return { issue, lockSubject, redeemLocked, cancel, cleanup, mysql };\n});\n\nexport const makeNativeProofServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyProofPersistenceMapping,\n): Effect.fn.Return<\n { readonly proofPersistence: P.ProofPersistence[\"Service\"] },\n P.ProofUnavailable,\n SqlClient | LifecycleHooks | Crypto.Crypto | SqlBatchCommit\n> {\n const batch = yield* SqlBatchCommit;\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const store = yield* makeNativeProofStore(tables, mapping, batch !== undefined);\n\n const run = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n mode: \"transaction\" | \"statement\" = \"transaction\",\n ) =>\n batch === undefined\n ? executor.run(effect, mode)\n : executor.batch(effect).pipe(Effect.provideService(SqlBatchCommit, batch));\n\n const prepare = <Value, A>(value: Value, project: P.PrepareProofCommit<Value, A>) =>\n Effect.gen(function* () {\n const journal = yield* CurrentCommitJournal;\n\n const receipt = project(value, journal);\n\n invariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n yield* registerSqlCommitReceipt(receipt);\n\n return receipt;\n });\n\n const proofPersistence: P.ProofPersistence[\"Service\"] = {\n issue: (input, project) =>\n run(\n Effect.gen(function* () {\n return yield* prepare(yield* store.issue(input), project);\n }),\n store.mysql ? \"transaction\" : \"statement\",\n ),\n redeem: (input, project) =>\n run(\n Effect.gen(function* () {\n const locked = yield* store.lockSubject(input.binding);\n\n return yield* prepare(\n locked ? (yield* store.redeemLocked(input)).decision : \"rejected\",\n project,\n );\n }),\n ),\n cancel: (input, project) =>\n run(\n Effect.gen(function* () {\n yield* store.cancel(input);\n\n return yield* prepare(undefined, project);\n }),\n \"statement\",\n ),\n cleanup: (input, project) =>\n run(\n Effect.gen(function* () {\n return yield* prepare(yield* store.cleanup(input), project);\n }),\n \"statement\",\n ),\n };\n\n return { proofPersistence };\n});\n"],"mappings":"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"}
@@ -1,70 +1,60 @@
1
1
  import { PersistenceConfigurationError } from "./configuration.mjs";
2
+ import { CurrentSqlCommit, makeSqlCommitExecutor } from "./sql-commit.mjs";
2
3
  import { randomId } from "./crypto.mjs";
3
- import { CurrentPasswordSql } from "./password-kernel.mjs";
4
- import { Crypto, Effect, Schema } from "effect";
5
- import { LifecycleHooks, coordinateCommit, hasCommitScope } from "@yielded/auth/Hooks";
6
- import { SecurityRevision } from "@yielded/auth/Sessions";
7
- import { reportPersistenceFailure } from "@yielded/auth/Persistence";
4
+ import { PasswordIdentifierTaken, makeNativePasswordRegistrationStore } from "./password-registration-native.mjs";
5
+ import { Cause, Crypto, Effect, Option, Schema } from "effect";
8
6
  import { PasswordUnavailable } from "@yielded/auth/Password";
7
+ import { SecurityRevision } from "@yielded/auth/Sessions";
8
+ import { SqlClient } from "effect/sql/SqlClient";
9
9
  //#region src/internal/registration.ts
10
- var IdentifierTaken = class extends Schema.TaggedError()("IdentifierTaken", {}) {};
11
- /** Registration reserves the command, provisions the application's subject, and
12
- * creates the unverified identifier and password in one SQL transaction. Replays
13
- * always suppress; a public request ID never recovers a private password intent.
14
- */
15
- const makeRegistrationAuthority = Effect.fn("makeRegistrationAuthority")(function* (mappings, operations, standalone, provisioning, strategy) {
16
- const database = yield* CurrentPasswordSql;
17
- const hooks = yield* LifecycleHooks;
10
+ /** Application provisioning and the unverified identifier/password binding share
11
+ * one physical owner. Identifier uniqueness arbitrates registration; correlation
12
+ * request IDs never become a retained credential-issuance receipt. */
13
+ const makeRegistrationAuthority = Effect.fnUntraced(function* (tables, mapping, provisioning, strategy) {
14
+ const sql = (yield* SqlClient).withoutTransforms();
18
15
  const crypto = yield* Crypto.Crypto;
16
+ const executor = yield* makeSqlCommitExecutor(() => PasswordUnavailable.make({}));
17
+ const parent = yield* Effect.serviceOption(CurrentSqlCommit);
18
+ const store = yield* makeNativePasswordRegistrationStore(tables, mapping);
19
19
  const createSubject = (yield* provisioning)[strategy];
20
20
  if (createSubject === void 0) return yield* PersistenceConfigurationError.make({ reason: `Missing subject provisioning for ${strategy}` });
21
- const { and, eq, column } = operations;
22
- const mapping = mappings.passwords();
23
- const receipts = mappings.table("passwordRegistrations");
24
- return { register: (input, prepare) => Effect.gen(function* () {
25
- if (yield* hasCommitScope) return yield* PasswordUnavailable.make({});
26
- yield* standalone;
27
- const receipt = {
28
- moduleId: input.moduleId,
29
- requestId: input.requestId
30
- };
31
- const suppress = coordinateCommit((journal) => database.transaction((tx) => Effect.gen(function* () {
32
- yield* tx.insert(receipts).values(receipt).onConflictDoNothing();
33
- return prepare({ _tag: "Suppressed" }, journal);
34
- })), { mode: "interactive" });
35
- return (yield* coordinateCommit((journal) => database.transaction((tx) => Effect.gen(function* () {
36
- if ((yield* tx.insert(receipts).values(receipt).onConflictDoNothing().returning()).length === 0) return prepare({ _tag: "Suppressed" }, journal);
37
- if ((yield* tx.select().from(mapping.identifier.table).where(and(eq(column(mapping.identifier.table, mapping.identifier.namespace), input.identifier.namespace), eq(column(mapping.identifier.table, mapping.identifier.value), input.identifier.value))).limit(1)).length !== 0) return prepare({ _tag: "Suppressed" }, journal);
38
- const subjectId = yield* createSubject({
39
- identifier: input.identifier,
40
- registration: input.registration
41
- });
42
- const nativeId = yield* mapping.subjectId.toNative(subjectId);
43
- const subjects = yield* tx.select().from(mapping.subject.table).where(eq(column(mapping.subject.table, mapping.subject.id), nativeId)).limit(1);
44
- if (subjects.length !== 1 || !mapping.subject.isActiveStatus(subjects[0][mapping.subject.status])) return yield* PasswordUnavailable.make({});
45
- yield* Schema.decodeUnknownEffect(SecurityRevision)(subjects[0][mapping.subject.securityRevision]);
46
- if ((yield* tx.insert(mapping.identifier.table).values(mapping.identifier.encodeInitialInsert(input.identifier, nativeId, SecurityRevision.make(yield* randomId))).onConflictDoNothing().returning()).length !== 1) return yield* new IdentifierTaken({});
47
- const credentialId = yield* randomId;
48
- const credentialRevision = SecurityRevision.make(yield* randomId);
49
- yield* tx.insert(mapping.credential.table).values(mapping.credential.encodeInsert({
50
- moduleId: input.moduleId,
51
- subjectId: nativeId,
52
- credentialId,
53
- credentialRevision,
54
- verifierVersion: SecurityRevision.make(yield* randomId),
55
- replacement: input.replacement
56
- }));
57
- yield* tx.insert(mapping.authorityCredential.table).values(mapping.authorityCredential.encodeInsert({
58
- subjectId: nativeId,
59
- credentialId,
60
- revision: credentialRevision
61
- }));
62
- return prepare({
63
- _tag: "Created",
64
- subjectId
65
- }, journal);
66
- })), { mode: "interactive" }).pipe(Effect.catchTag("IdentifierTaken", () => suppress))).value;
67
- }).pipe(Effect.provideService(LifecycleHooks, hooks), Effect.provideService(Crypto.Crypto, crypto), (work) => reportPersistenceFailure(work, Schema.is(PasswordUnavailable)), Effect.mapError(() => PasswordUnavailable.make({}))) };
21
+ const s = mapping.subject;
22
+ const subject = tables(s.table);
23
+ const lock = sql.onDialectOrElse({
24
+ sqlite: () => sql``,
25
+ orElse: () => sql`for update`
26
+ });
27
+ const run = (work, suppressed) => Option.isSome(parent) ? executor.run(work) : executor.operation(work.pipe(Effect.mapError((error) => error instanceof PasswordIdentifierTaken ? error : PasswordUnavailable.make({})))).pipe(Effect.catchCause((cause) => cause.reasons.length > 0 && cause.reasons.every((reason) => Cause.isFailReason(reason) && reason.error instanceof PasswordIdentifierTaken) ? executor.run(suppressed, "statement") : Effect.failCause(cause)), Effect.mapError(() => PasswordUnavailable.make({})));
28
+ return { register: (input, project) => executor.read(store.available(input.identifier)).pipe(Effect.flatMap((existing) => existing.length !== 0 ? executor.run(store.prepare({ _tag: "Suppressed" }, project), "statement") : run(Effect.gen(function* () {
29
+ const subjectId = yield* createSubject({
30
+ requestId: input.requestId,
31
+ identifier: input.identifier,
32
+ registration: input.registration
33
+ });
34
+ const nativeId = yield* mapping.subjectId.toNative(subjectId);
35
+ const rows = yield* sql`select ${subject.fields("registration_subject_")} from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, nativeId)} limit 2 ${lock}`;
36
+ if (rows.length !== 1) return yield* PasswordUnavailable.make({});
37
+ const row = subject.decode(rows[0], "registration_subject_");
38
+ if (!s.isActiveStatus(row[s.status])) return yield* PasswordUnavailable.make({});
39
+ const securityRevision = yield* Schema.decodeUnknownEffect(SecurityRevision)(row[s.securityRevision]);
40
+ const identifierRevision = SecurityRevision.make(yield* randomId);
41
+ const credentialId = yield* randomId;
42
+ const credentialRevision = SecurityRevision.make(yield* randomId);
43
+ const verifierVersion = SecurityRevision.make(yield* randomId);
44
+ yield* store.bind({
45
+ ...input,
46
+ subjectId,
47
+ securityRevision,
48
+ identifierRevision,
49
+ credentialId,
50
+ credentialRevision,
51
+ verifierVersion
52
+ });
53
+ return yield* store.prepare({
54
+ _tag: "Created",
55
+ subjectId
56
+ }, project);
57
+ }).pipe(Effect.provideService(Crypto.Crypto, crypto)), store.prepare({ _tag: "Suppressed" }, project)))) };
68
58
  });
69
59
  //#endregion
70
60
  export { makeRegistrationAuthority };
@@ -1 +1 @@
1
- {"version":3,"file":"registration.mjs","names":[],"sources":["../../src/internal/registration.ts"],"sourcesContent":["import { coordinateCommit, hasCommitScope, LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport { PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport { SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { type Context, Crypto, Effect, Schema } from \"effect\";\n\nimport { PersistenceConfigurationError } from \"./configuration\";\nimport { randomId } from \"./crypto\";\nimport { CurrentPasswordSql } from \"./password-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport type { PasswordRegistrationAuthority } from \"./registration-contract\";\nimport type { makeMappings } from \"./storage-mapping\";\n\nclass IdentifierTaken extends Schema.TaggedError<IdentifierTaken>()(\"IdentifierTaken\", {}) {}\n\ntype CreateSubject = (input: {\n readonly identifier: LoginIdentifier;\n readonly registration: unknown;\n}) => Effect.Effect<SubjectId, PasswordUnavailable>;\n\n/** Registration reserves the command, provisions the application's subject, and\n * creates the unverified identifier and password in one SQL transaction. Replays\n * always suppress; a public request ID never recovers a private password intent.\n */\nexport const makeRegistrationAuthority = Effect.fn(\"makeRegistrationAuthority\")(function* <R>(\n mappings: Effect.Success<ReturnType<typeof makeMappings>>,\n operations: QueryOperations,\n standalone: Effect.Effect<void, PasswordUnavailable>,\n provisioning: Context.Key<R, object>,\n strategy: string,\n): Effect.fn.Return<\n PasswordRegistrationAuthority<unknown>,\n PersistenceConfigurationError,\n LifecycleHooks | CurrentPasswordSql | Crypto.Crypto | R\n> {\n const database = yield* CurrentPasswordSql;\n const hooks = yield* LifecycleHooks;\n const crypto = yield* Crypto.Crypto;\n // Core has already decoded registration with the selected strategy's Schema;\n // the dynamic strategy table erases only that heterogeneous callback signature.\n const creators = (yield* provisioning) as Readonly<Record<string, CreateSubject>>;\n const createSubject = creators[strategy];\n\n if (createSubject === undefined)\n return yield* PersistenceConfigurationError.make({\n reason: `Missing subject provisioning for ${strategy}`,\n });\n const { and, eq, column } = operations;\n const mapping = mappings.passwords();\n const receipts = mappings.table(\"passwordRegistrations\");\n\n return {\n register: (input, prepare) =>\n Effect.gen(function* () {\n if (yield* hasCommitScope) return yield* PasswordUnavailable.make({});\n yield* standalone;\n\n const receipt = { moduleId: input.moduleId, requestId: input.requestId };\n\n const suppress = coordinateCommit(\n (journal) =>\n database.transaction((tx) =>\n Effect.gen(function* () {\n yield* tx.insert(receipts).values(receipt).onConflictDoNothing();\n\n return prepare({ _tag: \"Suppressed\" }, journal);\n }),\n ),\n { mode: \"interactive\" },\n );\n\n const committed = yield* coordinateCommit(\n (journal) =>\n database.transaction((tx) =>\n Effect.gen(function* () {\n const reserved = yield* tx\n .insert(receipts)\n .values(receipt)\n .onConflictDoNothing()\n .returning();\n\n if (reserved.length === 0) return prepare({ _tag: \"Suppressed\" }, journal);\n\n const identifiers = yield* tx\n .select()\n .from(mapping.identifier.table)\n .where(\n and(\n eq(\n column(mapping.identifier.table, mapping.identifier.namespace),\n input.identifier.namespace,\n ),\n eq(\n column(mapping.identifier.table, mapping.identifier.value),\n input.identifier.value,\n ),\n ),\n )\n .limit(1);\n\n if (identifiers.length !== 0) return prepare({ _tag: \"Suppressed\" }, journal);\n\n const subjectId = yield* createSubject({\n identifier: input.identifier,\n registration: input.registration,\n });\n\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const subjects = yield* tx\n .select()\n .from(mapping.subject.table)\n .where(eq(column(mapping.subject.table, mapping.subject.id), nativeId))\n .limit(1);\n\n if (\n subjects.length !== 1 ||\n !mapping.subject.isActiveStatus(subjects[0][mapping.subject.status])\n )\n return yield* PasswordUnavailable.make({});\n yield* Schema.decodeUnknownEffect(SecurityRevision)(\n subjects[0][mapping.subject.securityRevision],\n );\n\n const bound = yield* tx\n .insert(mapping.identifier.table)\n .values(\n mapping.identifier.encodeInitialInsert(\n input.identifier,\n nativeId,\n SecurityRevision.make(yield* randomId),\n ),\n )\n .onConflictDoNothing()\n .returning();\n\n // A concurrent registration won the identifier. Roll back the application\n // subject too, then persist a non-authorizing receipt in a new transaction.\n if (bound.length !== 1) return yield* new IdentifierTaken({});\n\n const credentialId = yield* randomId;\n const credentialRevision = SecurityRevision.make(yield* randomId);\n\n yield* tx.insert(mapping.credential.table).values(\n mapping.credential.encodeInsert({\n moduleId: input.moduleId,\n subjectId: nativeId,\n credentialId,\n credentialRevision,\n verifierVersion: SecurityRevision.make(yield* randomId),\n replacement: input.replacement,\n }),\n );\n yield* tx.insert(mapping.authorityCredential.table).values(\n mapping.authorityCredential.encodeInsert({\n subjectId: nativeId,\n credentialId,\n revision: credentialRevision,\n }),\n );\n\n return prepare({ _tag: \"Created\", subjectId }, journal);\n }),\n ),\n { mode: \"interactive\" },\n ).pipe(Effect.catchTag(\"IdentifierTaken\", () => suppress));\n\n return committed.value;\n }).pipe(\n Effect.provideService(LifecycleHooks, hooks),\n Effect.provideService(Crypto.Crypto, crypto),\n (work) => reportPersistenceFailure(work, Schema.is(PasswordUnavailable)),\n Effect.mapError(() => PasswordUnavailable.make({})),\n ),\n };\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"registration.mjs","names":[],"sources":["../../src/internal/registration.ts"],"sourcesContent":["import type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport { PasswordUnavailable } from \"@yielded/auth/Password\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport { SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { type Context, Crypto, Effect, Schema, Option, Cause } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\nimport { PersistenceConfigurationError } from \"./configuration\";\nimport { randomId } from \"./crypto\";\nimport type { AnyPasswordPersistenceMapping } from \"./models/password-model\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport {\n makeNativePasswordRegistrationStore,\n PasswordIdentifierTaken,\n} from \"./password-registration-native\";\nimport type { PasswordRegistrationAuthority } from \"./registration-contract\";\nimport { makeSqlCommitExecutor, CurrentSqlCommit } from \"./sql-commit\";\n\ntype CreateSubject = (input: {\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: unknown;\n}) => Effect.Effect<SubjectId, PasswordUnavailable>;\n\n/** Application provisioning and the unverified identifier/password binding share\n * one physical owner. Identifier uniqueness arbitrates registration; correlation\n * request IDs never become a retained credential-issuance receipt. */\nexport const makeRegistrationAuthority = Effect.fnUntraced(function* <R>(\n tables: NativeSqlTables,\n mapping: AnyPasswordPersistenceMapping,\n provisioning: Context.Key<R, object>,\n strategy: string,\n): Effect.fn.Return<\n PasswordRegistrationAuthority<unknown>,\n PersistenceConfigurationError,\n LifecycleHooks | SqlClient | Crypto.Crypto | R\n> {\n const sql = (yield* SqlClient).withoutTransforms();\n const crypto = yield* Crypto.Crypto;\n const executor = yield* makeSqlCommitExecutor(() => PasswordUnavailable.make({}));\n const parent = yield* Effect.serviceOption(CurrentSqlCommit);\n const store = yield* makeNativePasswordRegistrationStore(tables, mapping);\n // The strategy has already decoded its registration Schema. Only its callback\n // signature is erased by the heterogeneous strategy service map.\n const creators = (yield* provisioning) as Readonly<Record<string, CreateSubject>>;\n const createSubject = creators[strategy];\n\n if (createSubject === undefined)\n return yield* PersistenceConfigurationError.make({\n reason: `Missing subject provisioning for ${strategy}`,\n });\n const s = mapping.subject;\n const subject = tables(s.table);\n const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n\n const run = <A, E, R2>(work: Effect.Effect<A, E, R2>, suppressed: Effect.Effect<A, E, R2>) =>\n Option.isSome(parent)\n ? executor.run(work)\n : executor\n .operation(\n work.pipe(\n Effect.mapError((error) =>\n error instanceof PasswordIdentifierTaken ? error : PasswordUnavailable.make({}),\n ),\n ),\n )\n .pipe(\n Effect.catchCause((cause) =>\n cause.reasons.length > 0 &&\n cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) && reason.error instanceof PasswordIdentifierTaken,\n )\n ? executor.run(suppressed, \"statement\")\n : Effect.failCause(cause),\n ),\n Effect.mapError(() => PasswordUnavailable.make({})),\n );\n\n return {\n register: (input, project) =>\n executor.read(store.available(input.identifier)).pipe(\n Effect.flatMap((existing) =>\n existing.length !== 0\n ? executor.run(store.prepare({ _tag: \"Suppressed\" }, project), \"statement\")\n : run(\n Effect.gen(function* () {\n const subjectId = yield* createSubject({\n requestId: input.requestId,\n identifier: input.identifier,\n registration: input.registration,\n });\n\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const rows =\n yield* sql`select ${subject.fields(\"registration_subject_\")} from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, nativeId)} limit 2 ${lock}`;\n\n if (rows.length !== 1) return yield* PasswordUnavailable.make({});\n const row = subject.decode(rows[0]!, \"registration_subject_\");\n\n if (!s.isActiveStatus(row[s.status])) return yield* PasswordUnavailable.make({});\n\n const securityRevision = yield* Schema.decodeUnknownEffect(SecurityRevision)(\n row[s.securityRevision],\n );\n\n const identifierRevision = SecurityRevision.make(yield* randomId);\n const credentialId = yield* randomId;\n const credentialRevision = SecurityRevision.make(yield* randomId);\n const verifierVersion = SecurityRevision.make(yield* randomId);\n\n yield* store.bind({\n ...input,\n subjectId,\n securityRevision,\n identifierRevision,\n credentialId,\n credentialRevision,\n verifierVersion,\n });\n\n return yield* store.prepare({ _tag: \"Created\", subjectId }, project);\n }).pipe(Effect.provideService(Crypto.Crypto, crypto)),\n store.prepare({ _tag: \"Suppressed\" }, project),\n ),\n ),\n ),\n };\n});\n"],"mappings":";;;;;;;;;;;;AA4BA,MAAa,4BAA4B,OAAO,WAAW,WACzD,QACA,SACA,cACA,UAKA;CACA,MAAM,OAAO,OAAO,UAAA,CAAW,kBAAkB;CACjD,MAAM,SAAS,OAAO,OAAO;CAC7B,MAAM,WAAW,OAAO,4BAA4B,oBAAoB,KAAK,CAAC,CAAC,CAAC;CAChF,MAAM,SAAS,OAAO,OAAO,cAAc,gBAAgB;CAC3D,MAAM,QAAQ,OAAO,oCAAoC,QAAQ,OAAO;CAIxE,MAAM,iBAAgB,OADG,aAAA,CACM;CAE/B,IAAI,kBAAkB,KAAA,GACpB,OAAO,OAAO,8BAA8B,KAAK,EAC/C,QAAQ,oCAAoC,WAC9C,CAAC;CACH,MAAM,IAAI,QAAQ;CAClB,MAAM,UAAU,OAAO,EAAE,KAAK;CAC9B,MAAM,OAAO,IAAI,gBAAgB;EAAE,cAAc,GAAG;EAAI,cAAc,GAAG;CAAa,CAAC;CAEvF,MAAM,OAAiB,MAA+B,eACpD,OAAO,OAAO,MAAM,IAChB,SAAS,IAAI,IAAI,IACjB,SACG,UACC,KAAK,KACH,OAAO,UAAU,UACf,iBAAiB,0BAA0B,QAAQ,oBAAoB,KAAK,CAAC,CAAC,CAChF,CACF,CACF,CAAC,CACA,KACC,OAAO,YAAY,UACjB,MAAM,QAAQ,SAAS,KACvB,MAAM,QAAQ,OACX,WACC,MAAM,aAAa,MAAM,KAAK,OAAO,iBAAiB,uBAC1D,IACI,SAAS,IAAI,YAAY,WAAW,IACpC,OAAO,UAAU,KAAK,CAC5B,GACA,OAAO,eAAe,oBAAoB,KAAK,CAAC,CAAC,CAAC,CACpD;CAER,OAAO,EACL,WAAW,OAAO,YAChB,SAAS,KAAK,MAAM,UAAU,MAAM,UAAU,CAAC,CAAC,CAAC,KAC/C,OAAO,SAAS,aACd,SAAS,WAAW,IAChB,SAAS,IAAI,MAAM,QAAQ,EAAE,MAAM,aAAa,GAAG,OAAO,GAAG,WAAW,IACxE,IACE,OAAO,IAAI,aAAa;EACtB,MAAM,YAAY,OAAO,cAAc;GACrC,WAAW,MAAM;GACjB,YAAY,MAAM;GAClB,cAAc,MAAM;EACtB,CAAC;EAED,MAAM,WAAW,OAAO,QAAQ,UAAU,SAAS,SAAS;EAE5D,MAAM,OACJ,OAAO,GAAG,UAAU,QAAQ,OAAO,uBAAuB,EAAE,QAAQ,QAAQ,KAAK,SAAS,QAAQ,OAAO,EAAE,EAAE,EAAE,KAAK,QAAQ,MAAM,EAAE,IAAI,QAAQ,EAAE,WAAW;EAE/J,IAAI,KAAK,WAAW,GAAG,OAAO,OAAO,oBAAoB,KAAK,CAAC,CAAC;EAChE,MAAM,MAAM,QAAQ,OAAO,KAAK,IAAK,uBAAuB;EAE5D,IAAI,CAAC,EAAE,eAAe,IAAI,EAAE,OAAO,GAAG,OAAO,OAAO,oBAAoB,KAAK,CAAC,CAAC;EAE/E,MAAM,mBAAmB,OAAO,OAAO,oBAAoB,gBAAgB,CAAC,CAC1E,IAAI,EAAE,iBACR;EAEA,MAAM,qBAAqB,iBAAiB,KAAK,OAAO,QAAQ;EAChE,MAAM,eAAe,OAAO;EAC5B,MAAM,qBAAqB,iBAAiB,KAAK,OAAO,QAAQ;EAChE,MAAM,kBAAkB,iBAAiB,KAAK,OAAO,QAAQ;EAE7D,OAAO,MAAM,KAAK;GAChB,GAAG;GACH;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EAED,OAAO,OAAO,MAAM,QAAQ;GAAE,MAAM;GAAW;EAAU,GAAG,OAAO;CACrE,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,OAAO,QAAQ,MAAM,CAAC,GACpD,MAAM,QAAQ,EAAE,MAAM,aAAa,GAAG,OAAO,CAC/C,CACN,CACF,EACJ;AACF,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { AnyTableModel } from "./table-model.mjs";
2
+ import { AuthenticationAuthorityMapping } from "./models/session-model.mjs";
3
+ import { NativeSqlTables } from "./native-sql-table.mjs";
4
+ import { SqlBatchCommit } from "./sql-commit.mjs";
5
+ import { DateTime, Effect } from "effect";
6
+ import { LifecycleHooks } from "@yielded/auth/Hooks";
7
+ import { AuthenticationAuthority, StaleAuthentication } from "@yielded/auth/Sessions";
8
+ import { SqlClient } from "effect/sql/SqlClient";
9
+ //#region src/internal/session-native-authority.d.ts
10
+ export type NativeAuthenticationAuthorityMapping<Claims> = AuthenticationAuthorityMapping<Claims, AnyTableModel, AnyTableModel, AnyTableModel, unknown>;
11
+ export declare const makeNativeAuthenticationAuthorityServices: <Claims>(tables: NativeSqlTables, mapping: NativeAuthenticationAuthorityMapping<Claims>) => Effect.Effect<{
12
+ readonly authenticationAuthority: AuthenticationAuthority["Service"];
13
+ }, never, LifecycleHooks | SqlBatchCommit | SqlClient>;
14
+ //#endregion
15
+ //# sourceMappingURL=session-native-authority.d.mts.map
@@ -0,0 +1,91 @@
1
+ import { PersistenceMappingError } from "./mapping-error.mjs";
2
+ import { sqlBatchAssertion } from "./d1-planning.mjs";
3
+ import { CurrentSqlCommit, SqlBatchCommit, appendSqlBatchStatement, makeSqlCommitExecutor, registerSqlBatchPostcondition, registerSqlPostcondition } from "./sql-commit.mjs";
4
+ import { assessSessionAt, makeNativeSessionAuthorityState, normalizeSessionOperation, sameSessionRevision, sessionUnavailable } from "./session-native-state.mjs";
5
+ import { makeNativeSessionPending, prepareNativeSession } from "./session-native-pending.mjs";
6
+ import { preservesRevision } from "./session-policy.mjs";
7
+ import { DateTime, Effect, Option } from "effect";
8
+ import "@yielded/auth/Hooks";
9
+ import { PendingAuthenticationInvalid, StaleAuthentication } from "@yielded/auth/Sessions";
10
+ //#region src/internal/session-native-authority.ts
11
+ const sessionEvidenceDeadline = Effect.fnUntraced(function* (evidence, requirement, now) {
12
+ const assessed = yield* assessSessionAt(evidence, requirement, now);
13
+ if (!assessed.satisfied) return yield* StaleAuthentication.make({});
14
+ const boundaries = [...new Set(evidence.proofs.map((proof) => DateTime.toEpochMillis(proof.verifiedAt) + requirement.maximumAgeMillis))].filter((n) => n > now).sort((a, b) => a - b);
15
+ for (const boundary of boundaries) {
16
+ const after = yield* assessSessionAt(evidence, requirement, boundary).pipe(Effect.result);
17
+ if (after._tag === "Failure" || !after.success.satisfied) return {
18
+ assessed,
19
+ validUntil: boundary
20
+ };
21
+ }
22
+ return yield* StaleAuthentication.make({});
23
+ });
24
+ const makeNativeAuthenticationAuthorityServices = Effect.fnUntraced(function* (tables, mapping) {
25
+ const batch = yield* SqlBatchCommit;
26
+ const state = yield* makeNativeSessionAuthorityState(tables, mapping, batch !== void 0);
27
+ const executor = yield* makeSqlCommitExecutor(sessionUnavailable);
28
+ const external = yield* Effect.serviceOption(CurrentSqlCommit);
29
+ const pending = mapping.pending === void 0 ? void 0 : yield* makeNativeSessionPending(tables, {
30
+ ...mapping,
31
+ ...mapping.pending
32
+ }, batch !== void 0);
33
+ const { sql, now } = state;
34
+ const readEvidence = Effect.fnUntraced(function* (evidence, locking) {
35
+ const current = yield* state.read(evidence.revision.subjectId, locking);
36
+ return current !== void 0 && sameSessionRevision(current.revision, evidence.revision) ? current : void 0;
37
+ });
38
+ const consume = Effect.fnUntraced(function* (input, evidence, native) {
39
+ if (pending === void 0 || mapping.pending === void 0) return yield* PendingAuthenticationInvalid.make({});
40
+ const found = yield* pending.read("Login", input.digest);
41
+ if (found === void 0 || found.record.version !== input.version || found.record.flowId !== input.flowId || found.record.bindingDigest !== input.bindingDigest || found.record.subjectId !== evidence.revision.subjectId) return yield* PendingAuthenticationInvalid.make({});
42
+ const original = yield* mapping.pending.login.decode(found.record.snapshot);
43
+ if (original.digest !== input.digest || original.version !== input.version || !preservesRevision(evidence, original.evidence) || DateTime.toEpochMillis(original.expiresAt) !== found.record.expiresAtMillis || original.attemptLimit !== found.record.attemptLimit) return yield* PendingAuthenticationInvalid.make({});
44
+ yield* pending.consume("Login", input, native);
45
+ return found.record.expiresAtMillis;
46
+ });
47
+ const native = (work) => batch === void 0 ? executor.operation(normalizeSessionOperation(work)) : executor.operationBatch(normalizeSessionOperation(work)).pipe(Effect.provideService(SqlBatchCommit, batch));
48
+ return { authenticationAuthority: {
49
+ capture: (subjectId, credentialIds) => executor.read(state.read(subjectId)).pipe(Effect.flatMap((current) => current === void 0 || new Set(credentialIds).size !== credentialIds.length || credentialIds.some((id) => !current.revision.credentials.some((f) => f.credentialId === id)) ? Effect.fail(StaleAuthentication.make({})) : Effect.succeed({
50
+ revision: current.revision,
51
+ requirement: current.requirement
52
+ }))),
53
+ requirements: (evidence) => executor.read(readEvidence(evidence, false)).pipe(Effect.flatMap((current) => current === void 0 ? Effect.fail(StaleAuthentication.make({})) : Effect.succeed(current.requirement))),
54
+ approve: (input, project) => native(Effect.gen(function* () {
55
+ const current = yield* readEvidence(input.evidence, true);
56
+ if (current === void 0) return yield* StaleAuthentication.make({});
57
+ const assessment = yield* sessionEvidenceDeadline(input.evidence, current.requirement, current.now);
58
+ const expires = DateTime.toEpochMillis(input.expiresAt), absolute = DateTime.toEpochMillis(input.absoluteExpiresAt);
59
+ if (current.now >= expires || expires > absolute) return yield* StaleAuthentication.make({});
60
+ const pendingExpiry = input.pending === void 0 ? void 0 : yield* consume(input.pending, input.evidence, current.native);
61
+ const deadline = Math.min(assessment.validUntil, expires, pendingExpiry ?? Infinity);
62
+ const condition = sql`${state.authorityCondition(current.revision, current.native)} and ${state.policyCondition(current.row, current.native)} and ${now} >= ${current.now} and ${now} < ${deadline}`;
63
+ if (batch !== void 0) {
64
+ yield* appendSqlBatchStatement(sqlBatchAssertion(sql, condition));
65
+ yield* registerSqlBatchPostcondition({
66
+ name: "signed-session-issuance-authority",
67
+ statement: sqlBatchAssertion(sql, input.pending === void 0 || pending === void 0 ? condition : sql`${condition} and ${pending.consumedCondition("Login", input.pending, current.native)}`)
68
+ });
69
+ } else if (Option.isSome(external)) yield* registerSqlPostcondition({
70
+ name: "signed-session-issuance-authority",
71
+ check: Effect.gen(function* () {
72
+ const final = yield* readEvidence(input.evidence, false);
73
+ if (final === void 0 || final.now < current.now || final.now >= deadline) return yield* StaleAuthentication.make({});
74
+ yield* sessionEvidenceDeadline(input.evidence, final.requirement, final.now);
75
+ if (input.pending !== void 0 && pending !== void 0) {
76
+ if ((yield* sql`select 1 where ${pending.consumedCondition("Login", input.pending, current.native)}`).length !== 1) return yield* PendingAuthenticationInvalid.make({});
77
+ }
78
+ }).pipe(Effect.mapError((cause) => PersistenceMappingError.make({
79
+ operation: "decode",
80
+ cause
81
+ })))
82
+ });
83
+ else if ((yield* sql`select 1 where ${now} >= ${current.now} and ${now} < ${deadline}`).length !== 1) return yield* StaleAuthentication.make({});
84
+ return yield* prepareNativeSession(void 0, project);
85
+ }))
86
+ } };
87
+ });
88
+ //#endregion
89
+ export { makeNativeAuthenticationAuthorityServices, sessionEvidenceDeadline };
90
+
91
+ //# sourceMappingURL=session-native-authority.mjs.map