@yielded/auth-persistence-drizzle 0.1.0-beta.18 → 0.1.0-beta.20
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 +8 -1
- package/dist/D1.d.mts +8 -8
- package/dist/Libsql.d.mts +38 -38
- package/dist/Mysql2.d.mts +51 -51
- package/dist/Pglite.d.mts +51 -51
- package/dist/Postgres.d.mts +38 -38
- package/dist/SqliteBun.d.mts +51 -51
- package/dist/SqliteDo.d.mts +112 -134
- package/dist/SqliteDo.mjs +30 -45
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +44 -44
- package/dist/SqliteWasm.d.mts +38 -38
- package/dist/drizzle/crypto.mjs +11 -0
- package/dist/drizzle/crypto.mjs.map +1 -0
- package/dist/drizzle/d1-identity.mjs +2 -2
- package/dist/drizzle/d1-identity.mjs.map +1 -1
- package/dist/drizzle/d1-oauth.d.mts +11 -11
- package/dist/drizzle/d1-oauth.mjs.map +1 -1
- package/dist/drizzle/d1-passkey.d.mts +6 -6
- package/dist/drizzle/d1-passkey.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +1 -1
- package/dist/drizzle/d1-phone.d.mts +3 -3
- package/dist/drizzle/d1-phone.mjs.map +1 -1
- package/dist/drizzle/d1-proofs.d.mts +1 -1
- package/dist/drizzle/d1-sessions.d.mts +1 -1
- package/dist/drizzle/d1-totp.d.mts +3 -3
- package/dist/drizzle/d1-totp.mjs.map +1 -1
- package/dist/drizzle/mysql-identity.mjs +2 -2
- package/dist/drizzle/mysql-identity.mjs.map +1 -1
- package/dist/drizzle/oauth-accounts.mjs +9 -8
- package/dist/drizzle/oauth-accounts.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-collection.mjs +1 -1
- package/dist/drizzle/oauth-connected-collection.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-custody.mjs +5 -4
- package/dist/drizzle/oauth-connected-custody.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-flow.mjs +8 -7
- package/dist/drizzle/oauth-connected-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-management.mjs +3 -2
- package/dist/drizzle/oauth-connected-management.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-reference.mjs +8 -4
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-settlement.mjs +4 -4
- package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-sign-in.mjs +11 -10
- package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-state.d.mts +13 -13
- package/dist/drizzle/oauth-connected-state.mjs +23 -20
- package/dist/drizzle/oauth-connected-state.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-target.d.mts +9 -9
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
- package/dist/drizzle/oauth-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-flow.mjs +1 -1
- package/dist/drizzle/oauth-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-model.d.mts +4 -4
- package/dist/drizzle/oauth-model.mjs.map +1 -1
- package/dist/drizzle/oauth-registration.mjs +2 -2
- package/dist/drizzle/oauth-registration.mjs.map +1 -1
- package/dist/drizzle/oauth-state.mjs +11 -12
- package/dist/drizzle/oauth-state.mjs.map +1 -1
- package/dist/drizzle/oauth-target.d.mts +4 -4
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-target.d.mts +1 -1
- package/dist/drizzle/password-prepared-state.mjs +1 -1
- package/dist/drizzle/pg-identity.mjs +2 -2
- package/dist/drizzle/pg-identity.mjs.map +1 -1
- package/dist/drizzle/phone-model.d.mts +2 -2
- package/dist/drizzle/phone-model.mjs +3 -3
- package/dist/drizzle/phone-model.mjs.map +1 -1
- package/dist/drizzle/phone-target.d.mts +1 -1
- package/dist/drizzle/phone-target.mjs +2 -2
- package/dist/drizzle/phone-target.mjs.map +1 -1
- package/dist/drizzle/sqlite-do-database.d.mts +29 -0
- package/dist/drizzle/sqlite-do-database.mjs +45 -0
- package/dist/drizzle/sqlite-do-database.mjs.map +1 -0
- package/dist/drizzle/sqlite-emails.mjs.map +1 -1
- package/dist/drizzle/sqlite-identity.mjs +2 -2
- package/dist/drizzle/sqlite-identity.mjs.map +1 -1
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
- package/dist/drizzle/storage-validation.mjs +17 -9
- package/dist/drizzle/storage-validation.mjs.map +1 -1
- package/dist/drizzle/totp-state.mjs +8 -8
- package/dist/drizzle/totp-state.mjs.map +1 -1
- package/dist/drizzle/totp-target.d.mts +1 -1
- package/dist/drizzle/totp-target.mjs +2 -2
- package/dist/drizzle/totp-target.mjs.map +1 -1
- package/package.json +1 -1
- package/src/SqliteDo.ts +63 -70
- package/src/drizzle/crypto.ts +14 -0
- package/src/drizzle/d1-identity.ts +2 -2
- package/src/drizzle/d1-oauth.ts +14 -5
- package/src/drizzle/d1-passkey.ts +5 -1
- package/src/drizzle/d1-phone.ts +2 -1
- package/src/drizzle/d1-totp.ts +6 -2
- package/src/drizzle/mysql-identity.ts +2 -2
- package/src/drizzle/oauth-accounts.ts +14 -13
- package/src/drizzle/oauth-connected-collection.ts +1 -1
- package/src/drizzle/oauth-connected-custody.ts +8 -6
- package/src/drizzle/oauth-connected-drivers.ts +9 -3
- package/src/drizzle/oauth-connected-flow.ts +6 -6
- package/src/drizzle/oauth-connected-management.ts +1 -1
- package/src/drizzle/oauth-connected-reference.ts +14 -9
- package/src/drizzle/oauth-connected-settlement.ts +4 -4
- package/src/drizzle/oauth-connected-sign-in.ts +11 -10
- package/src/drizzle/oauth-connected-state.ts +40 -25
- package/src/drizzle/oauth-connected-target.ts +9 -5
- package/src/drizzle/oauth-drivers.ts +13 -5
- package/src/drizzle/oauth-flow.ts +1 -1
- package/src/drizzle/oauth-model.ts +4 -4
- package/src/drizzle/oauth-registration.ts +2 -2
- package/src/drizzle/oauth-state.ts +17 -15
- package/src/drizzle/oauth-target.ts +11 -3
- package/src/drizzle/passkey-drivers.ts +7 -3
- package/src/drizzle/passkey-write-drivers.ts +11 -2
- package/src/drizzle/pg-identity.ts +2 -2
- package/src/drizzle/phone-model.ts +3 -3
- package/src/drizzle/phone-target.ts +11 -4
- package/src/drizzle/sqlite-do-database.ts +87 -0
- package/src/drizzle/sqlite-emails.ts +1 -1
- package/src/drizzle/sqlite-identity.ts +2 -2
- package/src/drizzle/sqlite-passwords.ts +1 -1
- package/src/drizzle/sqlite-proofs.ts +2 -2
- package/src/drizzle/sqlite-sessions.ts +2 -2
- package/src/drizzle/storage-validation.ts +15 -6
- package/src/drizzle/totp-state.ts +8 -8
- package/src/drizzle/totp-target.ts +11 -5
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import type { SecurityRevision } from "@yielded/auth/Sessions";
|
|
29
29
|
/* oxlint-disable no-explicit-any -- concrete driver entry points restore table/database generics. */
|
|
30
30
|
import { eq, sql } from "drizzle-orm";
|
|
31
|
-
import { type Context, Effect, Layer } from "effect";
|
|
31
|
+
import { type Crypto, type Context, Effect, Layer } from "effect";
|
|
32
32
|
import type { Statement } from "effect/sql/Statement";
|
|
33
33
|
|
|
34
34
|
import type { PersistenceMappingError } from "./model";
|
|
@@ -91,7 +91,11 @@ export const sqlClientOAuthStandaloneGuard = (
|
|
|
91
91
|
export const makeOAuthExecution = Effect.fnUntraced(function* (
|
|
92
92
|
configuration: OAuthTargetConfiguration,
|
|
93
93
|
mapping: unknown,
|
|
94
|
-
): Effect.fn.Return<
|
|
94
|
+
): Effect.fn.Return<
|
|
95
|
+
OAuthExecution,
|
|
96
|
+
OAuthUnavailable,
|
|
97
|
+
LifecycleHooks | NativeDatabase | Crypto.Crypto
|
|
98
|
+
> {
|
|
95
99
|
const hooks = yield* LifecycleHooks;
|
|
96
100
|
|
|
97
101
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
@@ -435,7 +439,11 @@ export const coordinateOAuthOwner = <Services, Transaction, A, E, R>(
|
|
|
435
439
|
services: Services,
|
|
436
440
|
append: (statement: Statement<any>) => void,
|
|
437
441
|
) => Effect.Effect<A, E, R>,
|
|
438
|
-
): Effect.Effect<
|
|
442
|
+
): Effect.Effect<
|
|
443
|
+
A,
|
|
444
|
+
OAuthCoordinatorError<E>,
|
|
445
|
+
R | Crypto.Crypto | LifecycleHooks | NativeDatabase
|
|
446
|
+
> => {
|
|
439
447
|
const captured = captureOAuthMapping(mapping);
|
|
440
448
|
|
|
441
449
|
return Effect.flatMap(LifecycleHooks, (hooks) =>
|
|
@@ -2,7 +2,7 @@ import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
|
2
2
|
import type { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
3
3
|
import { PasskeyPersistence } from "@yielded/auth/Passkey";
|
|
4
4
|
import type { Table } from "drizzle-orm";
|
|
5
|
-
import { Effect, Context } from "effect";
|
|
5
|
+
import { type Crypto, Effect, Context } from "effect";
|
|
6
6
|
|
|
7
7
|
import { nativeDatabase } from "./native-database";
|
|
8
8
|
import type {
|
|
@@ -84,6 +84,7 @@ export const makePasskeyTarget = <
|
|
|
84
84
|
A,
|
|
85
85
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
86
86
|
| (Synchronous extends true ? never : Exclude<R, PasskeyPersistence>)
|
|
87
|
+
| Crypto.Crypto
|
|
87
88
|
| LifecycleHooks
|
|
88
89
|
| DatabaseRequirements
|
|
89
90
|
| RSetup
|
|
@@ -130,6 +131,7 @@ export const makePasskeyTarget = <
|
|
|
130
131
|
A,
|
|
131
132
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
132
133
|
| (Synchronous extends true ? never : Exclude<R, PasskeyPersistence | TxId>)
|
|
134
|
+
| Crypto.Crypto
|
|
133
135
|
| LifecycleHooks
|
|
134
136
|
| DatabaseRequirements
|
|
135
137
|
| RSetup
|
|
@@ -175,7 +177,7 @@ export const makePasskeyTarget = <
|
|
|
175
177
|
): Effect.Effect<
|
|
176
178
|
A,
|
|
177
179
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
178
|
-
Exclude<R, PasskeyPersistence> | LifecycleHooks | DatabaseRequirements | RSetup
|
|
180
|
+
Exclude<R, PasskeyPersistence> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements | RSetup
|
|
179
181
|
> {
|
|
180
182
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
181
183
|
coordinateTargetPasskey(
|
|
@@ -221,6 +223,7 @@ export const makePasskeyTarget = <
|
|
|
221
223
|
A,
|
|
222
224
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
223
225
|
| (Synchronous extends true ? never : Exclude<R, PasskeyPersistence>)
|
|
226
|
+
| Crypto.Crypto
|
|
224
227
|
| LifecycleHooks
|
|
225
228
|
| DatabaseRequirements
|
|
226
229
|
| RSetup
|
|
@@ -255,6 +258,7 @@ export const makePasskeyTarget = <
|
|
|
255
258
|
A,
|
|
256
259
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
257
260
|
| (Synchronous extends true ? never : Exclude<R, PasskeyPersistence | TxId>)
|
|
261
|
+
| Crypto.Crypto
|
|
258
262
|
| LifecycleHooks
|
|
259
263
|
| DatabaseRequirements
|
|
260
264
|
| RSetup
|
|
@@ -288,7 +292,7 @@ export const makePasskeyTarget = <
|
|
|
288
292
|
): Effect.Effect<
|
|
289
293
|
A,
|
|
290
294
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
291
|
-
Exclude<R, PasskeyPersistence> | LifecycleHooks | DatabaseRequirements | RSetup
|
|
295
|
+
Exclude<R, PasskeyPersistence> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements | RSetup
|
|
292
296
|
> {
|
|
293
297
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
294
298
|
coordinateTargetPasskeyRegistration(
|
|
@@ -2,7 +2,7 @@ import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
|
2
2
|
import type { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
3
3
|
import { PasskeyManagementPersistence, PasskeyPersistence } from "@yielded/auth/Passkey";
|
|
4
4
|
import type { Table } from "drizzle-orm";
|
|
5
|
-
import { Context, Effect } from "effect";
|
|
5
|
+
import { type Crypto, Context, Effect } from "effect";
|
|
6
6
|
|
|
7
7
|
import { nativeDatabase } from "./native-database";
|
|
8
8
|
import type { PasskeyMappingSource } from "./passkey-model";
|
|
@@ -73,6 +73,7 @@ export const makePasskeyWriteTarget = <
|
|
|
73
73
|
| (Synchronous extends true
|
|
74
74
|
? never
|
|
75
75
|
: Exclude<R, PasskeyPersistence | PasskeyManagementPersistence>)
|
|
76
|
+
| Crypto.Crypto
|
|
76
77
|
| LifecycleHooks
|
|
77
78
|
| RSetup
|
|
78
79
|
| DatabaseRequirements
|
|
@@ -120,6 +121,7 @@ export const makePasskeyWriteTarget = <
|
|
|
120
121
|
| (Synchronous extends true
|
|
121
122
|
? never
|
|
122
123
|
: Exclude<R, PasskeyPersistence | PasskeyManagementPersistence | TxId>)
|
|
124
|
+
| Crypto.Crypto
|
|
123
125
|
| LifecycleHooks
|
|
124
126
|
| RSetup
|
|
125
127
|
| DatabaseRequirements
|
|
@@ -159,6 +161,7 @@ export const makePasskeyWriteTarget = <
|
|
|
159
161
|
A,
|
|
160
162
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
161
163
|
| Exclude<R, PasskeyPersistence | PasskeyManagementPersistence>
|
|
164
|
+
| Crypto.Crypto
|
|
162
165
|
| LifecycleHooks
|
|
163
166
|
| RSetup
|
|
164
167
|
| DatabaseRequirements
|
|
@@ -250,6 +253,7 @@ export const makePasskeyWriteTarget = <
|
|
|
250
253
|
A,
|
|
251
254
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
252
255
|
| (Synchronous extends true ? never : Exclude<R, PasskeyPersistence | AuthorityId>)
|
|
256
|
+
| Crypto.Crypto
|
|
253
257
|
| LifecycleHooks
|
|
254
258
|
| RSetup
|
|
255
259
|
| DatabaseRequirements
|
|
@@ -297,6 +301,7 @@ export const makePasskeyWriteTarget = <
|
|
|
297
301
|
A,
|
|
298
302
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
299
303
|
| (Synchronous extends true ? never : Exclude<R, PasskeyPersistence | AuthorityId | TxId>)
|
|
304
|
+
| Crypto.Crypto
|
|
300
305
|
| LifecycleHooks
|
|
301
306
|
| RSetup
|
|
302
307
|
| DatabaseRequirements
|
|
@@ -339,7 +344,11 @@ export const makePasskeyWriteTarget = <
|
|
|
339
344
|
): Effect.Effect<
|
|
340
345
|
A,
|
|
341
346
|
PasskeyCoordinatorError<E> | DatabaseError,
|
|
342
|
-
Exclude<R, PasskeyPersistence | AuthorityId>
|
|
347
|
+
| Exclude<R, PasskeyPersistence | AuthorityId>
|
|
348
|
+
| Crypto.Crypto
|
|
349
|
+
| LifecycleHooks
|
|
350
|
+
| RSetup
|
|
351
|
+
| DatabaseRequirements
|
|
343
352
|
> {
|
|
344
353
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
345
354
|
coordinateTargetPasskeyRegistrationWriter(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
1
|
+
import { withStorageValidation, NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
2
2
|
import {
|
|
3
3
|
ExternalIdentityMutation,
|
|
4
4
|
IdentityConflict,
|
|
@@ -307,4 +307,4 @@ export const makePgIdentityServices = Effect.fnUntraced(function* <
|
|
|
307
307
|
...(yield* makePgSubjectProvisioningServices(mapping)),
|
|
308
308
|
...(yield* makePgExternalIdentityServices(mapping)),
|
|
309
309
|
};
|
|
310
|
-
});
|
|
310
|
+
}, withStorageValidation);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hooksLayer } from "@yielded/auth/Persistence";
|
|
2
2
|
import {
|
|
3
3
|
type PhoneAdmissionPolicy,
|
|
4
4
|
type PhoneLifecyclePolicy,
|
|
@@ -175,7 +175,7 @@ export interface PhonePersistenceServices {
|
|
|
175
175
|
readonly phoneSignInTargets: PhoneSignInTargets["Service"];
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
/** Bundle phone storage, admission, and lookup with
|
|
178
|
+
/** Bundle phone storage, admission, and lookup with empty hook defaults. */
|
|
179
179
|
export const phonePersistenceLayer = <E, R>(
|
|
180
180
|
services: Effect.Effect<PhonePersistenceServices, E, R>,
|
|
181
181
|
) =>
|
|
@@ -187,4 +187,4 @@ export const phonePersistenceLayer = <E, R>(
|
|
|
187
187
|
Layer.succeed(PhoneSignInTargets, value.phoneSignInTargets),
|
|
188
188
|
),
|
|
189
189
|
),
|
|
190
|
-
).pipe(Layer.provide(
|
|
190
|
+
).pipe(Layer.provide(hooksLayer));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomId } from "@yielded/auth-crypto";
|
|
2
1
|
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
3
2
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
4
3
|
import {
|
|
@@ -16,9 +15,10 @@ import {
|
|
|
16
15
|
import { ProofBinding } from "@yielded/auth/Proofs";
|
|
17
16
|
import { sql, type Table } from "drizzle-orm";
|
|
18
17
|
/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */
|
|
19
|
-
import { Context, Effect, Schema } from "effect";
|
|
18
|
+
import { type Crypto, Context, Effect, Schema } from "effect";
|
|
20
19
|
import type { Statement } from "effect/sql/Statement";
|
|
21
20
|
|
|
21
|
+
import { randomId } from "./crypto";
|
|
22
22
|
import { CurrentD1PlanningDatabase } from "./d1-planning";
|
|
23
23
|
import { compileD1ProofCompletionPlan } from "./d1-proofs";
|
|
24
24
|
import type { PersistenceMappingError } from "./model";
|
|
@@ -309,7 +309,11 @@ export const coordinateTargetPhone = <
|
|
|
309
309
|
services: PhonePersistenceServices,
|
|
310
310
|
append: (statement: Statement<any>) => void,
|
|
311
311
|
) => Effect.Effect<A, E, R>,
|
|
312
|
-
): Effect.Effect<
|
|
312
|
+
): Effect.Effect<
|
|
313
|
+
A,
|
|
314
|
+
PhoneCoordinatorError<E>,
|
|
315
|
+
R | RSetup | Crypto.Crypto | LifecycleHooks | NativeDatabase
|
|
316
|
+
> =>
|
|
313
317
|
Effect.gen(function* () {
|
|
314
318
|
const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);
|
|
315
319
|
|
|
@@ -342,7 +346,7 @@ type TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => an
|
|
|
342
346
|
? Parameters<Parameters<D["transaction"]>[0]>[0]
|
|
343
347
|
: never;
|
|
344
348
|
|
|
345
|
-
/** Concrete driver wrappers select transaction mode
|
|
349
|
+
/** Concrete driver wrappers select transaction mode. */
|
|
346
350
|
export const makePhoneTarget = <
|
|
347
351
|
DatabaseId,
|
|
348
352
|
D extends { readonly transaction: any },
|
|
@@ -383,6 +387,7 @@ export const makePhoneTarget = <
|
|
|
383
387
|
| (Synchronous extends true
|
|
384
388
|
? never
|
|
385
389
|
: Exclude<R, PhonePersistence | PhoneAdmission | PhoneSignInTargets>)
|
|
390
|
+
| Crypto.Crypto
|
|
386
391
|
| LifecycleHooks
|
|
387
392
|
| RSetup
|
|
388
393
|
| DatabaseRequirements
|
|
@@ -421,6 +426,7 @@ export const makePhoneTarget = <
|
|
|
421
426
|
| (Synchronous extends true
|
|
422
427
|
? never
|
|
423
428
|
: Exclude<R, PhonePersistence | PhoneAdmission | PhoneSignInTargets | TxId>)
|
|
429
|
+
| Crypto.Crypto
|
|
424
430
|
| LifecycleHooks
|
|
425
431
|
| RSetup
|
|
426
432
|
| DatabaseRequirements
|
|
@@ -451,6 +457,7 @@ export const makePhoneTarget = <
|
|
|
451
457
|
A,
|
|
452
458
|
PhoneCoordinatorError<E> | DatabaseError,
|
|
453
459
|
| Exclude<R, PhonePersistence | PhoneAdmission | PhoneSignInTargets>
|
|
460
|
+
| Crypto.Crypto
|
|
454
461
|
| LifecycleHooks
|
|
455
462
|
| RSetup
|
|
456
463
|
| DatabaseRequirements
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { SqliteClient } from "@effect/sql-sqlite-do/SqliteClient";
|
|
2
|
+
import { PersistenceConfigurationError } from "@yielded/auth-persistence/Adapter";
|
|
3
|
+
import type { AnyRelations } from "drizzle-orm";
|
|
4
|
+
import { EffectTransactionRollbackError } from "drizzle-orm/effect-core";
|
|
5
|
+
import type { EffectSQLiteDoDatabase } from "drizzle-orm/effect-sqlite-do";
|
|
6
|
+
import { Effect } from "effect";
|
|
7
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
8
|
+
|
|
9
|
+
type NativeDatabase<T extends AnyRelations> = EffectSQLiteDoDatabase<T> & {
|
|
10
|
+
readonly $client: SqliteClient;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type Queries<T extends AnyRelations> = Pick<
|
|
14
|
+
NativeDatabase<T>,
|
|
15
|
+
| "query"
|
|
16
|
+
| "$cache"
|
|
17
|
+
| "$with"
|
|
18
|
+
| "$count"
|
|
19
|
+
| "with"
|
|
20
|
+
| "select"
|
|
21
|
+
| "selectDistinct"
|
|
22
|
+
| "insert"
|
|
23
|
+
| "update"
|
|
24
|
+
| "delete"
|
|
25
|
+
| "run"
|
|
26
|
+
| "all"
|
|
27
|
+
| "get"
|
|
28
|
+
| "values"
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
/** Drizzle queries with transactions owned by the captured Effect SQL client. */
|
|
32
|
+
export type DatabaseValue<T extends AnyRelations = AnyRelations> = Queries<T> & {
|
|
33
|
+
readonly $client: SqliteClient;
|
|
34
|
+
readonly transaction: <A, E, R>(
|
|
35
|
+
body: (transaction: Transaction<T>) => Effect.Effect<A, E, R>,
|
|
36
|
+
) => Effect.Effect<A, E | SqlError, R>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** An asynchronous Durable Object transaction, including nested rollback. */
|
|
40
|
+
export type Transaction<T extends AnyRelations = AnyRelations> = DatabaseValue<T> & {
|
|
41
|
+
readonly rollback: () => EffectTransactionRollbackError;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Keep the application's Drizzle query configuration and capture its SQL client.
|
|
46
|
+
* Effect SQL owns storage.transaction, so cryptography may suspend before commit.
|
|
47
|
+
* Raw Drizzle transactionSync callbacks are not supported outer owners.
|
|
48
|
+
*/
|
|
49
|
+
export const makeDatabase = Effect.fnUntraced(function* <T extends AnyRelations>(
|
|
50
|
+
database: NativeDatabase<T>,
|
|
51
|
+
): Effect.fn.Return<DatabaseValue<T>, PersistenceConfigurationError> {
|
|
52
|
+
const client = database.$client;
|
|
53
|
+
|
|
54
|
+
if (client.config.storage === undefined)
|
|
55
|
+
return yield* PersistenceConfigurationError.make({
|
|
56
|
+
reason: "SqliteDo requires a SQL client configured with Durable Object storage",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const queries: Queries<T> = {
|
|
60
|
+
query: database.query,
|
|
61
|
+
$cache: database.$cache,
|
|
62
|
+
$with: database.$with.bind(database),
|
|
63
|
+
$count: database.$count.bind(database),
|
|
64
|
+
with: database.with.bind(database),
|
|
65
|
+
select: database.select.bind(database),
|
|
66
|
+
selectDistinct: database.selectDistinct.bind(database),
|
|
67
|
+
insert: database.insert.bind(database),
|
|
68
|
+
update: database.update.bind(database),
|
|
69
|
+
delete: database.delete.bind(database),
|
|
70
|
+
run: database.run.bind(database),
|
|
71
|
+
all: database.all.bind(database),
|
|
72
|
+
get: database.get.bind(database),
|
|
73
|
+
values: database.values.bind(database),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const transaction: DatabaseValue<T>["transaction"] = (body) =>
|
|
77
|
+
client.withTransaction(Effect.suspend(() => body(makeTransaction())));
|
|
78
|
+
|
|
79
|
+
const makeTransaction = (): Transaction<T> => ({
|
|
80
|
+
...queries,
|
|
81
|
+
$client: client,
|
|
82
|
+
transaction,
|
|
83
|
+
rollback: () => new EffectTransactionRollbackError(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return { ...queries, $client: client, transaction };
|
|
87
|
+
});
|
|
@@ -5,7 +5,6 @@ import type { LifecycleHooks, HookConfigurationError } from "@yielded/auth/Hooks
|
|
|
5
5
|
import type { AnyRelations } from "drizzle-orm";
|
|
6
6
|
import type { EffectLibsqlDatabase } from "drizzle-orm/effect-libsql";
|
|
7
7
|
import type { EffectSQLiteBunDatabase } from "drizzle-orm/effect-sqlite-bun";
|
|
8
|
-
import type { EffectSQLiteDoDatabase as DODatabase } from "drizzle-orm/effect-sqlite-do";
|
|
9
8
|
import type { EffectSQLiteNodeDatabase as NodeDatabase } from "drizzle-orm/effect-sqlite-node";
|
|
10
9
|
import type { EffectSQLiteWasmDatabase as WasmDatabase } from "drizzle-orm/effect-sqlite-wasm";
|
|
11
10
|
import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
|
|
@@ -31,6 +30,7 @@ import {
|
|
|
31
30
|
import { nativeDatabase } from "./native-database";
|
|
32
31
|
import type { ProofPersistenceMapping } from "./proof-model";
|
|
33
32
|
import type { ProofSqlQuery } from "./proof-sql";
|
|
33
|
+
import type { DatabaseValue as DODatabase } from "./sqlite-do-database";
|
|
34
34
|
import {
|
|
35
35
|
type TransactionService,
|
|
36
36
|
acquireTransactionService,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
1
|
+
import { withStorageValidation, NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
2
2
|
import {
|
|
3
3
|
ExternalIdentityMutation,
|
|
4
4
|
type ExternalIdentity,
|
|
@@ -326,4 +326,4 @@ export const makeSqliteIdentityServices = Effect.fnUntraced(function* <
|
|
|
326
326
|
...(yield* makeSqliteSubjectProvisioningServices(mapping, mode)),
|
|
327
327
|
...(yield* makeSqliteExternalIdentityServices(mapping)),
|
|
328
328
|
};
|
|
329
|
-
});
|
|
329
|
+
}, withStorageValidation);
|
|
@@ -5,7 +5,6 @@ import { type PasswordUnavailable, PasswordPersistence } from "@yielded/auth/Pas
|
|
|
5
5
|
import type { AnyRelations } from "drizzle-orm";
|
|
6
6
|
import type { EffectLibsqlDatabase } from "drizzle-orm/effect-libsql";
|
|
7
7
|
import type { EffectSQLiteBunDatabase } from "drizzle-orm/effect-sqlite-bun";
|
|
8
|
-
import type { EffectSQLiteDoDatabase as DODatabase } from "drizzle-orm/effect-sqlite-do";
|
|
9
8
|
import type { EffectSQLiteNodeDatabase as NodeDatabase } from "drizzle-orm/effect-sqlite-node";
|
|
10
9
|
import type { EffectSQLiteWasmDatabase as WasmDatabase } from "drizzle-orm/effect-sqlite-wasm";
|
|
11
10
|
import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
|
|
@@ -26,6 +25,7 @@ import {
|
|
|
26
25
|
} from "./password-target";
|
|
27
26
|
import type { ProofPersistenceMapping } from "./proof-model";
|
|
28
27
|
import type { ProofSqlQuery } from "./proof-sql";
|
|
28
|
+
import type { DatabaseValue as DODatabase } from "./sqlite-do-database";
|
|
29
29
|
import {
|
|
30
30
|
type TransactionService,
|
|
31
31
|
acquireTransactionService,
|
|
@@ -4,7 +4,6 @@ import { type ProofUnavailable, ProofPersistence } from "@yielded/auth/Proofs";
|
|
|
4
4
|
import type { AnyRelations } from "drizzle-orm";
|
|
5
5
|
import type { EffectLibsqlDatabase } from "drizzle-orm/effect-libsql";
|
|
6
6
|
import type { EffectSQLiteBunDatabase } from "drizzle-orm/effect-sqlite-bun";
|
|
7
|
-
import type { EffectSQLiteDoDatabase } from "drizzle-orm/effect-sqlite-do";
|
|
8
7
|
import type { EffectSQLiteNodeDatabase } from "drizzle-orm/effect-sqlite-node";
|
|
9
8
|
import type { EffectSQLiteWasmDatabase } from "drizzle-orm/effect-sqlite-wasm";
|
|
10
9
|
import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
|
|
@@ -19,6 +18,7 @@ import {
|
|
|
19
18
|
makeTargetProofPersistenceServices,
|
|
20
19
|
type ProofTargetConfiguration,
|
|
21
20
|
} from "./proof-target";
|
|
21
|
+
import type { DatabaseValue } from "./sqlite-do-database";
|
|
22
22
|
import {
|
|
23
23
|
type TransactionService,
|
|
24
24
|
acquireTransactionService,
|
|
@@ -29,7 +29,7 @@ import type { SuppliedService } from "./SuppliedService";
|
|
|
29
29
|
type Database =
|
|
30
30
|
| EffectLibsqlDatabase<AnyRelations>
|
|
31
31
|
| EffectSQLiteBunDatabase<AnyRelations>
|
|
32
|
-
|
|
|
32
|
+
| DatabaseValue<AnyRelations>
|
|
33
33
|
| EffectSQLiteNodeDatabase<AnyRelations>
|
|
34
34
|
| EffectSQLiteWasmDatabase<AnyRelations>;
|
|
35
35
|
type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
import type { AnyRelations } from "drizzle-orm";
|
|
13
13
|
import type { EffectLibsqlDatabase } from "drizzle-orm/effect-libsql";
|
|
14
14
|
import type { EffectSQLiteBunDatabase } from "drizzle-orm/effect-sqlite-bun";
|
|
15
|
-
import type { EffectSQLiteDoDatabase } from "drizzle-orm/effect-sqlite-do";
|
|
16
15
|
import type { EffectSQLiteNodeDatabase } from "drizzle-orm/effect-sqlite-node";
|
|
17
16
|
import type { EffectSQLiteWasmDatabase } from "drizzle-orm/effect-sqlite-wasm";
|
|
18
17
|
import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
|
|
@@ -40,6 +39,7 @@ import {
|
|
|
40
39
|
makeTargetSessionStepUpServices,
|
|
41
40
|
coordinateTargetSessionStepUp,
|
|
42
41
|
} from "./session-target";
|
|
42
|
+
import type { DatabaseValue } from "./sqlite-do-database";
|
|
43
43
|
import {
|
|
44
44
|
type TransactionService,
|
|
45
45
|
acquireTransactionService,
|
|
@@ -50,7 +50,7 @@ import type { SuppliedService } from "./SuppliedService";
|
|
|
50
50
|
type Database =
|
|
51
51
|
| EffectLibsqlDatabase<AnyRelations>
|
|
52
52
|
| EffectSQLiteBunDatabase<AnyRelations>
|
|
53
|
-
|
|
|
53
|
+
| DatabaseValue<AnyRelations>
|
|
54
54
|
| EffectSQLiteNodeDatabase<AnyRelations>
|
|
55
55
|
| EffectSQLiteWasmDatabase<AnyRelations>;
|
|
56
56
|
type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NativeDatabase,
|
|
3
3
|
PersistenceMappingError,
|
|
4
|
-
|
|
4
|
+
validateStorageBatch,
|
|
5
|
+
type StorageValidation,
|
|
5
6
|
} from "@yielded/auth-persistence/Adapter";
|
|
6
7
|
import { getTableColumns, getTableName, is, Table } from "drizzle-orm";
|
|
7
8
|
import { getTableConfig as getMysqlTableConfig, MySqlTable } from "drizzle-orm/mysql-core";
|
|
@@ -243,6 +244,8 @@ export const validateDrizzleStorage = Effect.fnUntraced(
|
|
|
243
244
|
|
|
244
245
|
const { $client: client } = yield* NativeDatabase;
|
|
245
246
|
|
|
247
|
+
const batches = new Map<"pg" | "mysql" | "sqlite", StorageValidation[]>();
|
|
248
|
+
|
|
246
249
|
for (const plan of physical) {
|
|
247
250
|
const pg = is(plan.table, PgTable);
|
|
248
251
|
const mysql = is(plan.table, MySqlTable);
|
|
@@ -255,15 +258,21 @@ export const validateDrizzleStorage = Effect.fnUntraced(
|
|
|
255
258
|
|
|
256
259
|
const columns = getTableColumns(plan.table);
|
|
257
260
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
+
const dialect = pg ? "pg" : mysql ? "mysql" : "sqlite";
|
|
262
|
+
const batch = batches.get(dialect) ?? [];
|
|
263
|
+
|
|
264
|
+
batch.push({
|
|
265
|
+
table: {
|
|
261
266
|
name: getTableName(plan.table),
|
|
262
267
|
...(schema === undefined ? {} : { schema }),
|
|
263
268
|
columns: Object.fromEntries(plan.keys.map((key) => [key, { name: columns[key]!.name }])),
|
|
264
269
|
},
|
|
265
|
-
[plan.keys],
|
|
266
|
-
)
|
|
270
|
+
required: [plan.keys],
|
|
271
|
+
});
|
|
272
|
+
batches.set(dialect, batch);
|
|
273
|
+
}
|
|
274
|
+
for (const [dialect, requirements] of batches) {
|
|
275
|
+
yield* validateStorageBatch(dialect, requirements).pipe(
|
|
267
276
|
Effect.provideService(SqlClient, client),
|
|
268
277
|
Effect.mapError(() =>
|
|
269
278
|
PersistenceMappingError.make({
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomId, digest } from "@yielded/auth-crypto";
|
|
2
1
|
import { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
3
2
|
import {
|
|
4
3
|
TotpUnavailable,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
import { sql, type SQL } from "drizzle-orm";
|
|
12
11
|
import { Context, Effect, Schema } from "effect";
|
|
13
12
|
|
|
13
|
+
import { randomId, digest } from "./crypto";
|
|
14
14
|
import { both, makeTransactionRows, type TransactionOwner } from "./transaction-owner";
|
|
15
15
|
export const unavailable = () => TotpUnavailable.make({});
|
|
16
16
|
|
|
@@ -59,7 +59,7 @@ export const captureTotp = Effect.fn("TotpNative.capture")(function* (
|
|
|
59
59
|
)
|
|
60
60
|
return undefined;
|
|
61
61
|
|
|
62
|
-
const scope = scopeFor(mapping.moduleId, subjectId),
|
|
62
|
+
const scope = yield* scopeFor(mapping.moduleId, subjectId),
|
|
63
63
|
found = yield* owner.read(factor.table, equal(factor.table, { [factor.scope]: scope }), {
|
|
64
64
|
limit: 1,
|
|
65
65
|
}),
|
|
@@ -140,7 +140,7 @@ export const mutateTotp = Effect.fn("TotpNative.mutate")(function* (
|
|
|
140
140
|
const guards: SQL[] = [];
|
|
141
141
|
const credentialGuards: { credentialId: string; condition: SQL }[] = [];
|
|
142
142
|
|
|
143
|
-
const commandScope = digest(
|
|
143
|
+
const commandScope = yield* digest(
|
|
144
144
|
`effect-auth/totp/command/v1/${mapping.moduleId.length}:${mapping.moduleId}/${input.subjectId.length}:${input.subjectId}/${input.commandId}`,
|
|
145
145
|
);
|
|
146
146
|
|
|
@@ -413,7 +413,7 @@ export const mutateTotp = Effect.fn("TotpNative.mutate")(function* (
|
|
|
413
413
|
secret: null,
|
|
414
414
|
pending: null,
|
|
415
415
|
recoveryDigests: [],
|
|
416
|
-
revision: randomId
|
|
416
|
+
revision: yield* randomId,
|
|
417
417
|
};
|
|
418
418
|
semantic = true;
|
|
419
419
|
}
|
|
@@ -428,7 +428,7 @@ export const mutateTotp = Effect.fn("TotpNative.mutate")(function* (
|
|
|
428
428
|
secret: null,
|
|
429
429
|
pending: null,
|
|
430
430
|
recoveryDigests: [],
|
|
431
|
-
revision: randomId
|
|
431
|
+
revision: yield* randomId,
|
|
432
432
|
};
|
|
433
433
|
else {
|
|
434
434
|
if (new Set(action.recoveryDigests).size !== 10) return reject;
|
|
@@ -436,7 +436,7 @@ export const mutateTotp = Effect.fn("TotpNative.mutate")(function* (
|
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
438
|
}
|
|
439
|
-
next = { ...next, version: randomId
|
|
439
|
+
next = { ...next, version: yield* randomId };
|
|
440
440
|
|
|
441
441
|
const subject = mapping.subject,
|
|
442
442
|
factor = mapping.factor,
|
|
@@ -445,7 +445,7 @@ export const mutateTotp = Effect.fn("TotpNative.mutate")(function* (
|
|
|
445
445
|
const subjectKey = { [subject.id]: nativeId };
|
|
446
446
|
|
|
447
447
|
if (semantic) {
|
|
448
|
-
const revision = randomId
|
|
448
|
+
const revision = yield* randomId,
|
|
449
449
|
updates = {
|
|
450
450
|
[subject.securityRevision]: revision,
|
|
451
451
|
[subject.factorEnabled]: subject.encodeEnabled(next.secret !== null),
|
|
@@ -500,7 +500,7 @@ export const mutateTotp = Effect.fn("TotpNative.mutate")(function* (
|
|
|
500
500
|
const values = factor.encodeInsert({
|
|
501
501
|
scope: commandScope,
|
|
502
502
|
state: "totp-command/v1",
|
|
503
|
-
version: randomId
|
|
503
|
+
version: yield* randomId,
|
|
504
504
|
});
|
|
505
505
|
|
|
506
506
|
invariant(values[factor.scope] === commandScope && values[factor.state] === "totp-command/v1");
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomId } from "@yielded/auth-crypto";
|
|
2
1
|
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
3
2
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
4
3
|
import {
|
|
@@ -10,9 +9,10 @@ import {
|
|
|
10
9
|
} from "@yielded/auth/Totp";
|
|
11
10
|
import type { Table } from "drizzle-orm";
|
|
12
11
|
/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */
|
|
13
|
-
import { Context, Effect, Schema } from "effect";
|
|
12
|
+
import { type Crypto, Context, Effect, Schema } from "effect";
|
|
14
13
|
import type { Statement } from "effect/sql/Statement";
|
|
15
14
|
|
|
15
|
+
import { randomId } from "./crypto";
|
|
16
16
|
import type { PersistenceMappingError } from "./model";
|
|
17
17
|
import { nativeDatabase } from "./native-database";
|
|
18
18
|
import { validateDrizzleStorage } from "./storage-validation";
|
|
@@ -164,7 +164,11 @@ export const coordinateTargetTotp = <M, A, E, R, RSetup = never>(
|
|
|
164
164
|
services: TotpPersistenceServices,
|
|
165
165
|
append: (statement: Statement<any>) => void,
|
|
166
166
|
) => Effect.Effect<A, E, R>,
|
|
167
|
-
): Effect.Effect<
|
|
167
|
+
): Effect.Effect<
|
|
168
|
+
A,
|
|
169
|
+
TotpCoordinatorError<E>,
|
|
170
|
+
R | RSetup | Crypto.Crypto | LifecycleHooks | NativeDatabase
|
|
171
|
+
> =>
|
|
168
172
|
Effect.gen(function* () {
|
|
169
173
|
const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);
|
|
170
174
|
|
|
@@ -196,7 +200,7 @@ type TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => an
|
|
|
196
200
|
? Parameters<Parameters<D["transaction"]>[0]>[0]
|
|
197
201
|
: never;
|
|
198
202
|
|
|
199
|
-
/** Concrete driver wrappers select transaction mode
|
|
203
|
+
/** Concrete driver wrappers select transaction mode. */
|
|
200
204
|
export const makeTotpTarget = <
|
|
201
205
|
DatabaseId,
|
|
202
206
|
D extends { readonly transaction: any },
|
|
@@ -230,6 +234,7 @@ export const makeTotpTarget = <
|
|
|
230
234
|
A,
|
|
231
235
|
TotpCoordinatorError<E> | DatabaseError,
|
|
232
236
|
| (Synchronous extends true ? never : Exclude<R, TotpPersistence>)
|
|
237
|
+
| Crypto.Crypto
|
|
233
238
|
| LifecycleHooks
|
|
234
239
|
| RSetup
|
|
235
240
|
| DatabaseRequirements
|
|
@@ -259,6 +264,7 @@ export const makeTotpTarget = <
|
|
|
259
264
|
A,
|
|
260
265
|
TotpCoordinatorError<E> | DatabaseError,
|
|
261
266
|
| (Synchronous extends true ? never : Exclude<R, TotpPersistence | TxId>)
|
|
267
|
+
| Crypto.Crypto
|
|
262
268
|
| LifecycleHooks
|
|
263
269
|
| RSetup
|
|
264
270
|
| DatabaseRequirements
|
|
@@ -287,7 +293,7 @@ export const makeTotpTarget = <
|
|
|
287
293
|
): Effect.Effect<
|
|
288
294
|
A,
|
|
289
295
|
TotpCoordinatorError<E> | DatabaseError,
|
|
290
|
-
Exclude<R, TotpPersistence> | LifecycleHooks | RSetup | DatabaseRequirements
|
|
296
|
+
Exclude<R, TotpPersistence> | Crypto.Crypto | LifecycleHooks | RSetup | DatabaseRequirements
|
|
291
297
|
> {
|
|
292
298
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
293
299
|
coordinateTargetTotp(
|