@yielded/auth-persistence 0.1.0-beta.23 → 0.1.0-beta.25

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 (182) hide show
  1. package/README.md +11 -0
  2. package/dist/Adapter.d.mts +12 -6
  3. package/dist/Adapter.mjs +8 -3
  4. package/dist/OAuthPersistence.d.mts +87 -0
  5. package/dist/OAuthPersistence.mjs +125 -0
  6. package/dist/OAuthPersistence.mjs.map +1 -0
  7. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  8. package/dist/index.d.mts +3 -1
  9. package/dist/index.mjs +3 -1
  10. package/dist/internal/configuration.d.mts +1 -1
  11. package/dist/internal/configuration.mjs.map +1 -1
  12. package/dist/internal/email-kernel.d.mts +1 -1
  13. package/dist/internal/email-kernel.mjs +1 -1
  14. package/dist/internal/email-kernel.mjs.map +1 -1
  15. package/dist/internal/models/oauth-connected-model.d.mts +294 -0
  16. package/dist/internal/models/oauth-connected-model.mjs +22 -0
  17. package/dist/internal/models/oauth-connected-model.mjs.map +1 -0
  18. package/dist/internal/models/oauth-model.d.mts +467 -0
  19. package/dist/internal/models/oauth-model.mjs +49 -0
  20. package/dist/internal/models/oauth-model.mjs.map +1 -0
  21. package/dist/internal/models/password-model.d.mts +6 -48
  22. package/dist/internal/models/password-model.mjs +0 -1
  23. package/dist/internal/models/password-model.mjs.map +1 -1
  24. package/dist/internal/native-sql-table.d.mts +4 -0
  25. package/dist/internal/native-sql-table.mjs +7 -0
  26. package/dist/internal/native-sql-table.mjs.map +1 -1
  27. package/dist/internal/oauth/accounts.d.mts +8 -0
  28. package/dist/internal/oauth/accounts.mjs +379 -0
  29. package/dist/internal/oauth/accounts.mjs.map +1 -0
  30. package/dist/internal/oauth/connected-access.d.mts +9 -0
  31. package/dist/internal/oauth/connected-access.mjs +229 -0
  32. package/dist/internal/oauth/connected-access.mjs.map +1 -0
  33. package/dist/internal/oauth/connected-collection.d.mts +7 -0
  34. package/dist/internal/oauth/connected-collection.mjs +214 -0
  35. package/dist/internal/oauth/connected-collection.mjs.map +1 -0
  36. package/dist/internal/oauth/connected-custody.d.mts +6 -0
  37. package/dist/internal/oauth/connected-custody.mjs +165 -0
  38. package/dist/internal/oauth/connected-custody.mjs.map +1 -0
  39. package/dist/internal/oauth/connected-flow.d.mts +7 -0
  40. package/dist/internal/oauth/connected-flow.mjs +324 -0
  41. package/dist/internal/oauth/connected-flow.mjs.map +1 -0
  42. package/dist/internal/oauth/connected-input.mjs +122 -0
  43. package/dist/internal/oauth/connected-input.mjs.map +1 -0
  44. package/dist/internal/oauth/connected-keys.d.mts +2 -0
  45. package/dist/internal/oauth/connected-keys.mjs +22 -0
  46. package/dist/internal/oauth/connected-keys.mjs.map +1 -0
  47. package/dist/internal/oauth/connected-maintenance.d.mts +9 -0
  48. package/dist/internal/oauth/connected-maintenance.mjs +226 -0
  49. package/dist/internal/oauth/connected-maintenance.mjs.map +1 -0
  50. package/dist/internal/oauth/connected-management.d.mts +9 -0
  51. package/dist/internal/oauth/connected-management.mjs +243 -0
  52. package/dist/internal/oauth/connected-management.mjs.map +1 -0
  53. package/dist/internal/oauth/connected-reference.mjs +63 -0
  54. package/dist/internal/oauth/connected-reference.mjs.map +1 -0
  55. package/dist/internal/oauth/connected-settlement.d.mts +8 -0
  56. package/dist/internal/oauth/connected-settlement.mjs +141 -0
  57. package/dist/internal/oauth/connected-settlement.mjs.map +1 -0
  58. package/dist/internal/oauth/connected-sign-in.d.mts +10 -0
  59. package/dist/internal/oauth/connected-sign-in.mjs +281 -0
  60. package/dist/internal/oauth/connected-sign-in.mjs.map +1 -0
  61. package/dist/internal/oauth/connected-state.d.mts +14 -0
  62. package/dist/internal/oauth/connected-state.mjs +469 -0
  63. package/dist/internal/oauth/connected-state.mjs.map +1 -0
  64. package/dist/internal/oauth/connected-target.d.mts +21 -0
  65. package/dist/internal/oauth/connected-target.mjs +117 -0
  66. package/dist/internal/oauth/connected-target.mjs.map +1 -0
  67. package/dist/internal/oauth/flow.d.mts +5 -0
  68. package/dist/internal/oauth/flow.mjs +279 -0
  69. package/dist/internal/oauth/flow.mjs.map +1 -0
  70. package/dist/internal/oauth/input.mjs +127 -0
  71. package/dist/internal/oauth/input.mjs.map +1 -0
  72. package/dist/internal/oauth/owner.d.mts +10 -0
  73. package/dist/internal/oauth/owner.mjs +10 -0
  74. package/dist/internal/oauth/owner.mjs.map +1 -0
  75. package/dist/internal/oauth/query-compiler.d.mts +7 -0
  76. package/dist/internal/oauth/query-compiler.mjs +9 -0
  77. package/dist/internal/oauth/query-compiler.mjs.map +1 -0
  78. package/dist/internal/oauth/registration.d.mts +7 -0
  79. package/dist/internal/oauth/registration.mjs +393 -0
  80. package/dist/internal/oauth/registration.mjs.map +1 -0
  81. package/dist/internal/oauth/state.mjs +107 -0
  82. package/dist/internal/oauth/state.mjs.map +1 -0
  83. package/dist/internal/oauth/target.d.mts +31 -0
  84. package/dist/internal/oauth/target.mjs +273 -0
  85. package/dist/internal/oauth/target.mjs.map +1 -0
  86. package/dist/internal/oauth-kernel.d.mts +1423 -0
  87. package/dist/internal/oauth-kernel.mjs +187 -0
  88. package/dist/internal/oauth-kernel.mjs.map +1 -0
  89. package/dist/internal/oauth-proxy.d.mts +31 -0
  90. package/dist/internal/oauth-proxy.mjs +129 -0
  91. package/dist/internal/oauth-proxy.mjs.map +1 -0
  92. package/dist/internal/passkey/write-state.mjs +9 -1
  93. package/dist/internal/passkey/write-state.mjs.map +1 -1
  94. package/dist/internal/passkey-kernel.d.mts +9 -9
  95. package/dist/internal/{password-attempts.d.mts → password-credentials.d.mts} +3 -4
  96. package/dist/internal/password-credentials.mjs +121 -0
  97. package/dist/internal/password-credentials.mjs.map +1 -0
  98. package/dist/internal/password-kernel.d.mts +8 -24
  99. package/dist/internal/password-kernel.mjs +5 -43
  100. package/dist/internal/password-kernel.mjs.map +1 -1
  101. package/dist/internal/persistence.d.mts +1 -1
  102. package/dist/internal/persistence.mjs +2 -2
  103. package/dist/internal/persistence.mjs.map +1 -1
  104. package/dist/internal/query-operations.d.mts +2 -0
  105. package/dist/internal/session-kernel.d.mts +2 -2
  106. package/dist/internal/session-kernel.mjs +74 -18
  107. package/dist/internal/session-kernel.mjs.map +1 -1
  108. package/dist/internal/sql-oauth-connected-model.d.mts +29 -0
  109. package/dist/internal/sql-oauth-connected-model.mjs +7 -0
  110. package/dist/internal/sql-oauth-connected-model.mjs.map +1 -0
  111. package/dist/internal/sql-oauth-model.d.mts +60 -0
  112. package/dist/internal/sql-oauth-model.mjs +10 -0
  113. package/dist/internal/sql-oauth-model.mjs.map +1 -0
  114. package/dist/internal/sql-query.d.mts +12 -0
  115. package/dist/internal/sql-query.mjs +15 -18
  116. package/dist/internal/sql-query.mjs.map +1 -1
  117. package/dist/internal/sql-storage-validation.mjs +54 -0
  118. package/dist/internal/sql-storage-validation.mjs.map +1 -0
  119. package/dist/internal/storage-mapping.mjs +1 -37
  120. package/dist/internal/storage-mapping.mjs.map +1 -1
  121. package/dist/internal/storage-plans.d.mts +7 -0
  122. package/dist/internal/storage-plans.mjs +189 -0
  123. package/dist/internal/storage-plans.mjs.map +1 -0
  124. package/dist/internal/storage-tables.d.mts +0 -56
  125. package/dist/internal/storage-tables.mjs +0 -17
  126. package/dist/internal/storage-tables.mjs.map +1 -1
  127. package/dist/internal/storage-validation.d.mts +6 -1
  128. package/dist/internal/storage-validation.mjs +42 -1
  129. package/dist/internal/storage-validation.mjs.map +1 -1
  130. package/dist/internal/transaction-kernel.mjs +3 -2
  131. package/dist/internal/transaction-kernel.mjs.map +1 -1
  132. package/package.json +1 -1
  133. package/src/Adapter.ts +89 -5
  134. package/src/OAuthPersistence.ts +427 -0
  135. package/src/index.ts +3 -0
  136. package/src/internal/configuration.ts +1 -3
  137. package/src/internal/email-kernel.ts +2 -1
  138. package/src/internal/models/oauth-connected-model.ts +396 -0
  139. package/src/internal/models/oauth-model.ts +708 -0
  140. package/src/internal/models/password-model.ts +2 -57
  141. package/src/internal/native-sql-table.ts +14 -0
  142. package/src/internal/oauth/accounts.ts +839 -0
  143. package/src/internal/oauth/connected-access.ts +388 -0
  144. package/src/internal/oauth/connected-collection.ts +345 -0
  145. package/src/internal/oauth/connected-custody.ts +308 -0
  146. package/src/internal/oauth/connected-flow.ts +562 -0
  147. package/src/internal/oauth/connected-input.ts +147 -0
  148. package/src/internal/oauth/connected-keys.ts +31 -0
  149. package/src/internal/oauth/connected-maintenance.ts +379 -0
  150. package/src/internal/oauth/connected-management.ts +391 -0
  151. package/src/internal/oauth/connected-reference.ts +135 -0
  152. package/src/internal/oauth/connected-settlement.ts +278 -0
  153. package/src/internal/oauth/connected-sign-in.ts +472 -0
  154. package/src/internal/oauth/connected-state.ts +924 -0
  155. package/src/internal/oauth/connected-target.ts +307 -0
  156. package/src/internal/oauth/flow.ts +505 -0
  157. package/src/internal/oauth/input.ts +201 -0
  158. package/src/internal/oauth/owner.ts +22 -0
  159. package/src/internal/oauth/query-compiler.ts +15 -0
  160. package/src/internal/oauth/registration.ts +676 -0
  161. package/src/internal/oauth/state.ts +218 -0
  162. package/src/internal/oauth/target.ts +803 -0
  163. package/src/internal/oauth-kernel.ts +294 -0
  164. package/src/internal/oauth-proxy.ts +176 -0
  165. package/src/internal/passkey/write-state.ts +18 -4
  166. package/src/internal/password-credentials.ts +245 -0
  167. package/src/internal/password-kernel.ts +7 -99
  168. package/src/internal/persistence.ts +1 -1
  169. package/src/internal/query-operations.ts +2 -0
  170. package/src/internal/session-kernel.ts +143 -55
  171. package/src/internal/sql-oauth-connected-model.ts +145 -0
  172. package/src/internal/sql-oauth-model.ts +263 -0
  173. package/src/internal/sql-query.ts +16 -13
  174. package/src/internal/sql-storage-validation.ts +64 -0
  175. package/src/internal/storage-mapping.ts +0 -37
  176. package/src/internal/storage-plans.ts +218 -0
  177. package/src/internal/storage-tables.ts +0 -20
  178. package/src/internal/storage-validation.ts +58 -0
  179. package/src/internal/transaction-kernel.ts +6 -2
  180. package/dist/internal/password-attempts.mjs +0 -197
  181. package/dist/internal/password-attempts.mjs.map +0 -1
  182. package/src/internal/password-attempts.ts +0 -466
