@yielded/auth-persistence-drizzle 0.1.0-beta.17 → 0.1.0-beta.19
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 +120 -120
- package/dist/Libsql.d.mts +154 -154
- package/dist/Mysql2.d.mts +166 -166
- package/dist/Pglite.d.mts +166 -166
- package/dist/Postgres.d.mts +152 -152
- package/dist/SqliteBun.d.mts +168 -168
- package/dist/SqliteDo.d.mts +237 -259
- package/dist/SqliteDo.mjs +30 -45
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +154 -154
- package/dist/SqliteWasm.d.mts +163 -163
- 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 +16 -16
- 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-password-prepared.mjs +3 -3
- package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +1 -1
- package/dist/drizzle/d1-passwords.mjs +1 -1
- package/dist/drizzle/d1-passwords.mjs.map +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-sessions.mjs +4 -3
- package/dist/drizzle/d1-sessions.mjs.map +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 +265 -265
- 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 +105 -105
- 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-sql.mjs +1 -1
- package/dist/drizzle/password-prepared-sql.mjs.map +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-password-prepared.ts +11 -5
- package/src/drizzle/d1-passwords.ts +1 -1
- package/src/drizzle/d1-phone.ts +2 -1
- package/src/drizzle/d1-sessions.ts +8 -2
- 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/password-prepared-sql.ts +1 -1
- 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
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
readFlow,
|
|
31
31
|
terminalFlow,
|
|
32
32
|
} from "./oauth-flow";
|
|
33
|
-
import type { OAuthEligibilityFact } from "./oauth-model";
|
|
33
|
+
import type { OAuthReferenceGuardDescriptor, OAuthEligibilityFact } from "./oauth-model";
|
|
34
34
|
import { both, col, copiedRow, equal, CurrentOAuthTransaction } from "./oauth-owner";
|
|
35
35
|
import { acquireTuple, readTuple } from "./oauth-registration";
|
|
36
36
|
import {
|
|
@@ -71,7 +71,7 @@ const authorization = (
|
|
|
71
71
|
mapping.subject.decodeActionRequirement(copiedRow(current.row), action),
|
|
72
72
|
);
|
|
73
73
|
|
|
74
|
-
const accepted = validAction(
|
|
74
|
+
const accepted = yield* validAction(
|
|
75
75
|
auth,
|
|
76
76
|
{
|
|
77
77
|
moduleId: auth.challenge.moduleId,
|
|
@@ -493,7 +493,7 @@ const targetCredential = (mapping: any, moduleId: string, credentialId: string,
|
|
|
493
493
|
subject: ownership[t.externalSubject],
|
|
494
494
|
};
|
|
495
495
|
|
|
496
|
-
invariant(oauthIdentityKey(identity) === row[cr.identityKey]);
|
|
496
|
+
invariant((yield* oauthIdentityKey(identity)) === row[cr.identityKey]);
|
|
497
497
|
|
|
498
498
|
const shared = current.revision.credentials.find(
|
|
499
499
|
(item: any) => item.credentialId === credentialId,
|
|
@@ -648,23 +648,24 @@ export const unlink = (mapping: any, input: any) =>
|
|
|
648
648
|
const current = yield* accountCurrent(mapping, expected.revision.subjectId);
|
|
649
649
|
|
|
650
650
|
if (current === undefined) return { _tag: "Rejected" } as const;
|
|
651
|
-
|
|
651
|
+
|
|
652
|
+
const guards: ReadonlyArray<OAuthReferenceGuardDescriptor<unknown>> =
|
|
653
|
+
mapping.connectedReferenceGuards ?? [];
|
|
652
654
|
|
|
653
655
|
invariant(guards.length <= 32);
|
|
654
656
|
let referencesGuarded = mapping.connectedReference !== undefined && guards.length > 0;
|
|
655
657
|
|
|
656
658
|
if (mapping.connectedReference !== undefined)
|
|
657
659
|
for (const guard of guards) {
|
|
660
|
+
const condition = guard.condition({
|
|
661
|
+
identity: snapshotOAuthSync(OAuthCredentialSnapshot.fields.identity, expected.identity),
|
|
662
|
+
identityKey: yield* oauthIdentityKey(expected.identity),
|
|
663
|
+
subjectId: copiedRow({ value: current.nativeId }).value,
|
|
664
|
+
});
|
|
665
|
+
|
|
658
666
|
const read = yield* owner.read(
|
|
659
667
|
guard.table,
|
|
660
|
-
|
|
661
|
-
identity: snapshotOAuthSync(
|
|
662
|
-
OAuthCredentialSnapshot.fields.identity,
|
|
663
|
-
expected.identity,
|
|
664
|
-
),
|
|
665
|
-
identityKey: oauthIdentityKey(expected.identity),
|
|
666
|
-
subjectId: copiedRow({ value: current.nativeId }).value,
|
|
667
|
-
}),
|
|
668
|
+
Effect.isEffect(condition) ? yield* condition : condition,
|
|
668
669
|
{ orderBy: col(guard.table, guard.orderBy) },
|
|
669
670
|
);
|
|
670
671
|
|
|
@@ -730,7 +731,7 @@ export const unlink = (mapping: any, input: any) =>
|
|
|
730
731
|
cr = mapping.credential,
|
|
731
732
|
a = mapping.authority;
|
|
732
733
|
|
|
733
|
-
const key = oauthIdentityKey(expected.identity),
|
|
734
|
+
const key = yield* oauthIdentityKey(expected.identity),
|
|
734
735
|
t = mapping.ownership.tuple;
|
|
735
736
|
|
|
736
737
|
const connected = mapping.connectedReference?.({
|
|
@@ -285,7 +285,7 @@ export const collect = Effect.fn("oauthConnected.collect")(function* (
|
|
|
285
285
|
subject: candidate[t.externalSubject],
|
|
286
286
|
};
|
|
287
287
|
|
|
288
|
-
invariant(oauthIdentityKey(identity) === candidate[t.identityKey]);
|
|
288
|
+
invariant((yield* oauthIdentityKey(identity)) === candidate[t.identityKey]);
|
|
289
289
|
|
|
290
290
|
const tuple = yield* F.inspectTuple(mapping, identity),
|
|
291
291
|
row = tuple.row;
|
|
@@ -113,9 +113,9 @@ export const storeJob = Effect.fn("oauthConnected.storeJob")(function* (
|
|
|
113
113
|
);
|
|
114
114
|
|
|
115
115
|
const j = mapping.revocation.job,
|
|
116
|
-
identity = oauthIdentityKey(token.identity),
|
|
117
|
-
client = S.clientKey(token.configuration),
|
|
118
|
-
cohort = S.cohortKey(client, identity);
|
|
116
|
+
identity = yield* oauthIdentityKey(token.identity),
|
|
117
|
+
client = yield* S.clientKey(token.configuration),
|
|
118
|
+
cohort = yield* S.cohortKey(client, identity);
|
|
119
119
|
|
|
120
120
|
const h = mapping.cohort;
|
|
121
121
|
|
|
@@ -254,14 +254,16 @@ export const noFormerOwner = (
|
|
|
254
254
|
client: string,
|
|
255
255
|
native: unknown,
|
|
256
256
|
) =>
|
|
257
|
-
Effect.
|
|
257
|
+
Effect.gen(function* () {
|
|
258
|
+
const owner = yield* CurrentOAuthTransaction;
|
|
259
|
+
|
|
258
260
|
const g = mapping.grant,
|
|
259
261
|
f = mapping.flow,
|
|
260
262
|
j = S.jobTable(mapping);
|
|
261
263
|
|
|
262
264
|
const condition = both(
|
|
263
265
|
sql`not exists(select 1 from ${g.table} where ${both(eq(col(g.table, g.identityKey), identity), sql`not (${owner.exact(g.table, { [g.subjectId]: native })})`)})`,
|
|
264
|
-
sql`not exists(select 1 from ${f.table} where ${both(eq(col(f.table, f.cohortKey), S.cohortKey(client, identity)), eq(col(f.table, f.work), "Unresolved"), sql`not (${owner.exact(f.table, { [f.subjectId]: native })})`)})`,
|
|
266
|
+
sql`not exists(select 1 from ${f.table} where ${both(eq(col(f.table, f.cohortKey), yield* S.cohortKey(client, identity)), eq(col(f.table, f.work), "Unresolved"), sql`not (${owner.exact(f.table, { [f.subjectId]: native })})`)})`,
|
|
265
267
|
...(j === undefined
|
|
266
268
|
? []
|
|
267
269
|
: [
|
|
@@ -269,7 +271,7 @@ export const noFormerOwner = (
|
|
|
269
271
|
]),
|
|
270
272
|
);
|
|
271
273
|
|
|
272
|
-
return Effect.map(owner.check(condition), (accepted) => {
|
|
274
|
+
return yield* Effect.map(owner.check(condition), (accepted) => {
|
|
273
275
|
if (accepted) owner.postconditions.push(condition);
|
|
274
276
|
|
|
275
277
|
return accepted;
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
OAuthUnavailable,
|
|
7
7
|
} from "@yielded/auth/OAuth";
|
|
8
8
|
import type { Table } from "drizzle-orm";
|
|
9
|
-
import { Effect, Context } from "effect";
|
|
9
|
+
import { type Crypto, Effect, Context } from "effect";
|
|
10
10
|
|
|
11
11
|
import { makeD1Owner } from "./d1-planning";
|
|
12
12
|
import { D1BatchStatements } from "./D1BatchStatements";
|
|
@@ -69,6 +69,7 @@ export const makeOAuthConnectedTarget = <
|
|
|
69
69
|
A,
|
|
70
70
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
71
71
|
| (Synchronous extends true ? never : Exclude<R, OAuthConnectedPersistence>)
|
|
72
|
+
| Crypto.Crypto
|
|
72
73
|
| LifecycleHooks
|
|
73
74
|
| DatabaseRequirements
|
|
74
75
|
>;
|
|
@@ -108,6 +109,7 @@ export const makeOAuthConnectedTarget = <
|
|
|
108
109
|
A,
|
|
109
110
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
110
111
|
| (Synchronous extends true ? never : Exclude<R, OAuthConnectedPersistence | TxId>)
|
|
112
|
+
| Crypto.Crypto
|
|
111
113
|
| LifecycleHooks
|
|
112
114
|
| DatabaseRequirements
|
|
113
115
|
>;
|
|
@@ -142,7 +144,7 @@ export const makeOAuthConnectedTarget = <
|
|
|
142
144
|
): Effect.Effect<
|
|
143
145
|
A,
|
|
144
146
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
145
|
-
Exclude<R, OAuthConnectedPersistence> | LifecycleHooks | DatabaseRequirements
|
|
147
|
+
Exclude<R, OAuthConnectedPersistence> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements
|
|
146
148
|
> {
|
|
147
149
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
148
150
|
coordinateTargetOAuthConnected<TransactionOf<D>, A, E, Exclude<R, OAuthConnectedPersistence>>(
|
|
@@ -193,6 +195,7 @@ export const makeOAuthConnectedTarget = <
|
|
|
193
195
|
A,
|
|
194
196
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
195
197
|
| (Synchronous extends true ? never : Exclude<R, OAuthConnectedRevocations>)
|
|
198
|
+
| Crypto.Crypto
|
|
196
199
|
| LifecycleHooks
|
|
197
200
|
| DatabaseRequirements
|
|
198
201
|
>;
|
|
@@ -228,6 +231,7 @@ export const makeOAuthConnectedTarget = <
|
|
|
228
231
|
A,
|
|
229
232
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
230
233
|
| (Synchronous extends true ? never : Exclude<R, OAuthConnectedRevocations | TxId>)
|
|
234
|
+
| Crypto.Crypto
|
|
231
235
|
| LifecycleHooks
|
|
232
236
|
| DatabaseRequirements
|
|
233
237
|
>;
|
|
@@ -258,7 +262,7 @@ export const makeOAuthConnectedTarget = <
|
|
|
258
262
|
): Effect.Effect<
|
|
259
263
|
A,
|
|
260
264
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
261
|
-
Exclude<R, OAuthConnectedRevocations> | LifecycleHooks | DatabaseRequirements
|
|
265
|
+
Exclude<R, OAuthConnectedRevocations> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements
|
|
262
266
|
> {
|
|
263
267
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
264
268
|
coordinateTargetOAuthConnectedRevocations<
|
|
@@ -361,6 +365,7 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
|
|
|
361
365
|
A,
|
|
362
366
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
363
367
|
| Exclude<R, OAuthConnectedPersistence | D1BatchStatements>
|
|
368
|
+
| Crypto.Crypto
|
|
364
369
|
| LifecycleHooks
|
|
365
370
|
| DatabaseRequirements
|
|
366
371
|
> {
|
|
@@ -435,6 +440,7 @@ export const makeD1OAuthConnectedTarget = <DatabaseId, Database, Family extends
|
|
|
435
440
|
A,
|
|
436
441
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
437
442
|
| Exclude<R, OAuthConnectedRevocations | D1BatchStatements>
|
|
443
|
+
| Crypto.Crypto
|
|
438
444
|
| LifecycleHooks
|
|
439
445
|
| DatabaseRequirements
|
|
440
446
|
> {
|
|
@@ -45,7 +45,7 @@ export const pending = Effect.fn("oauthConnected.pending")(function* (
|
|
|
45
45
|
row[f.flowId] === c.flowId &&
|
|
46
46
|
row[f.commandId] === c.commandId &&
|
|
47
47
|
mapping.subjectId.equals(native, row[f.subjectId]) &&
|
|
48
|
-
row[f.clientKey] === S.clientKey(S.configuration(flow)) &&
|
|
48
|
+
row[f.clientKey] === (yield* S.clientKey(S.configuration(flow))) &&
|
|
49
49
|
row[f.stateDigest] === c.stateDigest &&
|
|
50
50
|
mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
|
|
51
51
|
mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,
|
|
@@ -238,7 +238,7 @@ export const inspectPrepared = Effect.fn("oauthConnected.inspectPrepared")(funct
|
|
|
238
238
|
row[f.flowId] === c.flowId &&
|
|
239
239
|
row[f.commandId] === c.commandId &&
|
|
240
240
|
mapping.subjectId.equals(found.nativeId, row[f.subjectId]) &&
|
|
241
|
-
row[f.clientKey] === S.clientKey(S.configuration(flow)) &&
|
|
241
|
+
row[f.clientKey] === (yield* S.clientKey(S.configuration(flow))) &&
|
|
242
242
|
row[f.stateDigest] === c.stateDigest &&
|
|
243
243
|
mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
|
|
244
244
|
mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,
|
|
@@ -356,7 +356,7 @@ export const claim = Effect.fn("oauthConnected.claim")(function* (
|
|
|
356
356
|
{
|
|
357
357
|
[f.state]: "Claimed",
|
|
358
358
|
[f.claimId]: claimed.claimId,
|
|
359
|
-
[f.claimDigest]: digest(S.claimStorage.encode(claimed)),
|
|
359
|
+
[f.claimDigest]: yield* digest(S.claimStorage.encode(claimed)),
|
|
360
360
|
[f.claimOrder]: mapping.order.encode(order),
|
|
361
361
|
[f.claimedAt]: mapping.clock.encodeInstant(now),
|
|
362
362
|
[f.claimExpiresAt]: mapping.clock.encodeInstant(expires),
|
|
@@ -392,7 +392,7 @@ export const exact = Effect.fn("oauthConnected.exactClaim")(function* (
|
|
|
392
392
|
row === undefined ||
|
|
393
393
|
row[f.work] !== "Unresolved" ||
|
|
394
394
|
row[f.claimId] !== claim.claimId ||
|
|
395
|
-
row[f.claimDigest] !== digest(S.claimStorage.encode(claim))
|
|
395
|
+
row[f.claimDigest] !== (yield* digest(S.claimStorage.encode(claim)))
|
|
396
396
|
)
|
|
397
397
|
return undefined;
|
|
398
398
|
const native = yield* mapping.subjectId.toNative(c.revision.subjectId);
|
|
@@ -403,7 +403,7 @@ export const exact = Effect.fn("oauthConnected.exactClaim")(function* (
|
|
|
403
403
|
row[f.stateDigest] === c.stateDigest &&
|
|
404
404
|
mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
|
|
405
405
|
mapping.clock.decodeInstant(row[f.retentionUntil]) === claim.flow.retentionUntilMillis &&
|
|
406
|
-
row[f.clientKey] === S.clientKey(S.configuration(claim.flow)) &&
|
|
406
|
+
row[f.clientKey] === (yield* S.clientKey(S.configuration(claim.flow))) &&
|
|
407
407
|
S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(claim.order) &&
|
|
408
408
|
mapping.clock.decodeInstant(row[f.claimedAt]) === claim.claimedAtMillis &&
|
|
409
409
|
mapping.clock.decodeInstant(row[f.claimExpiresAt]) === claim.claimExpiresAtMillis,
|
|
@@ -448,7 +448,7 @@ export const inspectTuple = Effect.fn("oauthConnected.inspectTuple")(function* (
|
|
|
448
448
|
const owner = yield* CurrentOAuthTransaction;
|
|
449
449
|
|
|
450
450
|
const t = mapping.ownership.tuple,
|
|
451
|
-
key = oauthIdentityKey(identity);
|
|
451
|
+
key = yield* oauthIdentityKey(identity);
|
|
452
452
|
|
|
453
453
|
const read = yield* owner.read(t.table, equal(t.table, { [t.identityKey]: key }), { limit: 1 });
|
|
454
454
|
const row = read.rows[0];
|
|
@@ -341,7 +341,7 @@ export const disconnect = Effect.fn("oauthConnected.disconnect")(function* (
|
|
|
341
341
|
[d.grantId]: token.grantId,
|
|
342
342
|
[d.intent]: S.commandStorage.encode({
|
|
343
343
|
context: token,
|
|
344
|
-
originalDigest: digest(S.disconnectStorage.encode(input.grant)),
|
|
344
|
+
originalDigest: yield* digest(S.disconnectStorage.encode(input.grant)),
|
|
345
345
|
...(input.revocation === undefined
|
|
346
346
|
? {}
|
|
347
347
|
: { revocationJobId: input.revocation.context.jobId }),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { eq, is, sql, type SQL, type Table } from "drizzle-orm";
|
|
2
2
|
import { MySqlTable } from "drizzle-orm/mysql-core/table";
|
|
3
3
|
import { PgTable } from "drizzle-orm/pg-core/table";
|
|
4
|
+
import { Effect } from "effect";
|
|
4
5
|
|
|
5
6
|
import type { OAuthConnectedMapping } from "./oauth-connected-model";
|
|
6
7
|
import { scopeKey, type Mapping } from "./oauth-connected-state";
|
|
@@ -52,15 +53,19 @@ export const oauthConnectedOwnershipReferences = <
|
|
|
52
53
|
table: c.table,
|
|
53
54
|
orderBy: c.clientKey,
|
|
54
55
|
condition: (input) =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
Effect.gen(function* () {
|
|
57
|
+
const key = yield* scopeKey(input.identity.provider, input.identity.issuer);
|
|
58
|
+
|
|
59
|
+
return both(
|
|
60
|
+
equal(c.table, {
|
|
61
|
+
[c.clientKey]: key,
|
|
62
|
+
[c.counter]: mapping.order.encode(0),
|
|
63
|
+
}),
|
|
64
|
+
exactText(c.table, c.provider, input.identity.provider),
|
|
65
|
+
exactText(c.table, c.issuer, input.identity.issuer),
|
|
66
|
+
exactText(c.table, c.clientRegistrationId, ""),
|
|
67
|
+
);
|
|
68
|
+
}),
|
|
64
69
|
}),
|
|
65
70
|
],
|
|
66
71
|
connectedReference: (input) => connectedReferenceCondition(mapping, input.identityKey),
|
|
@@ -46,9 +46,9 @@ export const activateGrant = Effect.fn("oauthConnected.activateGrant")(function*
|
|
|
46
46
|
const owner = yield* CurrentOAuthTransaction;
|
|
47
47
|
const token = grant.context;
|
|
48
48
|
const g = mapping.grant;
|
|
49
|
-
const identityKey = oauthIdentityKey(token.identity);
|
|
50
|
-
const clientKey = S.clientKey(token.configuration);
|
|
51
|
-
const cohortKey = S.cohortKey(clientKey, identityKey);
|
|
49
|
+
const identityKey = yield* oauthIdentityKey(token.identity);
|
|
50
|
+
const clientKey = yield* S.clientKey(token.configuration);
|
|
51
|
+
const cohortKey = yield* S.cohortKey(clientKey, identityKey);
|
|
52
52
|
|
|
53
53
|
const values = {
|
|
54
54
|
...g.encodeInsert({
|
|
@@ -143,7 +143,7 @@ export const settle = Effect.fn("oauthConnected.settle")(function* (
|
|
|
143
143
|
token.grantId === c.grantId &&
|
|
144
144
|
token.identity.provider === c.provider &&
|
|
145
145
|
token.identity.issuer === c.issuer &&
|
|
146
|
-
S.clientKey(token.configuration) === cl.id &&
|
|
146
|
+
(yield* S.clientKey(token.configuration)) === cl.id &&
|
|
147
147
|
S.tokenContextStorage.encode({
|
|
148
148
|
...token,
|
|
149
149
|
configuration: S.configuration(input.claim.flow),
|
|
@@ -83,7 +83,7 @@ export const claimSignIn = Effect.fn("oauthConnected.claimSignIn")(function* (
|
|
|
83
83
|
[f.stateDigest]: c.stateDigest,
|
|
84
84
|
[f.snapshot]: null,
|
|
85
85
|
[f.claimId]: claim.claimId,
|
|
86
|
-
[f.claimDigest]: digest(reservationStorage.encode(reservation)),
|
|
86
|
+
[f.claimDigest]: yield* digest(reservationStorage.encode(reservation)),
|
|
87
87
|
[f.claimOrder]: mapping.order.encode(order),
|
|
88
88
|
[f.claimedAt]: mapping.clock.encodeInstant(claim.claimedAtMillis),
|
|
89
89
|
[f.claimExpiresAt]: mapping.clock.encodeInstant(claim.claimExpiresAtMillis),
|
|
@@ -116,13 +116,13 @@ const exact = Effect.fn("oauthConnected.exactSignIn")(function* (
|
|
|
116
116
|
row === undefined ||
|
|
117
117
|
row[f.work] !== "Unresolved" ||
|
|
118
118
|
row[f.claimId] !== reservation.claim.claimId ||
|
|
119
|
-
row[f.claimDigest] !== digest(reservationStorage.encode(reservation))
|
|
119
|
+
row[f.claimDigest] !== (yield* digest(reservationStorage.encode(reservation)))
|
|
120
120
|
)
|
|
121
121
|
return undefined;
|
|
122
122
|
invariant(
|
|
123
123
|
row[f.subjectId] === null &&
|
|
124
124
|
row[f.commandId] === c.commandId &&
|
|
125
|
-
row[f.clientKey] === S.clientKey(reservation.configuration) &&
|
|
125
|
+
row[f.clientKey] === (yield* S.clientKey(reservation.configuration)) &&
|
|
126
126
|
S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(reservation.order),
|
|
127
127
|
);
|
|
128
128
|
const now = yield* owner.now(mapping.clock);
|
|
@@ -164,7 +164,7 @@ const credential = Effect.fn("oauthConnected.signInCredential")(function* (
|
|
|
164
164
|
[c.moduleId]: context.moduleId,
|
|
165
165
|
[c.credentialId]: input.credentialId,
|
|
166
166
|
[c.subjectId]: found.nativeId,
|
|
167
|
-
[c.identityKey]: oauthIdentityKey(input.identity),
|
|
167
|
+
[c.identityKey]: yield* oauthIdentityKey(input.identity),
|
|
168
168
|
[c.credentialRevision]: input.credentialRevision,
|
|
169
169
|
}),
|
|
170
170
|
c.activeCondition,
|
|
@@ -242,18 +242,19 @@ const slot = Effect.fn("oauthConnected.signInSlot")(function* (
|
|
|
242
242
|
|
|
243
243
|
/** Orders belong to one client registration. Moving a profile to another client
|
|
244
244
|
* requires a newer profile generation; retired clients cannot replace it later. */
|
|
245
|
-
const canReplace = (
|
|
245
|
+
const canReplace = Effect.fnUntraced(function* (
|
|
246
246
|
reservation: M.OAuthSignInAccessClaim,
|
|
247
247
|
previous: M.OAuthConnectedTokenContext,
|
|
248
|
-
)
|
|
248
|
+
) {
|
|
249
249
|
const generation = reservation.configuration.profile.generation;
|
|
250
250
|
const oldGeneration = previous.configuration.profile.generation;
|
|
251
251
|
|
|
252
|
-
return S.clientKey(reservation.configuration) ===
|
|
252
|
+
return (yield* S.clientKey(reservation.configuration)) ===
|
|
253
|
+
(yield* S.clientKey(previous.configuration))
|
|
253
254
|
? generation >= oldGeneration &&
|
|
254
255
|
S.orderNumber(reservation.order) > S.orderNumber(previous.exchangeOrder)
|
|
255
256
|
: generation > oldGeneration;
|
|
256
|
-
};
|
|
257
|
+
});
|
|
257
258
|
|
|
258
259
|
export const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function* (
|
|
259
260
|
mapping: S.Mapping,
|
|
@@ -293,7 +294,7 @@ export const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function*
|
|
|
293
294
|
co.blocked ||
|
|
294
295
|
S.orderNumber(r.order) <= co.cutoff ||
|
|
295
296
|
previous?.row[mapping.grant.refreshWork] === "Unresolved" ||
|
|
296
|
-
(previous !== undefined && !canReplace(r, previous.context));
|
|
297
|
+
(previous !== undefined && !(yield* canReplace(r, previous.context)));
|
|
297
298
|
|
|
298
299
|
return snapshotOAuthSync(M.OAuthSignInAccessInspection, {
|
|
299
300
|
_tag: quarantine ? "Quarantine" : "Target",
|
|
@@ -377,7 +378,7 @@ export const settleSignIn = Effect.fn("oauthConnected.settleSignIn")(function* (
|
|
|
377
378
|
F.sameTarget(out.previous, previous.context) &&
|
|
378
379
|
sameIdentity(previous.context.identity, token.identity) &&
|
|
379
380
|
previous.row[mapping.grant.refreshWork] !== "Unresolved" &&
|
|
380
|
-
canReplace(r, previous.context);
|
|
381
|
+
(yield* canReplace(r, previous.context));
|
|
381
382
|
|
|
382
383
|
const previousSafe = yield* C.noFormerOwner(mapping, tuple.key, cl.id, native);
|
|
383
384
|
|
|
@@ -107,11 +107,11 @@ export const nativeOrder = (mapping: Authority, value: unknown) =>
|
|
|
107
107
|
const encoder = new TextEncoder();
|
|
108
108
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
109
109
|
|
|
110
|
-
const key = (domain: string, fields: ReadonlyArray<string>)
|
|
110
|
+
const key = Effect.fnUntraced(function* (domain: string, fields: ReadonlyArray<string>) {
|
|
111
111
|
for (const value of fields) invariant(decoder.decode(encoder.encode(value)) === value);
|
|
112
112
|
|
|
113
|
-
return "v1:" + digest(strings.encode([domain, ...fields]));
|
|
114
|
-
};
|
|
113
|
+
return "v1:" + (yield* digest(strings.encode([domain, ...fields])));
|
|
114
|
+
});
|
|
115
115
|
|
|
116
116
|
export const clientKey = (configuration: M.OAuthConnectedConfiguration) =>
|
|
117
117
|
key("effect-auth/oauth-connected-client/v1", [
|
|
@@ -124,7 +124,9 @@ export const cohortKey = (client: string, identity: string) =>
|
|
|
124
124
|
key("effect-auth/oauth-connected-cohort/v1", [client, identity]);
|
|
125
125
|
|
|
126
126
|
export const initialGeneration = (cohort: string) =>
|
|
127
|
-
|
|
127
|
+
digest(cohort).pipe(
|
|
128
|
+
Effect.map((value) => M.OAuthConnectedTarget.fields.cohortGeneration.make("initial:" + value)),
|
|
129
|
+
);
|
|
128
130
|
|
|
129
131
|
export const configuration = (flow: M.OAuthConnectedPendingFlow): M.OAuthConnectedConfiguration =>
|
|
130
132
|
snapshotOAuthSync(M.OAuthConnectedConfiguration, flow.context);
|
|
@@ -254,9 +256,9 @@ export const action = Effect.fn("oauthConnected.action")(function* (
|
|
|
254
256
|
? "connected-disconnect"
|
|
255
257
|
: "connected-complete";
|
|
256
258
|
|
|
257
|
-
const intentDigest = digest(expected.intent);
|
|
259
|
+
const intentDigest = yield* digest(expected.intent);
|
|
258
260
|
|
|
259
|
-
const binding = digest(
|
|
261
|
+
const binding = yield* digest(
|
|
260
262
|
strings.encode([
|
|
261
263
|
"effect-auth/oauth-connected-action/v1",
|
|
262
264
|
expected.moduleId,
|
|
@@ -364,7 +366,9 @@ export const useAuthority = Effect.fn("oauthConnected.useAuthority")(function* (
|
|
|
364
366
|
});
|
|
365
367
|
|
|
366
368
|
export const scopeKey = (provider: string, issuer: string) =>
|
|
367
|
-
|
|
369
|
+
key("effect-auth/oauth-connected-provider-issuer/v1", [provider, issuer]).pipe(
|
|
370
|
+
Effect.map((value) => "scope:" + value),
|
|
371
|
+
);
|
|
368
372
|
|
|
369
373
|
export interface ScopeAnchor {
|
|
370
374
|
readonly id: string;
|
|
@@ -412,7 +416,7 @@ export const scope = Effect.fn("oauthConnected.scope")(function* (
|
|
|
412
416
|
const owner = yield* CurrentOAuthTransaction;
|
|
413
417
|
|
|
414
418
|
const c = mapping.client,
|
|
415
|
-
id = scopeKey(config.provider, config.issuer),
|
|
419
|
+
id = yield* scopeKey(config.provider, config.issuer),
|
|
416
420
|
cache = yield* anchors(scopeCache, c.table);
|
|
417
421
|
|
|
418
422
|
const existing = cache.get(id);
|
|
@@ -497,7 +501,7 @@ export const readScope = Effect.fn("oauthConnected.readScope")(function* (
|
|
|
497
501
|
const owner = yield* CurrentOAuthTransaction;
|
|
498
502
|
|
|
499
503
|
const c = mapping.client,
|
|
500
|
-
id = scopeKey(provider, issuer),
|
|
504
|
+
id = yield* scopeKey(provider, issuer),
|
|
501
505
|
cache = yield* anchors(scopeCache, c.table),
|
|
502
506
|
cached = cache.get(id);
|
|
503
507
|
|
|
@@ -549,12 +553,12 @@ export const lockClientById = Effect.fn("oauthConnected.lockClientById")(functio
|
|
|
549
553
|
row !== undefined &&
|
|
550
554
|
row[c.clientRegistrationId] !== "" &&
|
|
551
555
|
id ===
|
|
552
|
-
key("effect-auth/oauth-connected-client/v1", [
|
|
556
|
+
(yield* key("effect-auth/oauth-connected-client/v1", [
|
|
553
557
|
row[c.provider],
|
|
554
558
|
row[c.issuer],
|
|
555
559
|
row[c.clientRegistrationId],
|
|
556
|
-
]) &&
|
|
557
|
-
scope.id === scopeKey(row[c.provider], row[c.issuer]),
|
|
560
|
+
])) &&
|
|
561
|
+
scope.id === (yield* scopeKey(row[c.provider], row[c.issuer])),
|
|
558
562
|
);
|
|
559
563
|
const found = { id, row, counter: nativeOrder(mapping, row[c.counter]), scope };
|
|
560
564
|
|
|
@@ -563,10 +567,15 @@ export const lockClientById = Effect.fn("oauthConnected.lockClientById")(functio
|
|
|
563
567
|
return found;
|
|
564
568
|
});
|
|
565
569
|
|
|
566
|
-
export const heldScope = (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
+
export const heldScope = Effect.fnUntraced(function* (
|
|
571
|
+
mapping: Authority,
|
|
572
|
+
provider: string,
|
|
573
|
+
issuer: string,
|
|
574
|
+
) {
|
|
575
|
+
const cache = yield* anchors(scopeCache, mapping.client.table);
|
|
576
|
+
|
|
577
|
+
return cache.get(yield* scopeKey(provider, issuer));
|
|
578
|
+
});
|
|
570
579
|
|
|
571
580
|
/** Cleanup obtains every scope then every client before entering any tuple. */
|
|
572
581
|
export const prelockClients = Effect.fn("oauthConnected.prelockClients")(function* (
|
|
@@ -583,7 +592,7 @@ export const prelockClients = Effect.fn("oauthConnected.prelockClients")(functio
|
|
|
583
592
|
const scopes = new Map<string, { provider: string; issuer: string; required: boolean }>();
|
|
584
593
|
|
|
585
594
|
for (const value of releaseScopes)
|
|
586
|
-
scopes.set(scopeKey(value.provider, value.issuer), { ...value, required: false });
|
|
595
|
+
scopes.set(yield* scopeKey(value.provider, value.issuer), { ...value, required: false });
|
|
587
596
|
for (const id of unique) {
|
|
588
597
|
const read = yield* owner.read(c.table, equal(c.table, { [c.clientKey]: id }), {
|
|
589
598
|
limit: 1,
|
|
@@ -593,7 +602,7 @@ export const prelockClients = Effect.fn("oauthConnected.prelockClients")(functio
|
|
|
593
602
|
row = read.rows[0];
|
|
594
603
|
|
|
595
604
|
invariant(row !== undefined);
|
|
596
|
-
scopes.set(scopeKey(row[c.provider], row[c.issuer]), {
|
|
605
|
+
scopes.set(yield* scopeKey(row[c.provider], row[c.issuer]), {
|
|
597
606
|
provider: row[c.provider],
|
|
598
607
|
issuer: row[c.issuer],
|
|
599
608
|
required: true,
|
|
@@ -629,7 +638,7 @@ export const client = Effect.fn("oauthConnected.client")(function* (
|
|
|
629
638
|
const owner = yield* CurrentOAuthTransaction;
|
|
630
639
|
|
|
631
640
|
const c = mapping.client,
|
|
632
|
-
id = clientKey(config),
|
|
641
|
+
id = yield* clientKey(config),
|
|
633
642
|
where = { [c.clientKey]: id };
|
|
634
643
|
|
|
635
644
|
const heldScope = yield* scope(mapping, config, create);
|
|
@@ -723,7 +732,7 @@ export const cohort = Effect.fn("oauthConnected.cohort")(function* (
|
|
|
723
732
|
const owner = yield* CurrentOAuthTransaction;
|
|
724
733
|
|
|
725
734
|
const c = mapping.cohort,
|
|
726
|
-
id = cohortKey(clientId, identityId),
|
|
735
|
+
id = yield* cohortKey(clientId, identityId),
|
|
727
736
|
where = { [c.cohortKey]: id };
|
|
728
737
|
|
|
729
738
|
let read = yield* owner.read(c.table, equal(c.table, where), { limit: 1 });
|
|
@@ -755,7 +764,7 @@ export const cohort = Effect.fn("oauthConnected.cohort")(function* (
|
|
|
755
764
|
...where,
|
|
756
765
|
[c.clientKey]: clientId,
|
|
757
766
|
[c.identityKey]: identityId,
|
|
758
|
-
[c.generation]: initialGeneration(id),
|
|
767
|
+
[c.generation]: yield* initialGeneration(id),
|
|
759
768
|
[c.cutoff]: mapping.order.encode(0),
|
|
760
769
|
[c.state]: "Open",
|
|
761
770
|
[c.version]: owner.marker,
|
|
@@ -769,7 +778,13 @@ export const cohort = Effect.fn("oauthConnected.cohort")(function* (
|
|
|
769
778
|
const row = read.rows[0];
|
|
770
779
|
|
|
771
780
|
if (row === undefined)
|
|
772
|
-
return {
|
|
781
|
+
return {
|
|
782
|
+
id,
|
|
783
|
+
row: undefined,
|
|
784
|
+
generation: yield* initialGeneration(id),
|
|
785
|
+
cutoff: 0,
|
|
786
|
+
blocked: false,
|
|
787
|
+
};
|
|
773
788
|
invariant(
|
|
774
789
|
row[c.clientKey] === clientId &&
|
|
775
790
|
row[c.identityKey] === identityId &&
|
|
@@ -816,9 +831,9 @@ export const readGrant = Effect.fn("oauthConnected.readGrant")(function* (
|
|
|
816
831
|
context.moduleId === moduleId &&
|
|
817
832
|
context.grantId === grantId &&
|
|
818
833
|
mapping.subjectId.equals(native, row[g.subjectId]) &&
|
|
819
|
-
row[g.identityKey] === oauthIdentityKey(context.identity) &&
|
|
820
|
-
row[g.clientKey] === clientKey(context.configuration) &&
|
|
821
|
-
row[g.cohortKey] === cohortKey(row[g.clientKey], row[g.identityKey]) &&
|
|
834
|
+
row[g.identityKey] === (yield* oauthIdentityKey(context.identity)) &&
|
|
835
|
+
row[g.clientKey] === (yield* clientKey(context.configuration)) &&
|
|
836
|
+
row[g.cohortKey] === (yield* cohortKey(row[g.clientKey], row[g.identityKey])) &&
|
|
822
837
|
row[g.profileKey] === context.configuration.profile.key &&
|
|
823
838
|
row[g.grantVersion] === context.grantVersion &&
|
|
824
839
|
row[g.tokenVersion] === context.tokenVersion &&
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type PrepareOAuthCommit,
|
|
9
9
|
} from "@yielded/auth/OAuth";
|
|
10
10
|
/* oxlint-disable no-explicit-any -- concrete adapters retain the native database, table and ID types. */
|
|
11
|
-
import { Effect, Layer, Schema } from "effect";
|
|
11
|
+
import { type Crypto, Effect, Layer, type PlatformError, Schema } from "effect";
|
|
12
12
|
import type { Statement } from "effect/sql/Statement";
|
|
13
13
|
|
|
14
14
|
import type { PersistenceMappingError } from "./model";
|
|
@@ -94,8 +94,10 @@ const mutation =
|
|
|
94
94
|
input: Input,
|
|
95
95
|
) => Effect.Effect<
|
|
96
96
|
Value,
|
|
97
|
-
import("@yielded/auth/OAuth").OAuthUnavailable
|
|
98
|
-
|
|
97
|
+
| import("@yielded/auth/OAuth").OAuthUnavailable
|
|
98
|
+
| PersistenceMappingError
|
|
99
|
+
| PlatformError.PlatformError,
|
|
100
|
+
CurrentOAuthTransaction | Crypto.Crypto
|
|
99
101
|
>,
|
|
100
102
|
schema: Schema.Codec<Value, Encoded, never, never>,
|
|
101
103
|
) =>
|
|
@@ -111,8 +113,10 @@ const read =
|
|
|
111
113
|
input: Input,
|
|
112
114
|
) => Effect.Effect<
|
|
113
115
|
Value,
|
|
114
|
-
import("@yielded/auth/OAuth").OAuthUnavailable
|
|
115
|
-
|
|
116
|
+
| import("@yielded/auth/OAuth").OAuthUnavailable
|
|
117
|
+
| PersistenceMappingError
|
|
118
|
+
| PlatformError.PlatformError,
|
|
119
|
+
CurrentOAuthTransaction | Crypto.Crypto
|
|
116
120
|
>,
|
|
117
121
|
) =>
|
|
118
122
|
(input: Input) =>
|