@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
@@ -5,10 +5,13 @@ import type { AnyRelations } from "drizzle-orm";
5
5
  import type { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
6
6
  import type { AnyMySqlTable } from "drizzle-orm/mysql-core";
7
7
  import { Effect, Context } from "effect";
8
- import type { SqlError } from "effect/unstable/sql/SqlError";
8
+ import type { SqlError } from "effect/sql/SqlError";
9
9
 
10
+ import { Database as DatabaseService } from "./mysql-database";
11
+ import { nativeDatabase } from "./native-database";
10
12
  import type { PasswordPersistenceMapping, PasswordRegistrationMapping } from "./password-model";
11
13
  import type { PasswordRegistrationAuthority } from "./password-registration";
14
+ import { CurrentPasswordSql } from "./password-sql";
12
15
  import type { PasswordSqlQuery } from "./password-sql";
13
16
  import {
14
17
  coordinateTargetPasswordPersistence,
@@ -20,22 +23,27 @@ import {
20
23
  import type { ProofPersistenceMapping } from "./proof-model";
21
24
  import type { ProofSqlQuery } from "./proof-sql";
22
25
  import { sqlClientProofStandaloneGuard } from "./proof-target";
26
+ import {
27
+ type TransactionService,
28
+ acquireTransactionService,
29
+ transactionService,
30
+ } from "./standalone-guard";
23
31
  import type { SuppliedService } from "./SuppliedService";
24
32
 
25
33
  type Database = EffectMysql2Database<AnyRelations>;
26
34
  type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
27
35
 
28
- const configuration = (database: Database) => ({
36
+ const configuration = (service: TransactionService | undefined) => ({
29
37
  mode: "interactive" as const,
30
38
  locking: true,
31
- standaloneGuard: sqlClientPasswordStandaloneGuard(database),
39
+ standaloneGuard: sqlClientPasswordStandaloneGuard(service),
32
40
  insertIfAbsent: (query: PasswordSqlQuery, selfKey: string, selfValue: unknown) =>
33
41
  query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } }),
34
42
  generatedSubjectRows: (query: PasswordSqlQuery) => query.$returningId(),
35
43
  proof: {
36
44
  mode: "interactive" as const,
37
45
  locking: true,
38
- standaloneGuard: sqlClientProofStandaloneGuard(database),
46
+ standaloneGuard: sqlClientProofStandaloneGuard(service),
39
47
  insertIfAbsent: (query: ProofSqlQuery, selfKey: string, selfValue: unknown) =>
40
48
  query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } }),
41
49
  },
@@ -64,7 +72,6 @@ export const makeMysqlPasswordPersistenceServices = <
64
72
  M extends AnyMySqlTable,
65
73
  NativeId,
66
74
  >(
67
- database: Database,
68
75
  mapping: Mapping<S, I, C, AC, A, RS, CE, M, NativeId>,
69
76
  proofMapping?: ProofPersistenceMapping<
70
77
  any,
@@ -81,7 +88,10 @@ export const makeMysqlPasswordPersistenceServices = <
81
88
  any
82
89
  >,
83
90
  ) =>
84
- makeTargetPasswordPersistenceServices(database, mapping, configuration(database), proofMapping);
91
+ Effect.flatMap(
92
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
93
+ (configuration) => makeTargetPasswordPersistenceServices(mapping, configuration, proofMapping),
94
+ ).pipe(Effect.provideServiceEffect(CurrentPasswordSql, nativeDatabase(DatabaseService)));
85
95
 
86
96
  export function coordinateMysqlPasswordPersistence<
87
97
  D extends Database,
@@ -189,7 +199,7 @@ export function coordinateMysqlPasswordPersistence<
189
199
  coordinateTargetPasswordPersistence<TransactionOf<D>, Out, E, Exclude<R, PasswordPersistence>>(
190
200
  database,
191
201
  options.mapping,
192
- configuration(database),
202
+ configuration(transactionService(database)),
193
203
  options.proofMapping,
194
204
  (
195
205
  transaction: TransactionOf<D>,
@@ -215,10 +225,12 @@ export const makeMysqlPasswordRegistrationServices = <
215
225
  Rq extends AnyMySqlTable,
216
226
  NativeId,
217
227
  >(
218
- database: Database,
219
228
  mapping: PasswordRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>,
220
229
  ) =>
221
- makeTargetPasswordRegistrationServices<Registration>(database, mapping, configuration(database));
230
+ Effect.flatMap(
231
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
232
+ (configuration) => makeTargetPasswordRegistrationServices<Registration>(mapping, configuration),
233
+ ).pipe(Effect.provideServiceEffect(CurrentPasswordSql, nativeDatabase(DatabaseService)));
222
234
 
223
235
  export function coordinateMysqlPasswordRegistration<
224
236
  TargetId,
@@ -320,7 +332,7 @@ export function coordinateMysqlPasswordRegistration<
320
332
  >(
321
333
  database,
322
334
  options.mapping,
323
- configuration(database),
335
+ configuration(transactionService(database)),
324
336
  (
325
337
  transaction: TransactionOf<D>,
326
338
  services: { readonly registrationAuthority: PasswordRegistrationAuthority<Registration> },
@@ -4,16 +4,24 @@ import type { AnyRelations } from "drizzle-orm";
4
4
  import type { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
5
5
  import type { AnyMySqlTable } from "drizzle-orm/mysql-core";
6
6
  import { Effect, Context } from "effect";
7
- import type { SqlError } from "effect/unstable/sql/SqlError";
7
+ import type { SqlError } from "effect/sql/SqlError";
8
8
 
9
9
  import { updateValues } from "./model";
10
+ import { Database as DatabaseService } from "./mysql-database";
11
+ import { nativeDatabase } from "./native-database";
10
12
  import type { ProofPersistenceMapping } from "./proof-model";
13
+ import { CurrentProofSql } from "./proof-sql";
11
14
  import type { ProofSqlQuery } from "./proof-sql";
12
15
  import {
13
16
  coordinateTargetProofPersistence,
14
17
  makeTargetProofPersistenceServices,
15
18
  sqlClientProofStandaloneGuard,
16
19
  } from "./proof-target";
20
+ import {
21
+ type TransactionService,
22
+ acquireTransactionService,
23
+ transactionService,
24
+ } from "./standalone-guard";
17
25
  import type { SuppliedService } from "./SuppliedService";
18
26
 
19
27
  type Database = EffectMysql2Database<AnyRelations>;
@@ -33,10 +41,10 @@ type Mapping<
33
41
  NativeId,
34
42
  > = ProofPersistenceMapping<Rq, S, G, Cn, Rs, A, F, C, Sub, I, Cr, NativeId>;
35
43
 
36
- const configuration = (database: Database) => ({
44
+ const configuration = (service: TransactionService | undefined) => ({
37
45
  mode: "interactive" as const,
38
46
  locking: true,
39
- standaloneGuard: sqlClientProofStandaloneGuard(database),
47
+ standaloneGuard: sqlClientProofStandaloneGuard(service),
40
48
  insertIfAbsent: (query: ProofSqlQuery, selfKey: string, selfValue: unknown) =>
41
49
  query.onDuplicateKeyUpdate({
42
50
  set: updateValues([[selfKey, selfValue]]),
@@ -57,9 +65,12 @@ export const makeMysqlProofPersistenceServices = <
57
65
  Cr extends AnyMySqlTable,
58
66
  NativeId,
59
67
  >(
60
- database: Database,
61
68
  mapping: Mapping<Rq, S, G, Cn, Rs, A, F, C, Sub, I, Cr, NativeId>,
62
- ) => makeTargetProofPersistenceServices(database, mapping, configuration(database));
69
+ ) =>
70
+ Effect.flatMap(
71
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
72
+ (configuration) => makeTargetProofPersistenceServices(mapping, configuration),
73
+ ).pipe(Effect.provideServiceEffect(CurrentProofSql, nativeDatabase(DatabaseService)));
63
74
 
64
75
  export function coordinateMysqlProofPersistence<
65
76
  D extends Database,
@@ -164,7 +175,7 @@ export function coordinateMysqlProofPersistence<
164
175
  coordinateTargetProofPersistence<Transaction, A, E, Exclude<R, ProofPersistence>>(
165
176
  database,
166
177
  options.mapping,
167
- configuration(database),
178
+ configuration(transactionService(database)),
168
179
  (
169
180
  transaction: Transaction,
170
181
  services: { readonly proofPersistence: ProofPersistence["Service"] },
@@ -12,14 +12,17 @@ import type { AnyRelations } from "drizzle-orm";
12
12
  import type { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
13
13
  import type { AnyMySqlTable } from "drizzle-orm/mysql-core";
14
14
  import { Effect, Context } from "effect";
15
- import type { SqlError } from "effect/unstable/sql/SqlError";
15
+ import type { SqlError } from "effect/sql/SqlError";
16
16
 
17
+ import { Database as DatabaseService } from "./mysql-database";
18
+ import { nativeDatabase } from "./native-database";
17
19
  import type {
18
20
  AuthenticationAuthorityMapping,
19
21
  PendingAuthenticationMapping,
20
22
  SignedSessionValidityMapping,
21
23
  StatefulSessionMapping,
22
24
  } from "./session-model";
25
+ import { CurrentSessionSql } from "./session-sql";
23
26
  import {
24
27
  coordinateTargetAuthenticationAuthority,
25
28
  coordinateTargetPendingAuthentication,
@@ -33,15 +36,20 @@ import {
33
36
  makeTargetSessionStepUpServices,
34
37
  coordinateTargetSessionStepUp,
35
38
  } from "./session-target";
39
+ import {
40
+ type TransactionService,
41
+ acquireTransactionService,
42
+ transactionService,
43
+ } from "./standalone-guard";
36
44
  import type { SuppliedService } from "./SuppliedService";
37
45
 
38
46
  type Database = EffectMysql2Database<AnyRelations>;
39
47
  type Transaction = Parameters<Parameters<Database["transaction"]>[0]>[0];
40
48
 
41
- const configuration = (database: Database) => ({
49
+ const configuration = (service: TransactionService | undefined) => ({
42
50
  mode: "interactive" as const,
43
51
  locking: true,
44
- standaloneGuard: sqlClientSessionStandaloneGuard(database),
52
+ standaloneGuard: sqlClientSessionStandaloneGuard(service),
45
53
  });
46
54
 
47
55
  export const makeMysqlAuthenticationAuthorityServices = <
@@ -52,9 +60,12 @@ export const makeMysqlAuthenticationAuthorityServices = <
52
60
  P extends AnyMySqlTable,
53
61
  NativeId,
54
62
  >(
55
- database: Database,
56
63
  mapping: AuthenticationAuthorityMapping<Claims, S, C, F, P, NativeId>,
57
- ) => makeTargetAuthenticationAuthorityServices<Claims>(database, mapping, configuration(database));
64
+ ) =>
65
+ Effect.flatMap(
66
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
67
+ (configuration) => makeTargetAuthenticationAuthorityServices<Claims>(mapping, configuration),
68
+ ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
58
69
 
59
70
  export const makeMysqlPendingAuthenticationServices = <
60
71
  Claims,
@@ -64,9 +75,12 @@ export const makeMysqlPendingAuthenticationServices = <
64
75
  F extends AnyMySqlTable,
65
76
  NativeId,
66
77
  >(
67
- database: Database,
68
78
  mapping: PendingAuthenticationMapping<Claims, S, C, P, F, NativeId>,
69
- ) => makeTargetPendingAuthenticationServices<Claims>(database, mapping, configuration(database));
79
+ ) =>
80
+ Effect.flatMap(
81
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
82
+ (configuration) => makeTargetPendingAuthenticationServices<Claims>(mapping, configuration),
83
+ ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
70
84
 
71
85
  export const makeMysqlStatefulSessionServices = <
72
86
  Claims,
@@ -78,9 +92,12 @@ export const makeMysqlStatefulSessionServices = <
78
92
  NativeId,
79
93
  NativeSessionId,
80
94
  >(
81
- database: Database,
82
95
  mapping: StatefulSessionMapping<Claims, S, C, Session, F, P, NativeId, NativeSessionId>,
83
- ) => makeTargetStatefulSessionServices<Claims>(database, mapping, configuration(database));
96
+ ) =>
97
+ Effect.flatMap(
98
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
99
+ (configuration) => makeTargetStatefulSessionServices<Claims>(mapping, configuration),
100
+ ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
84
101
 
85
102
  export const makeMysqlSignedSessionValidityServices = <
86
103
  S extends AnyMySqlTable,
@@ -88,9 +105,12 @@ export const makeMysqlSignedSessionValidityServices = <
88
105
  NativeId,
89
106
  NativeSessionId,
90
107
  >(
91
- database: Database,
92
108
  mapping: SignedSessionValidityMapping<S, T, NativeId, NativeSessionId>,
93
- ) => makeTargetSignedSessionValidityServices(database, mapping, configuration(database));
109
+ ) =>
110
+ Effect.flatMap(
111
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
112
+ (configuration) => makeTargetSignedSessionValidityServices(mapping, configuration),
113
+ ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
94
114
 
95
115
  export function coordinateMysqlAuthenticationAuthority<
96
116
  D extends Database,
@@ -183,7 +203,7 @@ export function coordinateMysqlAuthenticationAuthority<
183
203
  >(
184
204
  database,
185
205
  options.mapping,
186
- configuration(database),
206
+ configuration(transactionService(database)),
187
207
  (
188
208
  transaction: Transaction,
189
209
  services: { readonly authenticationAuthority: AuthenticationAuthority["Service"] },
@@ -290,7 +310,7 @@ export function coordinateMysqlPendingAuthentication<
290
310
  coordinateTargetPendingAuthentication<Claims, Transaction, A, E, Exclude<R, TargetId>>(
291
311
  database,
292
312
  options.mapping,
293
- configuration(database),
313
+ configuration(transactionService(database)),
294
314
  (
295
315
  transaction: Transaction,
296
316
  services: { readonly pendingAuthentication: PendingAuthentication<Claims> },
@@ -442,7 +462,7 @@ export function coordinateMysqlStatefulSessions<
442
462
  >(
443
463
  database,
444
464
  options.mapping,
445
- configuration(database),
465
+ configuration(transactionService(database)),
446
466
  (
447
467
  transaction: Transaction,
448
468
  services: {
@@ -550,7 +570,7 @@ export function coordinateMysqlSignedSessionValidity<
550
570
  coordinateTargetSignedSessionValidity<Transaction, A, E, Exclude<R, TargetId>>(
551
571
  database,
552
572
  options.mapping,
553
- configuration(database),
573
+ configuration(transactionService(database)),
554
574
  (
555
575
  transaction: Transaction,
556
576
  services: { readonly signedSessionValidity: SignedSessionValidity },
@@ -579,10 +599,13 @@ export const makeMysqlSessionStepUpServices = <
579
599
  NativeId,
580
600
  NativeSessionId,
581
601
  >(
582
- database: Database,
583
602
  mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, I, Session, T, NativeId, NativeSessionId>,
584
603
  target: Context.Service<Id, SessionStepUpPersistence<Claims>>,
585
- ) => makeTargetSessionStepUpServices(database, mapping, target, configuration(database));
604
+ ) =>
605
+ Effect.flatMap(
606
+ Effect.map(acquireTransactionService(DatabaseService), configuration),
607
+ (configuration) => makeTargetSessionStepUpServices(mapping, target, configuration),
608
+ ).pipe(Effect.provideServiceEffect(CurrentSessionSql, nativeDatabase(DatabaseService)));
586
609
 
587
610
  export function coordinateMysqlSessionStepUp<
588
611
  Claims,
@@ -724,7 +747,7 @@ export function coordinateMysqlSessionStepUp<
724
747
  database,
725
748
  options.mapping,
726
749
  options.target,
727
- configuration(database),
750
+ configuration(transactionService(database)),
728
751
  (
729
752
  transaction: Parameters<Parameters<D["transaction"]>[0]>[0],
730
753
  services: { readonly sessionStepUpPersistence: SessionStepUpPersistence<Claims> },
@@ -0,0 +1,22 @@
1
+ import type {
2
+ TransactionNativeDatabase,
3
+ SessionSqlDatabase,
4
+ PasswordSqlDatabase,
5
+ EmailSqlDatabase,
6
+ ProofSqlDatabase,
7
+ } from "@yielded/auth-persistence/Adapter";
8
+ import { type Context, Effect } from "effect";
9
+
10
+ /** Drizzle omits its captured $client from database class types, and only D1
11
+ * exposes batch. Its generic query builders implement the SQL kernel contracts
12
+ * through drizzleQueryOperations. The selected driver mode controls native calls. */
13
+ export const nativeDatabase = <Id, Database>(databaseService: Context.Key<Id, Database>) =>
14
+ Effect.map(
15
+ Effect.service(databaseService),
16
+ (database) =>
17
+ database as unknown as TransactionNativeDatabase &
18
+ SessionSqlDatabase &
19
+ PasswordSqlDatabase &
20
+ EmailSqlDatabase &
21
+ ProofSqlDatabase,
22
+ );
@@ -132,6 +132,7 @@ export const claimRefresh = Effect.fn("oauthConnected.claimRefresh")(function* (
132
132
 
133
133
  const claim = snapshotOAuthSync(M.OAuthConnectedRefreshClaim, {
134
134
  grant: input.grant,
135
+ order: String(yield* S.nextOrder(mapping, read.client)),
135
136
  claimId: input.claimId,
136
137
  claimedAtMillis: read.now,
137
138
  claimExpiresAtMillis: expires,
@@ -204,10 +205,16 @@ export const settleRefresh = Effect.fn("oauthConnected.settleRefresh")(function*
204
205
  if (incoming !== undefined)
205
206
  invariant(
206
207
  C.sameContext(
207
- { ...incoming.context, tokenVersion: old.tokenVersion, metadata: old.metadata },
208
+ {
209
+ ...incoming.context,
210
+ tokenVersion: old.tokenVersion,
211
+ metadata: old.metadata,
212
+ exchangeOrder: old.exchangeOrder,
213
+ },
208
214
  old,
209
215
  ) &&
210
216
  incoming.context.tokenVersion === input.claim.nextTokenVersion &&
217
+ incoming.context.exchangeOrder === input.claim.order &&
211
218
  validMetadata(incoming.context, now) &&
212
219
  incoming.context.metadata.obtainedAtMillis >= input.claim.claimedAtMillis &&
213
220
  (incoming.context.metadata.refreshUseUntilMillis === undefined ||
@@ -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
  OAuthConnectedPersistence,
@@ -9,6 +10,7 @@ import { Effect, Context } from "effect";
9
10
 
10
11
  import { makeD1Owner } from "./d1-planning";
11
12
  import { D1BatchStatements } from "./D1BatchStatements";
13
+ import { nativeDatabase } from "./native-database";
12
14
  import type {
13
15
  OAuthConnectedMapping,
14
16
  OAuthConnectedRevocationMapping,
@@ -28,11 +30,13 @@ type TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => an
28
30
  const unavailable = () => OAuthUnavailable.make({});
29
31
 
30
32
  export const makeOAuthConnectedTarget = <
33
+ DatabaseId,
31
34
  Database,
32
35
  Family extends Table,
33
36
  Extra = {},
34
37
  Synchronous extends boolean = false,
35
38
  >(
39
+ databaseService: Context.Service<DatabaseId, Database>,
36
40
  configuration: OAuthTargetConfiguration,
37
41
  ) => {
38
42
  function coordinateOAuthConnected<
@@ -300,9 +304,11 @@ export const makeOAuthConnectedTarget = <
300
304
  N,
301
305
  J extends Family = never,
302
306
  >(
303
- database: Database,
304
307
  mapping: OAuthConnectedMapping<S, AC, T, O, F, G, C, H, UA, DC, N, J> & Extra,
305
- ) => makeTargetOAuthConnectedServices(database, mapping, configuration),
308
+ ) =>
309
+ makeTargetOAuthConnectedServices(mapping, configuration).pipe(
310
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),
311
+ ),
306
312
  makeOAuthConnectedRevocationServices: <
307
313
  T extends Family,
308
314
  O extends Family,
@@ -313,15 +319,18 @@ export const makeOAuthConnectedTarget = <
313
319
  J extends Family,
314
320
  N,
315
321
  >(
316
- database: Database,
317
322
  mapping: OAuthConnectedRevocationMapping<T, O, F, G, C, H, J, N> & Extra,
318
- ) => makeTargetOAuthConnectedRevocationServices(database, mapping, configuration),
323
+ ) =>
324
+ makeTargetOAuthConnectedRevocationServices(mapping, configuration).pipe(
325
+ Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),
326
+ ),
319
327
  coordinateOAuthConnected,
320
328
  coordinateOAuthConnectedRevocations,
321
329
  };
322
330
  };
323
331
 
324
- export const makeD1OAuthConnectedTarget = <Database, Family extends Table, Extra>(
332
+ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends Table, Extra>(
333
+ databaseService: Context.Service<DatabaseId, Database>,
325
334
  configuration: OAuthTargetConfiguration,
326
335
  ) => {
327
336
  function coordinateOAuthConnected<
@@ -374,6 +383,9 @@ export const makeD1OAuthConnectedTarget = <Database, Family extends Table, Extra
374
383
  );
375
384
 
376
385
  const service: OAuthConnectedPersistence["Service"] = {
386
+ claimSignIn: (input, prepare) => owner.run(original.claimSignIn(input, prepare)),
387
+ inspectSignIn: (input) => owner.run(original.inspectSignIn(input)),
388
+ settleSignIn: (input, prepare) => owner.run(original.settleSignIn(input, prepare)),
377
389
  capture: (input) => owner.run(original.capture(input)),
378
390
  issue: (input, prepare) => owner.run(original.issue(input, prepare)),
379
391
  preflight: (input) => owner.run(original.preflight(input)),
@@ -458,7 +470,10 @@ export const makeD1OAuthConnectedTarget = <Database, Family extends Table, Extra
458
470
  }
459
471
 
460
472
  return {
461
- ...makeOAuthConnectedTarget<Database, Family, Extra>(configuration),
473
+ ...makeOAuthConnectedTarget<DatabaseId, Database, Family, Extra>(
474
+ databaseService,
475
+ configuration,
476
+ ),
462
477
  coordinateOAuthConnected,
463
478
  coordinateOAuthConnectedRevocations,
464
479
  };
@@ -105,6 +105,19 @@ const snapshot =
105
105
  snapshotOAuthSync(schema, input);
106
106
 
107
107
  export const connectedInputs = {
108
+ claimSignIn: snapshot(
109
+ Schema.Struct({ claim: M.OAuthClaim, configuration: M.OAuthConnectedConfiguration }),
110
+ ),
111
+ inspectSignIn: snapshot(
112
+ Schema.Struct({
113
+ reservation: M.OAuthSignInAccessClaim,
114
+ credential: M.OAuthCredentialSnapshot,
115
+ grantId: M.OAuthGrantId,
116
+ }),
117
+ ),
118
+ settleSignIn: snapshot(
119
+ Schema.Struct({ reservation: M.OAuthSignInAccessClaim, outcome: M.OAuthSignInAccessOutcome }),
120
+ ),
108
121
  capture: snapshot(capture),
109
122
  issue: snapshot(issue),
110
123
  preflight: snapshot(M.OAuthConnectedAccess),
@@ -7,6 +7,8 @@ import type { SubjectIdCodec } from "./model";
7
7
  import type {
8
8
  OAuthAuthorityReadTable,
9
9
  OAuthClock,
10
+ OAuthCredentialReadTable,
11
+ OAuthFlowTable,
10
12
  OAuthOwnershipMutation,
11
13
  OAuthSubjectReadTable,
12
14
  requiredOAuthTupleConstraints,
@@ -53,6 +55,9 @@ export interface OAuthConnectedFlowTable<F extends Table, N> {
53
55
  readonly work: Column<F>;
54
56
  /** Exact sealed quarantine when no correctly sealed revocation job is available. */
55
57
  readonly custody: Column<F>;
58
+ /** Required when retaining grants during sign-in. subjectId is NULL until
59
+ * identity resolution; custom required columns are supplied by this encoder. */
60
+ readonly encodeSignIn?: (reservation: M.OAuthSignInAccessClaim) => InferInsertModel<F>;
56
61
  readonly encodeInsert: (input: {
57
62
  readonly flow: M.OAuthConnectedPendingFlow;
58
63
  readonly subjectId: N;
@@ -192,6 +197,12 @@ export type OAuthConnectedPolicyInput<N> = {
192
197
  readonly configuration: M.OAuthConnectedConfiguration;
193
198
  readonly grant?: M.OAuthConnectedTokenContext;
194
199
  }
200
+ | {
201
+ readonly kind: "sign-in";
202
+ readonly credential: M.OAuthCredentialSnapshot;
203
+ readonly configuration: M.OAuthConnectedConfiguration;
204
+ readonly grant?: M.OAuthConnectedTokenContext;
205
+ }
195
206
  | {
196
207
  readonly kind: "metadata" | "use";
197
208
  readonly authorization: M.OAuthConnectedUseAuthorization;
@@ -307,6 +318,12 @@ export interface OAuthConnectedMapping<
307
318
  readonly subject: OAuthConnectedSubjectTable<S>;
308
319
  readonly authority: OAuthAuthorityReadTable<AC>;
309
320
  readonly admission: OAuthConnectedAdmissionTable<A, N>;
321
+ /** Same shared sign-in tables used by OAuthSignInPersistence. Enable only
322
+ * alongside a nullable connected-flow subjectId and flow.encodeSignIn. */
323
+ readonly signIn?: {
324
+ readonly credential: OAuthCredentialReadTable<Table>;
325
+ readonly flow: OAuthFlowTable<Table>;
326
+ };
310
327
  readonly command: OAuthConnectedCommandTable<D, N>;
311
328
  readonly policy: OAuthConnectedSqlPolicy<N>;
312
329
  readonly constraints: typeof requiredOAuthConnectedConstraints;
@@ -7,7 +7,7 @@ import * as C from "./oauth-connected-custody";
7
7
  import * as F from "./oauth-connected-flow";
8
8
  import * as S from "./oauth-connected-state";
9
9
  import { both, col, equal, CurrentOAuthTransaction } from "./oauth-owner";
10
- import { invariant, sameIdentity } from "./oauth-state";
10
+ import { invariant, sameIdentity, oauthIdentityKey } from "./oauth-state";
11
11
 
12
12
  export const validMetadata = (context: M.OAuthConnectedTokenContext, now: number) => {
13
13
  const m = context.metadata,
@@ -35,6 +35,67 @@ export const validMetadata = (context: M.OAuthConnectedTokenContext, now: number
35
35
  );
36
36
  };
37
37
 
38
+ /** The only writer that activates or replaces a confirmed connected grant. */
39
+ export const activateGrant = Effect.fn("oauthConnected.activateGrant")(function* (
40
+ mapping: S.Mapping,
41
+ grant: M.OAuthConnectedStoredGrant,
42
+ native: unknown,
43
+ now: number,
44
+ replacing: boolean,
45
+ ) {
46
+ const owner = yield* CurrentOAuthTransaction;
47
+ const token = grant.context;
48
+ const g = mapping.grant;
49
+ const identityKey = oauthIdentityKey(token.identity);
50
+ const clientKey = S.clientKey(token.configuration);
51
+ const cohortKey = S.cohortKey(clientKey, identityKey);
52
+
53
+ const values = {
54
+ ...g.encodeInsert({
55
+ grant: snapshotOAuthSync(M.OAuthConnectedStoredGrant, grant),
56
+ subjectId: S.nativeCopy(native),
57
+ }),
58
+ [g.moduleId]: token.moduleId,
59
+ [g.grantId]: token.grantId,
60
+ [g.subjectId]: native,
61
+ [g.identityKey]: identityKey,
62
+ [g.activeIdentityKey]: identityKey,
63
+ [g.clientKey]: clientKey,
64
+ [g.cohortKey]: cohortKey,
65
+ [g.profileKey]: token.configuration.profile.key,
66
+ [g.grantVersion]: token.grantVersion,
67
+ [g.tokenVersion]: token.tokenVersion,
68
+ [g.cohortGeneration]: token.cohortGeneration,
69
+ [g.state]: "Active",
70
+ [g.version]: owner.marker,
71
+ [g.context]: S.tokenContextStorage.encode(token),
72
+ [g.sealed]: S.sealedStorage.encode(grant.sealed),
73
+ [g.summary]: S.summaryStorage.encode(C.summary(token)),
74
+ [g.revocationJobId]: null,
75
+ [g.refreshWork]: "None",
76
+ [g.refreshClaim]: null,
77
+ [g.refreshClaimExpiresAt]: null,
78
+ [g.retentionUntil]: mapping.clock.encodeInstant(
79
+ S.retainedUntil(
80
+ mapping,
81
+ Math.max(now, token.metadata.useUntilMillis, token.metadata.refreshUseUntilMillis ?? 0),
82
+ ),
83
+ ),
84
+ };
85
+
86
+ if (!replacing) {
87
+ yield* owner.insert(g.table, values, {
88
+ [g.moduleId]: token.moduleId,
89
+ [g.grantId]: token.grantId,
90
+ });
91
+ } else
92
+ yield* owner.update(
93
+ g.table,
94
+ { [g.moduleId]: token.moduleId, [g.grantId]: token.grantId },
95
+ values,
96
+ );
97
+ });
98
+
38
99
  export const settle = Effect.fn("oauthConnected.settle")(function* (
39
100
  mapping: S.Mapping,
40
101
  input: F.Input<"settle">,
@@ -123,7 +184,8 @@ export const settle = Effect.fn("oauthConnected.settle")(function* (
123
184
 
124
185
  if (claimed === undefined) return { _tag: "Rejected" } as const;
125
186
  invariant(
126
- validMetadata(token, claimed.now) &&
187
+ token.exchangeOrder === input.claim.order &&
188
+ validMetadata(token, claimed.now) &&
127
189
  token.metadata.obtainedAtMillis >= input.claim.claimedAtMillis,
128
190
  );
129
191
  const reconnect = c.reconnect;
@@ -177,46 +239,7 @@ export const settle = Effect.fn("oauthConnected.settle")(function* (
177
239
  if (tuple.row[t.state] === "Unowned")
178
240
  yield* F.acquireTuple(mapping.ownership, token.identity, tuple.key, S.nativeCopy(native));
179
241
 
180
- const values = {
181
- ...g.encodeInsert({
182
- grant: snapshotOAuthSync(M.OAuthConnectedStoredGrant, grant),
183
- subjectId: S.nativeCopy(native),
184
- }),
185
- [g.moduleId]: c.moduleId,
186
- [g.grantId]: c.grantId,
187
- [g.subjectId]: native,
188
- [g.identityKey]: tuple.key,
189
- [g.activeIdentityKey]: tuple.key,
190
- [g.clientKey]: cl.id,
191
- [g.cohortKey]: co.id,
192
- [g.profileKey]: c.profile.key,
193
- [g.grantVersion]: token.grantVersion,
194
- [g.tokenVersion]: token.tokenVersion,
195
- [g.cohortGeneration]: token.cohortGeneration,
196
- [g.state]: "Active",
197
- [g.version]: owner.marker,
198
- [g.context]: S.tokenContextStorage.encode(token),
199
- [g.sealed]: S.sealedStorage.encode(grant.sealed),
200
- [g.summary]: S.summaryStorage.encode(C.summary(token)),
201
- [g.revocationJobId]: null,
202
- [g.refreshWork]: "None",
203
- [g.refreshClaim]: null,
204
- [g.refreshClaimExpiresAt]: null,
205
- [g.retentionUntil]: mapping.clock.encodeInstant(
206
- S.retainedUntil(
207
- mapping,
208
- Math.max(
209
- claimed.now,
210
- token.metadata.useUntilMillis,
211
- token.metadata.refreshUseUntilMillis ?? 0,
212
- ),
213
- ),
214
- ),
215
- };
216
-
217
- if (original === undefined) {
218
- yield* owner.insert(g.table, values, { [g.moduleId]: c.moduleId, [g.grantId]: c.grantId });
219
- } else yield* owner.update(g.table, { [g.moduleId]: c.moduleId, [g.grantId]: c.grantId }, values);
242
+ yield* activateGrant(mapping, grant, native, claimed.now, original !== undefined);
220
243
  yield* F.terminal(mapping, input.claim, "Connected", "Resolved", { cohort: co.id });
221
244
  owner.postconditions.push(
222
245
  sql`${mapping.clock.engineNowMillis} >= ${claimed.now} and ${mapping.clock.engineNowMillis} < ${Math.min(input.claim.claimExpiresAtMillis, token.metadata.useUntilMillis)}`,