@@ -0,0 +1,427 @@
1
+ /** Direct Effect SQL persistence for upstream OAuth accounts. PostgreSQL and SQLite
2
+ * require interactive transactions; provider exchanges occur outside coordinators. */
3
+ import type { LifecycleHooks } from "@yielded/auth/Hooks";
4
+ import {
5
+ OAuthAccountsPersistence,
6
+ OAuthSignInPersistence,
7
+ OAuthRegistrationIntents,
8
+ OAuthConnectedPersistence,
9
+ OAuthConnectedRevocations,
10
+ OAuthUnavailable,
11
+ } from "@yielded/auth/OAuth";
12
+ import type { AuthenticationAuthority } from "@yielded/auth/Sessions";
13
+ import { SessionUnavailable } from "@yielded/auth/Sessions";
14
+ import { type Context, type Crypto, Effect, Predicate, Schema } from "effect";
15
+ import { SqlClient } from "effect/sql";
16
+
17
+ import { PersistenceConfigurationError } from "./internal/configuration";
18
+ import type { AuthenticationAuthorityMapping as AuthorityMapping } from "./internal/models/session-model";
19
+ import { makeNativeSqlTables } from "./internal/native-sql-table";
20
+ import { makeOAuthKernel } from "./internal/oauth-kernel";
21
+ import type { OAuthCoordinatorError, OAuthTargetConfiguration } from "./internal/oauth/target";
22
+ import {
23
+ CurrentSessionSql,
24
+ makeSessionKernel,
25
+ type SessionSqlDatabase,
26
+ } from "./internal/session-kernel";
27
+ import type {
28
+ OAuthConnectedMapping,
29
+ OAuthConnectedRevocationMapping,
30
+ } from "./internal/sql-oauth-connected-model";
31
+ import type {
32
+ SqlTableModel,
33
+ OAuthAccountsMapping,
34
+ OAuthSignInMapping,
35
+ OAuthRegistrationIntentMapping,
36
+ OAuthRegistrationMapping,
37
+ OAuthRegistrationAuthority,
38
+ OAuthReferenceGuardDescriptor,
39
+ } from "./internal/sql-oauth-model";
40
+ import { makeSqlDatabase, sqlQueryOperations, sql } from "./internal/sql-query";
41
+ import { validateSqlStorage } from "./internal/sql-storage-validation";
42
+ import { Table, Fragment } from "./internal/sql-table";
43
+ import { requireStandalone } from "./internal/standalone";
44
+ import type { StorageTable } from "./internal/storage-tables";
45
+ import { NativeDatabase } from "./internal/transaction-kernel";
46
+ import type { TransactionNativeDatabase } from "./internal/transaction-kernel";
47
+ export * from "./internal/sql-oauth-model";
48
+ export * from "./internal/sql-oauth-connected-model";
49
+ export { sql };
50
+ export { and, eq } from "./internal/sql-query";
51
+
52
+ /** Physical identifiers and representations only; applications own migrations. */
53
+ export const table = (definition: StorageTable) =>
54
+ new Table(definition.name, definition.columns, definition.unique, definition.schema);
55
+
56
+ /** Integer-millisecond engine clock, sampled after locks on either supported dialect. */
57
+ export const clock = {
58
+ encodeInstant: Schema.encodeSync(Schema.Int),
59
+ decodeInstant: Schema.decodeUnknownSync(Schema.Int),
60
+ engineNowMillis: new Fragment((compiler) =>
61
+ compiler.dialect === "pg"
62
+ ? "cast(extract(epoch from clock_timestamp()) * 1000 as bigint)"
63
+ : "cast(round((julianday('now') - 2440587.5) * 86400000) as integer)",
64
+ ),
65
+ };
66
+
67
+ const operations = { ...sqlQueryOperations, validateStorage: validateSqlStorage };
68
+
69
+ const kernels = {
70
+ pg: makeOAuthKernel(operations, () => "pg"),
71
+ sqlite: makeOAuthKernel(operations, () => "sqlite"),
72
+ };
73
+
74
+ const acquire = Effect.gen(function* () {
75
+ const client = yield* SqlClient.SqlClient;
76
+
77
+ const dialect = client.onDialectOrElse({
78
+ pg: () => "pg" as const,
79
+ sqlite: () => "sqlite" as const,
80
+ orElse: () => undefined,
81
+ });
82
+
83
+ // D1 exposes the SQLite compiler but its public driver brand identifies a
84
+ // batch-only client. Keep the default package free of a D1 runtime dependency.
85
+ if (dialect === undefined || Predicate.hasProperty(client, "~@effect/sql-d1/D1Client"))
86
+ return yield* PersistenceConfigurationError.make({
87
+ reason: "OAuth persistence requires PostgreSQL or SQLite with interactive transactions",
88
+ });
89
+
90
+ const database = yield* makeSqlDatabase(dialect);
91
+
92
+ const configuration: OAuthTargetConfiguration = {
93
+ mode: "interactive",
94
+ dialect,
95
+ locking: dialect === "pg",
96
+ standaloneGuard: (service) => requireStandalone(() => OAuthUnavailable.make({}), service),
97
+ };
98
+
99
+ // Erase only the query-builder handle; batch methods are never selected by this adapter.
100
+ return {
101
+ database: database as unknown as TransactionNativeDatabase,
102
+ configuration,
103
+ kernel: kernels[dialect],
104
+ };
105
+ });
106
+
107
+ const using = <A, E, R>(body: (input: Effect.Success<typeof acquire>) => Effect.Effect<A, E, R>) =>
108
+ Effect.flatMap(acquire, (input) =>
109
+ body(input).pipe(Effect.provideService(NativeDatabase, input.database)),
110
+ );
111
+
112
+ export const makeOAuthSignInServices = <N>(
113
+ mapping: OAuthSignInMapping<Table, Table, Table, Table, Table, N>,
114
+ ): Effect.Effect<
115
+ { readonly oauthSignInPersistence: OAuthSignInPersistence["Service"] },
116
+ OAuthUnavailable | PersistenceConfigurationError,
117
+ Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
118
+ > =>
119
+ using(({ kernel, configuration }) =>
120
+ kernel.target.makeTargetOAuthSignInServices(mapping, configuration),
121
+ );
122
+
123
+ /** Run auth and application SQL in one adapter-owned transaction and commit journal. */
124
+ export const coordinateOAuthSignIn = <N, A, E, R>(
125
+ options: { readonly mapping: OAuthSignInMapping<Table, Table, Table, Table, Table, N> },
126
+ body: Effect.Effect<A, E, R>,
127
+ ): Effect.Effect<
128
+ A,
129
+ OAuthCoordinatorError<E> | PersistenceConfigurationError,
130
+ Exclude<R, OAuthSignInPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
131
+ > =>
132
+ using(({ kernel, configuration, database }) =>
133
+ kernel.target.coordinateTargetOAuthSignIn(
134
+ database,
135
+ options.mapping,
136
+ configuration,
137
+ (_transaction, services) =>
138
+ Effect.provideService(body, OAuthSignInPersistence, services.oauthSignInPersistence),
139
+ ),
140
+ );
141
+
142
+ export const makeOAuthRegistrationIntentServices = <N>(
143
+ mapping: OAuthRegistrationIntentMapping<Table, Table, Table, Table, Table, Table, Table, N>,
144
+ ): Effect.Effect<
145
+ { readonly oauthRegistrationIntents: OAuthRegistrationIntents["Service"] },
146
+ OAuthUnavailable | PersistenceConfigurationError,
147
+ Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
148
+ > =>
149
+ using(({ kernel, configuration }) =>
150
+ kernel.target.makeTargetOAuthRegistrationIntentServices(mapping, configuration),
151
+ );
152
+
153
+ /** Run auth and application SQL in one adapter-owned transaction and commit journal. */
154
+ export const coordinateOAuthRegistrationIntents = <N, A, E, R>(
155
+ options: {
156
+ readonly mapping: OAuthRegistrationIntentMapping<
157
+ Table,
158
+ Table,
159
+ Table,
160
+ Table,
161
+ Table,
162
+ Table,
163
+ Table,
164
+ N
165
+ >;
166
+ },
167
+ body: Effect.Effect<A, E, R>,
168
+ ): Effect.Effect<
169
+ A,
170
+ OAuthCoordinatorError<E> | PersistenceConfigurationError,
171
+ Exclude<R, OAuthRegistrationIntents> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
172
+ > =>
173
+ using(({ kernel, configuration, database }) =>
174
+ kernel.target.coordinateTargetOAuthRegistrationIntents(
175
+ database,
176
+ options.mapping,
177
+ configuration,
178
+ (_transaction, services) =>
179
+ Effect.provideService(body, OAuthRegistrationIntents, services.oauthRegistrationIntents),
180
+ ),
181
+ );
182
+
183
+ export const makeOAuthAccountsServices = <N>(
184
+ mapping: OAuthAccountsMapping<Table, Table, Table, Table, Table, Table, Table, N>,
185
+ ): Effect.Effect<
186
+ { readonly oauthAccountsPersistence: OAuthAccountsPersistence["Service"] },
187
+ OAuthUnavailable | PersistenceConfigurationError,
188
+ Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
189
+ > =>
190
+ using(({ kernel, configuration }) =>
191
+ kernel.target.makeTargetOAuthAccountsServices(mapping, configuration),
192
+ );
193
+
194
+ /** Run auth and application SQL in one adapter-owned transaction and commit journal. */
195
+ export const coordinateOAuthAccounts = <N, A, E, R>(
196
+ options: {
197
+ readonly mapping: OAuthAccountsMapping<Table, Table, Table, Table, Table, Table, Table, N>;
198
+ },
199
+ body: Effect.Effect<A, E, R>,
200
+ ): Effect.Effect<
201
+ A,
202
+ OAuthCoordinatorError<E> | PersistenceConfigurationError,
203
+ Exclude<R, OAuthAccountsPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
204
+ > =>
205
+ using(({ kernel, configuration, database }) =>
206
+ kernel.target.coordinateTargetOAuthAccounts(
207
+ database,
208
+ options.mapping,
209
+ configuration,
210
+ (_transaction, services) =>
211
+ Effect.provideService(body, OAuthAccountsPersistence, services.oauthAccountsPersistence),
212
+ ),
213
+ );
214
+
215
+ export const makeOAuthConnectedServices = <N>(
216
+ mapping: OAuthConnectedMapping<
217
+ Table,
218
+ Table,
219
+ Table,
220
+ Table,
221
+ Table,
222
+ Table,
223
+ Table,
224
+ Table,
225
+ Table,
226
+ Table,
227
+ N,
228
+ Table
229
+ >,
230
+ ): Effect.Effect<
231
+ { readonly oauthConnectedPersistence: OAuthConnectedPersistence["Service"] },
232
+ OAuthUnavailable | PersistenceConfigurationError,
233
+ Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
234
+ > =>
235
+ using(({ kernel, configuration }) =>
236
+ kernel.connectedTarget.makeTargetOAuthConnectedServices(mapping, configuration),
237
+ );
238
+
239
+ /** Run auth and application SQL in one adapter-owned transaction and commit journal. */
240
+ export const coordinateOAuthConnected = <N, A, E, R>(
241
+ options: {
242
+ readonly mapping: OAuthConnectedMapping<
243
+ Table,
244
+ Table,
245
+ Table,
246
+ Table,
247
+ Table,
248
+ Table,
249
+ Table,
250
+ Table,
251
+ Table,
252
+ Table,
253
+ N,
254
+ Table
255
+ >;
256
+ },
257
+ body: Effect.Effect<A, E, R>,
258
+ ): Effect.Effect<
259
+ A,
260
+ OAuthCoordinatorError<E> | PersistenceConfigurationError,
261
+ Exclude<R, OAuthConnectedPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
262
+ > =>
263
+ using(({ kernel, configuration, database }) =>
264
+ kernel.connectedTarget.coordinateTargetOAuthConnected(
265
+ database,
266
+ options.mapping,
267
+ configuration,
268
+ (_transaction, services) =>
269
+ Effect.provideService(body, OAuthConnectedPersistence, services.oauthConnectedPersistence),
270
+ ),
271
+ );
272
+
273
+ export const makeOAuthConnectedRevocationServices = <N>(
274
+ mapping: OAuthConnectedRevocationMapping<Table, Table, Table, Table, Table, Table, Table, N>,
275
+ ): Effect.Effect<
276
+ { readonly oauthConnectedRevocations: OAuthConnectedRevocations["Service"] },
277
+ OAuthUnavailable | PersistenceConfigurationError,
278
+ Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
279
+ > =>
280
+ using(({ kernel, configuration }) =>
281
+ kernel.connectedTarget.makeTargetOAuthConnectedRevocationServices(mapping, configuration),
282
+ );
283
+
284
+ /** Run auth and application SQL in one adapter-owned transaction and commit journal. */
285
+ export const coordinateOAuthConnectedRevocations = <N, A, E, R>(
286
+ options: {
287
+ readonly mapping: OAuthConnectedRevocationMapping<
288
+ Table,
289
+ Table,
290
+ Table,
291
+ Table,
292
+ Table,
293
+ Table,
294
+ Table,
295
+ N
296
+ >;
297
+ },
298
+ body: Effect.Effect<A, E, R>,
299
+ ): Effect.Effect<
300
+ A,
301
+ OAuthCoordinatorError<E> | PersistenceConfigurationError,
302
+ Exclude<R, OAuthConnectedRevocations> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
303
+ > =>
304
+ using(({ kernel, configuration, database }) =>
305
+ kernel.connectedTarget.coordinateTargetOAuthConnectedRevocations(
306
+ database,
307
+ options.mapping,
308
+ configuration,
309
+ (_transaction, services) =>
310
+ Effect.provideService(body, OAuthConnectedRevocations, services.oauthConnectedRevocations),
311
+ ),
312
+ );
313
+
314
+ export const makeOAuthRegistrationServices = <Registration, N>(
315
+ mapping: OAuthRegistrationMapping<
316
+ Registration,
317
+ Table,
318
+ Table,
319
+ Table,
320
+ Table,
321
+ Table,
322
+ Table,
323
+ Table,
324
+ N
325
+ >,
326
+ ): Effect.Effect<
327
+ { readonly registrationAuthority: OAuthRegistrationAuthority<Registration> },
328
+ OAuthUnavailable | PersistenceConfigurationError,
329
+ Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
330
+ > =>
331
+ using(({ kernel, configuration }) =>
332
+ kernel.target.makeTargetOAuthRegistrationServices<Registration>(mapping, configuration),
333
+ );
334
+
335
+ export const coordinateOAuthRegistration = <Id, Registration, N, A, E, R>(
336
+ options: {
337
+ readonly mapping: OAuthRegistrationMapping<
338
+ NoInfer<Registration>,
339
+ Table,
340
+ Table,
341
+ Table,
342
+ Table,
343
+ Table,
344
+ Table,
345
+ Table,
346
+ N
347
+ >;
348
+ readonly target: Context.Key<Id, OAuthRegistrationAuthority<Registration>>;
349
+ },
350
+ body: Effect.Effect<A, E, R>,
351
+ ): Effect.Effect<
352
+ A,
353
+ OAuthCoordinatorError<E> | PersistenceConfigurationError,
354
+ Exclude<R, Id> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient
355
+ > =>
356
+ using(({ kernel, configuration, database }) =>
357
+ kernel.target.coordinateTargetOAuthRegistration<Registration, unknown, A, E, Exclude<R, Id>>(
358
+ database,
359
+ options.mapping,
360
+ configuration,
361
+ (_transaction, services) =>
362
+ Effect.provideService(body, options.target, services.registrationAuthority),
363
+ ),
364
+ );
365
+
366
+ /** Include these guards when login ownership may also hold retained grants. */
367
+ export const oauthConnectedOwnershipReferences = <N>(
368
+ mapping: OAuthConnectedMapping<
369
+ Table,
370
+ Table,
371
+ Table,
372
+ Table,
373
+ Table,
374
+ Table,
375
+ Table,
376
+ Table,
377
+ Table,
378
+ Table,
379
+ N,
380
+ Table
381
+ >,
382
+ dialect: "pg" | "sqlite",
383
+ ) =>
384
+ // The selected compiler supplies Fragment handles; domain values retain their codecs.
385
+ kernels[dialect].connectedReference.oauthConnectedOwnershipReferences(mapping) as {
386
+ readonly connectedReferenceGuards: ReadonlyArray<OAuthReferenceGuardDescriptor<N>>;
387
+ readonly connectedReference: (input: {
388
+ readonly identityKey: string;
389
+ readonly subjectId: N;
390
+ }) => Fragment;
391
+ };
392
+
393
+ export const {
394
+ oauthAccountsPersistenceLayer,
395
+ oauthSignInPersistenceLayer,
396
+ oauthRegistrationIntentsLayer,
397
+ oauthRegistrationAuthorityLayer,
398
+ } = kernels.sqlite.target;
399
+
400
+ export const { oauthConnectedPersistenceLayer, oauthConnectedRevocationsLayer } =
401
+ kernels.sqlite.connectedTarget;
402
+
403
+ /** Shared session issuance must validate the same subject and credential authority
404
+ * as OAuth. Supply this service when it is not already provided by session storage. */
405
+ export const makeAuthenticationAuthorityServices = <Claims, N>(
406
+ mapping: AuthorityMapping<Claims, SqlTableModel, SqlTableModel, SqlTableModel, SqlTableModel, N>,
407
+ ): Effect.Effect<
408
+ { readonly authenticationAuthority: AuthenticationAuthority["Service"] },
409
+ SessionUnavailable | PersistenceConfigurationError,
410
+ LifecycleHooks | SqlClient.SqlClient
411
+ > =>
412
+ using(({ database, configuration }) =>
413
+ makeSessionKernel(operations, (client) => makeNativeSqlTables(client))
414
+ .makeSqlAuthenticationAuthority(mapping, {
415
+ mode: "interactive",
416
+ locking: configuration.locking,
417
+ standaloneGuard: requireStandalone(
418
+ () => SessionUnavailable.make({}),
419
+ database.$client.transactionService,
420
+ ),
421
+ })
422
+ .pipe(
423
+ // Both kernels capture the same raw SQL query-builder handle and client.
424
+ Effect.provideService(CurrentSessionSql, database as unknown as SessionSqlDatabase),
425
+ Effect.map((authenticationAuthority) => ({ authenticationAuthority })),
426
+ ),
427
+ );
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export { AuthPersistence } from "./internal/sql-persistence";
2
2
  export { OAuthServerPersistence } from "./internal/oauth-server";
