@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.
Files changed (200) hide show
  1. package/README.md +3 -0
  2. package/dist/D1.d.mts +11 -11
  3. package/dist/D1.mjs +2 -1
  4. package/dist/D1.mjs.map +1 -1
  5. package/dist/Libsql.d.mts +40 -56
  6. package/dist/Libsql.mjs +2 -1
  7. package/dist/Libsql.mjs.map +1 -1
  8. package/dist/Mysql2.d.mts +16 -17
  9. package/dist/Pglite.d.mts +18 -18
  10. package/dist/Pglite.mjs +2 -1
  11. package/dist/Pglite.mjs.map +1 -1
  12. package/dist/Postgres.d.mts +24 -24
  13. package/dist/Postgres.mjs +2 -1
  14. package/dist/Postgres.mjs.map +1 -1
  15. package/dist/SqliteBun.d.mts +39 -55
  16. package/dist/SqliteBun.mjs +2 -1
  17. package/dist/SqliteBun.mjs.map +1 -1
  18. package/dist/SqliteDo.d.mts +48 -64
  19. package/dist/SqliteDo.mjs +2 -1
  20. package/dist/SqliteDo.mjs.map +1 -1
  21. package/dist/SqliteNode.d.mts +45 -61
  22. package/dist/SqliteNode.mjs +2 -1
  23. package/dist/SqliteNode.mjs.map +1 -1
  24. package/dist/SqliteWasm.d.mts +48 -64
  25. package/dist/SqliteWasm.mjs +2 -1
  26. package/dist/SqliteWasm.mjs.map +1 -1
  27. package/dist/drizzle/crypto.mjs +1 -1
  28. package/dist/drizzle/d1-emails.d.mts +1 -1
  29. package/dist/drizzle/d1-oauth.d.mts +14 -14
  30. package/dist/drizzle/d1-passkey.d.mts +1 -1
  31. package/dist/drizzle/d1-password-prepared.d.mts +4 -4
  32. package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
  33. package/dist/drizzle/d1-passwords.d.mts +18 -35
  34. package/dist/drizzle/d1-passwords.mjs +78 -290
  35. package/dist/drizzle/d1-passwords.mjs.map +1 -1
  36. package/dist/drizzle/d1-phone.d.mts +1 -1
  37. package/dist/drizzle/d1-proofs.d.mts +2 -2
  38. package/dist/drizzle/d1-sessions.d.mts +3 -3
  39. package/dist/drizzle/d1-sessions.mjs +11 -6
  40. package/dist/drizzle/d1-sessions.mjs.map +1 -1
  41. package/dist/drizzle/d1-totp.d.mts +1 -1
  42. package/dist/drizzle/mysql-password-prepared.d.mts +5 -5
  43. package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
  44. package/dist/drizzle/mysql-passwords.d.mts +16 -32
  45. package/dist/drizzle/mysql-passwords.mjs.map +1 -1
  46. package/dist/drizzle/mysql-sessions.d.mts +1 -1
  47. package/dist/drizzle/native-sql-table.mjs +135 -0
  48. package/dist/drizzle/native-sql-table.mjs.map +1 -0
  49. package/dist/drizzle/oauth-connected-model.d.mts +20 -281
  50. package/dist/drizzle/oauth-connected-model.mjs +3 -17
  51. package/dist/drizzle/oauth-connected-model.mjs.map +1 -1
  52. package/dist/drizzle/oauth-connected-reference.d.mts +1 -3
  53. package/dist/drizzle/oauth-connected-reference.mjs +4 -53
  54. package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
  55. package/dist/drizzle/oauth-connected-target.d.mts +3 -990
  56. package/dist/drizzle/oauth-connected-target.mjs +8 -92
  57. package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
  58. package/dist/drizzle/oauth-kernel.mjs +11 -0
  59. package/dist/drizzle/oauth-kernel.mjs.map +1 -0
  60. package/dist/drizzle/oauth-model.d.mts +35 -438
  61. package/dist/drizzle/oauth-model.mjs +6 -44
  62. package/dist/drizzle/oauth-model.mjs.map +1 -1
  63. package/dist/drizzle/oauth-mysql.mjs +2 -2
  64. package/dist/drizzle/oauth-mysql.mjs.map +1 -1
  65. package/dist/drizzle/oauth-proxy.d.mts +10 -0
  66. package/dist/drizzle/oauth-proxy.mjs +54 -0
  67. package/dist/drizzle/oauth-proxy.mjs.map +1 -0
  68. package/dist/drizzle/oauth-target.d.mts +6 -107
  69. package/dist/drizzle/oauth-target.mjs +15 -245
  70. package/dist/drizzle/oauth-target.mjs.map +1 -1
  71. package/dist/drizzle/password-model.d.mts +5 -8
  72. package/dist/drizzle/password-prepared-model.d.mts +5 -5
  73. package/dist/drizzle/password-prepared-model.mjs.map +1 -1
  74. package/dist/drizzle/password-prepared-state.mjs +1 -1
  75. package/dist/drizzle/password-sql.mjs +2 -1
  76. package/dist/drizzle/password-sql.mjs.map +1 -1
  77. package/dist/drizzle/password-target.mjs +13 -2
  78. package/dist/drizzle/password-target.mjs.map +1 -1
  79. package/dist/drizzle/pg-password-prepared.d.mts +5 -5
  80. package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
  81. package/dist/drizzle/pg-passwords.d.mts +16 -32
  82. package/dist/drizzle/pg-passwords.mjs.map +1 -1
  83. package/dist/drizzle/pg-sessions.d.mts +1 -1
  84. package/dist/drizzle/phone-target.d.mts +2 -2
  85. package/dist/drizzle/phone-target.mjs +1 -1
  86. package/dist/drizzle/query-operations.mjs +3 -1
  87. package/dist/drizzle/query-operations.mjs.map +1 -1
  88. package/dist/drizzle/session-sql.mjs +2 -1
  89. package/dist/drizzle/session-sql.mjs.map +1 -1
  90. package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
  91. package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
  92. package/dist/drizzle/storage-validation.mjs +10 -198
  93. package/dist/drizzle/storage-validation.mjs.map +1 -1
  94. package/dist/drizzle/totp-target.d.mts +3 -3
  95. package/dist/drizzle/totp-target.mjs +2 -2
  96. package/dist/drizzle/transaction-execution.d.mts +2 -2
  97. package/dist/drizzle/transaction-owner.d.mts +1 -2
  98. package/dist/index.d.mts +3 -2
  99. package/dist/internal/drizzle-postgres-oauth-proxy.d.mts +138 -0
  100. package/dist/internal/drizzle-postgres-oauth-proxy.mjs +29 -0
  101. package/dist/internal/drizzle-postgres-oauth-proxy.mjs.map +1 -0
  102. package/dist/internal/drizzle-postgres.mjs +2 -0
  103. package/dist/internal/drizzle-postgres.mjs.map +1 -1
  104. package/dist/internal/drizzle-sqlite-oauth-proxy.d.mts +146 -0
  105. package/dist/internal/drizzle-sqlite-oauth-proxy.mjs +29 -0
  106. package/dist/internal/drizzle-sqlite-oauth-proxy.mjs.map +1 -0
  107. package/dist/internal/drizzle-sqlite.mjs +2 -0
  108. package/dist/internal/drizzle-sqlite.mjs.map +1 -1
  109. package/package.json +1 -1
  110. package/src/D1.ts +2 -0
  111. package/src/Libsql.ts +2 -0
  112. package/src/Pglite.ts +2 -0
  113. package/src/Postgres.ts +2 -0
  114. package/src/SqliteBun.ts +2 -0
  115. package/src/SqliteDo.ts +2 -0
  116. package/src/SqliteNode.ts +2 -0
  117. package/src/SqliteWasm.ts +2 -0
  118. package/src/drizzle/d1-password-prepared.ts +2 -23
  119. package/src/drizzle/d1-passwords.ts +158 -780
  120. package/src/drizzle/d1-sessions.ts +21 -6
  121. package/src/drizzle/mysql-password-prepared.ts +4 -16
  122. package/src/drizzle/mysql-passwords.ts +5 -20
  123. package/src/drizzle/native-sql-table.ts +259 -0
  124. package/src/drizzle/oauth-connected-model.ts +97 -315
  125. package/src/drizzle/oauth-connected-reference.ts +13 -93
  126. package/src/drizzle/oauth-connected-target.ts +14 -271
  127. package/src/drizzle/oauth-kernel.ts +10 -0
  128. package/src/drizzle/oauth-model.ts +188 -541
  129. package/src/drizzle/oauth-mysql.ts +2 -2
  130. package/src/drizzle/oauth-proxy.ts +101 -0
  131. package/src/drizzle/oauth-target.ts +33 -737
  132. package/src/drizzle/password-model.ts +0 -33
  133. package/src/drizzle/password-prepared-model.ts +0 -18
  134. package/src/drizzle/password-sql.ts +3 -0
  135. package/src/drizzle/password-target.ts +41 -4
  136. package/src/drizzle/pg-password-prepared.ts +4 -16
  137. package/src/drizzle/pg-passwords.ts +5 -20
  138. package/src/drizzle/query-operations.ts +4 -0
  139. package/src/drizzle/session-sql.ts +2 -1
  140. package/src/drizzle/sqlite-password-prepared.ts +4 -52
  141. package/src/drizzle/sqlite-passwords.ts +7 -28
  142. package/src/drizzle/storage-validation.ts +13 -222
  143. package/src/index.ts +2 -8
  144. package/src/internal/drizzle-postgres-oauth-proxy.ts +37 -0
  145. package/src/internal/drizzle-postgres.ts +2 -0
  146. package/src/internal/drizzle-sqlite-oauth-proxy.ts +44 -0
  147. package/src/internal/drizzle-sqlite.ts +2 -0
  148. package/dist/_virtual/_rolldown/runtime.mjs +0 -13
  149. package/dist/drizzle/oauth-accounts.mjs +0 -359
  150. package/dist/drizzle/oauth-accounts.mjs.map +0 -1
  151. package/dist/drizzle/oauth-connected-access.mjs +0 -212
  152. package/dist/drizzle/oauth-connected-access.mjs.map +0 -1
  153. package/dist/drizzle/oauth-connected-collection.mjs +0 -202
  154. package/dist/drizzle/oauth-connected-collection.mjs.map +0 -1
  155. package/dist/drizzle/oauth-connected-custody.mjs +0 -147
  156. package/dist/drizzle/oauth-connected-custody.mjs.map +0 -1
  157. package/dist/drizzle/oauth-connected-flow.mjs +0 -297
  158. package/dist/drizzle/oauth-connected-flow.mjs.map +0 -1
  159. package/dist/drizzle/oauth-connected-input.mjs +0 -122
  160. package/dist/drizzle/oauth-connected-input.mjs.map +0 -1
  161. package/dist/drizzle/oauth-connected-maintenance.mjs +0 -214
  162. package/dist/drizzle/oauth-connected-maintenance.mjs.map +0 -1
  163. package/dist/drizzle/oauth-connected-management.mjs +0 -229
  164. package/dist/drizzle/oauth-connected-management.mjs.map +0 -1
  165. package/dist/drizzle/oauth-connected-settlement.mjs +0 -128
  166. package/dist/drizzle/oauth-connected-settlement.mjs.map +0 -1
  167. package/dist/drizzle/oauth-connected-sign-in.mjs +0 -265
  168. package/dist/drizzle/oauth-connected-sign-in.mjs.map +0 -1
  169. package/dist/drizzle/oauth-connected-state.d.mts +0 -2062
  170. package/dist/drizzle/oauth-connected-state.mjs +0 -430
  171. package/dist/drizzle/oauth-connected-state.mjs.map +0 -1
  172. package/dist/drizzle/oauth-flow.d.mts +0 -22
  173. package/dist/drizzle/oauth-flow.mjs +0 -253
  174. package/dist/drizzle/oauth-flow.mjs.map +0 -1
  175. package/dist/drizzle/oauth-input.mjs +0 -127
  176. package/dist/drizzle/oauth-input.mjs.map +0 -1
  177. package/dist/drizzle/oauth-owner.d.mts +0 -10
  178. package/dist/drizzle/oauth-owner.mjs +0 -10
  179. package/dist/drizzle/oauth-owner.mjs.map +0 -1
  180. package/dist/drizzle/oauth-registration.d.mts +0 -5
  181. package/dist/drizzle/oauth-registration.mjs +0 -374
  182. package/dist/drizzle/oauth-registration.mjs.map +0 -1
  183. package/dist/drizzle/oauth-state.mjs +0 -107
  184. package/dist/drizzle/oauth-state.mjs.map +0 -1
  185. package/src/drizzle/oauth-accounts.ts +0 -805
  186. package/src/drizzle/oauth-connected-access.ts +0 -361
  187. package/src/drizzle/oauth-connected-collection.ts +0 -324
  188. package/src/drizzle/oauth-connected-custody.ts +0 -279
  189. package/src/drizzle/oauth-connected-flow.ts +0 -529
  190. package/src/drizzle/oauth-connected-input.ts +0 -147
  191. package/src/drizzle/oauth-connected-maintenance.ts +0 -346
  192. package/src/drizzle/oauth-connected-management.ts +0 -365
  193. package/src/drizzle/oauth-connected-settlement.ts +0 -251
  194. package/src/drizzle/oauth-connected-sign-in.ts +0 -443
  195. package/src/drizzle/oauth-connected-state.ts +0 -872
  196. package/src/drizzle/oauth-flow.ts +0 -462
  197. package/src/drizzle/oauth-input.ts +0 -201
  198. package/src/drizzle/oauth-owner.ts +0 -29
  199. package/src/drizzle/oauth-registration.ts +0 -640
  200. 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
- AuthenticationRevision,
561
+ AuthenticationCapture,
561
562
  StaleAuthentication | D1AdapterFailure,
562
563
  CurrentD1PlanningDatabase
563
564
  > {
564
565
  const details = yield* captureDetails(mapping, subjectId, credentialIds);
565
566
 
566
- return details.revision;
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 (input.pending === undefined && (yield* hasActiveFlow(mapping, input.evidence.flowId)))
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 (input.pending === undefined) {
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
- ? recoverFlowOrStale(mapping, input.evidence.flowId)
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, A, RS, CE, M, T, B, NativeId>,
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, A, RS, CE, M, T, B, NativeId>;
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, A, RS, CE, M, T, B, NativeId>;
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, A, RS, CE, M, T, B, NativeId>;
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, A, RS, CE, M, NativeId>;
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, A, RS, CE, M, NativeId>,
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, A, RS, CE, M, NativeId>;
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, A, RS, CE, M, NativeId>;
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, A, RS, CE, M, NativeId>;
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
+ };