@yielded/auth-persistence-drizzle 0.1.0-beta.0 → 0.1.0-beta.12

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 (291) hide show
  1. package/README.md +6 -1
  2. package/dist/D1.d.mts +155 -40
  3. package/dist/D1.mjs +10 -6
  4. package/dist/D1.mjs.map +1 -1
  5. package/dist/Libsql.d.mts +251 -129
  6. package/dist/Libsql.mjs +20 -21
  7. package/dist/Libsql.mjs.map +1 -1
  8. package/dist/Mysql2.d.mts +208 -56
  9. package/dist/Mysql2.mjs +13 -8
  10. package/dist/Mysql2.mjs.map +1 -1
  11. package/dist/Pglite.d.mts +209 -57
  12. package/dist/Pglite.mjs +13 -9
  13. package/dist/Pglite.mjs.map +1 -1
  14. package/dist/Postgres.d.mts +207 -55
  15. package/dist/Postgres.mjs +13 -9
  16. package/dist/Postgres.mjs.map +1 -1
  17. package/dist/SqliteBun.d.mts +249 -126
  18. package/dist/SqliteBun.mjs +20 -18
  19. package/dist/SqliteBun.mjs.map +1 -1
  20. package/dist/SqliteDo.d.mts +248 -158
  21. package/dist/SqliteDo.mjs +26 -44
  22. package/dist/SqliteDo.mjs.map +1 -1
  23. package/dist/SqliteNode.d.mts +247 -124
  24. package/dist/SqliteNode.mjs +20 -18
  25. package/dist/SqliteNode.mjs.map +1 -1
  26. package/dist/SqliteWasm.d.mts +251 -128
  27. package/dist/SqliteWasm.mjs +20 -18
  28. package/dist/SqliteWasm.mjs.map +1 -1
  29. package/dist/drizzle/D1BatchStatements.d.mts +1 -1
  30. package/dist/drizzle/D1BatchStatements.mjs.map +1 -1
  31. package/dist/drizzle/d1-database.d.mts +11 -0
  32. package/dist/drizzle/d1-database.mjs +8 -0
  33. package/dist/drizzle/d1-database.mjs.map +1 -0
  34. package/dist/drizzle/d1-emails.d.mts +8 -7
  35. package/dist/drizzle/d1-emails.mjs +7 -4
  36. package/dist/drizzle/d1-emails.mjs.map +1 -1
  37. package/dist/drizzle/d1-generated-statement.mjs.map +1 -1
  38. package/dist/drizzle/d1-identity.mjs +12 -9
  39. package/dist/drizzle/d1-identity.mjs.map +1 -1
  40. package/dist/drizzle/d1-oauth.d.mts +41 -10
  41. package/dist/drizzle/d1-oauth.mjs +8 -5
  42. package/dist/drizzle/d1-oauth.mjs.map +1 -1
  43. package/dist/drizzle/d1-passkey.d.mts +3 -14
  44. package/dist/drizzle/d1-passkey.mjs +2 -1
  45. package/dist/drizzle/d1-passkey.mjs.map +1 -1
  46. package/dist/drizzle/d1-password-prepared.d.mts +4 -3
  47. package/dist/drizzle/d1-password-prepared.mjs +3 -1
  48. package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
  49. package/dist/drizzle/d1-passwords.d.mts +7 -6
  50. package/dist/drizzle/d1-passwords.mjs +5 -2
  51. package/dist/drizzle/d1-passwords.mjs.map +1 -1
  52. package/dist/drizzle/d1-phone.d.mts +3 -4
  53. package/dist/drizzle/d1-phone.mjs +2 -1
  54. package/dist/drizzle/d1-phone.mjs.map +1 -1
  55. package/dist/drizzle/d1-planning.d.mts +1 -1
  56. package/dist/drizzle/d1-proofs.d.mts +5 -4
  57. package/dist/drizzle/d1-proofs.mjs +3 -1
  58. package/dist/drizzle/d1-proofs.mjs.map +1 -1
  59. package/dist/drizzle/d1-sessions.d.mts +14 -13
  60. package/dist/drizzle/d1-sessions.mjs +15 -9
  61. package/dist/drizzle/d1-sessions.mjs.map +1 -1
  62. package/dist/drizzle/d1-totp.d.mts +3 -4
  63. package/dist/drizzle/d1-totp.mjs +2 -1
  64. package/dist/drizzle/d1-totp.mjs.map +1 -1
  65. package/dist/drizzle/email-registration.d.mts +1 -1
  66. package/dist/drizzle/email-registration.mjs +2 -1
  67. package/dist/drizzle/email-registration.mjs.map +1 -1
  68. package/dist/drizzle/email-target.d.mts +8 -7
  69. package/dist/drizzle/email-target.mjs +10 -10
  70. package/dist/drizzle/email-target.mjs.map +1 -1
  71. package/dist/drizzle/model.d.mts +2 -126
  72. package/dist/drizzle/model.mjs +2 -21
  73. package/dist/drizzle/model.mjs.map +1 -1
  74. package/dist/drizzle/mysql-database.d.mts +8 -0
  75. package/dist/drizzle/mysql-database.mjs +8 -0
  76. package/dist/drizzle/mysql-database.mjs.map +1 -0
  77. package/dist/drizzle/mysql-emails.d.mts +8 -7
  78. package/dist/drizzle/mysql-emails.mjs +12 -8
  79. package/dist/drizzle/mysql-emails.mjs.map +1 -1
  80. package/dist/drizzle/mysql-identity.mjs +12 -9
  81. package/dist/drizzle/mysql-identity.mjs.map +1 -1
  82. package/dist/drizzle/mysql-password-prepared.d.mts +4 -3
  83. package/dist/drizzle/mysql-password-prepared.mjs +6 -2
  84. package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
  85. package/dist/drizzle/mysql-passwords.d.mts +7 -5
  86. package/dist/drizzle/mysql-passwords.mjs +11 -7
  87. package/dist/drizzle/mysql-passwords.mjs.map +1 -1
  88. package/dist/drizzle/mysql-proofs.d.mts +4 -3
  89. package/dist/drizzle/mysql-proofs.mjs +8 -4
  90. package/dist/drizzle/mysql-proofs.mjs.map +1 -1
  91. package/dist/drizzle/mysql-sessions.d.mts +12 -11
  92. package/dist/drizzle/mysql-sessions.mjs +16 -12
  93. package/dist/drizzle/mysql-sessions.mjs.map +1 -1
  94. package/dist/drizzle/native-database.mjs +10 -0
  95. package/dist/drizzle/native-database.mjs.map +1 -0
  96. package/dist/drizzle/oauth-accounts.mjs +1 -1
  97. package/dist/drizzle/oauth-connected-access.mjs +14 -12
  98. package/dist/drizzle/oauth-connected-access.mjs.map +1 -1
  99. package/dist/drizzle/oauth-connected-custody.mjs +2 -2
  100. package/dist/drizzle/oauth-connected-drivers.mjs +11 -6
  101. package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
  102. package/dist/drizzle/oauth-connected-flow.mjs +2 -2
  103. package/dist/drizzle/oauth-connected-input.mjs +14 -1
  104. package/dist/drizzle/oauth-connected-input.mjs.map +1 -1
  105. package/dist/drizzle/oauth-connected-maintenance.mjs +1 -1
  106. package/dist/drizzle/oauth-connected-management.mjs +2 -2
  107. package/dist/drizzle/oauth-connected-model.d.mts +17 -3
  108. package/dist/drizzle/oauth-connected-model.mjs.map +1 -1
  109. package/dist/drizzle/oauth-connected-settlement.mjs +51 -41
  110. package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
  111. package/dist/drizzle/oauth-connected-sign-in.mjs +263 -0
  112. package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -0
  113. package/dist/drizzle/oauth-connected-state.d.mts +110 -2
  114. package/dist/drizzle/oauth-connected-state.mjs +9 -4
  115. package/dist/drizzle/oauth-connected-state.mjs.map +1 -1
  116. package/dist/drizzle/oauth-connected-target.d.mts +142 -15
  117. package/dist/drizzle/oauth-connected-target.mjs +9 -6
  118. package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
  119. package/dist/drizzle/oauth-drivers.mjs +9 -7
  120. package/dist/drizzle/oauth-drivers.mjs.map +1 -1
  121. package/dist/drizzle/oauth-flow.d.mts +1 -1
  122. package/dist/drizzle/oauth-flow.mjs +1 -1
  123. package/dist/drizzle/oauth-input.mjs +1 -1
  124. package/dist/drizzle/oauth-model.d.mts +1 -1
  125. package/dist/drizzle/oauth-owner.d.mts +1 -1
  126. package/dist/drizzle/oauth-registration.d.mts +2 -2
  127. package/dist/drizzle/oauth-registration.mjs +1 -1
  128. package/dist/drizzle/oauth-state.mjs +5 -4
  129. package/dist/drizzle/oauth-state.mjs.map +1 -1
  130. package/dist/drizzle/oauth-target.d.mts +14 -13
  131. package/dist/drizzle/oauth-target.mjs +14 -13
  132. package/dist/drizzle/oauth-target.mjs.map +1 -1
  133. package/dist/drizzle/passkey-drivers.mjs +8 -6
  134. package/dist/drizzle/passkey-drivers.mjs.map +1 -1
  135. package/dist/drizzle/passkey-write-drivers.mjs +5 -3
  136. package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
  137. package/dist/drizzle/passkey-write-target.d.mts +1 -1
  138. package/dist/drizzle/password-prepared-sql.mjs +2 -1
  139. package/dist/drizzle/password-prepared-sql.mjs.map +1 -1
  140. package/dist/drizzle/password-prepared-state.mjs +1 -1
  141. package/dist/drizzle/password-prepared-target.d.mts +4 -3
  142. package/dist/drizzle/password-prepared-target.mjs +4 -3
  143. package/dist/drizzle/password-prepared-target.mjs.map +1 -1
  144. package/dist/drizzle/password-registration.mjs +2 -1
  145. package/dist/drizzle/password-registration.mjs.map +1 -1
  146. package/dist/drizzle/password-target.d.mts +6 -5
  147. package/dist/drizzle/password-target.mjs +8 -8
  148. package/dist/drizzle/password-target.mjs.map +1 -1
  149. package/dist/drizzle/pg-database.d.mts +9 -0
  150. package/dist/drizzle/pg-database.mjs +8 -0
  151. package/dist/drizzle/pg-database.mjs.map +1 -0
  152. package/dist/drizzle/pg-emails.d.mts +8 -7
  153. package/dist/drizzle/pg-emails.mjs +12 -8
  154. package/dist/drizzle/pg-emails.mjs.map +1 -1
  155. package/dist/drizzle/pg-identity.mjs +92 -0
  156. package/dist/drizzle/pg-identity.mjs.map +1 -0
  157. package/dist/drizzle/pg-password-prepared.d.mts +4 -3
  158. package/dist/drizzle/pg-password-prepared.mjs +6 -2
  159. package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
  160. package/dist/drizzle/pg-passwords.d.mts +7 -5
  161. package/dist/drizzle/pg-passwords.mjs +11 -7
  162. package/dist/drizzle/pg-passwords.mjs.map +1 -1
  163. package/dist/drizzle/pg-proofs.d.mts +4 -3
  164. package/dist/drizzle/pg-proofs.mjs +8 -4
  165. package/dist/drizzle/pg-proofs.mjs.map +1 -1
  166. package/dist/drizzle/pg-sessions.d.mts +12 -11
  167. package/dist/drizzle/pg-sessions.mjs +16 -12
  168. package/dist/drizzle/pg-sessions.mjs.map +1 -1
  169. package/dist/drizzle/phone-model.d.mts +1 -1
  170. package/dist/drizzle/phone-target.d.mts +5 -4
  171. package/dist/drizzle/phone-target.mjs +12 -11
  172. package/dist/drizzle/phone-target.mjs.map +1 -1
  173. package/dist/drizzle/proof-target.d.mts +4 -3
  174. package/dist/drizzle/proof-target.mjs +5 -5
  175. package/dist/drizzle/proof-target.mjs.map +1 -1
  176. package/dist/drizzle/session-sql.d.mts +1 -0
  177. package/dist/drizzle/session-target.d.mts +11 -9
  178. package/dist/drizzle/session-target.mjs +11 -11
  179. package/dist/drizzle/session-target.mjs.map +1 -1
  180. package/dist/drizzle/sqlite-emails.mjs +9 -5
  181. package/dist/drizzle/sqlite-emails.mjs.map +1 -1
  182. package/dist/drizzle/sqlite-identity.mjs +14 -11
  183. package/dist/drizzle/sqlite-identity.mjs.map +1 -1
  184. package/dist/drizzle/sqlite-password-prepared.mjs +7 -3
  185. package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
  186. package/dist/drizzle/sqlite-passwords.mjs +10 -6
  187. package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
  188. package/dist/drizzle/sqlite-proofs.mjs +7 -3
  189. package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
  190. package/dist/drizzle/sqlite-sessions.mjs +16 -12
  191. package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
  192. package/dist/drizzle/standalone-guard.d.mts +2 -0
  193. package/dist/drizzle/standalone-guard.mjs +8 -4
  194. package/dist/drizzle/standalone-guard.mjs.map +1 -1
  195. package/dist/drizzle/totp-model.d.mts +1 -1
  196. package/dist/drizzle/totp-target.d.mts +5 -4
  197. package/dist/drizzle/totp-target.mjs +31 -28
  198. package/dist/drizzle/totp-target.mjs.map +1 -1
  199. package/dist/drizzle/transaction-mysql.mjs +1 -1
  200. package/dist/drizzle/transaction-mysql.mjs.map +1 -1
  201. package/dist/index.d.mts +2 -4
  202. package/dist/index.mjs +2 -4
  203. package/dist/internal/drizzle-postgres.mjs.map +1 -1
  204. package/dist/internal/drizzle-sqlite.mjs.map +1 -1
  205. package/package.json +1 -1
  206. package/src/D1.ts +37 -26
  207. package/src/Libsql.ts +45 -61
  208. package/src/Mysql2.ts +39 -35
  209. package/src/Pglite.ts +48 -30
  210. package/src/Postgres.ts +48 -30
  211. package/src/SqliteBun.ts +59 -68
  212. package/src/SqliteDo.ts +61 -274
  213. package/src/SqliteNode.ts +56 -66
  214. package/src/SqliteWasm.ts +56 -66
  215. package/src/drizzle/D1BatchStatements.ts +1 -1
  216. package/src/drizzle/d1-database.ts +10 -0
  217. package/src/drizzle/d1-emails.ts +86 -88
  218. package/src/drizzle/d1-generated-statement.ts +1 -1
  219. package/src/drizzle/d1-identity.ts +17 -20
  220. package/src/drizzle/d1-oauth.ts +19 -8
  221. package/src/drizzle/d1-passkey.ts +5 -1
  222. package/src/drizzle/d1-password-prepared.ts +40 -42
  223. package/src/drizzle/d1-passwords.ts +76 -80
  224. package/src/drizzle/d1-phone.ts +5 -1
  225. package/src/drizzle/d1-proofs.ts +31 -34
  226. package/src/drizzle/d1-sessions.ts +53 -40
  227. package/src/drizzle/d1-totp.ts +5 -1
  228. package/src/drizzle/email-registration.ts +6 -2
  229. package/src/drizzle/email-target.ts +18 -20
  230. package/src/drizzle/model.ts +1 -208
  231. package/src/drizzle/mysql-database.ts +8 -0
  232. package/src/drizzle/mysql-emails.ts +29 -17
  233. package/src/drizzle/mysql-identity.ts +18 -21
  234. package/src/drizzle/mysql-password-prepared.ts +11 -9
  235. package/src/drizzle/mysql-passwords.ts +22 -10
  236. package/src/drizzle/mysql-proofs.ts +17 -6
  237. package/src/drizzle/mysql-sessions.ts +41 -18
  238. package/src/drizzle/native-database.ts +22 -0
  239. package/src/drizzle/oauth-connected-access.ts +8 -1
  240. package/src/drizzle/oauth-connected-drivers.ts +21 -6
  241. package/src/drizzle/oauth-connected-input.ts +13 -0
  242. package/src/drizzle/oauth-connected-model.ts +17 -0
  243. package/src/drizzle/oauth-connected-settlement.ts +65 -42
  244. package/src/drizzle/oauth-connected-sign-in.ts +438 -0
  245. package/src/drizzle/oauth-connected-state.ts +19 -7
  246. package/src/drizzle/oauth-connected-target.ts +26 -18
  247. package/src/drizzle/oauth-drivers.ts +26 -10
  248. package/src/drizzle/oauth-state.ts +5 -4
  249. package/src/drizzle/oauth-target.ts +31 -43
  250. package/src/drizzle/passkey-drivers.ts +21 -13
  251. package/src/drizzle/passkey-write-drivers.ts +11 -6
  252. package/src/drizzle/password-prepared-sql.ts +2 -4
  253. package/src/drizzle/password-prepared-target.ts +10 -7
  254. package/src/drizzle/password-registration.ts +7 -8
  255. package/src/drizzle/password-target.ts +20 -19
  256. package/src/drizzle/pg-database.ts +10 -0
  257. package/src/drizzle/pg-emails.ts +29 -17
  258. package/src/drizzle/pg-identity.ts +297 -0
  259. package/src/drizzle/pg-password-prepared.ts +11 -9
  260. package/src/drizzle/pg-passwords.ts +22 -10
  261. package/src/drizzle/pg-proofs.ts +17 -6
  262. package/src/drizzle/pg-sessions.ts +41 -18
  263. package/src/drizzle/phone-target.ts +23 -18
  264. package/src/drizzle/proof-target.ts +10 -13
  265. package/src/drizzle/session-target.ts +33 -51
  266. package/src/drizzle/sqlite-emails.ts +31 -14
  267. package/src/drizzle/sqlite-identity.ts +22 -42
  268. package/src/drizzle/sqlite-password-prepared.ts +24 -10
  269. package/src/drizzle/sqlite-passwords.ts +30 -16
  270. package/src/drizzle/sqlite-proofs.ts +29 -6
  271. package/src/drizzle/sqlite-sessions.ts +50 -24
  272. package/src/drizzle/standalone-guard.ts +19 -7
  273. package/src/drizzle/totp-target.ts +62 -61
  274. package/src/drizzle/transaction-mysql.ts +1 -1
  275. package/src/index.ts +0 -24
  276. package/src/internal/drizzle-postgres.ts +1 -1
  277. package/src/internal/drizzle-sqlite.ts +1 -1
  278. package/dist/drizzle/d1-identity.d.mts +0 -30
  279. package/dist/drizzle/mysql-identity.d.mts +0 -21
  280. package/dist/drizzle/mysql.d.mts +0 -69
  281. package/dist/drizzle/mysql.mjs +0 -218
  282. package/dist/drizzle/mysql.mjs.map +0 -1
  283. package/dist/drizzle/pg.d.mts +0 -80
  284. package/dist/drizzle/pg.mjs +0 -289
  285. package/dist/drizzle/pg.mjs.map +0 -1
  286. package/dist/drizzle/sqlite.d.mts +0 -77
  287. package/dist/drizzle/sqlite.mjs +0 -217
  288. package/dist/drizzle/sqlite.mjs.map +0 -1
  289. package/src/drizzle/mysql.ts +0 -687
  290. package/src/drizzle/pg.ts +0 -984
  291. package/src/drizzle/sqlite.ts +0 -705
