@yielded/auth-persistence 0.1.0-beta.7 → 0.1.0-beta.8

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.
package/README.md CHANGED
@@ -8,6 +8,11 @@ or from `@yielded/auth-persistence/drizzle/<driver>` for Drizzle. The raw entry
8
8
  does not require Drizzle. Core workflows and replaceable service contracts remain
9
9
  in `@yielded/auth`.
10
10
 
11
+ `OAuthAppPersistence` separately supplies the single-table store for
12
+ [`OAuthApp`](../../docs/guide/oauth.md#sign-in-and-connect-provider-access).
13
+ It has no dependency on the broader auth schema or a session repository. Apply its
14
+ exported migration with the application's runner and provide an Effect SQL client.
15
+
11
16
  Applications own subject provisioning, policy, claims, delivery, and their database
12
17
  connection. Drizzle Kit generates migrations from managed or application-declared
13
18
  Drizzle tables. Install `AuthPersistence.migrationsLayer({ migrationsFolder })`
@@ -300,14 +300,14 @@ declare const makeOAuthConnectedServices: <S extends AnySQLiteTable<{
300
300
  };
301
301
  }) => Effect.Effect<{
302
302
  readonly _tag: "Rejected";
303
+ } | {
304
+ readonly _tag: "Conflict";
303
305
  } | {
304
306
  readonly _tag: "Target";
305
307
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
306
308
  } | {
307
309
  readonly _tag: "Quarantine";
308
310
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
309
- } | {
310
- readonly _tag: "Conflict";
311
311
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
312
312
  readonly settle: <A>(input: {
313
313
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -316,12 +316,12 @@ declare const makeOAuthConnectedServices: <S extends AnySQLiteTable<{
316
316
  readonly nowMillis: number;
317
317
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
318
318
  readonly _tag: "Rejected";
319
+ } | {
320
+ readonly _tag: "Cancelled";
319
321
  } | {
320
322
  readonly _tag: "Ambiguous";
321
323
  } | {
322
324
  readonly _tag: "Conflict";
323
- } | {
324
- readonly _tag: "Cancelled";
325
325
  } | {
326
326
  readonly _tag: "Connected";
327
327
  readonly grant: {
@@ -645,8 +645,6 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
645
645
  readonly _tag: "Rejected";
646
646
  } | {
647
647
  readonly _tag: "Ambiguous";
648
- } | {
649
- readonly _tag: "Conflict";
650
648
  } | {
651
649
  readonly _tag: "Cancelled";
652
650
  } | {
@@ -670,6 +668,8 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
670
668
  };
671
669
  };
672
670
  readonly changed: boolean;
671
+ } | {
672
+ readonly _tag: "Conflict";
673
673
  }, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, import("@yielded/auth/OAuth").OAuthUnavailable>;
674
674
  readonly inspectUnlink: (input: {
675
675
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -1224,14 +1224,14 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
1224
1224
  };
1225
1225
  }) => Effect.Effect<{
1226
1226
  readonly _tag: "Rejected";
1227
+ } | {
1228
+ readonly _tag: "Conflict";
1227
1229
  } | {
1228
1230
  readonly _tag: "Target";
1229
1231
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
1230
1232
  } | {
1231
1233
  readonly _tag: "Quarantine";
1232
1234
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
1233
- } | {
1234
- readonly _tag: "Conflict";
1235
1235
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
1236
1236
  readonly settle: <A>(input: {
1237
1237
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -1242,10 +1242,10 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
1242
1242
  readonly _tag: "Rejected";
1243
1243
  } | {
1244
1244
  readonly _tag: "Ambiguous";
1245
- } | {
1246
- readonly _tag: "Conflict";
1247
1245
  } | {
1248
1246
  readonly _tag: "Cancelled";
1247
+ } | {
1248
+ readonly _tag: "Conflict";
1249
1249
  } | {
1250
1250
  readonly _tag: "Connected";
1251
1251
  readonly grant: {
@@ -184,11 +184,9 @@ declare const makeOAuthAccountsServices: <S extends AnyMySqlTable<{
184
184
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
185
185
  readonly _tag: "Rejected";
186
186
  } | {
187
- readonly _tag: "Conflict";
187
+ readonly _tag: "Ambiguous";
188
188
  } | {
189
189
  readonly _tag: "Cancelled";
190
- } | {
191
- readonly _tag: "Ambiguous";
192
190
  } | {
193
191
  readonly _tag: "Linked";
194
192
  readonly credential: {
@@ -210,6 +208,8 @@ declare const makeOAuthAccountsServices: <S extends AnyMySqlTable<{
210
208
  };
211
209
  };
212
210
  readonly changed: boolean;
211
+ } | {
212
+ readonly _tag: "Conflict";
213
213
  }, A>) => import("effect/Effect").Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, import("@yielded/auth/OAuth").OAuthUnavailable>;
214
214
  readonly inspectUnlink: (input: {
215
215
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -764,14 +764,14 @@ declare const makeOAuthAccountsServices: <S extends AnyMySqlTable<{
764
764
  };
765
765
  }) => import("effect/Effect").Effect<{
766
766
  readonly _tag: "Rejected";
767
+ } | {
768
+ readonly _tag: "Conflict";
767
769
  } | {
768
770
  readonly _tag: "Target";
769
771
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
770
772
  } | {
771
773
  readonly _tag: "Quarantine";
772
774
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
773
- } | {
774
- readonly _tag: "Conflict";
775
775
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
776
776
  readonly settle: <A>(input: {
777
777
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -781,11 +781,11 @@ declare const makeOAuthAccountsServices: <S extends AnyMySqlTable<{
781
781
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
782
782
  readonly _tag: "Rejected";
783
783
  } | {
784
- readonly _tag: "Conflict";
784
+ readonly _tag: "Ambiguous";
785
785
  } | {
786
786
  readonly _tag: "Cancelled";
787
787
  } | {
788
- readonly _tag: "Ambiguous";
788
+ readonly _tag: "Conflict";
789
789
  } | {
790
790
  readonly _tag: "Connected";
791
791
  readonly grant: {
@@ -187,8 +187,6 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
187
187
  readonly _tag: "Rejected";
188
188
  } | {
189
189
  readonly _tag: "Ambiguous";
190
- } | {
191
- readonly _tag: "Conflict";
192
190
  } | {
193
191
  readonly _tag: "Cancelled";
194
192
  } | {
@@ -212,6 +210,8 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
212
210
  };
213
211
  };
214
212
  readonly changed: boolean;
213
+ } | {
214
+ readonly _tag: "Conflict";
215
215
  }, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, import("@yielded/auth/OAuth").OAuthUnavailable>;
216
216
  readonly inspectUnlink: (input: {
217
217
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -766,14 +766,14 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
766
766
  };
767
767
  }) => Effect.Effect<{
768
768
  readonly _tag: "Rejected";
769
+ } | {
770
+ readonly _tag: "Conflict";
769
771
  } | {
770
772
  readonly _tag: "Target";
771
773
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
772
774
  } | {
773
775
  readonly _tag: "Quarantine";
774
776
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
775
- } | {
776
- readonly _tag: "Conflict";
777
777
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
778
778
  readonly settle: <A>(input: {
779
779
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -784,10 +784,10 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
784
784
  readonly _tag: "Rejected";
785
785
  } | {
786
786
  readonly _tag: "Ambiguous";
787
- } | {
788
- readonly _tag: "Conflict";
789
787
  } | {
790
788
  readonly _tag: "Cancelled";
789
+ } | {
790
+ readonly _tag: "Conflict";
791
791
  } | {
792
792
  readonly _tag: "Connected";
793
793
  readonly grant: {
@@ -186,11 +186,9 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
186
186
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
187
187
  readonly _tag: "Rejected";
188
188
  } | {
189
- readonly _tag: "Conflict";
189
+ readonly _tag: "Ambiguous";
190
190
  } | {
191
191
  readonly _tag: "Cancelled";
192
- } | {
193
- readonly _tag: "Ambiguous";
194
192
  } | {
195
193
  readonly _tag: "Linked";
196
194
  readonly credential: {
@@ -212,6 +210,8 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
212
210
  };
213
211
  };
214
212
  readonly changed: boolean;
213
+ } | {
214
+ readonly _tag: "Conflict";
215
215
  }, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, import("@yielded/auth/OAuth").OAuthUnavailable>;
216
216
  readonly inspectUnlink: (input: {
217
217
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -766,14 +766,14 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
766
766
  };
767
767
  }) => Effect.Effect<{
768
768
  readonly _tag: "Rejected";
769
+ } | {
770
+ readonly _tag: "Conflict";
769
771
  } | {
770
772
  readonly _tag: "Target";
771
773
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
772
774
  } | {
773
775
  readonly _tag: "Quarantine";
774
776
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
775
- } | {
776
- readonly _tag: "Conflict";
777
777
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
778
778
  readonly settle: <A>(input: {
779
779
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -783,11 +783,11 @@ declare const makeOAuthAccountsServices: <S extends AnyPgTable<{
783
783
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
784
784
  readonly _tag: "Rejected";
785
785
  } | {
786
- readonly _tag: "Conflict";
786
+ readonly _tag: "Ambiguous";
787
787
  } | {
788
788
  readonly _tag: "Cancelled";
789
789
  } | {
790
- readonly _tag: "Ambiguous";
790
+ readonly _tag: "Conflict";
791
791
  } | {
792
792
  readonly _tag: "Connected";
793
793
  readonly grant: {
@@ -640,8 +640,6 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
640
640
  readonly _tag: "Rejected";
641
641
  } | {
642
642
  readonly _tag: "Ambiguous";
643
- } | {
644
- readonly _tag: "Conflict";
645
643
  } | {
646
644
  readonly _tag: "Cancelled";
647
645
  } | {
@@ -665,6 +663,8 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
665
663
  };
666
664
  };
667
665
  readonly changed: boolean;
666
+ } | {
667
+ readonly _tag: "Conflict";
668
668
  }, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, import("@yielded/auth/OAuth").OAuthUnavailable>;
669
669
  readonly inspectUnlink: (input: {
670
670
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -1219,14 +1219,14 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
1219
1219
  };
1220
1220
  }) => Effect.Effect<{
1221
1221
  readonly _tag: "Rejected";
1222
+ } | {
1223
+ readonly _tag: "Conflict";
1222
1224
  } | {
1223
1225
  readonly _tag: "Target";
1224
1226
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
1225
1227
  } | {
1226
1228
  readonly _tag: "Quarantine";
1227
1229
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
1228
- } | {
1229
- readonly _tag: "Conflict";
1230
1230
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
1231
1231
  readonly settle: <A>(input: {
1232
1232
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -1237,10 +1237,10 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
1237
1237
  readonly _tag: "Rejected";
1238
1238
  } | {
1239
1239
  readonly _tag: "Ambiguous";
1240
- } | {
1241
- readonly _tag: "Conflict";
1242
1240
  } | {
1243
1241
  readonly _tag: "Cancelled";
1242
+ } | {
1243
+ readonly _tag: "Conflict";
1244
1244
  } | {
1245
1245
  readonly _tag: "Connected";
1246
1246
  readonly grant: {
@@ -638,12 +638,10 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
638
638
  readonly nowMillis: number;
639
639
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
640
640
  readonly _tag: "Rejected";
641
- } | {
642
- readonly _tag: "Ambiguous";
643
- } | {
644
- readonly _tag: "Conflict";
645
641
  } | {
646
642
  readonly _tag: "Cancelled";
643
+ } | {
644
+ readonly _tag: "Ambiguous";
647
645
  } | {
648
646
  readonly _tag: "Linked";
649
647
  readonly credential: {
@@ -665,6 +663,8 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
665
663
  };
666
664
  };
667
665
  readonly changed: boolean;
666
+ } | {
667
+ readonly _tag: "Conflict";
668
668
  }, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, import("@yielded/auth/OAuth").OAuthUnavailable>;
669
669
  readonly inspectUnlink: (input: {
670
670
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -1219,14 +1219,14 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
1219
1219
  };
1220
1220
  }) => Effect.Effect<{
1221
1221
  readonly _tag: "Rejected";
1222
+ } | {
1223
+ readonly _tag: "Conflict";
1222
1224
  } | {
1223
1225
  readonly _tag: "Target";
1224
1226
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
1225
1227
  } | {
1226
1228
  readonly _tag: "Quarantine";
1227
1229
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
1228
- } | {
1229
- readonly _tag: "Conflict";
1230
1230
  }, import("@yielded/auth/OAuth").OAuthUnavailable>;
1231
1231
  readonly settle: <A>(input: {
1232
1232
  readonly claim: import("@yielded/auth/OAuth").OAuthConnectedClaim;
@@ -1235,12 +1235,12 @@ declare const makeOAuthAccountsServices: <S extends AnySQLiteTable<{
1235
1235
  readonly nowMillis: number;
1236
1236
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
1237
1237
  readonly _tag: "Rejected";
1238
+ } | {
1239
+ readonly _tag: "Cancelled";
1238
1240
  } | {
1239
1241
  readonly _tag: "Ambiguous";
1240
1242
  } | {
1241
1243
  readonly _tag: "Conflict";
1242
- } | {
1243
- readonly _tag: "Cancelled";
1244
1244
  } | {
1245
1245
  readonly _tag: "Connected";
1246
1246
  readonly grant: {
@@ -133,11 +133,9 @@ declare const makeD1OAuthAccountsServices: <S extends SQLiteTable, O extends SQL
133
133
  }, prepare: import("@yielded/auth/OAuth").PrepareOAuthCommit<{
134
134
  readonly _tag: "Rejected";
135
135
  } | {
136
- readonly _tag: "Conflict";
136
+ readonly _tag: "Ambiguous";
137
137
  } | {
138
138
  readonly _tag: "Cancelled";
139
- } | {
140
- readonly _tag: "Ambiguous";
141
139
  } | {
142
140
  readonly _tag: "Linked";
143
141
  readonly credential: {
@@ -159,6 +157,8 @@ declare const makeD1OAuthAccountsServices: <S extends SQLiteTable, O extends SQL
159
157
  };
160
158
  };
161
159
  readonly changed: boolean;
160
+ } | {
161
+ readonly _tag: "Conflict";
162
162
  }, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, OAuthUnavailable>;
163
163
  readonly inspectUnlink: (input: {
164
164
  readonly moduleId: string & import("effect/Brand").Brand<"effect-auth/OAuthModuleId">;
@@ -3,9 +3,9 @@ import { DateTime, Effect, Layer } from "effect";
3
3
  import { ChallengeConsumeDecision } from "@yielded/auth/Persistence";
4
4
  import { ConsumeChallenge, NewChallenge, NewRegistration, PendingRegistration, SubjectId } from "@yielded/auth/Schema";
5
5
  import { ExternalIdentity, ExternalIdentityMutation, LoginIdentifier, SubjectProvisioner, SubjectProvisioningInput } from "@yielded/auth/Identity";
6
+ import { OAuthState, OAuthStateStore } from "@yielded/auth/OAuth";
6
7
  import { AuthStore, ConsumeDecision } from "@yielded/auth/AuthStore";
7
8
  import { AuthStoreError } from "@yielded/auth/Errors";
8
- import { OAuthState, OAuthStateStore } from "@yielded/auth/OAuth";
9
9
  import { AnyColumn, InferInsertModel, InferSelectModel, Table } from "drizzle-orm";
10
10
  import * as SqlClient from "effect/unstable/sql/SqlClient";
11
11
  //#region src/drizzle/model.d.ts
@@ -2,9 +2,9 @@ import { PersistenceMappingError, isMappedConstraintConflict } from "../internal
2
2
  import { Context, DateTime, Effect, Layer, Option } from "effect";
3
3
  import "@yielded/auth/Schema";
4
4
  import { ExternalIdentityMutation, SubjectProvisioner } from "@yielded/auth/Identity";
5
+ import { OAuthStateStore } from "@yielded/auth/OAuth";
5
6
  import { AuthStore } from "@yielded/auth/AuthStore";
6
7
  import { AuthStoreError } from "@yielded/auth/Errors";
7
- import { OAuthStateStore } from "@yielded/auth/OAuth";
8
8
  import { getTableColumns } from "drizzle-orm";
9
9
  //#region src/drizzle/model.ts
10
10
  const requireStandaloneConsume = (database) => Effect.serviceOption(database.$client.transactionService).pipe(Effect.flatMap(Option.match({
@@ -3,9 +3,9 @@ import { SuppliedService } from "./SuppliedService.mjs";
3
3
  import { Effect } from "effect";
4
4
  import { AuthStoreDecisions } from "@yielded/auth/Persistence";
5
5
  import { ConsumeChallenge, ConsumeRegistration, NewChallenge, NewRegistration, TokenDigest, VerifiedEmail } from "@yielded/auth/Schema";
6
+ import { InvalidOAuthState, OAuthState, OAuthStateDecisions } from "@yielded/auth/OAuth";
6
7
  import { EmailOtpRejected } from "@yielded/auth/AuthStore";
7
8
  import { AuthStoreError, InvalidRegistration } from "@yielded/auth/Errors";
8
- import { InvalidOAuthState, OAuthState, OAuthStateDecisions } from "@yielded/auth/OAuth";
9
9
  import { AnyRelations } from "drizzle-orm";
10
10
  import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
11
11
  import { SqlError } from "effect/unstable/sql/SqlError";
@@ -2,9 +2,9 @@ import { column, requireStandaloneConsume, updateValues } from "./model.mjs";
2
2
  import { Cause, Context, DateTime, Duration, Effect, Schema } from "effect";
3
3
  import { AuthStoreDecisions, reportPersistenceFailure } from "@yielded/auth/Persistence";
4
4
  import { VerifiedEmail, timingSafeStringEqual } from "@yielded/auth/Schema";
5
+ import { InvalidOAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
5
6
  import { AuthStore, EmailOtpRejected } from "@yielded/auth/AuthStore";
6
7
  import { AuthRateLimited, AuthStoreError, InvalidRegistration } from "@yielded/auth/Errors";
7
- import { InvalidOAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
8
8
  import { and, eq, gt, sql } from "drizzle-orm";
9
9
  //#region src/drizzle/mysql.ts
10
10
  const selected = (row) => row;
@@ -226,14 +226,14 @@ declare const makeTargetOAuthConnectedServices: (database: any, mapping: Mapping
226
226
  readonly identity: typeof OAuthExternalIdentity.Type;
227
227
  }) => Effect.Effect<{
228
228
  readonly _tag: "Rejected";
229
+ } | {
230
+ readonly _tag: "Conflict";
229
231
  } | {
230
232
  readonly _tag: "Target";
231
233
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
232
234
  } | {
233
235
  readonly _tag: "Quarantine";
234
236
  readonly cohortGeneration: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
235
- } | {
236
- readonly _tag: "Conflict";
237
237
  }, M.OAuthUnavailable>;
238
238
  readonly settle: <A>(input: {
239
239
  readonly claim: M.OAuthConnectedClaim;
@@ -243,11 +243,11 @@ declare const makeTargetOAuthConnectedServices: (database: any, mapping: Mapping
243
243
  }, prepare: PrepareOAuthCommit<{
244
244
  readonly _tag: "Rejected";
245
245
  } | {
246
- readonly _tag: "Conflict";
246
+ readonly _tag: "Ambiguous";
247
247
  } | {
248
248
  readonly _tag: "Cancelled";
249
249
  } | {
250
- readonly _tag: "Ambiguous";
250
+ readonly _tag: "Conflict";
251
251
  } | {
252
252
  readonly _tag: "Connected";
253
253
  readonly grant: {
@@ -4,9 +4,9 @@ import { Context, Effect, Layer } from "effect";
4
4
  import { AuthStoreDecisions } from "@yielded/auth/Persistence";
5
5
  import { ConsumeChallenge, ConsumeRegistration, NewChallenge, NewRegistration, SubjectId, TokenDigest, VerifiedEmail } from "@yielded/auth/Schema";
6
6
  import { ExternalIdentity, ExternalIdentityMutation, IdentityConflict, IdentityUnavailable, SubjectProvisioner, SubjectProvisioningInput } from "@yielded/auth/Identity";
7
+ import { InvalidOAuthState, OAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
7
8
  import { AuthStore, EmailOtpRejected } from "@yielded/auth/AuthStore";
8
9
  import { AuthStoreError, InvalidRegistration } from "@yielded/auth/Errors";
9
- import { InvalidOAuthState, OAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
10
10
  import { AnyRelations } from "drizzle-orm";
11
11
  import { EffectPgDatabase } from "drizzle-orm/effect-pglite";
12
12
  import { AnyPgTable } from "drizzle-orm/pg-core";
@@ -4,9 +4,9 @@ import { Cause, Context, DateTime, Duration, Effect, Schema } from "effect";
4
4
  import { AuthStoreDecisions, reportPersistenceFailure } from "@yielded/auth/Persistence";
5
5
  import { VerifiedEmail } from "@yielded/auth/Schema";
6
6
  import { ExternalIdentityMutation, IdentityConflict, IdentityUnavailable, SubjectProvisioned, SubjectProvisioner } from "@yielded/auth/Identity";
7
+ import { InvalidOAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
7
8
  import { AuthStore, EmailOtpRejected } from "@yielded/auth/AuthStore";
8
9
  import { AuthRateLimited, AuthStoreError, InvalidRegistration } from "@yielded/auth/Errors";
9
- import { InvalidOAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
10
10
  import { and, eq, gt, lt, lte, ne, or, sql } from "drizzle-orm";
11
11
  import "drizzle-orm/pg-core";
12
12
  //#region src/drizzle/pg.ts
@@ -3,9 +3,9 @@ import { SuppliedService } from "./SuppliedService.mjs";
3
3
  import { Effect } from "effect";
4
4
  import { AuthStoreDecisions } from "@yielded/auth/Persistence";
5
5
  import { ConsumeChallenge, ConsumeRegistration, NewChallenge, NewRegistration, TokenDigest, VerifiedEmail } from "@yielded/auth/Schema";
6
+ import { InvalidOAuthState, OAuthState, OAuthStateDecisions } from "@yielded/auth/OAuth";
6
7
  import { EmailOtpRejected } from "@yielded/auth/AuthStore";
7
8
  import { AuthStoreError, InvalidRegistration } from "@yielded/auth/Errors";
8
- import { InvalidOAuthState, OAuthState, OAuthStateDecisions } from "@yielded/auth/OAuth";
9
9
  import { AnyRelations } from "drizzle-orm";
10
10
  import { AnySQLiteTable } from "drizzle-orm/sqlite-core";
11
11
  import { SqlError } from "effect/unstable/sql/SqlError";
@@ -2,9 +2,9 @@ import { column, requireStandaloneConsume, updateValues } from "./model.mjs";
2
2
  import { Cause, Context, DateTime, Duration, Effect, Schema } from "effect";
3
3
  import { AuthStoreDecisions, reportPersistenceFailure } from "@yielded/auth/Persistence";
4
4
  import { VerifiedEmail } from "@yielded/auth/Schema";
5
+ import { InvalidOAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
5
6
  import { AuthStore, EmailOtpRejected } from "@yielded/auth/AuthStore";
6
7
  import { AuthRateLimited, AuthStoreError, InvalidRegistration } from "@yielded/auth/Errors";
7
- import { InvalidOAuthState, OAuthStateDecisions, OAuthStateStore } from "@yielded/auth/OAuth";
8
8
  import { and, eq, gt, lt, lte, ne, or, sql } from "drizzle-orm";
9
9
  //#region src/drizzle/sqlite.ts
10
10
  const storeReadError = () => AuthStoreError.make({ message: "Auth store read failed" });
package/dist/index.d.mts CHANGED
@@ -2,4 +2,5 @@ import { PersistenceMappingError } from "./internal/mapping-error.mjs";
2
2
  import { StorageColumn, StorageTable } from "./internal/storage-tables.mjs";
3
3
  import { PersistenceConfigurationError } from "./internal/configuration.mjs";
4
4
  import { AuthPersistence } from "./internal/sql-persistence.mjs";
5
- export { AuthPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
5
+ import { OAuthAppPersistence } from "./internal/oauth-app.mjs";
6
+ export { AuthPersistence, OAuthAppPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
package/dist/index.mjs CHANGED
@@ -2,4 +2,5 @@ import { PersistenceConfigurationError } from "./internal/configuration.mjs";
2
2
  import { PersistenceMappingError } from "./internal/mapping-error.mjs";
3
3
  import { StorageColumn, StorageTable } from "./internal/storage-tables.mjs";
4
4
  import { AuthPersistence } from "./internal/sql-persistence.mjs";
5
- export { AuthPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
5
+ import { OAuthAppPersistence } from "./internal/oauth-app.mjs";
6
+ export { AuthPersistence, OAuthAppPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
@@ -0,0 +1,12 @@
1
+ import { Layer } from "effect";
2
+ import { SqlClient } from "effect/unstable/sql";
3
+ import { OAuthUnavailable } from "@yielded/auth/OAuth";
4
+ import { Persistence } from "@yielded/auth/OAuthApp";
5
+ //#region src/internal/oauth-app.d.ts
6
+ declare const OAuthAppPersistence: {
7
+ layer: Layer.Layer<Persistence, OAuthUnavailable, SqlClient.SqlClient>;
8
+ migration: string;
9
+ };
10
+ //#endregion
11
+ export { OAuthAppPersistence };
12
+ //# sourceMappingURL=oauth-app.d.mts.map
@@ -0,0 +1,58 @@
1
+ import { Effect, Layer, Option, Schema } from "effect";
2
+ import { SqlClient } from "effect/unstable/sql";
3
+ import { OAuthUnavailable } from "@yielded/auth/OAuth";
4
+ import { Persistence, Record } from "@yielded/auth/OAuthApp";
5
+ //#region src/internal/oauth-app.ts
6
+ const codec = Schema.fromJsonString(Record);
7
+ const Row = Schema.Struct({
8
+ payload: Schema.String,
9
+ version: Schema.String
10
+ });
11
+ const OAuthAppPersistence = {
12
+ layer: Layer.effect(Persistence, Effect.gen(function* () {
13
+ const sql = yield* SqlClient.SqlClient;
14
+ if (!sql.onDialectOrElse({
15
+ sqlite: () => true,
16
+ pg: () => true,
17
+ orElse: () => false
18
+ })) return yield* OAuthUnavailable.make({});
19
+ const noTransaction = Effect.gen(function* () {
20
+ if (Option.isSome(yield* Effect.serviceOption(sql.transactionService))) return yield* OAuthUnavailable.make({});
21
+ });
22
+ const failure = (effect) => effect.pipe(Effect.mapError(() => OAuthUnavailable.make({})));
23
+ return Persistence.of({
24
+ get: Effect.fn("OAuthAppPersistence.get")(function* (namespace, key) {
25
+ yield* noTransaction;
26
+ const rows = yield* sql`SELECT payload, version FROM yielded_oauth_app WHERE namespace = ${namespace} AND record_key = ${key}`;
27
+ if (rows.length === 0) return void 0;
28
+ if (rows.length !== 1) return yield* OAuthUnavailable.make({});
29
+ const row = yield* Schema.decodeEffect(Row)(rows[0]);
30
+ const value = yield* Schema.decodeEffect(codec)(row.payload);
31
+ if (value.version !== row.version) return yield* OAuthUnavailable.make({});
32
+ return value;
33
+ }, failure),
34
+ insert: Effect.fn("OAuthAppPersistence.insert")(function* (namespace, key, value) {
35
+ yield* noTransaction;
36
+ const payload = yield* Schema.encodeEffect(codec)(value);
37
+ return (yield* sql`INSERT INTO yielded_oauth_app (namespace, record_key, version, payload) VALUES (${namespace}, ${key}, ${value.version}, ${payload}) ON CONFLICT (namespace, record_key) DO NOTHING RETURNING version`).length === 1;
38
+ }, failure),
39
+ compareAndSet: Effect.fn("OAuthAppPersistence.compareAndSet")(function* (namespace, key, version, value) {
40
+ yield* noTransaction;
41
+ if (value.version === version) return yield* OAuthUnavailable.make({});
42
+ const payload = yield* Schema.encodeEffect(codec)(value);
43
+ return (yield* sql`UPDATE yielded_oauth_app SET version = ${value.version}, payload = ${payload} WHERE namespace = ${namespace} AND record_key = ${key} AND version = ${version} RETURNING version`).length === 1;
44
+ }, failure)
45
+ });
46
+ })),
47
+ migration: `CREATE TABLE yielded_oauth_app (
48
+ namespace TEXT NOT NULL,
49
+ record_key TEXT NOT NULL,
50
+ version TEXT NOT NULL,
51
+ payload TEXT NOT NULL,
52
+ PRIMARY KEY (namespace, record_key)
53
+ )`
54
+ };
55
+ //#endregion
56
+ export { OAuthAppPersistence };
57
+
58
+ //# sourceMappingURL=oauth-app.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-app.mjs","names":[],"sources":["../../src/internal/oauth-app.ts"],"sourcesContent":["import { OAuthUnavailable } from \"@yielded/auth/OAuth\";\nimport { Persistence, Record } from \"@yielded/auth/OAuthApp\";\nimport { Effect, Layer, Option, Schema } from \"effect\";\nimport { SqlClient } from \"effect/unstable/sql\";\n\nconst codec = Schema.fromJsonString(Record);\nconst Row = Schema.Struct({ payload: Schema.String, version: Schema.String });\n\n/** Apply with the application's migrations. SQLite (including D1) and PostgreSQL.\n * Each transition is one conditional statement, so D1 needs no interactive\n * transaction and parallel workers share the same refresh/code claim.\n */\nconst migration = `CREATE TABLE yielded_oauth_app (\n namespace TEXT NOT NULL,\n record_key TEXT NOT NULL,\n version TEXT NOT NULL,\n payload TEXT NOT NULL,\n PRIMARY KEY (namespace, record_key)\n)`;\n\nconst layer = Layer.effect(\n Persistence,\n Effect.gen(function* () {\n const sql = yield* SqlClient.SqlClient;\n\n if (!sql.onDialectOrElse({ sqlite: () => true, pg: () => true, orElse: () => false }))\n return yield* OAuthUnavailable.make({});\n\n const noTransaction = Effect.gen(function* () {\n if (Option.isSome(yield* Effect.serviceOption(sql.transactionService)))\n return yield* OAuthUnavailable.make({});\n });\n\n const failure = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n effect.pipe(Effect.mapError(() => OAuthUnavailable.make({})));\n\n return Persistence.of({\n get: Effect.fn(\"OAuthAppPersistence.get\")(function* (namespace, key) {\n yield* noTransaction;\n\n const rows = yield* sql<{\n payload: string;\n version: string;\n }>`SELECT payload, version FROM yielded_oauth_app WHERE namespace = ${namespace} AND record_key = ${key}`;\n\n if (rows.length === 0) return undefined;\n if (rows.length !== 1) return yield* OAuthUnavailable.make({});\n const row = yield* Schema.decodeEffect(Row)(rows[0]);\n const value = yield* Schema.decodeEffect(codec)(row.payload);\n\n if (value.version !== row.version) return yield* OAuthUnavailable.make({});\n\n return value;\n }, failure),\n insert: Effect.fn(\"OAuthAppPersistence.insert\")(function* (namespace, key, value) {\n yield* noTransaction;\n const payload = yield* Schema.encodeEffect(codec)(value);\n\n const rows =\n yield* sql`INSERT INTO yielded_oauth_app (namespace, record_key, version, payload) VALUES (${namespace}, ${key}, ${value.version}, ${payload}) ON CONFLICT (namespace, record_key) DO NOTHING RETURNING version`;\n\n return rows.length === 1;\n }, failure),\n compareAndSet: Effect.fn(\"OAuthAppPersistence.compareAndSet\")(function* (\n namespace,\n key,\n version,\n value,\n ) {\n yield* noTransaction;\n if (value.version === version) return yield* OAuthUnavailable.make({});\n const payload = yield* Schema.encodeEffect(codec)(value);\n\n const rows =\n yield* sql`UPDATE yielded_oauth_app SET version = ${value.version}, payload = ${payload} WHERE namespace = ${namespace} AND record_key = ${key} AND version = ${version} RETURNING version`;\n\n return rows.length === 1;\n }, failure),\n });\n }),\n);\n\nexport const OAuthAppPersistence = { layer, migration };\n"],"mappings":";;;;;AAKA,MAAM,QAAQ,OAAO,eAAe,MAAM;AAC1C,MAAM,MAAM,OAAO,OAAO;CAAE,SAAS,OAAO;CAAQ,SAAS,OAAO;AAAO,CAAC;AA4E5E,MAAa,sBAAsB;CAAE,OA9DvB,MAAM,OAClB,aACA,OAAO,IAAI,aAAa;EACtB,MAAM,MAAM,OAAO,UAAU;EAE7B,IAAI,CAAC,IAAI,gBAAgB;GAAE,cAAc;GAAM,UAAU;GAAM,cAAc;EAAM,CAAC,GAClF,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;EAExC,MAAM,gBAAgB,OAAO,IAAI,aAAa;GAC5C,IAAI,OAAO,OAAO,OAAO,OAAO,cAAc,IAAI,kBAAkB,CAAC,GACnE,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;EAC1C,CAAC;EAED,MAAM,WAAoB,WACxB,OAAO,KAAK,OAAO,eAAe,iBAAiB,KAAK,CAAC,CAAC,CAAC,CAAC;EAE9D,OAAO,YAAY,GAAG;GACpB,KAAK,OAAO,GAAG,yBAAyB,CAAC,CAAC,WAAW,WAAW,KAAK;IACnE,OAAO;IAEP,MAAM,OAAO,OAAO,GAGlB,oEAAoE,UAAU,oBAAoB;IAEpG,IAAI,KAAK,WAAW,GAAG,OAAO,KAAA;IAC9B,IAAI,KAAK,WAAW,GAAG,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;IAC7D,MAAM,MAAM,OAAO,OAAO,aAAa,GAAG,CAAC,CAAC,KAAK,EAAE;IACnD,MAAM,QAAQ,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,IAAI,OAAO;IAE3D,IAAI,MAAM,YAAY,IAAI,SAAS,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;IAEzE,OAAO;GACT,GAAG,OAAO;GACV,QAAQ,OAAO,GAAG,4BAA4B,CAAC,CAAC,WAAW,WAAW,KAAK,OAAO;IAChF,OAAO;IACP,MAAM,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,KAAK;IAKvD,QAAO,OAFE,GAAG,mFAAmF,UAAU,IAAI,IAAI,IAAI,MAAM,QAAQ,IAAI,QAAQ,oEAAA,CAEnI,WAAW;GACzB,GAAG,OAAO;GACV,eAAe,OAAO,GAAG,mCAAmC,CAAC,CAAC,WAC5D,WACA,KACA,SACA,OACA;IACA,OAAO;IACP,IAAI,MAAM,YAAY,SAAS,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;IACrE,MAAM,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,KAAK;IAKvD,QAAO,OAFE,GAAG,0CAA0C,MAAM,QAAQ,cAAc,QAAQ,qBAAqB,UAAU,oBAAoB,IAAI,iBAAiB,QAAQ,oBAAA,CAE9J,WAAW;GACzB,GAAG,OAAO;EACZ,CAAC;CACH,CAAC,CAGkC;CAAO;;;;;;;AAAU"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@yielded/auth-persistence","version":"0.1.0-beta.7","dependencies":{"@noble/hashes":"2.3.0","@yielded/auth":"0.1.0-beta.7"},"devDependencies":{"@effect/platform-bun":"4.0.0-rc.112","@effect/platform-node":"4.0.0-rc.112","@effect/sql-d1":"4.0.0-rc.112","@effect/sql-libsql":"4.0.0-rc.112","@effect/sql-mysql2":"4.0.0-rc.112","@effect/sql-pg":"4.0.0-rc.112","@effect/sql-pglite":"4.0.0-rc.112","@effect/sql-sqlite-bun":"4.0.0-rc.112","@effect/sql-sqlite-do":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112","@effect/sql-sqlite-wasm":"4.0.0-rc.112","@effect/vitest":"4.0.0-rc.112","drizzle-orm":"1.0.0-rc.5-ab785fc","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"@effect/sql-d1":">=4.0.0-rc.112","@effect/sql-libsql":">=4.0.0-rc.112","@effect/sql-mysql2":">=4.0.0-rc.112","@effect/sql-pg":">=4.0.0-rc.112","@effect/sql-pglite":">=4.0.0-rc.112","@effect/sql-sqlite-bun":">=4.0.0-rc.112","@effect/sql-sqlite-do":">=4.0.0-rc.112","@effect/sql-sqlite-node":">=4.0.0-rc.112","@effect/sql-sqlite-wasm":">=4.0.0-rc.112","drizzle-orm":">=1.0.0-rc.5-ab785fc","effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./drizzle":{"types":"./dist/Drizzle.d.mts","default":"./dist/Drizzle.mjs"},"./drizzle/d1":{"types":"./dist/DrizzleD1.d.mts","default":"./dist/DrizzleD1.mjs"},"./drizzle/libsql":{"types":"./dist/DrizzleLibsql.d.mts","default":"./dist/DrizzleLibsql.mjs"},"./drizzle/mysql2":{"types":"./dist/DrizzleMysql2.d.mts","default":"./dist/DrizzleMysql2.mjs"},"./drizzle/pglite":{"types":"./dist/DrizzlePglite.d.mts","default":"./dist/DrizzlePglite.mjs"},"./drizzle/postgres":{"types":"./dist/DrizzlePostgres.d.mts","default":"./dist/DrizzlePostgres.mjs"},"./drizzle/sqlite-bun":{"types":"./dist/DrizzleSqliteBun.d.mts","default":"./dist/DrizzleSqliteBun.mjs"},"./drizzle/sqlite-do":{"types":"./dist/DrizzleSqliteDo.d.mts","default":"./dist/DrizzleSqliteDo.mjs"},"./drizzle/sqlite-node":{"types":"./dist/DrizzleSqliteNode.d.mts","default":"./dist/DrizzleSqliteNode.mjs"},"./drizzle/sqlite-wasm":{"types":"./dist/DrizzleSqliteWasm.d.mts","default":"./dist/DrizzleSqliteWasm.mjs"}},"description":"SQL persistence, Drizzle bindings, and managed schemas for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests","example:totp":"bun test/fixtures/totp-sqlite-bun.ts"},"peerDependenciesMeta":{"@effect/sql-d1":{"optional":true},"@effect/sql-libsql":{"optional":true},"@effect/sql-mysql2":{"optional":true},"@effect/sql-pg":{"optional":true},"@effect/sql-pglite":{"optional":true},"@effect/sql-sqlite-bun":{"optional":true},"@effect/sql-sqlite-do":{"optional":true},"@effect/sql-sqlite-node":{"optional":true},"@effect/sql-sqlite-wasm":{"optional":true},"drizzle-orm":{"optional":true}}}
1
+ {"name":"@yielded/auth-persistence","version":"0.1.0-beta.8","dependencies":{"@noble/hashes":"2.3.0","@yielded/auth":"0.1.0-beta.8"},"devDependencies":{"@effect/platform-bun":"4.0.0-rc.112","@effect/platform-node":"4.0.0-rc.112","@effect/sql-d1":"4.0.0-rc.112","@effect/sql-libsql":"4.0.0-rc.112","@effect/sql-mysql2":"4.0.0-rc.112","@effect/sql-pg":"4.0.0-rc.112","@effect/sql-pglite":"4.0.0-rc.112","@effect/sql-sqlite-bun":"4.0.0-rc.112","@effect/sql-sqlite-do":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112","@effect/sql-sqlite-wasm":"4.0.0-rc.112","@effect/vitest":"4.0.0-rc.112","drizzle-orm":"1.0.0-rc.5-ab785fc","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"@effect/sql-d1":">=4.0.0-rc.112","@effect/sql-libsql":">=4.0.0-rc.112","@effect/sql-mysql2":">=4.0.0-rc.112","@effect/sql-pg":">=4.0.0-rc.112","@effect/sql-pglite":">=4.0.0-rc.112","@effect/sql-sqlite-bun":">=4.0.0-rc.112","@effect/sql-sqlite-do":">=4.0.0-rc.112","@effect/sql-sqlite-node":">=4.0.0-rc.112","@effect/sql-sqlite-wasm":">=4.0.0-rc.112","drizzle-orm":">=1.0.0-rc.5-ab785fc","effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./drizzle":{"types":"./dist/Drizzle.d.mts","default":"./dist/Drizzle.mjs"},"./drizzle/d1":{"types":"./dist/DrizzleD1.d.mts","default":"./dist/DrizzleD1.mjs"},"./drizzle/libsql":{"types":"./dist/DrizzleLibsql.d.mts","default":"./dist/DrizzleLibsql.mjs"},"./drizzle/mysql2":{"types":"./dist/DrizzleMysql2.d.mts","default":"./dist/DrizzleMysql2.mjs"},"./drizzle/pglite":{"types":"./dist/DrizzlePglite.d.mts","default":"./dist/DrizzlePglite.mjs"},"./drizzle/postgres":{"types":"./dist/DrizzlePostgres.d.mts","default":"./dist/DrizzlePostgres.mjs"},"./drizzle/sqlite-bun":{"types":"./dist/DrizzleSqliteBun.d.mts","default":"./dist/DrizzleSqliteBun.mjs"},"./drizzle/sqlite-do":{"types":"./dist/DrizzleSqliteDo.d.mts","default":"./dist/DrizzleSqliteDo.mjs"},"./drizzle/sqlite-node":{"types":"./dist/DrizzleSqliteNode.d.mts","default":"./dist/DrizzleSqliteNode.mjs"},"./drizzle/sqlite-wasm":{"types":"./dist/DrizzleSqliteWasm.d.mts","default":"./dist/DrizzleSqliteWasm.mjs"}},"description":"SQL persistence, Drizzle bindings, and managed schemas for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests","example:totp":"bun test/fixtures/totp-sqlite-bun.ts"},"peerDependenciesMeta":{"@effect/sql-d1":{"optional":true},"@effect/sql-libsql":{"optional":true},"@effect/sql-mysql2":{"optional":true},"@effect/sql-pg":{"optional":true},"@effect/sql-pglite":{"optional":true},"@effect/sql-sqlite-bun":{"optional":true},"@effect/sql-sqlite-do":{"optional":true},"@effect/sql-sqlite-node":{"optional":true},"@effect/sql-sqlite-wasm":{"optional":true},"drizzle-orm":{"optional":true}}}
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { AuthPersistence } from "./internal/sql-persistence";
2
+ export { OAuthAppPersistence } from "./internal/oauth-app";
2
3
  export { PersistenceConfigurationError } from "./internal/configuration";
3
4
  export { PersistenceMappingError } from "./internal/mapping-error";
4
5
  export { StorageColumn, StorageTable } from "./internal/storage-tables";
@@ -0,0 +1,83 @@
1
+ import { OAuthUnavailable } from "@yielded/auth/OAuth";
2
+ import { Persistence, Record } from "@yielded/auth/OAuthApp";
3
+ import { Effect, Layer, Option, Schema } from "effect";
4
+ import { SqlClient } from "effect/unstable/sql";
5
+
6
+ const codec = Schema.fromJsonString(Record);
7
+ const Row = Schema.Struct({ payload: Schema.String, version: Schema.String });
8
+
9
+ /** Apply with the application's migrations. SQLite (including D1) and PostgreSQL.
10
+ * Each transition is one conditional statement, so D1 needs no interactive
11
+ * transaction and parallel workers share the same refresh/code claim.
12
+ */
13
+ const migration = `CREATE TABLE yielded_oauth_app (
14
+ namespace TEXT NOT NULL,
15
+ record_key TEXT NOT NULL,
16
+ version TEXT NOT NULL,
17
+ payload TEXT NOT NULL,
18
+ PRIMARY KEY (namespace, record_key)
19
+ )`;
20
+
21
+ const layer = Layer.effect(
22
+ Persistence,
23
+ Effect.gen(function* () {
24
+ const sql = yield* SqlClient.SqlClient;
25
+
26
+ if (!sql.onDialectOrElse({ sqlite: () => true, pg: () => true, orElse: () => false }))
27
+ return yield* OAuthUnavailable.make({});
28
+
29
+ const noTransaction = Effect.gen(function* () {
30
+ if (Option.isSome(yield* Effect.serviceOption(sql.transactionService)))
31
+ return yield* OAuthUnavailable.make({});
32
+ });
33
+
34
+ const failure = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
35
+ effect.pipe(Effect.mapError(() => OAuthUnavailable.make({})));
36
+
37
+ return Persistence.of({
38
+ get: Effect.fn("OAuthAppPersistence.get")(function* (namespace, key) {
39
+ yield* noTransaction;
40
+
41
+ const rows = yield* sql<{
42
+ payload: string;
43
+ version: string;
44
+ }>`SELECT payload, version FROM yielded_oauth_app WHERE namespace = ${namespace} AND record_key = ${key}`;
45
+
46
+ if (rows.length === 0) return undefined;
47
+ if (rows.length !== 1) return yield* OAuthUnavailable.make({});
48
+ const row = yield* Schema.decodeEffect(Row)(rows[0]);
49
+ const value = yield* Schema.decodeEffect(codec)(row.payload);
50
+
51
+ if (value.version !== row.version) return yield* OAuthUnavailable.make({});
52
+
53
+ return value;
54
+ }, failure),
55
+ insert: Effect.fn("OAuthAppPersistence.insert")(function* (namespace, key, value) {
56
+ yield* noTransaction;
57
+ const payload = yield* Schema.encodeEffect(codec)(value);
58
+
59
+ const rows =
60
+ yield* sql`INSERT INTO yielded_oauth_app (namespace, record_key, version, payload) VALUES (${namespace}, ${key}, ${value.version}, ${payload}) ON CONFLICT (namespace, record_key) DO NOTHING RETURNING version`;
61
+
62
+ return rows.length === 1;
63
+ }, failure),
64
+ compareAndSet: Effect.fn("OAuthAppPersistence.compareAndSet")(function* (
65
+ namespace,
66
+ key,
67
+ version,
68
+ value,
69
+ ) {
70
+ yield* noTransaction;
71
+ if (value.version === version) return yield* OAuthUnavailable.make({});
72
+ const payload = yield* Schema.encodeEffect(codec)(value);
73
+
74
+ const rows =
75
+ yield* sql`UPDATE yielded_oauth_app SET version = ${value.version}, payload = ${payload} WHERE namespace = ${namespace} AND record_key = ${key} AND version = ${version} RETURNING version`;
76
+
77
+ return rows.length === 1;
78
+ }, failure),
79
+ });
80
+ }),
81
+ );
82
+
83
+ export const OAuthAppPersistence = { layer, migration };