@yielded/auth-persistence-drizzle 0.1.0-beta.22 → 0.1.0-beta.24
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 +3 -0
- package/dist/D1.d.mts +11 -11
- package/dist/D1.mjs +2 -1
- package/dist/D1.mjs.map +1 -1
- package/dist/Libsql.d.mts +40 -56
- package/dist/Libsql.mjs +2 -1
- package/dist/Libsql.mjs.map +1 -1
- package/dist/Mysql2.d.mts +16 -17
- package/dist/Pglite.d.mts +18 -18
- package/dist/Pglite.mjs +2 -1
- package/dist/Pglite.mjs.map +1 -1
- package/dist/Postgres.d.mts +24 -24
- package/dist/Postgres.mjs +2 -1
- package/dist/Postgres.mjs.map +1 -1
- package/dist/SqliteBun.d.mts +39 -55
- package/dist/SqliteBun.mjs +2 -1
- package/dist/SqliteBun.mjs.map +1 -1
- package/dist/SqliteDo.d.mts +48 -64
- package/dist/SqliteDo.mjs +2 -1
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +45 -61
- package/dist/SqliteNode.mjs +2 -1
- package/dist/SqliteNode.mjs.map +1 -1
- package/dist/SqliteWasm.d.mts +48 -64
- package/dist/SqliteWasm.mjs +2 -1
- package/dist/SqliteWasm.mjs.map +1 -1
- package/dist/drizzle/crypto.mjs +1 -1
- package/dist/drizzle/d1-emails.d.mts +1 -1
- package/dist/drizzle/d1-oauth.d.mts +14 -14
- package/dist/drizzle/d1-passkey.d.mts +1 -1
- package/dist/drizzle/d1-password-prepared.d.mts +4 -4
- package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +18 -35
- package/dist/drizzle/d1-passwords.mjs +78 -290
- package/dist/drizzle/d1-passwords.mjs.map +1 -1
- package/dist/drizzle/d1-phone.d.mts +1 -1
- package/dist/drizzle/d1-proofs.d.mts +2 -2
- package/dist/drizzle/d1-sessions.d.mts +3 -3
- package/dist/drizzle/d1-sessions.mjs +11 -6
- package/dist/drizzle/d1-sessions.mjs.map +1 -1
- package/dist/drizzle/d1-totp.d.mts +1 -1
- package/dist/drizzle/mysql-password-prepared.d.mts +5 -5
- package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
- package/dist/drizzle/mysql-passwords.d.mts +16 -32
- package/dist/drizzle/mysql-passwords.mjs.map +1 -1
- package/dist/drizzle/mysql-sessions.d.mts +1 -1
- package/dist/drizzle/native-sql-table.mjs +135 -0
- package/dist/drizzle/native-sql-table.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-model.d.mts +20 -281
- package/dist/drizzle/oauth-connected-model.mjs +3 -17
- package/dist/drizzle/oauth-connected-model.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-reference.d.mts +1 -3
- package/dist/drizzle/oauth-connected-reference.mjs +4 -53
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-target.d.mts +3 -990
- package/dist/drizzle/oauth-connected-target.mjs +8 -92
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
- package/dist/drizzle/oauth-kernel.mjs +11 -0
- package/dist/drizzle/oauth-kernel.mjs.map +1 -0
- package/dist/drizzle/oauth-model.d.mts +35 -438
- package/dist/drizzle/oauth-model.mjs +6 -44
- package/dist/drizzle/oauth-model.mjs.map +1 -1
- package/dist/drizzle/oauth-mysql.mjs +2 -2
- package/dist/drizzle/oauth-mysql.mjs.map +1 -1
- package/dist/drizzle/oauth-proxy.d.mts +10 -0
- package/dist/drizzle/oauth-proxy.mjs +54 -0
- package/dist/drizzle/oauth-proxy.mjs.map +1 -0
- package/dist/drizzle/oauth-target.d.mts +6 -107
- package/dist/drizzle/oauth-target.mjs +15 -245
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/password-model.d.mts +5 -8
- package/dist/drizzle/password-prepared-model.d.mts +5 -5
- package/dist/drizzle/password-prepared-model.mjs.map +1 -1
- package/dist/drizzle/password-prepared-state.mjs +1 -1
- package/dist/drizzle/password-sql.mjs +2 -1
- package/dist/drizzle/password-sql.mjs.map +1 -1
- package/dist/drizzle/password-target.mjs +13 -2
- package/dist/drizzle/password-target.mjs.map +1 -1
- package/dist/drizzle/pg-password-prepared.d.mts +5 -5
- package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
- package/dist/drizzle/pg-passwords.d.mts +16 -32
- package/dist/drizzle/pg-passwords.mjs.map +1 -1
- package/dist/drizzle/pg-sessions.d.mts +1 -1
- package/dist/drizzle/phone-target.d.mts +2 -2
- package/dist/drizzle/phone-target.mjs +1 -1
- package/dist/drizzle/query-operations.mjs +3 -1
- package/dist/drizzle/query-operations.mjs.map +1 -1
- package/dist/drizzle/session-sql.mjs +2 -1
- package/dist/drizzle/session-sql.mjs.map +1 -1
- package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
- package/dist/drizzle/storage-validation.mjs +10 -198
- package/dist/drizzle/storage-validation.mjs.map +1 -1
- package/dist/drizzle/totp-target.d.mts +3 -3
- package/dist/drizzle/totp-target.mjs +2 -2
- package/dist/drizzle/transaction-execution.d.mts +2 -2
- package/dist/drizzle/transaction-owner.d.mts +1 -2
- package/dist/index.d.mts +3 -2
- package/dist/internal/drizzle-postgres-oauth-proxy.d.mts +138 -0
- package/dist/internal/drizzle-postgres-oauth-proxy.mjs +29 -0
- package/dist/internal/drizzle-postgres-oauth-proxy.mjs.map +1 -0
- package/dist/internal/drizzle-postgres.mjs +2 -0
- package/dist/internal/drizzle-postgres.mjs.map +1 -1
- package/dist/internal/drizzle-sqlite-oauth-proxy.d.mts +146 -0
- package/dist/internal/drizzle-sqlite-oauth-proxy.mjs +29 -0
- package/dist/internal/drizzle-sqlite-oauth-proxy.mjs.map +1 -0
- package/dist/internal/drizzle-sqlite.mjs +2 -0
- package/dist/internal/drizzle-sqlite.mjs.map +1 -1
- package/package.json +1 -1
- package/src/D1.ts +2 -0
- package/src/Libsql.ts +2 -0
- package/src/Pglite.ts +2 -0
- package/src/Postgres.ts +2 -0
- package/src/SqliteBun.ts +2 -0
- package/src/SqliteDo.ts +2 -0
- package/src/SqliteNode.ts +2 -0
- package/src/SqliteWasm.ts +2 -0
- package/src/drizzle/d1-password-prepared.ts +2 -23
- package/src/drizzle/d1-passwords.ts +158 -780
- package/src/drizzle/d1-sessions.ts +21 -6
- package/src/drizzle/mysql-password-prepared.ts +4 -16
- package/src/drizzle/mysql-passwords.ts +5 -20
- package/src/drizzle/native-sql-table.ts +259 -0
- package/src/drizzle/oauth-connected-model.ts +97 -315
- package/src/drizzle/oauth-connected-reference.ts +13 -93
- package/src/drizzle/oauth-connected-target.ts +14 -271
- package/src/drizzle/oauth-kernel.ts +10 -0
- package/src/drizzle/oauth-model.ts +188 -541
- package/src/drizzle/oauth-mysql.ts +2 -2
- package/src/drizzle/oauth-proxy.ts +101 -0
- package/src/drizzle/oauth-target.ts +33 -737
- package/src/drizzle/password-model.ts +0 -33
- package/src/drizzle/password-prepared-model.ts +0 -18
- package/src/drizzle/password-sql.ts +3 -0
- package/src/drizzle/password-target.ts +41 -4
- package/src/drizzle/pg-password-prepared.ts +4 -16
- package/src/drizzle/pg-passwords.ts +5 -20
- package/src/drizzle/query-operations.ts +4 -0
- package/src/drizzle/session-sql.ts +2 -1
- package/src/drizzle/sqlite-password-prepared.ts +4 -52
- package/src/drizzle/sqlite-passwords.ts +7 -28
- package/src/drizzle/storage-validation.ts +13 -222
- package/src/index.ts +2 -8
- package/src/internal/drizzle-postgres-oauth-proxy.ts +37 -0
- package/src/internal/drizzle-postgres.ts +2 -0
- package/src/internal/drizzle-sqlite-oauth-proxy.ts +44 -0
- package/src/internal/drizzle-sqlite.ts +2 -0
- package/dist/_virtual/_rolldown/runtime.mjs +0 -13
- package/dist/drizzle/oauth-accounts.mjs +0 -359
- package/dist/drizzle/oauth-accounts.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-access.mjs +0 -212
- package/dist/drizzle/oauth-connected-access.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-collection.mjs +0 -202
- package/dist/drizzle/oauth-connected-collection.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-custody.mjs +0 -147
- package/dist/drizzle/oauth-connected-custody.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-flow.mjs +0 -297
- package/dist/drizzle/oauth-connected-flow.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-input.mjs +0 -122
- package/dist/drizzle/oauth-connected-input.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-maintenance.mjs +0 -214
- package/dist/drizzle/oauth-connected-maintenance.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-management.mjs +0 -229
- package/dist/drizzle/oauth-connected-management.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-settlement.mjs +0 -128
- package/dist/drizzle/oauth-connected-settlement.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-sign-in.mjs +0 -265
- package/dist/drizzle/oauth-connected-sign-in.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-state.d.mts +0 -2062
- package/dist/drizzle/oauth-connected-state.mjs +0 -430
- package/dist/drizzle/oauth-connected-state.mjs.map +0 -1
- package/dist/drizzle/oauth-flow.d.mts +0 -22
- package/dist/drizzle/oauth-flow.mjs +0 -253
- package/dist/drizzle/oauth-flow.mjs.map +0 -1
- package/dist/drizzle/oauth-input.mjs +0 -127
- package/dist/drizzle/oauth-input.mjs.map +0 -1
- package/dist/drizzle/oauth-owner.d.mts +0 -10
- package/dist/drizzle/oauth-owner.mjs +0 -10
- package/dist/drizzle/oauth-owner.mjs.map +0 -1
- package/dist/drizzle/oauth-registration.d.mts +0 -5
- package/dist/drizzle/oauth-registration.mjs +0 -374
- package/dist/drizzle/oauth-registration.mjs.map +0 -1
- package/dist/drizzle/oauth-state.mjs +0 -107
- package/dist/drizzle/oauth-state.mjs.map +0 -1
- package/src/drizzle/oauth-accounts.ts +0 -805
- package/src/drizzle/oauth-connected-access.ts +0 -361
- package/src/drizzle/oauth-connected-collection.ts +0 -324
- package/src/drizzle/oauth-connected-custody.ts +0 -279
- package/src/drizzle/oauth-connected-flow.ts +0 -529
- package/src/drizzle/oauth-connected-input.ts +0 -147
- package/src/drizzle/oauth-connected-maintenance.ts +0 -346
- package/src/drizzle/oauth-connected-management.ts +0 -365
- package/src/drizzle/oauth-connected-settlement.ts +0 -251
- package/src/drizzle/oauth-connected-sign-in.ts +0 -443
- package/src/drizzle/oauth-connected-state.ts +0 -872
- package/src/drizzle/oauth-flow.ts +0 -462
- package/src/drizzle/oauth-input.ts +0 -201
- package/src/drizzle/oauth-owner.ts +0 -29
- package/src/drizzle/oauth-registration.ts +0 -640
- package/src/drizzle/oauth-state.ts +0 -218
|
@@ -17,6 +17,7 @@ import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
|
17
17
|
import type { SubjectId, TokenDigest } from "@yielded/auth/Schema";
|
|
18
18
|
import {
|
|
19
19
|
assessAuthentication,
|
|
20
|
+
AuthenticationCapture,
|
|
20
21
|
snapshotSessionAuthenticationProvenance,
|
|
21
22
|
AuthenticationAuthority,
|
|
22
23
|
PendingAuthenticationInvalid,
|
|
@@ -557,13 +558,18 @@ const capture = Effect.fn("DrizzleD1Session.capture")(function* (
|
|
|
557
558
|
subjectId: SubjectId,
|
|
558
559
|
credentialIds: ReadonlyArray<string>,
|
|
559
560
|
): Effect.fn.Return<
|
|
560
|
-
|
|
561
|
+
AuthenticationCapture,
|
|
561
562
|
StaleAuthentication | D1AdapterFailure,
|
|
562
563
|
CurrentD1PlanningDatabase
|
|
563
564
|
> {
|
|
564
565
|
const details = yield* captureDetails(mapping, subjectId, credentialIds);
|
|
565
566
|
|
|
566
|
-
|
|
567
|
+
const requirement = yield* mapping.subject.decodeRequirement(details.subject);
|
|
568
|
+
|
|
569
|
+
return yield* Schema.decodeEffect(AuthenticationCapture)({
|
|
570
|
+
revision: details.revision,
|
|
571
|
+
requirement,
|
|
572
|
+
});
|
|
567
573
|
});
|
|
568
574
|
|
|
569
575
|
const requirement = Effect.fn("DrizzleD1Session.requirement")(function* (
|
|
@@ -1122,7 +1128,11 @@ export const makeD1StatefulSessions = <Claims>(
|
|
|
1122
1128
|
input.evidence.revision.subjectId,
|
|
1123
1129
|
);
|
|
1124
1130
|
|
|
1125
|
-
if (
|
|
1131
|
+
if (
|
|
1132
|
+
input.pending === undefined &&
|
|
1133
|
+
(input.fresh !== true || input.handoffSourceSessionId !== undefined) &&
|
|
1134
|
+
(yield* hasActiveFlow(mapping, input.evidence.flowId))
|
|
1135
|
+
)
|
|
1126
1136
|
return yield* SessionConflict.make({});
|
|
1127
1137
|
|
|
1128
1138
|
const nativeSessionId = yield* allocate(
|
|
@@ -1169,7 +1179,10 @@ export const makeD1StatefulSessions = <Claims>(
|
|
|
1169
1179
|
let condition = commitCondition;
|
|
1170
1180
|
const statements: Statement<any>[] = [];
|
|
1171
1181
|
|
|
1172
|
-
if (
|
|
1182
|
+
if (
|
|
1183
|
+
input.pending === undefined &&
|
|
1184
|
+
(input.fresh !== true || input.handoffSourceSessionId !== undefined)
|
|
1185
|
+
) {
|
|
1173
1186
|
const f = flowColumns(mapping);
|
|
1174
1187
|
|
|
1175
1188
|
condition = and(
|
|
@@ -1205,7 +1218,7 @@ export const makeD1StatefulSessions = <Claims>(
|
|
|
1205
1218
|
),
|
|
1206
1219
|
),
|
|
1207
1220
|
);
|
|
1208
|
-
} else {
|
|
1221
|
+
} else if (input.pending !== undefined) {
|
|
1209
1222
|
if (mapping.pending === undefined) return yield* invalidPending();
|
|
1210
1223
|
const stored = yield* readPending(mapping, input.pending.digest);
|
|
1211
1224
|
|
|
@@ -1244,7 +1257,9 @@ export const makeD1StatefulSessions = <Claims>(
|
|
|
1244
1257
|
CurrentD1PlanningDatabase
|
|
1245
1258
|
>(() =>
|
|
1246
1259
|
input.pending === undefined
|
|
1247
|
-
?
|
|
1260
|
+
? input.fresh === true && input.handoffSourceSessionId === undefined
|
|
1261
|
+
? Effect.fail(stale())
|
|
1262
|
+
: recoverFlowOrStale(mapping, input.evidence.flowId)
|
|
1248
1263
|
: recoverPendingOrStale(mapping, input.pending, input.evidence.revision.subjectId),
|
|
1249
1264
|
),
|
|
1250
1265
|
),
|
|
@@ -29,9 +29,6 @@ export const makeMySqlPasswordPreparedPersistenceServices = <
|
|
|
29
29
|
I extends AnyMySqlTable,
|
|
30
30
|
C extends AnyMySqlTable,
|
|
31
31
|
AC extends AnyMySqlTable,
|
|
32
|
-
A extends AnyMySqlTable,
|
|
33
|
-
RS extends AnyMySqlTable,
|
|
34
|
-
CE extends AnyMySqlTable,
|
|
35
32
|
M extends AnyMySqlTable,
|
|
36
33
|
T extends AnyMySqlTable,
|
|
37
34
|
B extends AnyMySqlTable,
|
|
@@ -44,7 +41,7 @@ export const makeMySqlPasswordPreparedPersistenceServices = <
|
|
|
44
41
|
PCr extends AnyMySqlTable = AnyMySqlTable,
|
|
45
42
|
PNativeId = unknown,
|
|
46
43
|
>(
|
|
47
|
-
mapping: PasswordPreparedPersistenceMapping<S, I, C, AC,
|
|
44
|
+
mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, M, T, B, NativeId>,
|
|
48
45
|
proofMapping?: PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>,
|
|
49
46
|
) =>
|
|
50
47
|
Effect.flatMap(
|
|
@@ -63,9 +60,6 @@ export function coordinateMySqlPasswordPreparedPersistence<
|
|
|
63
60
|
I extends AnyMySqlTable,
|
|
64
61
|
C extends AnyMySqlTable,
|
|
65
62
|
AC extends AnyMySqlTable,
|
|
66
|
-
A extends AnyMySqlTable,
|
|
67
|
-
RS extends AnyMySqlTable,
|
|
68
|
-
CE extends AnyMySqlTable,
|
|
69
63
|
M extends AnyMySqlTable,
|
|
70
64
|
T extends AnyMySqlTable,
|
|
71
65
|
B extends AnyMySqlTable,
|
|
@@ -85,7 +79,7 @@ export function coordinateMySqlPasswordPreparedPersistence<
|
|
|
85
79
|
>(
|
|
86
80
|
acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,
|
|
87
81
|
options: {
|
|
88
|
-
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC,
|
|
82
|
+
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, M, T, B, NativeId>;
|
|
89
83
|
readonly proofMapping?:
|
|
90
84
|
| PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>
|
|
91
85
|
| undefined;
|
|
@@ -106,9 +100,6 @@ export function coordinateMySqlPasswordPreparedPersistence<
|
|
|
106
100
|
I extends AnyMySqlTable,
|
|
107
101
|
C extends AnyMySqlTable,
|
|
108
102
|
AC extends AnyMySqlTable,
|
|
109
|
-
A extends AnyMySqlTable,
|
|
110
|
-
RS extends AnyMySqlTable,
|
|
111
|
-
CE extends AnyMySqlTable,
|
|
112
103
|
M extends AnyMySqlTable,
|
|
113
104
|
T extends AnyMySqlTable,
|
|
114
105
|
B extends AnyMySqlTable,
|
|
@@ -130,7 +121,7 @@ export function coordinateMySqlPasswordPreparedPersistence<
|
|
|
130
121
|
>(
|
|
131
122
|
acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,
|
|
132
123
|
options: {
|
|
133
|
-
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC,
|
|
124
|
+
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, M, T, B, NativeId>;
|
|
134
125
|
readonly proofMapping?:
|
|
135
126
|
| PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>
|
|
136
127
|
| undefined;
|
|
@@ -151,9 +142,6 @@ export function coordinateMySqlPasswordPreparedPersistence<
|
|
|
151
142
|
I extends AnyMySqlTable,
|
|
152
143
|
C extends AnyMySqlTable,
|
|
153
144
|
AC extends AnyMySqlTable,
|
|
154
|
-
A extends AnyMySqlTable,
|
|
155
|
-
RS extends AnyMySqlTable,
|
|
156
|
-
CE extends AnyMySqlTable,
|
|
157
145
|
M extends AnyMySqlTable,
|
|
158
146
|
T extends AnyMySqlTable,
|
|
159
147
|
B extends AnyMySqlTable,
|
|
@@ -175,7 +163,7 @@ export function coordinateMySqlPasswordPreparedPersistence<
|
|
|
175
163
|
>(
|
|
176
164
|
acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,
|
|
177
165
|
options: {
|
|
178
|
-
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC,
|
|
166
|
+
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, M, T, B, NativeId>;
|
|
179
167
|
readonly proofMapping?:
|
|
180
168
|
| PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>
|
|
181
169
|
| undefined;
|
|
@@ -55,25 +55,19 @@ type Mapping<
|
|
|
55
55
|
I extends AnyMySqlTable,
|
|
56
56
|
C extends AnyMySqlTable,
|
|
57
57
|
AC extends AnyMySqlTable,
|
|
58
|
-
A extends AnyMySqlTable,
|
|
59
|
-
RS extends AnyMySqlTable,
|
|
60
|
-
CE extends AnyMySqlTable,
|
|
61
58
|
M extends AnyMySqlTable,
|
|
62
59
|
NativeId,
|
|
63
|
-
> = PasswordPersistenceMapping<S, I, C, AC,
|
|
60
|
+
> = PasswordPersistenceMapping<S, I, C, AC, M, NativeId>;
|
|
64
61
|
|
|
65
62
|
export const makeMysqlPasswordPersistenceServices = <
|
|
66
63
|
S extends AnyMySqlTable,
|
|
67
64
|
I extends AnyMySqlTable,
|
|
68
65
|
C extends AnyMySqlTable,
|
|
69
66
|
AC extends AnyMySqlTable,
|
|
70
|
-
A extends AnyMySqlTable,
|
|
71
|
-
RS extends AnyMySqlTable,
|
|
72
|
-
CE extends AnyMySqlTable,
|
|
73
67
|
M extends AnyMySqlTable,
|
|
74
68
|
NativeId,
|
|
75
69
|
>(
|
|
76
|
-
mapping: Mapping<S, I, C, AC,
|
|
70
|
+
mapping: Mapping<S, I, C, AC, M, NativeId>,
|
|
77
71
|
proofMapping?: ProofPersistenceMapping<
|
|
78
72
|
any,
|
|
79
73
|
any,
|
|
@@ -103,9 +97,6 @@ export function coordinateMysqlPasswordPersistence<
|
|
|
103
97
|
I extends AnyMySqlTable,
|
|
104
98
|
C extends AnyMySqlTable,
|
|
105
99
|
AC extends AnyMySqlTable,
|
|
106
|
-
A extends AnyMySqlTable,
|
|
107
|
-
RS extends AnyMySqlTable,
|
|
108
|
-
CE extends AnyMySqlTable,
|
|
109
100
|
M extends AnyMySqlTable,
|
|
110
101
|
NativeId,
|
|
111
102
|
PM extends
|
|
@@ -119,7 +110,7 @@ export function coordinateMysqlPasswordPersistence<
|
|
|
119
110
|
>(
|
|
120
111
|
acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,
|
|
121
112
|
options: {
|
|
122
|
-
readonly mapping: Mapping<S, I, C, AC,
|
|
113
|
+
readonly mapping: Mapping<S, I, C, AC, M, NativeId>;
|
|
123
114
|
readonly proofMapping?: PM;
|
|
124
115
|
readonly transaction?: never;
|
|
125
116
|
},
|
|
@@ -136,9 +127,6 @@ export function coordinateMysqlPasswordPersistence<
|
|
|
136
127
|
I extends AnyMySqlTable,
|
|
137
128
|
C extends AnyMySqlTable,
|
|
138
129
|
AC extends AnyMySqlTable,
|
|
139
|
-
A extends AnyMySqlTable,
|
|
140
|
-
RS extends AnyMySqlTable,
|
|
141
|
-
CE extends AnyMySqlTable,
|
|
142
130
|
M extends AnyMySqlTable,
|
|
143
131
|
NativeId,
|
|
144
132
|
PM extends
|
|
@@ -154,7 +142,7 @@ export function coordinateMysqlPasswordPersistence<
|
|
|
154
142
|
>(
|
|
155
143
|
acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,
|
|
156
144
|
options: {
|
|
157
|
-
readonly mapping: Mapping<S, I, C, AC,
|
|
145
|
+
readonly mapping: Mapping<S, I, C, AC, M, NativeId>;
|
|
158
146
|
readonly proofMapping?: PM;
|
|
159
147
|
readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;
|
|
160
148
|
},
|
|
@@ -171,9 +159,6 @@ export function coordinateMysqlPasswordPersistence<
|
|
|
171
159
|
I extends AnyMySqlTable,
|
|
172
160
|
C extends AnyMySqlTable,
|
|
173
161
|
AC extends AnyMySqlTable,
|
|
174
|
-
A extends AnyMySqlTable,
|
|
175
|
-
RS extends AnyMySqlTable,
|
|
176
|
-
CE extends AnyMySqlTable,
|
|
177
162
|
M extends AnyMySqlTable,
|
|
178
163
|
NativeId,
|
|
179
164
|
PM extends
|
|
@@ -189,7 +174,7 @@ export function coordinateMysqlPasswordPersistence<
|
|
|
189
174
|
>(
|
|
190
175
|
acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,
|
|
191
176
|
options: {
|
|
192
|
-
readonly mapping: Mapping<S, I, C, AC,
|
|
177
|
+
readonly mapping: Mapping<S, I, C, AC, M, NativeId>;
|
|
193
178
|
readonly proofMapping?: PM;
|
|
194
179
|
readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;
|
|
195
180
|
},
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PersistenceMappingError,
|
|
3
|
+
makeNativeSqlTables,
|
|
4
|
+
nativeSqlAlias,
|
|
5
|
+
type NativeSqlTables,
|
|
6
|
+
type SqlTable,
|
|
7
|
+
} from "@yielded/auth-persistence/Adapter";
|
|
8
|
+
import {
|
|
9
|
+
getTableColumns,
|
|
10
|
+
getTableName,
|
|
11
|
+
is,
|
|
12
|
+
Param,
|
|
13
|
+
Placeholder,
|
|
14
|
+
type SQL,
|
|
15
|
+
Table,
|
|
16
|
+
sql,
|
|
17
|
+
type BuildQueryConfig,
|
|
18
|
+
type SQLWrapper,
|
|
19
|
+
} from "drizzle-orm";
|
|
20
|
+
import { getTableConfig as getMysqlTableConfig, MySqlTable } from "drizzle-orm/mysql-core";
|
|
21
|
+
import { getTableConfig as getPgTableConfig, PgTable } from "drizzle-orm/pg-core";
|
|
22
|
+
import { Predicate } from "effect";
|
|
23
|
+
import type { SqlClient } from "effect/sql/SqlClient";
|
|
24
|
+
import * as Statement from "effect/sql/Statement";
|
|
25
|
+
|
|
26
|
+
type CapturedDialect = Pick<BuildQueryConfig, "escapeName" | "escapeString" | "codecs">;
|
|
27
|
+
|
|
28
|
+
/** Foreign compiler boundary only: builders are used to materialize SQL, never
|
|
29
|
+
* executed. The select builder exposes the original dialect even through the
|
|
30
|
+
* Durable Object database projection, which retains bound query methods. */
|
|
31
|
+
interface CapturedDatabase {
|
|
32
|
+
readonly select: () => { readonly dialect: CapturedDialect };
|
|
33
|
+
readonly insert: (table: Table) => {
|
|
34
|
+
readonly values: (values: Record<string, unknown>) => SQLWrapper;
|
|
35
|
+
};
|
|
36
|
+
readonly update: (table: Table) => {
|
|
37
|
+
readonly set: (values: Record<string, unknown>) => SQLWrapper;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const invalid = (cause: string): never => {
|
|
42
|
+
throw PersistenceMappingError.make({ operation: "mapping", cause });
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const capture = (
|
|
46
|
+
database: object,
|
|
47
|
+
): { readonly database: CapturedDatabase; readonly dialect: CapturedDialect } => {
|
|
48
|
+
if (
|
|
49
|
+
!Predicate.hasProperty(database, "select") ||
|
|
50
|
+
typeof database.select !== "function" ||
|
|
51
|
+
!Predicate.hasProperty(database, "insert") ||
|
|
52
|
+
typeof database.insert !== "function" ||
|
|
53
|
+
!Predicate.hasProperty(database, "update") ||
|
|
54
|
+
typeof database.update !== "function"
|
|
55
|
+
)
|
|
56
|
+
return invalid("Expected a captured Drizzle database");
|
|
57
|
+
|
|
58
|
+
const selection: unknown = database.select();
|
|
59
|
+
|
|
60
|
+
if (!Predicate.hasProperty(selection, "dialect"))
|
|
61
|
+
return invalid("Expected a captured Drizzle dialect");
|
|
62
|
+
const dialect = selection.dialect;
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
!Predicate.hasProperty(dialect, "escapeName") ||
|
|
66
|
+
typeof dialect.escapeName !== "function" ||
|
|
67
|
+
!Predicate.hasProperty(dialect, "escapeString") ||
|
|
68
|
+
typeof dialect.escapeString !== "function"
|
|
69
|
+
)
|
|
70
|
+
return invalid("Expected Drizzle dialect escaping methods");
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
Predicate.hasProperty(dialect, "codecs") &&
|
|
74
|
+
dialect.codecs !== undefined &&
|
|
75
|
+
(!Predicate.hasProperty(dialect.codecs, "apply") || typeof dialect.codecs.apply !== "function")
|
|
76
|
+
)
|
|
77
|
+
return invalid("Expected Drizzle dialect codecs");
|
|
78
|
+
|
|
79
|
+
// Drizzle's private dialect and generic query builders are erased only here.
|
|
80
|
+
return { database: database as CapturedDatabase, dialect: dialect as CapturedDialect };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const compileWith =
|
|
84
|
+
(dialect: CapturedDialect) =>
|
|
85
|
+
(expression: SQL): Statement.Fragment => {
|
|
86
|
+
const slots: string[] = [];
|
|
87
|
+
|
|
88
|
+
const query = expression.toQuery({
|
|
89
|
+
escapeName: (name) => {
|
|
90
|
+
if (name.includes("\0")) return invalid("NUL in SQL identifier");
|
|
91
|
+
|
|
92
|
+
return dialect.escapeName(name);
|
|
93
|
+
},
|
|
94
|
+
escapeString: (value) => {
|
|
95
|
+
if (value.includes("\0")) return invalid("NUL in SQL literal");
|
|
96
|
+
|
|
97
|
+
return dialect.escapeString(value);
|
|
98
|
+
},
|
|
99
|
+
escapeParam: (index) => {
|
|
100
|
+
if (index !== slots.length) return invalid("Invalid Drizzle parameter order");
|
|
101
|
+
const slot = `yielded_parameter_${index}`;
|
|
102
|
+
|
|
103
|
+
slots.push(slot);
|
|
104
|
+
|
|
105
|
+
return `\0${slot}\0`;
|
|
106
|
+
},
|
|
107
|
+
...(dialect.codecs === undefined ? {} : { codecs: dialect.codecs }),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Only compiler-emitted slots are translated. Native Statement parameters
|
|
111
|
+
// receive their final positions when composed; SQL literals containing $1 or
|
|
112
|
+
// ? are never inspected or rewritten. NUL is reserved for this compilation.
|
|
113
|
+
const parts = query.sql.split("\0");
|
|
114
|
+
|
|
115
|
+
if (parts.length !== slots.length * 2 + 1 || query.params.length !== slots.length)
|
|
116
|
+
return invalid("NUL or parameter marker collision in Drizzle SQL");
|
|
117
|
+
|
|
118
|
+
const segments: Statement.Segment[] = [];
|
|
119
|
+
const consumed = new Set<number>();
|
|
120
|
+
|
|
121
|
+
for (let offset = 0; offset < parts.length; offset += 2) {
|
|
122
|
+
segments.push(Statement.literal(parts[offset]));
|
|
123
|
+
if (offset + 1 === parts.length) break;
|
|
124
|
+
const index = slots.indexOf(parts[offset + 1]);
|
|
125
|
+
|
|
126
|
+
if (index < 0 || consumed.has(index))
|
|
127
|
+
return invalid("NUL or parameter marker collision in Drizzle SQL");
|
|
128
|
+
consumed.add(index);
|
|
129
|
+
const value: unknown = query.params[index];
|
|
130
|
+
|
|
131
|
+
if (is(value, Placeholder) || is(value, Param)) return invalid("Unbound Drizzle placeholder");
|
|
132
|
+
if (Statement.isFragment(value)) segments.push(...value.segments);
|
|
133
|
+
else segments.push(Statement.parameter(value));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return Statement.fragment(segments);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/** Preserve native Statement expressions in writes without applying a column
|
|
140
|
+
* codec to them. Ordinary values still pass through Drizzle's own builders. */
|
|
141
|
+
const writeValues = (values: Readonly<Record<string, unknown>>) =>
|
|
142
|
+
Object.fromEntries(
|
|
143
|
+
Object.entries(values).map(([key, value]) => [
|
|
144
|
+
key,
|
|
145
|
+
Statement.isFragment(value) ? sql`${sql.param(value)}` : value,
|
|
146
|
+
]),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
/** Capture the root database's compiler, not a later transaction object's
|
|
150
|
+
* client. Call insert/update inside the operation to materialize hooks once. */
|
|
151
|
+
export const makeDrizzleSqlTables = (
|
|
152
|
+
client: SqlClient,
|
|
153
|
+
capturedDatabase: object,
|
|
154
|
+
): NativeSqlTables => {
|
|
155
|
+
const { database, dialect } = capture(capturedDatabase);
|
|
156
|
+
const compile = compileWith(dialect);
|
|
157
|
+
|
|
158
|
+
return makeNativeSqlTables(client, (_client, physical): SqlTable => {
|
|
159
|
+
if (!is(physical, Table)) return invalid("Expected a Drizzle table");
|
|
160
|
+
const columns = getTableColumns(physical);
|
|
161
|
+
const entries = Object.entries(columns);
|
|
162
|
+
|
|
163
|
+
const schema = is(physical, PgTable)
|
|
164
|
+
? getPgTableConfig(physical).schema
|
|
165
|
+
: is(physical, MySqlTable)
|
|
166
|
+
? getMysqlTableConfig(physical).schema
|
|
167
|
+
: undefined;
|
|
168
|
+
|
|
169
|
+
const table = { name: getTableName(physical), ...(schema === undefined ? {} : { schema }) };
|
|
170
|
+
|
|
171
|
+
const getColumn = (key: string) => {
|
|
172
|
+
const column = Object.hasOwn(columns, key) ? columns[key] : undefined;
|
|
173
|
+
|
|
174
|
+
if (column === undefined) return invalid("Missing Drizzle column");
|
|
175
|
+
|
|
176
|
+
return column;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const bind = (alias?: string): SqlTable => {
|
|
180
|
+
const reference = (key: string) => {
|
|
181
|
+
const column = getColumn(key);
|
|
182
|
+
|
|
183
|
+
return alias === undefined
|
|
184
|
+
? sql`${column}`
|
|
185
|
+
: sql`${sql.identifier(alias)}.${sql.identifier(column.name)}`;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
name: compile(
|
|
190
|
+
alias === undefined ? sql`${physical}` : sql`${physical} AS ${sql.identifier(alias)}`,
|
|
191
|
+
),
|
|
192
|
+
as: bind,
|
|
193
|
+
column: (key) => compile(reference(key)),
|
|
194
|
+
unencodedTextColumn: (key) => {
|
|
195
|
+
const column = getColumn(key);
|
|
196
|
+
|
|
197
|
+
return ["PgText", "PgVarchar", "SQLiteText", "MySqlText", "MySqlVarChar"].includes(
|
|
198
|
+
column.columnType,
|
|
199
|
+
) &&
|
|
200
|
+
Predicate.hasProperty(column.mapToDriverValue, "isNoop") &&
|
|
201
|
+
column.mapToDriverValue.isNoop === true &&
|
|
202
|
+
Predicate.hasProperty(column.mapFromDriverValue, "isNoop") &&
|
|
203
|
+
column.mapFromDriverValue.isNoop === true &&
|
|
204
|
+
(dialect.codecs === undefined ||
|
|
205
|
+
(Predicate.hasProperty(dialect.codecs, "get") &&
|
|
206
|
+
typeof dialect.codecs.get === "function" &&
|
|
207
|
+
(["cast", "normalize", "castParam", "normalizeParam"] as const).every(
|
|
208
|
+
(kind) => dialect.codecs?.get(column, kind) === undefined,
|
|
209
|
+
)))
|
|
210
|
+
? { table, name: column.name }
|
|
211
|
+
: undefined;
|
|
212
|
+
},
|
|
213
|
+
fields: (prefix) =>
|
|
214
|
+
compile(
|
|
215
|
+
sql.join(
|
|
216
|
+
entries.map(([key, column], index) => {
|
|
217
|
+
const selection =
|
|
218
|
+
dialect.codecs === undefined
|
|
219
|
+
? reference(key)
|
|
220
|
+
: dialect.codecs.apply(column, "cast", reference(key));
|
|
221
|
+
|
|
222
|
+
return sql`${selection} as ${sql.identifier(nativeSqlAlias(prefix, index))}`;
|
|
223
|
+
}),
|
|
224
|
+
sql`, `,
|
|
225
|
+
),
|
|
226
|
+
),
|
|
227
|
+
decode: (row, prefix) =>
|
|
228
|
+
Object.fromEntries(
|
|
229
|
+
entries.map(([key, column], index) => {
|
|
230
|
+
const alias = nativeSqlAlias(prefix, index);
|
|
231
|
+
|
|
232
|
+
if (!Object.hasOwn(row, alias)) return invalid("Missing SQL projection field");
|
|
233
|
+
const value = row[alias];
|
|
234
|
+
|
|
235
|
+
return [
|
|
236
|
+
key,
|
|
237
|
+
value === null
|
|
238
|
+
? null
|
|
239
|
+
: column.mapFromDriverValue(
|
|
240
|
+
dialect.codecs === undefined
|
|
241
|
+
? value
|
|
242
|
+
: dialect.codecs.apply(column, "normalize", value),
|
|
243
|
+
),
|
|
244
|
+
];
|
|
245
|
+
}),
|
|
246
|
+
),
|
|
247
|
+
value: (key, value) => {
|
|
248
|
+
const column = getColumn(key);
|
|
249
|
+
|
|
250
|
+
return Statement.isFragment(value) ? value : compile(sql`${sql.param(value, column)}`);
|
|
251
|
+
},
|
|
252
|
+
insert: (values) => compile(database.insert(physical).values(writeValues(values)).getSQL()),
|
|
253
|
+
update: (values) => compile(database.update(physical).set(writeValues(values)).getSQL()),
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
return bind();
|
|
258
|
+
});
|
|
259
|
+
};
|