@@ -0,0 +1,438 @@
1
+ import * as M from "@yielded/auth/OAuth";
2
+ import { snapshotOAuthSync } from "@yielded/auth/OAuth";
3
+ import { sql } from "drizzle-orm";
4
+ import { Effect, Schema } from "effect";
5
+
6
+ import * as C from "./oauth-connected-custody";
7
+ import * as F from "./oauth-connected-flow";
8
+ import { activateGrant, validMetadata } from "./oauth-connected-settlement";
9
+ import * as S from "./oauth-connected-state";
10
+ import { exactClaim } from "./oauth-flow";
11
+ import { both, equal, CurrentOAuthTransaction } from "./oauth-owner";
12
+ import {
13
+ digest,
14
+ invariant,
15
+ oauthIdentityKey,
16
+ sameIdentity,
17
+ sameRevision,
18
+ storage,
19
+ unavailable,
20
+ } from "./oauth-state";
21
+
22
+ const reservationStorage = storage(M.OAuthSignInAccessClaim);
23
+ const configurationStorage = storage(M.OAuthConnectedConfiguration);
24
+
25
+ /** Reservation rows share the connected-work ledger, but have no browser
26
+ * snapshot or subject. They can never enter the authenticated connect flow. */
27
+ export const claimSignIn = Effect.fn("oauthConnected.claimSignIn")(function* (
28
+ mapping: S.Mapping,
29
+ input: F.Input<"claimSignIn">,
30
+ ) {
31
+ const owner = yield* CurrentOAuthTransaction;
32
+ const signIn = mapping.signIn;
33
+ const encode = mapping.flow.encodeSignIn;
34
+
35
+ if (signIn === undefined || encode === undefined) return yield* unavailable();
36
+ const { claim, configuration } = input;
37
+ const c = claim.flow.context;
38
+
39
+ invariant(
40
+ c.access !== undefined &&
41
+ configurationStorage.encode(configuration) ===
42
+ configurationStorage.encode({ ...c, profile: c.access }),
43
+ );
44
+ if (configuration.profile.revocation === "cohort")
45
+ invariant(mapping.revocation.mode === "cohort");
46
+ const client = yield* S.client(mapping, configuration, true);
47
+
48
+ invariant(client !== undefined);
49
+ const exact = yield* exactClaim({ ...mapping, flow: signIn.flow }, claim, "sign-in");
50
+
51
+ if (exact === undefined) return yield* unavailable();
52
+ const f = mapping.flow;
53
+ const key = { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId };
54
+ const prior = yield* owner.read(f.table, equal(f.table, key), { limit: 1 });
55
+
56
+ const command = yield* owner.read(
57
+ f.table,
58
+ equal(f.table, { [f.moduleId]: c.moduleId, [f.commandId]: c.commandId }),
59
+ { limit: 1 },
60
+ );
61
+
62
+ if (prior.rows.length || command.rows.length) return yield* unavailable();
63
+ yield* S.touchScope(mapping, client.scope);
64
+ const order = yield* S.nextOrder(mapping, client);
65
+
66
+ const reservation = snapshotOAuthSync(M.OAuthSignInAccessClaim, {
67
+ claim,
68
+ configuration,
69
+ order: String(order),
70
+ });
71
+
72
+ const inserted = yield* owner.insert(
73
+ f.table,
74
+ {
75
+ ...encode(reservation),
76
+ ...key,
77
+ [f.commandId]: c.commandId,
78
+ [f.subjectId]: null,
79
+ [f.clientKey]: client.id,
80
+ [f.cohortKey]: null,
81
+ [f.state]: "Claimed",
82
+ [f.version]: owner.marker,
83
+ [f.stateDigest]: c.stateDigest,
84
+ [f.snapshot]: null,
85
+ [f.claimId]: claim.claimId,
86
+ [f.claimDigest]: digest(reservationStorage.encode(reservation)),
87
+ [f.claimOrder]: mapping.order.encode(order),
88
+ [f.claimedAt]: mapping.clock.encodeInstant(claim.claimedAtMillis),
89
+ [f.claimExpiresAt]: mapping.clock.encodeInstant(claim.claimExpiresAtMillis),
90
+ [f.expiresAt]: mapping.clock.encodeInstant(c.expiresAtMillis),
91
+ [f.retentionUntil]: mapping.clock.encodeInstant(claim.flow.retentionUntilMillis),
92
+ [f.work]: "Unresolved",
93
+ [f.custody]: null,
94
+ },
95
+ key,
96
+ );
97
+
98
+ prior.rows = inserted.rows;
99
+ command.rows = inserted.rows;
100
+
101
+ return reservation;
102
+ });
103
+
104
+ const exact = Effect.fn("oauthConnected.exactSignIn")(function* (
105
+ mapping: S.Mapping,
106
+ reservation: M.OAuthSignInAccessClaim,
107
+ ) {
108
+ const owner = yield* CurrentOAuthTransaction;
109
+ const f = mapping.flow;
110
+ const c = reservation.claim.flow.context;
111
+ const key = { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId };
112
+ const read = yield* owner.read(f.table, equal(f.table, key), { limit: 1 });
113
+ const row = read.rows[0];
114
+
115
+ if (
116
+ row === undefined ||
117
+ row[f.work] !== "Unresolved" ||
118
+ row[f.claimId] !== reservation.claim.claimId ||
119
+ row[f.claimDigest] !== digest(reservationStorage.encode(reservation))
120
+ )
121
+ return undefined;
122
+ invariant(
123
+ row[f.subjectId] === null &&
124
+ row[f.commandId] === c.commandId &&
125
+ row[f.clientKey] === S.clientKey(reservation.configuration) &&
126
+ S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(reservation.order),
127
+ );
128
+ const now = yield* owner.now(mapping.clock);
129
+
130
+ invariant(now >= reservation.claim.claimedAtMillis);
131
+
132
+ return {
133
+ key,
134
+ row,
135
+ now,
136
+ active: row[f.state] === "Claimed" && now < reservation.claim.claimExpiresAtMillis,
137
+ };
138
+ });
139
+
140
+ const credential = Effect.fn("oauthConnected.signInCredential")(function* (
141
+ mapping: S.Mapping,
142
+ reservation: M.OAuthSignInAccessClaim,
143
+ input: M.OAuthCredentialSnapshot,
144
+ ) {
145
+ const owner = yield* CurrentOAuthTransaction;
146
+ const signIn = mapping.signIn;
147
+
148
+ if (signIn === undefined) return undefined;
149
+ const context = reservation.claim.flow.context;
150
+
151
+ if (
152
+ input.moduleId !== context.moduleId ||
153
+ input.identity.provider !== context.provider ||
154
+ input.identity.issuer !== context.issuer
155
+ )
156
+ return undefined;
157
+ const found = yield* S.current(mapping, input.revision.subjectId);
158
+
159
+ if (found === undefined || !sameRevision(found.revision, input.revision)) return undefined;
160
+ const c = signIn.credential;
161
+
162
+ const loginWhere = both(
163
+ equal(c.table, {
164
+ [c.moduleId]: context.moduleId,
165
+ [c.credentialId]: input.credentialId,
166
+ [c.subjectId]: found.nativeId,
167
+ [c.identityKey]: oauthIdentityKey(input.identity),
168
+ [c.credentialRevision]: input.credentialRevision,
169
+ }),
170
+ c.activeCondition,
171
+ );
172
+
173
+ const login = yield* owner.read(c.table, loginWhere, { limit: 1 });
174
+
175
+ if (login.rows.length !== 1 || !c.isActiveStatus(login.rows[0]![c.status])) return undefined;
176
+ const f = signIn.flow;
177
+
178
+ const verifiedWhere = equal(f.table, {
179
+ [f.moduleId]: context.moduleId,
180
+ [f.flowId]: context.flowId,
181
+ [f.state]: "Verified",
182
+ [f.claimId]: reservation.claim.claimId,
183
+ [f.stateDigest]: context.stateDigest,
184
+ [f.claimedAt]: mapping.clock.encodeInstant(reservation.claim.claimedAtMillis),
185
+ [f.claimExpiresAt]: mapping.clock.encodeInstant(reservation.claim.claimExpiresAtMillis),
186
+ });
187
+
188
+ const verified = yield* owner.read(f.table, verifiedWhere, { limit: 1 });
189
+
190
+ if (verified.rows.length !== 1) return undefined;
191
+ owner.postconditions.push(
192
+ sql`exists(select 1 from ${c.table} where ${loginWhere})`,
193
+ sql`exists(select 1 from ${f.table} where ${verifiedWhere})`,
194
+ );
195
+ if (
196
+ !(yield* S.policy(mapping, {
197
+ kind: "sign-in",
198
+ subjectId: found.nativeId,
199
+ revision: found.revision,
200
+ credential: snapshotOAuthSync(M.OAuthCredentialSnapshot, input),
201
+ configuration: reservation.configuration,
202
+ }))
203
+ )
204
+ return undefined;
205
+
206
+ return found;
207
+ });
208
+
209
+ const slot = Effect.fn("oauthConnected.signInSlot")(function* (
210
+ mapping: S.Mapping,
211
+ moduleId: string,
212
+ native: unknown,
213
+ identityKey: string,
214
+ profileKey: string,
215
+ ) {
216
+ const owner = yield* CurrentOAuthTransaction;
217
+ const g = mapping.grant;
218
+
219
+ const rows = yield* owner.read(
220
+ g.table,
221
+ equal(g.table, {
222
+ [g.moduleId]: moduleId,
223
+ [g.subjectId]: native,
224
+ [g.profileKey]: profileKey,
225
+ [g.activeIdentityKey]: identityKey,
226
+ }),
227
+ { limit: 1, admissionOnly: true },
228
+ );
229
+
230
+ const row = rows.rows[0];
231
+
232
+ if (row === undefined) return undefined;
233
+
234
+ return yield* S.readGrant(
235
+ mapping,
236
+ moduleId,
237
+ yield* Schema.decodeUnknownEffect(M.OAuthGrantId)(row[g.grantId]).pipe(
238
+ Effect.mapError(unavailable),
239
+ ),
240
+ );
241
+ });
242
+
243
+ /** Orders belong to one client registration. Moving a profile to another client
244
+ * requires a newer profile generation; retired clients cannot replace it later. */
245
+ const canReplace = (
246
+ reservation: M.OAuthSignInAccessClaim,
247
+ previous: M.OAuthConnectedTokenContext,
248
+ ) => {
249
+ const generation = reservation.configuration.profile.generation;
250
+ const oldGeneration = previous.configuration.profile.generation;
251
+
252
+ return S.clientKey(reservation.configuration) === S.clientKey(previous.configuration)
253
+ ? generation >= oldGeneration &&
254
+ S.orderNumber(reservation.order) > S.orderNumber(previous.exchangeOrder)
255
+ : generation > oldGeneration;
256
+ };
257
+
258
+ export const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function* (
259
+ mapping: S.Mapping,
260
+ input: F.Input<"inspectSignIn">,
261
+ ) {
262
+ const found = yield* credential(mapping, input.reservation, input.credential);
263
+
264
+ if (found === undefined) return { _tag: "Rejected" } as const;
265
+ const r = input.reservation;
266
+ const cl = yield* S.client(mapping, r.configuration, false);
267
+
268
+ if (cl === undefined) return { _tag: "Rejected" } as const;
269
+ const tuple = yield* F.inspectTuple(mapping, input.credential.identity);
270
+ const t = mapping.ownership.tuple;
271
+
272
+ if (
273
+ tuple.row?.[t.state] !== "Owned" ||
274
+ !mapping.subjectId.equals(tuple.row[t.subjectId], found.nativeId)
275
+ )
276
+ return { _tag: "Rejected" } as const;
277
+ const co = yield* S.cohort(mapping, cl.id, tuple.key, false);
278
+
279
+ const previous = yield* slot(
280
+ mapping,
281
+ r.claim.flow.context.moduleId,
282
+ found.nativeId,
283
+ tuple.key,
284
+ r.configuration.profile.key,
285
+ );
286
+
287
+ const held = yield* exact(mapping, r);
288
+
289
+ if (held === undefined) return { _tag: "Rejected" } as const;
290
+
291
+ const quarantine =
292
+ !held.active ||
293
+ co.blocked ||
294
+ S.orderNumber(r.order) <= co.cutoff ||
295
+ previous?.row[mapping.grant.refreshWork] === "Unresolved" ||
296
+ (previous !== undefined && !canReplace(r, previous.context));
297
+
298
+ return snapshotOAuthSync(M.OAuthSignInAccessInspection, {
299
+ _tag: quarantine ? "Quarantine" : "Target",
300
+ grantId: previous?.context.grantId ?? input.grantId,
301
+ cohortGeneration: co.generation,
302
+ ...(previous === undefined
303
+ ? {}
304
+ : { previous: snapshotOAuthSync(M.OAuthConnectedTarget, previous.context) }),
305
+ });
306
+ });
307
+
308
+ export const settleSignIn = Effect.fn("oauthConnected.settleSignIn")(function* (
309
+ mapping: S.Mapping,
310
+ input: F.Input<"settleSignIn">,
311
+ ) {
312
+ const owner = yield* CurrentOAuthTransaction;
313
+ const r = input.reservation;
314
+ const out = input.outcome;
315
+ const found = out._tag === "Verified" ? yield* credential(mapping, r, out.credential) : undefined;
316
+ const cl = yield* S.client(mapping, r.configuration, false);
317
+
318
+ if (cl === undefined) return { _tag: "Rejected" } as const;
319
+ const f = mapping.flow;
320
+
321
+ if (out._tag !== "Verified") {
322
+ const held = yield* exact(mapping, r);
323
+
324
+ if (held === undefined) return { _tag: "Rejected" } as const;
325
+ yield* owner.update(f.table, held.key, {
326
+ [f.state]: out._tag,
327
+ [f.work]: out._tag === "Cancelled" ? "Resolved" : "Unresolved",
328
+ [f.version]: owner.marker,
329
+ });
330
+
331
+ return { _tag: out._tag };
332
+ }
333
+ const token = out.grant.context;
334
+
335
+ invariant(
336
+ token.moduleId === r.claim.flow.context.moduleId &&
337
+ token.subjectId === out.credential.revision.subjectId &&
338
+ sameIdentity(token.identity, out.credential.identity) &&
339
+ configurationStorage.encode(token.configuration) ===
340
+ configurationStorage.encode(r.configuration),
341
+ );
342
+ const native = yield* mapping.subjectId.toNative(token.subjectId);
343
+ const tuple = yield* F.readTuple(mapping.ownership, token.identity);
344
+ const t = mapping.ownership.tuple;
345
+
346
+ const owned =
347
+ tuple.row[t.state] === "Owned" && mapping.subjectId.equals(tuple.row[t.subjectId], native);
348
+
349
+ const co = yield* S.cohort(mapping, cl.id, tuple.key, true);
350
+ const previous = yield* S.readGrant(mapping, token.moduleId, token.grantId);
351
+
352
+ const activeSlot = yield* slot(
353
+ mapping,
354
+ token.moduleId,
355
+ native,
356
+ tuple.key,
357
+ token.configuration.profile.key,
358
+ );
359
+
360
+ const held = yield* exact(mapping, r);
361
+
362
+ if (held === undefined) return { _tag: "Rejected" } as const;
363
+ invariant(
364
+ token.exchangeOrder === r.order &&
365
+ validMetadata(token, held.now) &&
366
+ token.metadata.obtainedAtMillis >= r.claim.claimedAtMillis,
367
+ );
368
+
369
+ const target =
370
+ out.previous === undefined
371
+ ? previous === undefined
372
+ : previous !== undefined &&
373
+ F.sameTarget(out.previous, previous.context) &&
374
+ sameIdentity(previous.context.identity, token.identity) &&
375
+ previous.row[mapping.grant.refreshWork] !== "Unresolved" &&
376
+ canReplace(r, previous.context);
377
+
378
+ const previousSafe = yield* C.noFormerOwner(mapping, tuple.key, cl.id, native);
379
+
380
+ if (!owned || !previousSafe) {
381
+ yield* owner.update(f.table, held.key, { [f.state]: "Conflict", [f.version]: owner.marker });
382
+
383
+ return { _tag: "Conflict" } as const;
384
+ }
385
+ if (
386
+ out.quarantine ||
387
+ found === undefined ||
388
+ !held.active ||
389
+ !target ||
390
+ (activeSlot !== undefined && activeSlot.context.grantId !== token.grantId) ||
391
+ co.blocked ||
392
+ S.orderNumber(r.order) <= co.cutoff ||
393
+ co.generation !== token.cohortGeneration ||
394
+ token.metadata.useUntilMillis <= held.now ||
395
+ token.configuration.profile.issuance !== "active"
396
+ ) {
397
+ if (token.configuration.profile.revocation === "unsupported") {
398
+ // No remote cleanup can run for this profile. Discard the losing material;
399
+ // it must neither replace nor revoke the currently installed grant.
400
+ yield* owner.update(f.table, held.key, {
401
+ [f.state]: "Rejected",
402
+ [f.work]: "Resolved",
403
+ [f.subjectId]: native,
404
+ [f.cohortKey]: co.id,
405
+ [f.custody]: null,
406
+ [f.version]: owner.marker,
407
+ });
408
+ } else {
409
+ yield* C.fence(mapping, cl, co);
410
+ if (out.cleanup === undefined) return yield* unavailable();
411
+ yield* C.storeJob(mapping, out.cleanup, token, native, held.now);
412
+ yield* owner.update(f.table, held.key, {
413
+ [f.state]: "Quarantined",
414
+ [f.work]: "Resolved",
415
+ [f.subjectId]: native,
416
+ [f.cohortKey]: co.id,
417
+ [f.custody]: null,
418
+ [f.version]: owner.marker,
419
+ });
420
+ }
421
+
422
+ return { _tag: "Rejected" } as const;
423
+ }
424
+ yield* activateGrant(mapping, out.grant, native, held.now, previous !== undefined);
425
+ yield* owner.update(f.table, held.key, {
426
+ [f.state]: "Connected",
427
+ [f.work]: "Resolved",
428
+ [f.subjectId]: native,
429
+ [f.cohortKey]: co.id,
430
+ [f.custody]: null,
431
+ [f.version]: owner.marker,
432
+ });
433
+ owner.postconditions.push(
434
+ sql`${mapping.clock.engineNowMillis} >= ${held.now} and ${mapping.clock.engineNowMillis} < ${Math.min(r.claim.claimExpiresAtMillis, token.metadata.useUntilMillis)}`,
435
+ );
436
+
437
+ return { _tag: "Connected", grant: out.grant } as const;
438
+ });
@@ -173,13 +173,25 @@ const policyData = (input: OAuthConnectedPolicyInput<any>): OAuthConnectedPolicy
173
173
  ...input,