3
+ export { OAuthProxyPersistence } from "./internal/oauth-proxy";
3
4
  export { BrowserLoginPersistence } from "./internal/browser-login";
4
5
  export { PersistenceConfigurationError } from "./internal/configuration";
5
6
  export { PersistenceMappingError } from "./internal/mapping-error";
6
7
  export { StorageColumn, StorageTable } from "./internal/storage-tables";
8
+
9
+ export * as OAuthPersistence from "./OAuthPersistence.ts";
@@ -149,9 +149,7 @@ export type Roles<C extends ClaimsCodec, Id extends string, A extends Definition
149
149
  | "credentials"
150
150
  | "sessions"
151
151
  | "sessionFlows"
152
- | (Enabled<A, "password"> extends never
153
- ? never
154
- : "passwords" | "passwordAttempts" | "passwordCommands")
152
+ | (Enabled<A, "password"> extends never ? never : "passwords" | "passwordCommands")
155
153
  | (ManagedPassword<A> extends never ? never : "passwordRegistrations")
156
154
  | (Enabled<A, "phone"> extends never ? never : "phoneState")
157
155
  | (Enabled<A, "email"> extends never ? never : "emailCredentials" | "emailCommands")
@@ -809,7 +809,8 @@ export const makeEmailKernel = <
809
809
  (action === "verify-address" && input.captured.source !== undefined) ||
810
810
  (action === "change-address" && input.captured.source === undefined) ||
811
811
  confirmsExisting !== (input.invalidation === undefined) ||
812
- (input.invalidation?.existingSessions === "immediate" &&
812
+ ((input.invalidation?.existingSessions === "immediate" ||
813
+ input.invalidation?.existingSessions === "cache-expiry") &&
813
814
  mapping.sessionInvalidation !== "same-authority-immediate")
814
815
  )
815
816
  return undefined;