@yielded/auth-persistence 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 (182) hide show
  1. package/README.md +11 -0
  2. package/dist/Adapter.d.mts +13 -5
  3. package/dist/Adapter.mjs +9 -2
  4. package/dist/OAuthPersistence.d.mts +87 -0
  5. package/dist/OAuthPersistence.mjs +125 -0
  6. package/dist/OAuthPersistence.mjs.map +1 -0
  7. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  8. package/dist/index.d.mts +3 -1
  9. package/dist/index.mjs +3 -1
  10. package/dist/internal/authority-snapshot.mjs +53 -0
  11. package/dist/internal/authority-snapshot.mjs.map +1 -0
  12. package/dist/internal/configuration.d.mts +1 -1
  13. package/dist/internal/configuration.mjs.map +1 -1
  14. package/dist/internal/models/oauth-connected-model.d.mts +294 -0
  15. package/dist/internal/models/oauth-connected-model.mjs +22 -0
  16. package/dist/internal/models/oauth-connected-model.mjs.map +1 -0
  17. package/dist/internal/models/oauth-model.d.mts +467 -0
  18. package/dist/internal/models/oauth-model.mjs +49 -0
  19. package/dist/internal/models/oauth-model.mjs.map +1 -0
  20. package/dist/internal/models/password-model.d.mts +4 -97
  21. package/dist/internal/models/password-model.mjs +0 -3
  22. package/dist/internal/models/password-model.mjs.map +1 -1
  23. package/dist/internal/native-sql-table.d.mts +34 -0
  24. package/dist/internal/native-sql-table.mjs +111 -0
  25. package/dist/internal/native-sql-table.mjs.map +1 -0
  26. package/dist/internal/oauth/accounts.d.mts +8 -0
  27. package/dist/internal/oauth/accounts.mjs +379 -0
  28. package/dist/internal/oauth/accounts.mjs.map +1 -0
  29. package/dist/internal/oauth/connected-access.d.mts +9 -0
  30. package/dist/internal/oauth/connected-access.mjs +229 -0
  31. package/dist/internal/oauth/connected-access.mjs.map +1 -0
  32. package/dist/internal/oauth/connected-collection.d.mts +7 -0
  33. package/dist/internal/oauth/connected-collection.mjs +214 -0
  34. package/dist/internal/oauth/connected-collection.mjs.map +1 -0
  35. package/dist/internal/oauth/connected-custody.d.mts +6 -0
  36. package/dist/internal/oauth/connected-custody.mjs +165 -0
  37. package/dist/internal/oauth/connected-custody.mjs.map +1 -0
  38. package/dist/internal/oauth/connected-flow.d.mts +7 -0
  39. package/dist/internal/oauth/connected-flow.mjs +324 -0
  40. package/dist/internal/oauth/connected-flow.mjs.map +1 -0
  41. package/dist/internal/oauth/connected-input.mjs +122 -0
  42. package/dist/internal/oauth/connected-input.mjs.map +1 -0
  43. package/dist/internal/oauth/connected-keys.d.mts +2 -0
  44. package/dist/internal/oauth/connected-keys.mjs +22 -0
  45. package/dist/internal/oauth/connected-keys.mjs.map +1 -0
  46. package/dist/internal/oauth/connected-maintenance.d.mts +9 -0
  47. package/dist/internal/oauth/connected-maintenance.mjs +226 -0
  48. package/dist/internal/oauth/connected-maintenance.mjs.map +1 -0
  49. package/dist/internal/oauth/connected-management.d.mts +9 -0
  50. package/dist/internal/oauth/connected-management.mjs +243 -0
  51. package/dist/internal/oauth/connected-management.mjs.map +1 -0
  52. package/dist/internal/oauth/connected-reference.mjs +63 -0
  53. package/dist/internal/oauth/connected-reference.mjs.map +1 -0
  54. package/dist/internal/oauth/connected-settlement.d.mts +8 -0
  55. package/dist/internal/oauth/connected-settlement.mjs +141 -0
  56. package/dist/internal/oauth/connected-settlement.mjs.map +1 -0
  57. package/dist/internal/oauth/connected-sign-in.d.mts +10 -0
  58. package/dist/internal/oauth/connected-sign-in.mjs +281 -0
  59. package/dist/internal/oauth/connected-sign-in.mjs.map +1 -0
  60. package/dist/internal/oauth/connected-state.d.mts +14 -0
  61. package/dist/internal/oauth/connected-state.mjs +469 -0
  62. package/dist/internal/oauth/connected-state.mjs.map +1 -0
  63. package/dist/internal/oauth/connected-target.d.mts +21 -0
  64. package/dist/internal/oauth/connected-target.mjs +117 -0
  65. package/dist/internal/oauth/connected-target.mjs.map +1 -0
  66. package/dist/internal/oauth/flow.d.mts +5 -0
  67. package/dist/internal/oauth/flow.mjs +279 -0
  68. package/dist/internal/oauth/flow.mjs.map +1 -0
  69. package/dist/internal/oauth/input.mjs +127 -0
  70. package/dist/internal/oauth/input.mjs.map +1 -0
  71. package/dist/internal/oauth/owner.d.mts +10 -0
  72. package/dist/internal/oauth/owner.mjs +10 -0
  73. package/dist/internal/oauth/owner.mjs.map +1 -0
  74. package/dist/internal/oauth/query-compiler.d.mts +7 -0
  75. package/dist/internal/oauth/query-compiler.mjs +9 -0
  76. package/dist/internal/oauth/query-compiler.mjs.map +1 -0
  77. package/dist/internal/oauth/registration.d.mts +7 -0
  78. package/dist/internal/oauth/registration.mjs +393 -0
  79. package/dist/internal/oauth/registration.mjs.map +1 -0
  80. package/dist/internal/oauth/state.mjs +107 -0
  81. package/dist/internal/oauth/state.mjs.map +1 -0
  82. package/dist/internal/oauth/target.d.mts +31 -0
  83. package/dist/internal/oauth/target.mjs +273 -0
  84. package/dist/internal/oauth/target.mjs.map +1 -0
  85. package/dist/internal/oauth-kernel.d.mts +1423 -0
  86. package/dist/internal/oauth-kernel.mjs +187 -0
  87. package/dist/internal/oauth-kernel.mjs.map +1 -0
  88. package/dist/internal/oauth-proxy.d.mts +31 -0
  89. package/dist/internal/oauth-proxy.mjs +129 -0
  90. package/dist/internal/oauth-proxy.mjs.map +1 -0
  91. package/dist/internal/passkey/target.d.mts +1 -1
  92. package/dist/internal/passkey-kernel.d.mts +5 -5
  93. package/dist/internal/passkeys.mjs +1 -1
  94. package/dist/internal/password-credentials.d.mts +11 -0
  95. package/dist/internal/password-credentials.mjs +121 -0
  96. package/dist/internal/password-credentials.mjs.map +1 -0
  97. package/dist/internal/password-kernel.d.mts +15 -28
  98. package/dist/internal/password-kernel.mjs +35 -236
  99. package/dist/internal/password-kernel.mjs.map +1 -1
  100. package/dist/internal/persistence.d.mts +2 -0
  101. package/dist/internal/persistence.mjs +5 -5
  102. package/dist/internal/persistence.mjs.map +1 -1
  103. package/dist/internal/query-operations.d.mts +2 -0
  104. package/dist/internal/session-kernel.d.mts +5 -3
  105. package/dist/internal/session-kernel.mjs +95 -29
  106. package/dist/internal/session-kernel.mjs.map +1 -1
  107. package/dist/internal/sql-oauth-connected-model.d.mts +29 -0
  108. package/dist/internal/sql-oauth-connected-model.mjs +7 -0
  109. package/dist/internal/sql-oauth-connected-model.mjs.map +1 -0
  110. package/dist/internal/sql-oauth-model.d.mts +60 -0
  111. package/dist/internal/sql-oauth-model.mjs +10 -0
  112. package/dist/internal/sql-oauth-model.mjs.map +1 -0
  113. package/dist/internal/sql-persistence.mjs +3 -1
  114. package/dist/internal/sql-persistence.mjs.map +1 -1
  115. package/dist/internal/sql-query.d.mts +12 -0
  116. package/dist/internal/sql-query.mjs +15 -18
  117. package/dist/internal/sql-query.mjs.map +1 -1
  118. package/dist/internal/sql-storage-validation.mjs +54 -0
  119. package/dist/internal/sql-storage-validation.mjs.map +1 -0
  120. package/dist/internal/storage-mapping.mjs +2 -67
  121. package/dist/internal/storage-mapping.mjs.map +1 -1
  122. package/dist/internal/storage-plans.d.mts +7 -0
  123. package/dist/internal/storage-plans.mjs +189 -0
  124. package/dist/internal/storage-plans.mjs.map +1 -0
  125. package/dist/internal/storage-tables.d.mts +0 -99
  126. package/dist/internal/storage-tables.mjs +0 -43
  127. package/dist/internal/storage-tables.mjs.map +1 -1
  128. package/dist/internal/storage-validation.d.mts +6 -1
  129. package/dist/internal/storage-validation.mjs +42 -1
  130. package/dist/internal/storage-validation.mjs.map +1 -1
  131. package/dist/internal/transaction-execution-kernel.d.mts +1 -1
  132. package/dist/internal/transaction-kernel.d.mts +1 -1
  133. package/dist/internal/transaction-kernel.mjs +3 -2
  134. package/dist/internal/transaction-kernel.mjs.map +1 -1
  135. package/package.json +1 -1
  136. package/src/Adapter.ts +97 -8
  137. package/src/OAuthPersistence.ts +427 -0
  138. package/src/index.ts +3 -0
  139. package/src/internal/authority-snapshot.ts +91 -0
  140. package/src/internal/configuration.ts +1 -8
  141. package/src/internal/models/oauth-connected-model.ts +396 -0
  142. package/src/internal/models/oauth-model.ts +708 -0
  143. package/src/internal/models/password-model.ts +0 -120
  144. package/src/internal/native-sql-table.ts +178 -0
  145. package/src/internal/oauth/accounts.ts +838 -0
  146. package/src/internal/oauth/connected-access.ts +388 -0
  147. package/src/internal/oauth/connected-collection.ts +345 -0
  148. package/src/internal/oauth/connected-custody.ts +308 -0
  149. package/src/internal/oauth/connected-flow.ts +562 -0
  150. package/src/internal/oauth/connected-input.ts +147 -0
  151. package/src/internal/oauth/connected-keys.ts +31 -0
  152. package/src/internal/oauth/connected-maintenance.ts +379 -0
  153. package/src/internal/oauth/connected-management.ts +391 -0
  154. package/src/internal/oauth/connected-reference.ts +135 -0
  155. package/src/internal/oauth/connected-settlement.ts +278 -0
  156. package/src/internal/oauth/connected-sign-in.ts +472 -0
  157. package/src/internal/oauth/connected-state.ts +924 -0
  158. package/src/internal/oauth/connected-target.ts +307 -0
  159. package/src/internal/oauth/flow.ts +505 -0
  160. package/src/internal/oauth/input.ts +201 -0
  161. package/src/internal/oauth/owner.ts +22 -0
  162. package/src/internal/oauth/query-compiler.ts +15 -0
  163. package/src/internal/oauth/registration.ts +676 -0
  164. package/src/internal/oauth/state.ts +218 -0
  165. package/src/internal/oauth/target.ts +803 -0
  166. package/src/internal/oauth-kernel.ts +294 -0
  167. package/src/internal/oauth-proxy.ts +176 -0
  168. package/src/internal/password-credentials.ts +245 -0
  169. package/src/internal/password-kernel.ts +98 -712
  170. package/src/internal/persistence.ts +5 -10
  171. package/src/internal/query-operations.ts +2 -0
  172. package/src/internal/session-kernel.ts +231 -81
  173. package/src/internal/sql-oauth-connected-model.ts +145 -0
  174. package/src/internal/sql-oauth-model.ts +263 -0
  175. package/src/internal/sql-persistence.ts +2 -0
  176. package/src/internal/sql-query.ts +16 -13
  177. package/src/internal/sql-storage-validation.ts +64 -0
  178. package/src/internal/storage-mapping.ts +0 -66
  179. package/src/internal/storage-plans.ts +218 -0
  180. package/src/internal/storage-tables.ts +0 -35
  181. package/src/internal/storage-validation.ts +58 -0
  182. package/src/internal/transaction-kernel.ts +6 -2