174
174
  subjectId: nativeCopy(input.subjectId),
175
175
  revision: snapshotOAuthSync(M.OAuthConnectedUseAuthorization.fields.revision, input.revision),
176
- authorization:
177
- input.kind === "action"
178
- ? snapshotOAuthSync(M.OAuthConnectedActionAuthorization, input.authorization)
179
- : snapshotOAuthSync(M.OAuthConnectedUseAuthorization, input.authorization),
180
- ...(input.kind === "action"
181
- ? { configuration: snapshotOAuthSync(M.OAuthConnectedConfiguration, input.configuration) }
182
- : {}),
176
+ ...(input.kind === "sign-in"
177
+ ? {
178
+ credential: snapshotOAuthSync(M.OAuthCredentialSnapshot, input.credential),
179
+ configuration: snapshotOAuthSync(M.OAuthConnectedConfiguration, input.configuration),
180
+ }
181
+ : {
182
+ authorization:
183
+ input.kind === "action"
184
+ ? snapshotOAuthSync(M.OAuthConnectedActionAuthorization, input.authorization)
185
+ : snapshotOAuthSync(M.OAuthConnectedUseAuthorization, input.authorization),
186
+ ...(input.kind === "action"
187
+ ? {
188
+ configuration: snapshotOAuthSync(
189
+ M.OAuthConnectedConfiguration,
190
+ input.configuration,
191
+ ),
192
+ }
193
+ : {}),
194
+ }),
183
195
  ...(input.grant === undefined
184
196
  ? {}
185
197
  : { grant: snapshotOAuthSync(M.OAuthConnectedTokenContext, input.grant) }),
@@ -1,4 +1,3 @@
1
- import { LifecycleHooks } from "@yielded/auth/Hooks";
2
1
  import * as M from "@yielded/auth/OAuth";
3
2
  import {
4
3
  OAuthConnectedPersistence,
@@ -10,7 +9,7 @@ import {
10
9
  } from "@yielded/auth/OAuth";
11
10
  /* oxlint-disable no-explicit-any -- concrete adapters retain the native database, table and ID types. */
12
11
  import { Effect, Layer, Schema } from "effect";
13
- import type { Statement } from "effect/unstable/sql/Statement";
12
+ import type { Statement } from "effect/sql/Statement";
14
13
 
15
14
  import type { PersistenceMappingError } from "./model";
16
15
  import * as A from "./oauth-connected-access";
@@ -19,6 +18,7 @@ import { connectedInputs, connectedRevocationInputs } from "./oauth-connected-in
19
18
  import * as Maintenance from "./oauth-connected-maintenance";
20
19
  import * as Management from "./oauth-connected-management";
21
20
  import { settle } from "./oauth-connected-settlement";
21
+ import * as SignIn from "./oauth-connected-sign-in";
22
22
  import * as S from "./oauth-connected-state";
23
23
  import { capturedOAuthService } from "./oauth-input";
24
24
  import { CurrentOAuthTransaction } from "./oauth-owner";
@@ -124,6 +124,14 @@ export const makeConnected = (
124
124
  ): OAuthConnectedPersistence["Service"] =>
125
125
  capturedOAuthService<OAuthConnectedPersistence["Service"]>(
126
126
  {
127
+ claimSignIn: mutation(mapping, execute, SignIn.claimSignIn, M.OAuthSignInAccessClaim),
128
+ inspectSignIn: read(mapping, execute, SignIn.inspectSignIn),
129
+ settleSignIn: mutation(
130
+ mapping,
131
+ execute,
132
+ SignIn.settleSignIn,
133
+ M.OAuthConnectedSettlementDecision,
134
+ ),
127
135
  capture: read(mapping, execute, F.capture),
128
136
  issue: mutation(mapping, execute, F.issue, M.OAuthConnectedIssueDecision),
129
137
  preflight: read(mapping, execute, F.preflight),
@@ -176,32 +184,24 @@ export const makeRevocations = (
176
184
  );
177
185
 
178
186
  export const makeTargetOAuthConnectedServices = (
179
- database: any,
180
187
  mapping: S.Mapping,
181
188
  configuration: OAuthTargetConfiguration,
182
189
  ) => {
183
190
  const retained = captured(mapping);
184
191
 
185
- return Effect.map(LifecycleHooks, (hooks) => ({
186
- oauthConnectedPersistence: makeConnected(
187
- retained,
188
- makeOAuthExecution(database, hooks, configuration),
189
- ),
192
+ return Effect.map(makeOAuthExecution(configuration), (execution) => ({
193
+ oauthConnectedPersistence: makeConnected(retained, execution),
190
194
  }));
191
195
  };
192
196
 
193
197
  export const makeTargetOAuthConnectedRevocationServices = (
194
- database: any,
195
198
  mapping: S.Revocations,
196
199
  configuration: OAuthTargetConfiguration,
197
200
  ) => {
198
201
  const retained = captured(mapping);
199
202
 
200
- return Effect.map(LifecycleHooks, (hooks) => ({
201
- oauthConnectedRevocations: makeRevocations(
202
- retained,
203
- makeOAuthExecution(database, hooks, configuration),
204
- ),
203
+ return Effect.map(makeOAuthExecution(configuration), (execution) => ({
204
+ oauthConnectedRevocations: makeRevocations(retained, execution),
205
205
  }));
206
206
  };
207
207
 
@@ -247,16 +247,24 @@ export const coordinateTargetOAuthConnectedRevocations = <Transaction, A, E, R>(
247
247
  owner,
248
248
  );
249
249
 
250
- export const oauthConnectedPersistenceLayer = (
251
- services: ReturnType<typeof makeTargetOAuthConnectedServices>,
250
+ export const oauthConnectedPersistenceLayer = <E, R>(
251
+ services: Effect.Effect<
252
+ Effect.Success<ReturnType<typeof makeTargetOAuthConnectedServices>>,
253
+ E,
254
+ R
255
+ >,
252
256
  ) =>
253
257
  Layer.effect(
254
258
  OAuthConnectedPersistence,
255
259
  Effect.map(services, (value) => value.oauthConnectedPersistence),
256
260
  );
257
261
 
258
- export const oauthConnectedRevocationsLayer = (
259
- services: ReturnType<typeof makeTargetOAuthConnectedRevocationServices>,
262
+ export const oauthConnectedRevocationsLayer = <E, R>(
263
+ services: Effect.Effect<
264
+ Effect.Success<ReturnType<typeof makeTargetOAuthConnectedRevocationServices>>,
265
+ E,
266
+ R
267
+ >,
260
268
  ) =>
261
269
  Layer.effect(
262
270
  OAuthConnectedRevocations,
@@ -1,3 +1,4 @@
1
+ import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
1
2
  import type { LifecycleHooks } from "@yielded/auth/Hooks";
2
3
  import {
3
4
  OAuthAccountsPersistence,
@@ -7,6 +8,7 @@ import {
7
8
  import type { Table } from "drizzle-orm";
8
9
  import { Effect, Context } from "effect";
9
10
 
11
+ import { nativeDatabase } from "./native-database";
10
12
  import { makeOAuthConnectedTarget } from "./oauth-connected-drivers";
11
13
  import type {
12
14
  OAuthAccountsMapping,
@@ -35,7 +37,13 @@ type TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => an
35
37
  : never;
36
38
 
37
39
  /** Driver-specific entry points instantiate both the database and table family. */
38
- export const makeOAuthTarget = <D, T extends Table, Synchronous extends boolean = false>(
40
+ export const makeOAuthTarget = <
41
+ DatabaseId,
42
+ D,
43
+ T extends Table,
44
+ Synchronous extends boolean = false,
45
+ >(
46
+ databaseService: Context.Service<DatabaseId, D>,
39
47
  configuration: OAuthTargetConfiguration,
40
48
  ) => {
41
49
  function coordinateOAuthSignIn<
@@ -516,7 +524,7 @@ export const makeOAuthTarget = <D, T extends Table, Synchronous extends boolean
516
524
  }
517
525
 
518
526
  return {
519
- ...makeOAuthConnectedTarget<D, T, {}, Synchronous>(configuration),
527
+ ...makeOAuthConnectedTarget<DatabaseId, D, T, {}, Synchronous>(databaseService, configuration),
520
528
  coordinateOAuthSignIn,
521
529
  coordinateOAuthRegistrationIntents,
522
530
  coordinateOAuthAccounts,
@@ -530,13 +538,17 @@ export const makeOAuthTarget = <D, T extends Table, Synchronous extends boolean
530
538
  U extends T,
531
539
  N,
532
540
  >(
533
- database: D,
534
541
  mapping: OAuthAccountsMapping<S, O, C, AC, F, TA, U, N>,
535
- ) => makeTargetOAuthAccountsServices(database, mapping, configuration),
542
+ ) =>
543
+ makeTargetOAuthAccountsServices(mapping, configuration).pipe(
544
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),
545
+ ),
536
546
  makeOAuthSignInServices: <S extends T, O extends T, C extends T, AC extends T, F extends T, N>(
537
- database: D,
538
547
  mapping: OAuthSignInMapping<S, O, C, AC, F, N>,
539
- ) => makeTargetOAuthSignInServices(database, mapping, configuration),
548
+ ) =>
549
+ makeTargetOAuthSignInServices(mapping, configuration).pipe(
550
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),
551
+ ),
540
552
  makeOAuthRegistrationIntentServices: <
541
553
  S extends T,
542
554
  O extends T,
@@ -547,9 +559,11 @@ export const makeOAuthTarget = <D, T extends Table, Synchronous extends boolean
547
559
  I extends T,
548
560
  N,
549
561
  >(
550
- database: D,
551
562
  mapping: OAuthRegistrationIntentMapping<S, O, C, AC, F, TA, I, N>,
552
- ) => makeTargetOAuthRegistrationIntentServices(database, mapping, configuration),
563
+ ) =>
564
+ makeTargetOAuthRegistrationIntentServices(mapping, configuration).pipe(
565
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),
566
+ ),
553
567
  makeOAuthRegistrationServices: <
554
568
  Registration,
555
569
  S extends T,
@@ -561,9 +575,11 @@ export const makeOAuthTarget = <D, T extends Table, Synchronous extends boolean
561
575
  R extends T,
562
576
  N,
563
577
  >(
564
- database: D,
565
578
  mapping: OAuthRegistrationMapping<Registration, S, O, C, AC, TA, I, R, N>,
566
- ) => makeTargetOAuthRegistrationServices<Registration>(database, mapping, configuration),
579
+ ) =>
580
+ makeTargetOAuthRegistrationServices<Registration>(mapping, configuration).pipe(
581
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),
582
+ ),
567
583
  coordinateOAuthRegistration,
568
584
  };
569
585
  };
@@ -10,7 +10,8 @@ import {
10
10
  snapshotOAuthSync,
11
11
  } from "@yielded/auth/OAuth";
12
12
  import type { AuthenticationRequirement } from "@yielded/auth/Sessions";
13
- import { DateTime, Effect, Encoding, Schema } from "effect";
13
+ import { DateTime, Effect, Schema } from "effect";
14
+ import { Base64Url } from "effect/encoding";
14
15
 
15
16
  const encoder = new TextEncoder();
16
17
  const decoder = new TextDecoder("utf-8", { fatal: true });
@@ -21,8 +22,8 @@ export const invariant: (value: unknown) => asserts value = (value) => {
21
22
  if (!value) throw unavailable();
22
23
  };
23
24
 
24
- export const nonce = () => Encoding.encodeBase64Url(randomBytes(32));
25
- export const digest = (value: string) => Encoding.encodeBase64Url(sha256(encoder.encode(value)));
25
+ export const nonce = () => Base64Url.encode(randomBytes(32));
26
+ export const digest = (value: string) => Base64Url.encode(sha256(encoder.encode(value)));
26
27
 
27
28
  /** Capture configuration/callback references while preserving Drizzle table, SQL
28
29
  * and Effect objects. Never freeze or mutate the consumer's original graph. */
@@ -84,7 +85,7 @@ export const oauthIdentityKey = (input: typeof OAuthExternalIdentity.Type): stri
84
85
  offset += 4 + value.length;
85
86
  }
86
87
 
87
- return "v1:" + Encoding.encodeBase64Url(sha256(packed));
88
+ return "v1:" + Base64Url.encode(sha256(packed));
88
89
  };
89
90
 
90
91
  export const sameIdentity = (