@@ -3,18 +3,10 @@ import { AnyTableModel, SqlExpression, TableModel } from "../query-operations.mj
3
3
  import { SubjectIdCodec } from "./common.mjs";
4
4
  import { Effect, Redacted } from "effect";
5
5
  import { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
6
- import { EncodedPasswordHash, PasswordAction, PasswordAttemptId, PasswordCredentialSnapshot, PasswordRegistrationDecision, PasswordReplacement } from "@yielded/auth/Password";
6
+ import { EncodedPasswordHash, PasswordAction, PasswordCredentialSnapshot, PasswordRegistrationDecision, PasswordReplacement } from "@yielded/auth/Password";
7
7
  import { LoginIdentifier, RecoveryReference } from "@yielded/auth/Identity";
8
8
  //#region src/internal/models/password-model.d.ts
9
9
  type ColumnKey<T extends TableModel> = T["column"];
10
- export type PasswordAttemptAction = "sign-in" | "change";
11
- export type PasswordAttemptState = "pending" | "verified" | "rejected";
12
- export type PasswordRateScopeKind = "action" | "identifier" | "subject";
13
- export interface PasswordScopeKeys {
14
- readonly action: string;
15
- readonly identifier: string;
16
- readonly subject?: string;
17
- }
18
10
  export interface PasswordSubjectTable<Subject extends TableModel, _NativeSubjectId> {
19
11
  readonly table: Subject["table"];
20
12
  readonly id: ColumnKey<Subject>;
@@ -90,75 +82,6 @@ export interface PasswordCredentialTable<Subject extends TableModel, Identifier
90
82
  readonly credential: Credential["select"];
91
83
  }) => Effect.Effect<PasswordCredentialSnapshot, PersistenceMappingError>;
92
84
  }
93
- export interface PasswordAttemptRecord {
94
- readonly moduleId: string;
95
- readonly action: PasswordAttemptAction;
96
- readonly attemptId: PasswordAttemptId;
97
- readonly identifier: LoginIdentifier;
98
- readonly subjectId?: string;
99
- readonly credentialId?: string;
100
- readonly securityRevision?: SecurityRevision;
101
- readonly credentialRevision?: SecurityRevision;
102
- readonly verifierVersion?: SecurityRevision;
103
- readonly identifierBindingRevision?: SecurityRevision;
104
- readonly admittedAtMillis: number;
105
- readonly deadlineMillis: number;
106
- readonly retentionUntilMillis: number;
107
- }
108
- export interface PasswordAttemptTable<Attempt extends TableModel, NativeSubjectId> {
109
- readonly table: Attempt["table"];
110
- readonly moduleId: ColumnKey<Attempt>;
111
- readonly action: ColumnKey<Attempt>;
112
- readonly attemptId: ColumnKey<Attempt>;
113
- readonly identifierNamespace: ColumnKey<Attempt>;
114
- readonly identifierValue: ColumnKey<Attempt>;
115
- readonly subjectId: ColumnKey<Attempt>;
116
- readonly credentialId: ColumnKey<Attempt>;
117
- readonly securityRevision: ColumnKey<Attempt>;
118
- readonly credentialRevision: ColumnKey<Attempt>;
119
- readonly verifierVersion: ColumnKey<Attempt>;
120
- readonly identifierBindingRevision: ColumnKey<Attempt>;
121
- readonly admittedAt: ColumnKey<Attempt>;
122
- readonly deadline: ColumnKey<Attempt>;
123
- readonly retentionUntil: ColumnKey<Attempt>;
124
- readonly state: ColumnKey<Attempt>;
125
- readonly encodeInsert: (record: PasswordAttemptRecord, input: {
126
- readonly nativeSubjectId?: NativeSubjectId;
127
- readonly state: "pending";
128
- }) => Attempt["insert"];
129
- }
130
- export interface PasswordRateScopeTable<RateScope extends TableModel> {
131
- readonly table: RateScope["table"];
132
- readonly moduleId: ColumnKey<RateScope>;
133
- readonly action: ColumnKey<RateScope>;
134
- readonly scopeKind: ColumnKey<RateScope>;
135
- readonly scopeKey: ColumnKey<RateScope>;
136
- readonly encodeInsert: (input: {
137
- readonly moduleId: string;
138
- readonly action: PasswordAttemptAction;
139
- readonly scopeKind: PasswordRateScopeKind;
140
- readonly scopeKey: string;
141
- }) => RateScope["insert"];
142
- }
143
- export interface PasswordChargeTable<Charge extends TableModel> {
144
- readonly table: Charge["table"];
145
- readonly moduleId: ColumnKey<Charge>;
146
- readonly action: ColumnKey<Charge>;
147
- readonly scopeKind: ColumnKey<Charge>;
148
- readonly scopeKey: ColumnKey<Charge>;
149
- readonly attemptId: ColumnKey<Charge>;
150
- readonly occurredAt: ColumnKey<Charge>;
151
- readonly retentionUntil: ColumnKey<Charge>;
152
- readonly encodeInsert: (input: {
153
- readonly moduleId: string;
154
- readonly action: PasswordAttemptAction;
155
- readonly scopeKind: PasswordRateScopeKind;
156
- readonly scopeKey: string;
157
- readonly attemptId: PasswordAttemptId;
158
- readonly occurredAtMillis: number;
159
- readonly retentionUntilMillis: number;
160
- }) => Charge["insert"];
161
- }
162
85
  export interface PasswordCommandTable<Command extends TableModel> {
163
86
  readonly table: Command["table"];
164
87
  readonly moduleId: ColumnKey<Command>;
@@ -181,17 +104,12 @@ export interface RequiredPasswordConstraints {
181
104
  readonly authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)";
182
105
  readonly credentialSubject: "unique(credential.moduleId,credential.subjectId)";
183
106
  readonly credentialId: "unique(credential.moduleId,credential.credentialId)";
184
- readonly attempt: "unique(attempt.moduleId,attempt.attemptId)";
185
- readonly rateScope: "unique(rateScope.moduleId,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)";
186
- readonly charge: "unique(charge.moduleId,charge.action,charge.scopeKind,charge.scopeKey,charge.attemptId)";
187
107
  readonly command: "unique(command.moduleId,command.commandId)";
188
108
  }
189
109
  export declare const requiredPasswordConstraints: RequiredPasswordConstraints;
190
110
  export interface PasswordConstraintClassifier {
191
111
  /** Match only the mapped command uniqueness constraint. */
192
112
  readonly isCommandConflict: (cause: unknown) => boolean;
193
- /** Match only the mapped rate-scope uniqueness constraint. */
194
- readonly isRateScopeConflict: (cause: unknown) => boolean;
195
113
  }
196
114
  export interface PasswordD1Clock<Expression extends SqlExpression = SqlExpression> {
197
115
  readonly engineNow: Expression;
@@ -199,28 +117,17 @@ export interface PasswordD1Clock<Expression extends SqlExpression = SqlExpressio
199
117
  readonly engineInstantMinus: (millis: number) => Expression;
200
118
  readonly engineInstantPlus: (millis: number) => Expression;
201
119
  }
202
- export interface PasswordPersistenceMapping<Subject extends TableModel, Identifier extends TableModel, Credential extends TableModel, AuthorityCredential extends TableModel, Attempt extends TableModel, RateScope extends TableModel, Charge extends TableModel, Command extends TableModel, NativeSubjectId, Expression extends SqlExpression = SqlExpression> extends PasswordConstraintClassifier {
120
+ export interface PasswordPersistenceMapping<Subject extends TableModel, Identifier extends TableModel, Credential extends TableModel, AuthorityCredential extends TableModel, Command extends TableModel, NativeSubjectId, Expression extends SqlExpression = SqlExpression> extends PasswordConstraintClassifier {
203
121
  readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;
204
122
  readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;
205
123
  readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;
206
124
  /** Every factor revision named by action evidence, including non-password factors. */
207
125
  readonly authorityCredential: PasswordAuthorityCredentialTable<AuthorityCredential, NativeSubjectId>;
208
- readonly attempt: PasswordAttemptTable<Attempt, NativeSubjectId>;
209
- readonly rateScope: PasswordRateScopeTable<RateScope>;
210
- readonly charge: PasswordChargeTable<Charge>;
211
126
  readonly command: PasswordCommandTable<Command>;
212
127
  readonly subjectId: SubjectIdCodec<NativeSubjectId>;
213
128
  readonly constraints: RequiredPasswordConstraints;
214
- readonly scopeKeys: (input: {
215
- readonly moduleId: string;
216
- readonly action: PasswordAttemptAction;
217
- readonly identifier: LoginIdentifier;
218
- readonly subjectId?: string;
219
- }) => PasswordScopeKeys;
220
129
  readonly encodeInstant: (epochMillis: number) => unknown;
221
130
  readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;
222
- readonly allocateAttemptId?: Effect.Effect<PasswordAttemptId, PersistenceMappingError>;
223
- readonly allocateAttemptIdSync?: () => PasswordAttemptId;
224
131
  readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;
225
132
  readonly allocateCredentialIdSync?: () => string;
226
133
  readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;
@@ -230,7 +137,7 @@ export interface PasswordPersistenceMapping<Subject extends TableModel, Identifi
230
137
  readonly sessionInvalidation: "same-authority-immediate" | "original-absolute-expiry";
231
138
  readonly d1?: PasswordD1Clock<Expression>;
232
139
  }
233
- export type D1PasswordPersistenceMapping<Subject extends TableModel, Identifier extends TableModel, Credential extends TableModel, AuthorityCredential extends TableModel, Attempt extends TableModel, RateScope extends TableModel, Charge extends TableModel, Command extends TableModel, NativeSubjectId, Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<Subject, Identifier, Credential, AuthorityCredential, Attempt, RateScope, Charge, Command, NativeSubjectId, Expression> & {
140
+ export type D1PasswordPersistenceMapping<Subject extends TableModel, Identifier extends TableModel, Credential extends TableModel, AuthorityCredential extends TableModel, Command extends TableModel, NativeSubjectId, Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<Subject, Identifier, Credential, AuthorityCredential, Command, NativeSubjectId, Expression> & {
234
141
  readonly d1: PasswordD1Clock<Expression>;
235
142
  readonly subject: PasswordSubjectTable<Subject, NativeSubjectId> & {
236
143
  readonly d1ActiveStatusValue: unknown;
@@ -322,7 +229,7 @@ export type PasswordRegistrationMapping<Registration, Subject extends TableModel
322
229
  readonly allocateRecoveryReference?: Effect.Effect<typeof RecoveryReference.Type, PersistenceMappingError>;
323
230
  readonly allocateRecoveryReferenceSync?: () => typeof RecoveryReference.Type;
324
231
  });
325
- export type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, unknown, Expression>;
232
+ export type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, unknown, Expression>;
326
233
  export type AnyPasswordRegistrationMapping<Registration = unknown, Expression extends SqlExpression = SqlExpression> = PasswordRegistrationMapping<Registration, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, unknown, Expression>;
327
234
  //#endregion
328
235
  //# sourceMappingURL=password-model.d.mts.map
@@ -5,9 +5,6 @@ const requiredPasswordConstraints = {
5
5
  authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)",
6
6
  credentialSubject: "unique(credential.moduleId,credential.subjectId)",
7
7
  credentialId: "unique(credential.moduleId,credential.credentialId)",
8
- attempt: "unique(attempt.moduleId,attempt.attemptId)",
9
- rateScope: "unique(rateScope.moduleId,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)",
10
- charge: "unique(charge.moduleId,charge.action,charge.scopeKind,charge.scopeKey,charge.attemptId)",
11
8
  command: "unique(command.moduleId,command.commandId)"
12
9
  };
13
10
  const requiredPasswordRegistrationConstraints = {
@@ -1 +1 @@
1
- {"version":3,"file":"password-model.mjs","names":[],"sources":["../../../src/internal/models/password-model.ts"],"sourcesContent":["import { type RecoveryReference, type LoginIdentifier } from \"@yielded/auth/Identity\";\nimport type {\n PasswordAction,\n PasswordAttemptId,\n PasswordCredentialSnapshot,\n PasswordReplacement,\n PasswordRegistrationDecision,\n EncodedPasswordHash,\n} from \"@yielded/auth/Password\";\nimport type { AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport type { Effect, Redacted } from \"effect\";\n\nimport type { AnyTableModel, TableModel as Table, SqlExpression } from \"../query-operations\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\n\ntype ColumnKey<T extends Table> = T[\"column\"];\n\nexport type PasswordAttemptAction = \"sign-in\" | \"change\";\n\nexport type PasswordAttemptState = \"pending\" | \"verified\" | \"rejected\";\n\nexport type PasswordRateScopeKind = \"action\" | \"identifier\" | \"subject\";\n\nexport interface PasswordScopeKeys {\n readonly action: string;\n readonly identifier: string;\n readonly subject?: string;\n}\n\nexport interface PasswordSubjectTable<Subject extends Table, _NativeSubjectId> {\n readonly table: Subject[\"table\"];\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly securityRevision: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly decodeRequirement: (\n row: Subject[\"select\"],\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n /** Current policy for this exact credential mutation, decoded under the subject lock. */\n readonly decodeActionRequirement: (\n row: Subject[\"select\"],\n action: PasswordAction,\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n readonly nextSecurityRevision?: (\n current: SecurityRevision,\n ) => Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;\n /** Required only by D1 conditional statements. */\n readonly d1ActiveStatusValue?: unknown;\n}\n\nexport interface PasswordIdentifierTable<\n Identifier extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: Identifier[\"table\"];\n readonly namespace: ColumnKey<Identifier>;\n readonly value: ColumnKey<Identifier>;\n readonly subjectId: ColumnKey<Identifier>;\n readonly verifiedAt: ColumnKey<Identifier>;\n readonly bindingRevision: ColumnKey<Identifier>;\n /** Consumer-owned current login/recovery eligibility, including row status. */\n readonly isCurrent: (row: Identifier[\"select\"]) => boolean;\n /** Required by D1 so current ownership/eligibility is rechecked in the batch. */\n readonly d1CurrentCondition?: (input: {\n readonly identifier: LoginIdentifier;\n readonly nativeSubjectId: NativeSubjectId;\n }) => Expression;\n readonly encodeInitialInsert: (\n identifier: LoginIdentifier,\n subjectId: NativeSubjectId,\n bindingRevision: SecurityRevision,\n ) => Identifier[\"insert\"];\n}\n\nexport interface PasswordAuthorityCredentialTable<Credential extends Table, NativeSubjectId> {\n readonly table: Credential[\"table\"];\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly revision: ColumnKey<Credential>;\n readonly status?: ColumnKey<Credential>;\n readonly isActiveStatus?: (value: unknown) => boolean;\n readonly d1ActiveStatusValue?: unknown;\n readonly encodeInsert: (input: {\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n }) => Credential[\"insert\"];\n readonly encodeRevision: (revision: SecurityRevision) => Partial<Credential[\"insert\"]>;\n}\n\nexport interface PasswordCredentialTable<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n NativeSubjectId,\n> {\n readonly table: Credential[\"table\"];\n readonly moduleId: ColumnKey<Credential>;\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly credentialRevision: ColumnKey<Credential>;\n readonly verifierVersion: ColumnKey<Credential>;\n readonly verifier: ColumnKey<Credential>;\n readonly normalization: ColumnKey<Credential>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n readonly replacement: PasswordReplacement;\n }) => Credential[\"insert\"];\n readonly encodeVerifier: (\n verifier: Redacted.Redacted<EncodedPasswordHash>,\n verifierVersion: SecurityRevision,\n ) => Partial<Credential[\"insert\"]>;\n readonly encodeReplacement: (input: {\n readonly replacement: PasswordReplacement;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n }) => Partial<Credential[\"insert\"]>;\n readonly decode: (input: {\n readonly moduleId: string;\n readonly subject: Subject[\"select\"];\n readonly identifier: Identifier[\"select\"];\n readonly credential: Credential[\"select\"];\n }) => Effect.Effect<PasswordCredentialSnapshot, PersistenceMappingError>;\n}\n\nexport interface PasswordAttemptRecord {\n readonly moduleId: string;\n readonly action: PasswordAttemptAction;\n readonly attemptId: PasswordAttemptId;\n readonly identifier: LoginIdentifier;\n readonly subjectId?: string;\n readonly credentialId?: string;\n readonly securityRevision?: SecurityRevision;\n readonly credentialRevision?: SecurityRevision;\n readonly verifierVersion?: SecurityRevision;\n readonly identifierBindingRevision?: SecurityRevision;\n readonly admittedAtMillis: number;\n readonly deadlineMillis: number;\n readonly retentionUntilMillis: number;\n}\n\nexport interface PasswordAttemptTable<Attempt extends Table, NativeSubjectId> {\n readonly table: Attempt[\"table\"];\n readonly moduleId: ColumnKey<Attempt>;\n readonly action: ColumnKey<Attempt>;\n readonly attemptId: ColumnKey<Attempt>;\n readonly identifierNamespace: ColumnKey<Attempt>;\n readonly identifierValue: ColumnKey<Attempt>;\n readonly subjectId: ColumnKey<Attempt>;\n readonly credentialId: ColumnKey<Attempt>;\n readonly securityRevision: ColumnKey<Attempt>;\n readonly credentialRevision: ColumnKey<Attempt>;\n readonly verifierVersion: ColumnKey<Attempt>;\n readonly identifierBindingRevision: ColumnKey<Attempt>;\n readonly admittedAt: ColumnKey<Attempt>;\n readonly deadline: ColumnKey<Attempt>;\n readonly retentionUntil: ColumnKey<Attempt>;\n readonly state: ColumnKey<Attempt>;\n readonly encodeInsert: (\n record: PasswordAttemptRecord,\n input: {\n readonly nativeSubjectId?: NativeSubjectId;\n readonly state: \"pending\";\n },\n ) => Attempt[\"insert\"];\n}\n\nexport interface PasswordRateScopeTable<RateScope extends Table> {\n readonly table: RateScope[\"table\"];\n readonly moduleId: ColumnKey<RateScope>;\n readonly action: ColumnKey<RateScope>;\n readonly scopeKind: ColumnKey<RateScope>;\n readonly scopeKey: ColumnKey<RateScope>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly action: PasswordAttemptAction;\n readonly scopeKind: PasswordRateScopeKind;\n readonly scopeKey: string;\n }) => RateScope[\"insert\"];\n}\n\nexport interface PasswordChargeTable<Charge extends Table> {\n readonly table: Charge[\"table\"];\n readonly moduleId: ColumnKey<Charge>;\n readonly action: ColumnKey<Charge>;\n readonly scopeKind: ColumnKey<Charge>;\n readonly scopeKey: ColumnKey<Charge>;\n readonly attemptId: ColumnKey<Charge>;\n readonly occurredAt: ColumnKey<Charge>;\n readonly retentionUntil: ColumnKey<Charge>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly action: PasswordAttemptAction;\n readonly scopeKind: PasswordRateScopeKind;\n readonly scopeKey: string;\n readonly attemptId: PasswordAttemptId;\n readonly occurredAtMillis: number;\n readonly retentionUntilMillis: number;\n }) => Charge[\"insert\"];\n}\n\nexport interface PasswordCommandTable<Command extends Table> {\n readonly table: Command[\"table\"];\n readonly moduleId: ColumnKey<Command>;\n readonly commandId: ColumnKey<Command>;\n readonly action: ColumnKey<Command>;\n readonly bindingDigest: ColumnKey<Command>;\n readonly decision: ColumnKey<Command>;\n readonly retentionUntil: ColumnKey<Command>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly commandId: string;\n readonly action: string;\n readonly bindingDigest: string;\n readonly decision: \"changed\";\n readonly retentionUntilMillis: number;\n }) => Command[\"insert\"];\n}\n\nexport interface RequiredPasswordConstraints {\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly credentialId: \"unique(credential.moduleId,credential.credentialId)\";\n readonly attempt: \"unique(attempt.moduleId,attempt.attemptId)\";\n readonly rateScope: \"unique(rateScope.moduleId,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)\";\n readonly charge: \"unique(charge.moduleId,charge.action,charge.scopeKind,charge.scopeKey,charge.attemptId)\";\n readonly command: \"unique(command.moduleId,command.commandId)\";\n}\n\nexport const requiredPasswordConstraints: RequiredPasswordConstraints = {\n identifier: \"unique(identifier.namespace,identifier.value)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n credentialId: \"unique(credential.moduleId,credential.credentialId)\",\n attempt: \"unique(attempt.moduleId,attempt.attemptId)\",\n rateScope: \"unique(rateScope.moduleId,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)\",\n charge: \"unique(charge.moduleId,charge.action,charge.scopeKind,charge.scopeKey,charge.attemptId)\",\n command: \"unique(command.moduleId,command.commandId)\",\n};\n\nexport interface PasswordConstraintClassifier {\n /** Match only the mapped command uniqueness constraint. */\n readonly isCommandConflict: (cause: unknown) => boolean;\n /** Match only the mapped rate-scope uniqueness constraint. */\n readonly isRateScopeConflict: (cause: unknown) => boolean;\n}\n\nexport interface PasswordD1Clock<Expression extends SqlExpression = SqlExpression> {\n readonly engineNow: Expression;\n readonly engineNowMillis: Expression;\n readonly engineInstantMinus: (millis: number) => Expression;\n readonly engineInstantPlus: (millis: number) => Expression;\n}\n\nexport interface PasswordPersistenceMapping<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n Attempt extends Table,\n RateScope extends Table,\n Charge extends Table,\n Command extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> extends PasswordConstraintClassifier {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n /** Every factor revision named by action evidence, including non-password factors. */\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly attempt: PasswordAttemptTable<Attempt, NativeSubjectId>;\n readonly rateScope: PasswordRateScopeTable<RateScope>;\n readonly charge: PasswordChargeTable<Charge>;\n readonly command: PasswordCommandTable<Command>;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordConstraints;\n readonly scopeKeys: (input: {\n readonly moduleId: string;\n readonly action: PasswordAttemptAction;\n readonly identifier: LoginIdentifier;\n readonly subjectId?: string;\n }) => PasswordScopeKeys;\n readonly encodeInstant: (epochMillis: number) => unknown;\n readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;\n readonly allocateAttemptId?: Effect.Effect<PasswordAttemptId, PersistenceMappingError>;\n readonly allocateAttemptIdSync?: () => PasswordAttemptId;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n readonly commandRetentionMillis: number;\n /** All semantic replacements still bump subject revision. This flag only declares bearer invalidation latency. */\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n readonly d1?: PasswordD1Clock<Expression>;\n}\n\nexport type D1PasswordPersistenceMapping<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n Attempt extends Table,\n RateScope extends Table,\n Charge extends Table,\n Command extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordPersistenceMapping<\n Subject,\n Identifier,\n Credential,\n AuthorityCredential,\n Attempt,\n RateScope,\n Charge,\n Command,\n NativeSubjectId,\n Expression\n> & {\n readonly d1: PasswordD1Clock<Expression>;\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId> & {\n readonly d1ActiveStatusValue: unknown;\n };\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression> & {\n readonly d1CurrentCondition: (input: {\n readonly identifier: LoginIdentifier;\n readonly nativeSubjectId: NativeSubjectId;\n }) => Expression;\n };\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n > & {\n readonly d1ActiveStatusValue: unknown;\n };\n};\n\nexport type PasswordRegistrationState = \"pending\" | \"created\";\n\nexport interface PasswordRegistrationIntent<Registration> {\n readonly moduleId: string;\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: Registration;\n readonly replacement: PasswordReplacement;\n}\n\nexport interface PasswordRegistrationTable<Registration, Request extends Table, NativeSubjectId> {\n readonly table: Request[\"table\"];\n readonly moduleId: ColumnKey<Request>;\n readonly requestId: ColumnKey<Request>;\n readonly state: ColumnKey<Request>;\n readonly subjectId: ColumnKey<Request>;\n readonly recoveryReference: ColumnKey<Request>;\n readonly encodeInsert: (\n input: PasswordRegistrationIntent<Registration>,\n state: {\n readonly state: PasswordRegistrationState;\n readonly nativeSubjectId?: NativeSubjectId;\n readonly recoveryReference?: typeof RecoveryReference.Type;\n },\n ) => Request[\"insert\"];\n /** Replay projection must never expose a stored subject or decode protected intent. */\n readonly decodeReplay: (row: Request[\"select\"]) => Effect.Effect<\n Exclude<\n PasswordRegistrationDecision,\n {\n readonly _tag: \"Created\";\n }\n >,\n PersistenceMappingError\n >;\n}\n\nexport interface PasswordRegistrationProvisioning<\n Registration,\n Subject extends Table,\n NativeSubjectId,\n> {\n readonly encodeSubjectInsert: (\n input: PasswordRegistrationIntent<Registration>,\n values: {\n readonly nativeSubjectId: NativeSubjectId | undefined;\n readonly securityRevision: SecurityRevision;\n },\n ) => Subject[\"insert\"];\n readonly allocateSubjectId?: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n readonly allocateSubjectIdSync?: () => NativeSubjectId;\n /** Interactive targets use this for database-generated/autoincrement keys. */\n readonly decodeGeneratedId?: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n}\n\nexport interface RequiredPasswordRegistrationConstraints {\n readonly request: \"unique(registration.moduleId,registration.requestId)\";\n readonly recoveryReference: \"unique(registration.recoveryReference)\";\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n}\n\nexport const requiredPasswordRegistrationConstraints: RequiredPasswordRegistrationConstraints = {\n request: \"unique(registration.moduleId,registration.requestId)\",\n recoveryReference: \"unique(registration.recoveryReference)\",\n identifier: \"unique(identifier.namespace,identifier.value)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n};\n\nexport interface PasswordRegistrationConstraintClassifier {\n readonly isRequestConflict: (cause: unknown) => boolean;\n readonly isIdentifierConflict: (cause: unknown) => boolean;\n readonly isCredentialConflict: (cause: unknown) => boolean;\n}\n\nexport type PasswordRegistrationMapping<\n Registration,\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n Request extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationConstraintClassifier & {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly registration: PasswordRegistrationTable<Registration, Request, NativeSubjectId>;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordRegistrationConstraints;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n} & (\n | {\n readonly mode: \"atomic\";\n readonly provisioning: PasswordRegistrationProvisioning<\n Registration,\n Subject,\n NativeSubjectId\n > &\n (\n | {\n readonly idMode: \"allocated\";\n readonly allocateSubjectId: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n | {\n readonly idMode: \"synchronous\";\n readonly allocateSubjectIdSync: () => NativeSubjectId;\n }\n | {\n readonly idMode: \"generated\";\n readonly decodeGeneratedId: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n );\n }\n | {\n readonly mode: \"pending\";\n readonly allocateRecoveryReference?: Effect.Effect<\n typeof RecoveryReference.Type,\n PersistenceMappingError\n >;\n readonly allocateRecoveryReferenceSync?: () => typeof RecoveryReference.Type;\n }\n );\n\nexport type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> =\n PasswordPersistenceMapping<\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n >;\n\nexport type AnyPasswordRegistrationMapping<\n Registration = unknown,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationMapping<\n Registration,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n>;\n"],"mappings":";;AA4OA,MAAa,8BAA2D;CACtE,YAAY;CACZ,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;CACd,SAAS;CACT,WAAW;CACX,QAAQ;CACR,SAAS;AACX;AAwKA,MAAa,0CAAmF;CAC9F,SAAS;CACT,mBAAmB;CACnB,YAAY;CACZ,mBAAmB;CACnB,qBAAqB;AACvB"}
1
+ {"version":3,"file":"password-model.mjs","names":[],"sources":["../../../src/internal/models/password-model.ts"],"sourcesContent":["import { type RecoveryReference, type LoginIdentifier } from \"@yielded/auth/Identity\";\nimport type {\n PasswordAction,\n PasswordCredentialSnapshot,\n PasswordReplacement,\n PasswordRegistrationDecision,\n EncodedPasswordHash,\n} from \"@yielded/auth/Password\";\nimport type { AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport type { Effect, Redacted } from \"effect\";\n\nimport type { AnyTableModel, TableModel as Table, SqlExpression } from \"../query-operations\";\nimport type { PersistenceMappingError, SubjectIdCodec } from \"./common\";\n\ntype ColumnKey<T extends Table> = T[\"column\"];\n\nexport interface PasswordSubjectTable<Subject extends Table, _NativeSubjectId> {\n readonly table: Subject[\"table\"];\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly securityRevision: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly decodeRequirement: (\n row: Subject[\"select\"],\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n /** Current policy for this exact credential mutation, decoded under the subject lock. */\n readonly decodeActionRequirement: (\n row: Subject[\"select\"],\n action: PasswordAction,\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n readonly nextSecurityRevision?: (\n current: SecurityRevision,\n ) => Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;\n /** Required only by D1 conditional statements. */\n readonly d1ActiveStatusValue?: unknown;\n}\n\nexport interface PasswordIdentifierTable<\n Identifier extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> {\n readonly table: Identifier[\"table\"];\n readonly namespace: ColumnKey<Identifier>;\n readonly value: ColumnKey<Identifier>;\n readonly subjectId: ColumnKey<Identifier>;\n readonly verifiedAt: ColumnKey<Identifier>;\n readonly bindingRevision: ColumnKey<Identifier>;\n /** Consumer-owned current login/recovery eligibility, including row status. */\n readonly isCurrent: (row: Identifier[\"select\"]) => boolean;\n /** Required by D1 so current ownership/eligibility is rechecked in the batch. */\n readonly d1CurrentCondition?: (input: {\n readonly identifier: LoginIdentifier;\n readonly nativeSubjectId: NativeSubjectId;\n }) => Expression;\n readonly encodeInitialInsert: (\n identifier: LoginIdentifier,\n subjectId: NativeSubjectId,\n bindingRevision: SecurityRevision,\n ) => Identifier[\"insert\"];\n}\n\nexport interface PasswordAuthorityCredentialTable<Credential extends Table, NativeSubjectId> {\n readonly table: Credential[\"table\"];\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly revision: ColumnKey<Credential>;\n readonly status?: ColumnKey<Credential>;\n readonly isActiveStatus?: (value: unknown) => boolean;\n readonly d1ActiveStatusValue?: unknown;\n readonly encodeInsert: (input: {\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n }) => Credential[\"insert\"];\n readonly encodeRevision: (revision: SecurityRevision) => Partial<Credential[\"insert\"]>;\n}\n\nexport interface PasswordCredentialTable<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n NativeSubjectId,\n> {\n readonly table: Credential[\"table\"];\n readonly moduleId: ColumnKey<Credential>;\n readonly subjectId: ColumnKey<Credential>;\n readonly credentialId: ColumnKey<Credential>;\n readonly credentialRevision: ColumnKey<Credential>;\n readonly verifierVersion: ColumnKey<Credential>;\n readonly verifier: ColumnKey<Credential>;\n readonly normalization: ColumnKey<Credential>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly subjectId: NativeSubjectId;\n readonly credentialId: string;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n readonly replacement: PasswordReplacement;\n }) => Credential[\"insert\"];\n readonly encodeVerifier: (\n verifier: Redacted.Redacted<EncodedPasswordHash>,\n verifierVersion: SecurityRevision,\n ) => Partial<Credential[\"insert\"]>;\n readonly encodeReplacement: (input: {\n readonly replacement: PasswordReplacement;\n readonly credentialRevision: SecurityRevision;\n readonly verifierVersion: SecurityRevision;\n }) => Partial<Credential[\"insert\"]>;\n readonly decode: (input: {\n readonly moduleId: string;\n readonly subject: Subject[\"select\"];\n readonly identifier: Identifier[\"select\"];\n readonly credential: Credential[\"select\"];\n }) => Effect.Effect<PasswordCredentialSnapshot, PersistenceMappingError>;\n}\n\nexport interface PasswordCommandTable<Command extends Table> {\n readonly table: Command[\"table\"];\n readonly moduleId: ColumnKey<Command>;\n readonly commandId: ColumnKey<Command>;\n readonly action: ColumnKey<Command>;\n readonly bindingDigest: ColumnKey<Command>;\n readonly decision: ColumnKey<Command>;\n readonly retentionUntil: ColumnKey<Command>;\n readonly encodeInsert: (input: {\n readonly moduleId: string;\n readonly commandId: string;\n readonly action: string;\n readonly bindingDigest: string;\n readonly decision: \"changed\";\n readonly retentionUntilMillis: number;\n }) => Command[\"insert\"];\n}\n\nexport interface RequiredPasswordConstraints {\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly credentialId: \"unique(credential.moduleId,credential.credentialId)\";\n readonly command: \"unique(command.moduleId,command.commandId)\";\n}\n\nexport const requiredPasswordConstraints: RequiredPasswordConstraints = {\n identifier: \"unique(identifier.namespace,identifier.value)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n credentialId: \"unique(credential.moduleId,credential.credentialId)\",\n command: \"unique(command.moduleId,command.commandId)\",\n};\n\nexport interface PasswordConstraintClassifier {\n /** Match only the mapped command uniqueness constraint. */\n readonly isCommandConflict: (cause: unknown) => boolean;\n}\n\nexport interface PasswordD1Clock<Expression extends SqlExpression = SqlExpression> {\n readonly engineNow: Expression;\n readonly engineNowMillis: Expression;\n readonly engineInstantMinus: (millis: number) => Expression;\n readonly engineInstantPlus: (millis: number) => Expression;\n}\n\nexport interface PasswordPersistenceMapping<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n Command extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> extends PasswordConstraintClassifier {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n /** Every factor revision named by action evidence, including non-password factors. */\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly command: PasswordCommandTable<Command>;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordConstraints;\n readonly encodeInstant: (epochMillis: number) => unknown;\n readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n readonly commandRetentionMillis: number;\n /** All semantic replacements still bump subject revision. This flag only declares bearer invalidation latency. */\n readonly sessionInvalidation: \"same-authority-immediate\" | \"original-absolute-expiry\";\n readonly d1?: PasswordD1Clock<Expression>;\n}\n\nexport type D1PasswordPersistenceMapping<\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n Command extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordPersistenceMapping<\n Subject,\n Identifier,\n Credential,\n AuthorityCredential,\n Command,\n NativeSubjectId,\n Expression\n> & {\n readonly d1: PasswordD1Clock<Expression>;\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId> & {\n readonly d1ActiveStatusValue: unknown;\n };\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression> & {\n readonly d1CurrentCondition: (input: {\n readonly identifier: LoginIdentifier;\n readonly nativeSubjectId: NativeSubjectId;\n }) => Expression;\n };\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n > & {\n readonly d1ActiveStatusValue: unknown;\n };\n};\n\nexport type PasswordRegistrationState = \"pending\" | \"created\";\n\nexport interface PasswordRegistrationIntent<Registration> {\n readonly moduleId: string;\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: Registration;\n readonly replacement: PasswordReplacement;\n}\n\nexport interface PasswordRegistrationTable<Registration, Request extends Table, NativeSubjectId> {\n readonly table: Request[\"table\"];\n readonly moduleId: ColumnKey<Request>;\n readonly requestId: ColumnKey<Request>;\n readonly state: ColumnKey<Request>;\n readonly subjectId: ColumnKey<Request>;\n readonly recoveryReference: ColumnKey<Request>;\n readonly encodeInsert: (\n input: PasswordRegistrationIntent<Registration>,\n state: {\n readonly state: PasswordRegistrationState;\n readonly nativeSubjectId?: NativeSubjectId;\n readonly recoveryReference?: typeof RecoveryReference.Type;\n },\n ) => Request[\"insert\"];\n /** Replay projection must never expose a stored subject or decode protected intent. */\n readonly decodeReplay: (row: Request[\"select\"]) => Effect.Effect<\n Exclude<\n PasswordRegistrationDecision,\n {\n readonly _tag: \"Created\";\n }\n >,\n PersistenceMappingError\n >;\n}\n\nexport interface PasswordRegistrationProvisioning<\n Registration,\n Subject extends Table,\n NativeSubjectId,\n> {\n readonly encodeSubjectInsert: (\n input: PasswordRegistrationIntent<Registration>,\n values: {\n readonly nativeSubjectId: NativeSubjectId | undefined;\n readonly securityRevision: SecurityRevision;\n },\n ) => Subject[\"insert\"];\n readonly allocateSubjectId?: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n readonly allocateSubjectIdSync?: () => NativeSubjectId;\n /** Interactive targets use this for database-generated/autoincrement keys. */\n readonly decodeGeneratedId?: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n}\n\nexport interface RequiredPasswordRegistrationConstraints {\n readonly request: \"unique(registration.moduleId,registration.requestId)\";\n readonly recoveryReference: \"unique(registration.recoveryReference)\";\n readonly identifier: \"unique(identifier.namespace,identifier.value)\";\n readonly credentialSubject: \"unique(credential.moduleId,credential.subjectId)\";\n readonly authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\";\n}\n\nexport const requiredPasswordRegistrationConstraints: RequiredPasswordRegistrationConstraints = {\n request: \"unique(registration.moduleId,registration.requestId)\",\n recoveryReference: \"unique(registration.recoveryReference)\",\n identifier: \"unique(identifier.namespace,identifier.value)\",\n credentialSubject: \"unique(credential.moduleId,credential.subjectId)\",\n authorityCredential: \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\",\n};\n\nexport interface PasswordRegistrationConstraintClassifier {\n readonly isRequestConflict: (cause: unknown) => boolean;\n readonly isIdentifierConflict: (cause: unknown) => boolean;\n readonly isCredentialConflict: (cause: unknown) => boolean;\n}\n\nexport type PasswordRegistrationMapping<\n Registration,\n Subject extends Table,\n Identifier extends Table,\n Credential extends Table,\n AuthorityCredential extends Table,\n Request extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationConstraintClassifier & {\n readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;\n readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;\n readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;\n readonly authorityCredential: PasswordAuthorityCredentialTable<\n AuthorityCredential,\n NativeSubjectId\n >;\n readonly registration: PasswordRegistrationTable<Registration, Request, NativeSubjectId>;\n readonly subjectId: SubjectIdCodec<NativeSubjectId>;\n readonly constraints: RequiredPasswordRegistrationConstraints;\n readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;\n readonly allocateCredentialIdSync?: () => string;\n readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;\n readonly allocateRevisionSync?: () => SecurityRevision;\n} & (\n | {\n readonly mode: \"atomic\";\n readonly provisioning: PasswordRegistrationProvisioning<\n Registration,\n Subject,\n NativeSubjectId\n > &\n (\n | {\n readonly idMode: \"allocated\";\n readonly allocateSubjectId: Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n | {\n readonly idMode: \"synchronous\";\n readonly allocateSubjectIdSync: () => NativeSubjectId;\n }\n | {\n readonly idMode: \"generated\";\n readonly decodeGeneratedId: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;\n }\n );\n }\n | {\n readonly mode: \"pending\";\n readonly allocateRecoveryReference?: Effect.Effect<\n typeof RecoveryReference.Type,\n PersistenceMappingError\n >;\n readonly allocateRecoveryReferenceSync?: () => typeof RecoveryReference.Type;\n }\n );\n\nexport type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> =\n PasswordPersistenceMapping<\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n >;\n\nexport type AnyPasswordRegistrationMapping<\n Registration = unknown,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordRegistrationMapping<\n Registration,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n AnyTableModel,\n unknown,\n Expression\n>;\n"],"mappings":";;AAgJA,MAAa,8BAA2D;CACtE,YAAY;CACZ,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;CACd,SAAS;AACX;AAkJA,MAAa,0CAAmF;CAC9F,SAAS;CACT,mBAAmB;CACnB,YAAY;CACZ,mBAAmB;CACnB,qBAAqB;AACvB"}
@@ -0,0 +1,34 @@
1
+ import "./mapping-error.mjs";
2
+ import { PhysicalTextColumn } from "./storage-validation.mjs";
3
+ import { Effect } from "effect";
4
+ import * as Statement$1 from "effect/sql/Statement";
5
+ import { SqlClient } from "effect/sql/SqlClient";
6
+ //#region src/internal/native-sql-table.d.ts
7
+ /** Physical SQL representation only. Semantic row codecs and policy remain in
8
+ * the owning mapping. Execute assembled statements without name/result transforms. */
9
+ export interface SqlTable {
10
+ readonly name: Statement$1.Fragment;
11
+ /** Alias reads only; writes continue to target the original physical table. */
12
+ readonly as: (alias: string) => SqlTable;
13
+ readonly column: (key: string) => Statement$1.Fragment;
14
+ /** Optional codec-free text candidate. Physical type/collation compatibility
15
+ * must still be checked against the database before comparing columns. */
16
+ readonly unencodedTextColumn?: (key: string) => PhysicalTextColumn | undefined;
17
+ /** Project every column under an ordinal alias, using a distinct prefix per table. */
18
+ readonly fields: (prefix: string) => Statement$1.Fragment;
19
+ readonly decode: (row: Readonly<Record<string, unknown>>, prefix: string) => Record<string, unknown>;
20
+ readonly value: (key: string, value: unknown) => Statement$1.Fragment;
21
+ /** Complete INSERT prefix; append conflict/returning clauses in the owning operation. */
22
+ readonly insert: (values: Readonly<Record<string, unknown>>) => Statement$1.Fragment;
23
+ /** Complete UPDATE ... SET prefix; the owning operation supplies its predicate. */
24
+ readonly update: (values: Readonly<Record<string, unknown>>) => Statement$1.Fragment;
25
+ }
26
+ export type NativeSqlTables = (table: object) => SqlTable;
27
+ /** Prefixes are short ASCII identifiers so ordinal aliases cannot be truncated
28
+ * by PostgreSQL. Callers distinguish tables by prefix, never by physical names. */
29
+ export declare const nativeSqlAlias: (prefix: string, index: number) => string;
30
+ /** Cache physical metadata only; insert/update materialize values and hooks at
31
+ * each call. Construction acquires no client and owns no transaction. */
32
+ export declare const makeNativeSqlTables: (client: SqlClient, convert?: (client: SqlClient, table: object) => SqlTable) => NativeSqlTables;
33
+ //#endregion
34
+ //# sourceMappingURL=native-sql-table.d.mts.map
@@ -0,0 +1,111 @@
1
+ import { PersistenceMappingError } from "./mapping-error.mjs";
2
+ import { Table, identifier } from "./sql-table.mjs";
3
+ import { Effect } from "effect";
4
+ import * as Statement$1 from "effect/sql/Statement";
5
+ //#region src/internal/native-sql-table.ts
6
+ /** Capture synchronous mapping callbacks without changing SQL execution errors. */
7
+ const sqlMapping = (thunk) => Effect.try({
8
+ try: thunk,
9
+ catch: (cause) => PersistenceMappingError.make({
10
+ operation: "mapping",
11
+ cause
12
+ })
13
+ });
14
+ /** Prefixes are short ASCII identifiers so ordinal aliases cannot be truncated
15
+ * by PostgreSQL. Callers distinguish tables by prefix, never by physical names. */
16
+ const nativeSqlAlias = (prefix, index) => {
17
+ if (!/^[A-Za-z_][A-Za-z0-9_]{0,39}$/.test(prefix)) throw PersistenceMappingError.make({
18
+ operation: "mapping",
19
+ cause: "Invalid SQL alias prefix"
20
+ });
21
+ return `${prefix}${index}`;
22
+ };
23
+ const directTable = (client, physical) => {
24
+ if (!(physical instanceof Table)) throw PersistenceMappingError.make({
25
+ operation: "mapping",
26
+ cause: "Expected a SQL table"
27
+ });
28
+ const quote = (name) => {
29
+ if (name.includes("\0")) throw PersistenceMappingError.make({
30
+ operation: "mapping",
31
+ cause: "NUL in SQL identifier"
32
+ });
33
+ return client.literal(identifier(name));
34
+ };
35
+ const name = physical.schema === void 0 ? quote(physical.name) : client`${quote(physical.schema)}.${quote(physical.name)}`;
36
+ const columns = Object.entries(physical.columns);
37
+ const getColumn = (key) => {
38
+ const column = Object.hasOwn(physical.columns, key) ? physical.columns[key] : void 0;
39
+ if (column === void 0) throw PersistenceMappingError.make({
40
+ operation: "column",
41
+ cause: "Missing SQL column"
42
+ });
43
+ return column;
44
+ };
45
+ const value = (key, input) => {
46
+ const mapped = getColumn(key);
47
+ if (Statement$1.isFragment(input)) return input;
48
+ const encoded = input === null ? null : mapped.mapToDriverValue(input);
49
+ return Statement$1.fragment([Statement$1.parameter(typeof encoded === "boolean" ? client.onDialectOrElse({
50
+ sqlite: () => Number(encoded),
51
+ orElse: () => encoded
52
+ }) : encoded)]);
53
+ };
54
+ const entries = (values) => Object.entries(values).filter(([key, input]) => Object.hasOwn(physical.columns, key) && input !== void 0);
55
+ const bind = (alias) => {
56
+ const reference = alias === void 0 ? name : quote(alias);
57
+ const column = (key) => client`${reference}.${quote(getColumn(key).options.name)}`;
58
+ return {
59
+ name: alias === void 0 ? name : client`${name} AS ${reference}`,
60
+ as: bind,
61
+ column,
62
+ unencodedTextColumn: (key) => getColumn(key).options.type === "text" ? {
63
+ table: {
64
+ name: physical.name,
65
+ ...physical.schema === void 0 ? {} : { schema: physical.schema }
66
+ },
67
+ name: getColumn(key).options.name
68
+ } : void 0,
69
+ value,
70
+ fields: (prefix) => client.join(", ", false)(columns.map(([key], index) => client`${column(key)} AS ${quote(nativeSqlAlias(prefix, index))}`)),
71
+ decode: (row, prefix) => Object.fromEntries(columns.map(([key, field], index) => {
72
+ const alias = nativeSqlAlias(prefix, index);
73
+ if (!Object.hasOwn(row, alias)) throw PersistenceMappingError.make({
74
+ operation: "decode",
75
+ cause: "Missing SQL projection field"
76
+ });
77
+ return [key, field.decode(row[alias])];
78
+ })),
79
+ insert: (values) => {
80
+ const fields = entries(values);
81
+ if (fields.length === 0) return client`INSERT INTO ${name} DEFAULT VALUES`;
82
+ return client`INSERT INTO ${name} (${client.join(", ", false)(fields.map(([key]) => quote(getColumn(key).options.name)))}) VALUES (${client.join(", ", false)(fields.map(([key, input]) => value(key, input)))})`;
83
+ },
84
+ update: (values) => {
85
+ const fields = entries(values);
86
+ if (fields.length === 0) throw PersistenceMappingError.make({
87
+ operation: "mapping",
88
+ cause: "Empty SQL update"
89
+ });
90
+ return client`UPDATE ${name} SET ${client.join(", ", false)(fields.map(([key, input]) => client`${quote(getColumn(key).options.name)} = ${value(key, input)}`))}`;
91
+ }
92
+ };
93
+ };
94
+ return bind();
95
+ };
96
+ /** Cache physical metadata only; insert/update materialize values and hooks at
97
+ * each call. Construction acquires no client and owns no transaction. */
98
+ const makeNativeSqlTables = (client, convert = directTable) => {
99
+ const tables = /* @__PURE__ */ new WeakMap();
100
+ return (table) => {
101
+ const existing = tables.get(table);
102
+ if (existing !== void 0) return existing;
103
+ const mapped = convert(client, table);
104
+ tables.set(table, mapped);
105
+ return mapped;
106
+ };
107
+ };
108
+ //#endregion
109
+ export { makeNativeSqlTables, nativeSqlAlias, sqlMapping };
110
+
111
+ //# sourceMappingURL=native-sql-table.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-sql-table.mjs","names":["Statement"],"sources":["../../src/internal/native-sql-table.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport type { SqlClient } from \"effect/sql/SqlClient\";\nimport * as Statement from \"effect/sql/Statement\";\n\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport { Table, identifier } from \"./sql-table\";\nimport type { PhysicalTextColumn } from \"./storage-validation\";\n\n/** Capture synchronous mapping callbacks without changing SQL execution errors. */\nexport const sqlMapping = <A>(thunk: () => A): Effect.Effect<A, PersistenceMappingError> =>\n Effect.try({\n try: thunk,\n catch: (cause) => PersistenceMappingError.make({ operation: \"mapping\", cause }),\n });\n\n/** Physical SQL representation only. Semantic row codecs and policy remain in\n * the owning mapping. Execute assembled statements without name/result transforms. */\nexport interface SqlTable {\n readonly name: Statement.Fragment;\n /** Alias reads only; writes continue to target the original physical table. */\n readonly as: (alias: string) => SqlTable;\n readonly column: (key: string) => Statement.Fragment;\n /** Optional codec-free text candidate. Physical type/collation compatibility\n * must still be checked against the database before comparing columns. */\n readonly unencodedTextColumn?: (key: string) => PhysicalTextColumn | undefined;\n /** Project every column under an ordinal alias, using a distinct prefix per table. */\n readonly fields: (prefix: string) => Statement.Fragment;\n readonly decode: (\n row: Readonly<Record<string, unknown>>,\n prefix: string,\n ) => Record<string, unknown>;\n readonly value: (key: string, value: unknown) => Statement.Fragment;\n /** Complete INSERT prefix; append conflict/returning clauses in the owning operation. */\n readonly insert: (values: Readonly<Record<string, unknown>>) => Statement.Fragment;\n /** Complete UPDATE ... SET prefix; the owning operation supplies its predicate. */\n readonly update: (values: Readonly<Record<string, unknown>>) => Statement.Fragment;\n}\n\nexport type NativeSqlTables = (table: object) => SqlTable;\n\n/** Prefixes are short ASCII identifiers so ordinal aliases cannot be truncated\n * by PostgreSQL. Callers distinguish tables by prefix, never by physical names. */\nexport const nativeSqlAlias = (prefix: string, index: number): string => {\n if (!/^[A-Za-z_][A-Za-z0-9_]{0,39}$/.test(prefix))\n throw PersistenceMappingError.make({ operation: \"mapping\", cause: \"Invalid SQL alias prefix\" });\n\n return `${prefix}${index}`;\n};\n\nconst directTable = (client: SqlClient, physical: object): SqlTable => {\n if (!(physical instanceof Table))\n throw PersistenceMappingError.make({ operation: \"mapping\", cause: \"Expected a SQL table\" });\n\n const quote = (name: string) => {\n if (name.includes(\"\\0\"))\n throw PersistenceMappingError.make({ operation: \"mapping\", cause: \"NUL in SQL identifier\" });\n\n return client.literal(identifier(name));\n };\n\n const name =\n physical.schema === undefined\n ? quote(physical.name)\n : client`${quote(physical.schema)}.${quote(physical.name)}`;\n\n const columns = Object.entries(physical.columns);\n\n const getColumn = (key: string) => {\n const column = Object.hasOwn(physical.columns, key) ? physical.columns[key] : undefined;\n\n if (column === undefined)\n throw PersistenceMappingError.make({ operation: \"column\", cause: \"Missing SQL column\" });\n\n return column;\n };\n\n const value = (key: string, input: unknown): Statement.Fragment => {\n const mapped = getColumn(key);\n\n if (Statement.isFragment(input)) return input;\n const encoded = input === null ? null : mapped.mapToDriverValue(input);\n\n return Statement.fragment([\n Statement.parameter(\n typeof encoded === \"boolean\"\n ? client.onDialectOrElse({ sqlite: () => Number(encoded), orElse: () => encoded })\n : encoded,\n ),\n ]);\n };\n\n const entries = (values: Readonly<Record<string, unknown>>) =>\n Object.entries(values).filter(\n ([key, input]) => Object.hasOwn(physical.columns, key) && input !== undefined,\n );\n\n const bind = (alias?: string): SqlTable => {\n const reference = alias === undefined ? name : quote(alias);\n const column = (key: string) => client`${reference}.${quote(getColumn(key).options.name)}`;\n\n return {\n name: alias === undefined ? name : client`${name} AS ${reference}`,\n as: bind,\n column,\n unencodedTextColumn: (key) =>\n getColumn(key).options.type === \"text\"\n ? {\n table: {\n name: physical.name,\n ...(physical.schema === undefined ? {} : { schema: physical.schema }),\n },\n name: getColumn(key).options.name,\n }\n : undefined,\n value,\n fields: (prefix) =>\n client.join(\n \", \",\n false,\n )(\n columns.map(\n ([key], index) => client`${column(key)} AS ${quote(nativeSqlAlias(prefix, index))}`,\n ),\n ),\n decode: (row, prefix) =>\n Object.fromEntries(\n columns.map(([key, field], index) => {\n const alias = nativeSqlAlias(prefix, index);\n\n if (!Object.hasOwn(row, alias))\n throw PersistenceMappingError.make({\n operation: \"decode\",\n cause: \"Missing SQL projection field\",\n });\n\n return [key, field.decode(row[alias])];\n }),\n ),\n insert: (values) => {\n const fields = entries(values);\n\n if (fields.length === 0) return client`INSERT INTO ${name} DEFAULT VALUES`;\n\n return client`INSERT INTO ${name} (${client.join(\", \", false)(fields.map(([key]) => quote(getColumn(key).options.name)))}) VALUES (${client.join(\", \", false)(fields.map(([key, input]) => value(key, input)))})`;\n },\n update: (values) => {\n const fields = entries(values);\n\n if (fields.length === 0)\n throw PersistenceMappingError.make({ operation: \"mapping\", cause: \"Empty SQL update\" });\n\n return client`UPDATE ${name} SET ${client.join(\", \", false)(fields.map(([key, input]) => client`${quote(getColumn(key).options.name)} = ${value(key, input)}`))}`;\n },\n };\n };\n\n return bind();\n};\n\n/** Cache physical metadata only; insert/update materialize values and hooks at\n * each call. Construction acquires no client and owns no transaction. */\nexport const makeNativeSqlTables = (\n client: SqlClient,\n convert: (client: SqlClient, table: object) => SqlTable = directTable,\n): NativeSqlTables => {\n const tables = new WeakMap<object, SqlTable>();\n\n return (table) => {\n const existing = tables.get(table);\n\n if (existing !== undefined) return existing;\n const mapped = convert(client, table);\n\n tables.set(table, mapped);\n\n return mapped;\n };\n};\n"],"mappings":";;;;;;AASA,MAAa,cAAiB,UAC5B,OAAO,IAAI;CACT,KAAK;CACL,QAAQ,UAAU,wBAAwB,KAAK;EAAE,WAAW;EAAW;CAAM,CAAC;AAChF,CAAC;;;AA6BH,MAAa,kBAAkB,QAAgB,UAA0B;CACvE,IAAI,CAAC,gCAAgC,KAAK,MAAM,GAC9C,MAAM,wBAAwB,KAAK;EAAE,WAAW;EAAW,OAAO;CAA2B,CAAC;CAEhG,OAAO,GAAG,SAAS;AACrB;AAEA,MAAM,eAAe,QAAmB,aAA+B;CACrE,IAAI,EAAE,oBAAoB,QACxB,MAAM,wBAAwB,KAAK;EAAE,WAAW;EAAW,OAAO;CAAuB,CAAC;CAE5F,MAAM,SAAS,SAAiB;EAC9B,IAAI,KAAK,SAAS,IAAI,GACpB,MAAM,wBAAwB,KAAK;GAAE,WAAW;GAAW,OAAO;EAAwB,CAAC;EAE7F,OAAO,OAAO,QAAQ,WAAW,IAAI,CAAC;CACxC;CAEA,MAAM,OACJ,SAAS,WAAW,KAAA,IAChB,MAAM,SAAS,IAAI,IACnB,MAAM,GAAG,MAAM,SAAS,MAAM,EAAE,GAAG,MAAM,SAAS,IAAI;CAE5D,MAAM,UAAU,OAAO,QAAQ,SAAS,OAAO;CAE/C,MAAM,aAAa,QAAgB;EACjC,MAAM,SAAS,OAAO,OAAO,SAAS,SAAS,GAAG,IAAI,SAAS,QAAQ,OAAO,KAAA;EAE9E,IAAI,WAAW,KAAA,GACb,MAAM,wBAAwB,KAAK;GAAE,WAAW;GAAU,OAAO;EAAqB,CAAC;EAEzF,OAAO;CACT;CAEA,MAAM,SAAS,KAAa,UAAuC;EACjE,MAAM,SAAS,UAAU,GAAG;EAE5B,IAAIA,YAAU,WAAW,KAAK,GAAG,OAAO;EACxC,MAAM,UAAU,UAAU,OAAO,OAAO,OAAO,iBAAiB,KAAK;EAErE,OAAOA,YAAU,SAAS,CACxBA,YAAU,UACR,OAAO,YAAY,YACf,OAAO,gBAAgB;GAAE,cAAc,OAAO,OAAO;GAAG,cAAc;EAAQ,CAAC,IAC/E,OACN,CACF,CAAC;CACH;CAEA,MAAM,WAAW,WACf,OAAO,QAAQ,MAAM,CAAC,CAAC,QACpB,CAAC,KAAK,WAAW,OAAO,OAAO,SAAS,SAAS,GAAG,KAAK,UAAU,KAAA,CACtE;CAEF,MAAM,QAAQ,UAA6B;EACzC,MAAM,YAAY,UAAU,KAAA,IAAY,OAAO,MAAM,KAAK;EAC1D,MAAM,UAAU,QAAgB,MAAM,GAAG,UAAU,GAAG,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,IAAI;EAEvF,OAAO;GACL,MAAM,UAAU,KAAA,IAAY,OAAO,MAAM,GAAG,KAAK,MAAM;GACvD,IAAI;GACJ;GACA,sBAAsB,QACpB,UAAU,GAAG,CAAC,CAAC,QAAQ,SAAS,SAC5B;IACE,OAAO;KACL,MAAM,SAAS;KACf,GAAI,SAAS,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,SAAS,OAAO;IACrE;IACA,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ;GAC/B,IACA,KAAA;GACN;GACA,SAAS,WACP,OAAO,KACL,MACA,KACF,CAAC,CACC,QAAQ,KACL,CAAC,MAAM,UAAU,MAAM,GAAG,OAAO,GAAG,EAAE,MAAM,MAAM,eAAe,QAAQ,KAAK,CAAC,GAClF,CACF;GACF,SAAS,KAAK,WACZ,OAAO,YACL,QAAQ,KAAK,CAAC,KAAK,QAAQ,UAAU;IACnC,MAAM,QAAQ,eAAe,QAAQ,KAAK;IAE1C,IAAI,CAAC,OAAO,OAAO,KAAK,KAAK,GAC3B,MAAM,wBAAwB,KAAK;KACjC,WAAW;KACX,OAAO;IACT,CAAC;IAEH,OAAO,CAAC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC;GACvC,CAAC,CACH;GACF,SAAS,WAAW;IAClB,MAAM,SAAS,QAAQ,MAAM;IAE7B,IAAI,OAAO,WAAW,GAAG,OAAO,MAAM,eAAe,KAAK;IAE1D,OAAO,MAAM,eAAe,KAAK,IAAI,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,SAAS,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,YAAY,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,WAAW,MAAM,KAAK,KAAK,CAAC,CAAC,EAAE;GACjN;GACA,SAAS,WAAW;IAClB,MAAM,SAAS,QAAQ,MAAM;IAE7B,IAAI,OAAO,WAAW,GACpB,MAAM,wBAAwB,KAAK;KAAE,WAAW;KAAW,OAAO;IAAmB,CAAC;IAExF,OAAO,MAAM,UAAU,KAAK,OAAO,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,WAAW,MAAM,GAAG,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,IAAI,EAAE,KAAK,MAAM,KAAK,KAAK,GAAG,CAAC;GAChK;EACF;CACF;CAEA,OAAO,KAAK;AACd;;;AAIA,MAAa,uBACX,QACA,UAA0D,gBACtC;CACpB,MAAM,yBAAS,IAAI,QAA0B;CAE7C,QAAQ,UAAU;EAChB,MAAM,WAAW,OAAO,IAAI,KAAK;EAEjC,IAAI,aAAa,KAAA,GAAW,OAAO;EACnC,MAAM,SAAS,QAAQ,QAAQ,KAAK;EAEpC,OAAO,IAAI,OAAO,MAAM;EAExB,OAAO;CACT;AACF"}
@@ -0,0 +1,8 @@
1
+ import "../mapping-error.mjs";
2
+ import "./owner.mjs";
3
+ import "./query-compiler.mjs";
4
+ import "./flow.mjs";
5
+ import "./registration.mjs";
6
+ import { Context, Effect, Layer } from "effect";
7
+ import { SecurityRevision } from "@yielded/auth/Sessions";
8
+ import { OAuthAccountRevision, OAuthLinkAccess } from "@yielded/auth/OAuth";