@yielded/auth-persistence 0.1.0-beta.23 → 0.1.0-beta.25

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 +12 -6
  3. package/dist/Adapter.mjs +8 -3
  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/configuration.d.mts +1 -1
  11. package/dist/internal/configuration.mjs.map +1 -1
  12. package/dist/internal/email-kernel.d.mts +1 -1
  13. package/dist/internal/email-kernel.mjs +1 -1
  14. package/dist/internal/email-kernel.mjs.map +1 -1
  15. package/dist/internal/models/oauth-connected-model.d.mts +294 -0
  16. package/dist/internal/models/oauth-connected-model.mjs +22 -0
  17. package/dist/internal/models/oauth-connected-model.mjs.map +1 -0
  18. package/dist/internal/models/oauth-model.d.mts +467 -0
  19. package/dist/internal/models/oauth-model.mjs +49 -0
  20. package/dist/internal/models/oauth-model.mjs.map +1 -0
  21. package/dist/internal/models/password-model.d.mts +6 -48
  22. package/dist/internal/models/password-model.mjs +0 -1
  23. package/dist/internal/models/password-model.mjs.map +1 -1
  24. package/dist/internal/native-sql-table.d.mts +4 -0
  25. package/dist/internal/native-sql-table.mjs +7 -0
  26. package/dist/internal/native-sql-table.mjs.map +1 -1
  27. package/dist/internal/oauth/accounts.d.mts +8 -0
  28. package/dist/internal/oauth/accounts.mjs +379 -0
  29. package/dist/internal/oauth/accounts.mjs.map +1 -0
  30. package/dist/internal/oauth/connected-access.d.mts +9 -0
  31. package/dist/internal/oauth/connected-access.mjs +229 -0
  32. package/dist/internal/oauth/connected-access.mjs.map +1 -0
  33. package/dist/internal/oauth/connected-collection.d.mts +7 -0
  34. package/dist/internal/oauth/connected-collection.mjs +214 -0
  35. package/dist/internal/oauth/connected-collection.mjs.map +1 -0
  36. package/dist/internal/oauth/connected-custody.d.mts +6 -0
  37. package/dist/internal/oauth/connected-custody.mjs +165 -0
  38. package/dist/internal/oauth/connected-custody.mjs.map +1 -0
  39. package/dist/internal/oauth/connected-flow.d.mts +7 -0
  40. package/dist/internal/oauth/connected-flow.mjs +324 -0
  41. package/dist/internal/oauth/connected-flow.mjs.map +1 -0
  42. package/dist/internal/oauth/connected-input.mjs +122 -0
  43. package/dist/internal/oauth/connected-input.mjs.map +1 -0
  44. package/dist/internal/oauth/connected-keys.d.mts +2 -0
  45. package/dist/internal/oauth/connected-keys.mjs +22 -0
  46. package/dist/internal/oauth/connected-keys.mjs.map +1 -0
  47. package/dist/internal/oauth/connected-maintenance.d.mts +9 -0
  48. package/dist/internal/oauth/connected-maintenance.mjs +226 -0
  49. package/dist/internal/oauth/connected-maintenance.mjs.map +1 -0
  50. package/dist/internal/oauth/connected-management.d.mts +9 -0
  51. package/dist/internal/oauth/connected-management.mjs +243 -0
  52. package/dist/internal/oauth/connected-management.mjs.map +1 -0
  53. package/dist/internal/oauth/connected-reference.mjs +63 -0
  54. package/dist/internal/oauth/connected-reference.mjs.map +1 -0
  55. package/dist/internal/oauth/connected-settlement.d.mts +8 -0
  56. package/dist/internal/oauth/connected-settlement.mjs +141 -0
  57. package/dist/internal/oauth/connected-settlement.mjs.map +1 -0
  58. package/dist/internal/oauth/connected-sign-in.d.mts +10 -0
  59. package/dist/internal/oauth/connected-sign-in.mjs +281 -0
  60. package/dist/internal/oauth/connected-sign-in.mjs.map +1 -0
  61. package/dist/internal/oauth/connected-state.d.mts +14 -0
  62. package/dist/internal/oauth/connected-state.mjs +469 -0
  63. package/dist/internal/oauth/connected-state.mjs.map +1 -0
  64. package/dist/internal/oauth/connected-target.d.mts +21 -0
  65. package/dist/internal/oauth/connected-target.mjs +117 -0
  66. package/dist/internal/oauth/connected-target.mjs.map +1 -0
  67. package/dist/internal/oauth/flow.d.mts +5 -0
  68. package/dist/internal/oauth/flow.mjs +279 -0
  69. package/dist/internal/oauth/flow.mjs.map +1 -0
  70. package/dist/internal/oauth/input.mjs +127 -0
  71. package/dist/internal/oauth/input.mjs.map +1 -0
  72. package/dist/internal/oauth/owner.d.mts +10 -0
  73. package/dist/internal/oauth/owner.mjs +10 -0
  74. package/dist/internal/oauth/owner.mjs.map +1 -0
  75. package/dist/internal/oauth/query-compiler.d.mts +7 -0
  76. package/dist/internal/oauth/query-compiler.mjs +9 -0
  77. package/dist/internal/oauth/query-compiler.mjs.map +1 -0
  78. package/dist/internal/oauth/registration.d.mts +7 -0
  79. package/dist/internal/oauth/registration.mjs +393 -0
  80. package/dist/internal/oauth/registration.mjs.map +1 -0
  81. package/dist/internal/oauth/state.mjs +107 -0
  82. package/dist/internal/oauth/state.mjs.map +1 -0
  83. package/dist/internal/oauth/target.d.mts +31 -0
  84. package/dist/internal/oauth/target.mjs +273 -0
  85. package/dist/internal/oauth/target.mjs.map +1 -0
  86. package/dist/internal/oauth-kernel.d.mts +1423 -0
  87. package/dist/internal/oauth-kernel.mjs +187 -0
  88. package/dist/internal/oauth-kernel.mjs.map +1 -0
  89. package/dist/internal/oauth-proxy.d.mts +31 -0
  90. package/dist/internal/oauth-proxy.mjs +129 -0
  91. package/dist/internal/oauth-proxy.mjs.map +1 -0
  92. package/dist/internal/passkey/write-state.mjs +9 -1
  93. package/dist/internal/passkey/write-state.mjs.map +1 -1
  94. package/dist/internal/passkey-kernel.d.mts +9 -9
  95. package/dist/internal/{password-attempts.d.mts → password-credentials.d.mts} +3 -4
  96. package/dist/internal/password-credentials.mjs +121 -0
  97. package/dist/internal/password-credentials.mjs.map +1 -0
  98. package/dist/internal/password-kernel.d.mts +8 -24
  99. package/dist/internal/password-kernel.mjs +5 -43
  100. package/dist/internal/password-kernel.mjs.map +1 -1
  101. package/dist/internal/persistence.d.mts +1 -1
  102. package/dist/internal/persistence.mjs +2 -2
  103. package/dist/internal/persistence.mjs.map +1 -1
  104. package/dist/internal/query-operations.d.mts +2 -0
  105. package/dist/internal/session-kernel.d.mts +2 -2
  106. package/dist/internal/session-kernel.mjs +74 -18
  107. package/dist/internal/session-kernel.mjs.map +1 -1
  108. package/dist/internal/sql-oauth-connected-model.d.mts +29 -0
  109. package/dist/internal/sql-oauth-connected-model.mjs +7 -0
  110. package/dist/internal/sql-oauth-connected-model.mjs.map +1 -0
  111. package/dist/internal/sql-oauth-model.d.mts +60 -0
  112. package/dist/internal/sql-oauth-model.mjs +10 -0
  113. package/dist/internal/sql-oauth-model.mjs.map +1 -0
  114. package/dist/internal/sql-query.d.mts +12 -0
  115. package/dist/internal/sql-query.mjs +15 -18
  116. package/dist/internal/sql-query.mjs.map +1 -1
  117. package/dist/internal/sql-storage-validation.mjs +54 -0
  118. package/dist/internal/sql-storage-validation.mjs.map +1 -0
  119. package/dist/internal/storage-mapping.mjs +1 -37
  120. package/dist/internal/storage-mapping.mjs.map +1 -1
  121. package/dist/internal/storage-plans.d.mts +7 -0
  122. package/dist/internal/storage-plans.mjs +189 -0
  123. package/dist/internal/storage-plans.mjs.map +1 -0
  124. package/dist/internal/storage-tables.d.mts +0 -56
  125. package/dist/internal/storage-tables.mjs +0 -17
  126. package/dist/internal/storage-tables.mjs.map +1 -1
  127. package/dist/internal/storage-validation.d.mts +6 -1
  128. package/dist/internal/storage-validation.mjs +42 -1
  129. package/dist/internal/storage-validation.mjs.map +1 -1
  130. package/dist/internal/transaction-kernel.mjs +3 -2
  131. package/dist/internal/transaction-kernel.mjs.map +1 -1
  132. package/package.json +1 -1
  133. package/src/Adapter.ts +89 -5
  134. package/src/OAuthPersistence.ts +427 -0
  135. package/src/index.ts +3 -0
  136. package/src/internal/configuration.ts +1 -3
  137. package/src/internal/email-kernel.ts +2 -1
  138. package/src/internal/models/oauth-connected-model.ts +396 -0
  139. package/src/internal/models/oauth-model.ts +708 -0
  140. package/src/internal/models/password-model.ts +2 -57
  141. package/src/internal/native-sql-table.ts +14 -0
  142. package/src/internal/oauth/accounts.ts +839 -0
  143. package/src/internal/oauth/connected-access.ts +388 -0
  144. package/src/internal/oauth/connected-collection.ts +345 -0
  145. package/src/internal/oauth/connected-custody.ts +308 -0
  146. package/src/internal/oauth/connected-flow.ts +562 -0
  147. package/src/internal/oauth/connected-input.ts +147 -0
  148. package/src/internal/oauth/connected-keys.ts +31 -0
  149. package/src/internal/oauth/connected-maintenance.ts +379 -0
  150. package/src/internal/oauth/connected-management.ts +391 -0
  151. package/src/internal/oauth/connected-reference.ts +135 -0
  152. package/src/internal/oauth/connected-settlement.ts +278 -0
  153. package/src/internal/oauth/connected-sign-in.ts +472 -0
  154. package/src/internal/oauth/connected-state.ts +924 -0
  155. package/src/internal/oauth/connected-target.ts +307 -0
  156. package/src/internal/oauth/flow.ts +505 -0
  157. package/src/internal/oauth/input.ts +201 -0
  158. package/src/internal/oauth/owner.ts +22 -0
  159. package/src/internal/oauth/query-compiler.ts +15 -0
  160. package/src/internal/oauth/registration.ts +676 -0
  161. package/src/internal/oauth/state.ts +218 -0
  162. package/src/internal/oauth/target.ts +803 -0
  163. package/src/internal/oauth-kernel.ts +294 -0
  164. package/src/internal/oauth-proxy.ts +176 -0
  165. package/src/internal/passkey/write-state.ts +18 -4
  166. package/src/internal/password-credentials.ts +245 -0
  167. package/src/internal/password-kernel.ts +7 -99
  168. package/src/internal/persistence.ts +1 -1
  169. package/src/internal/query-operations.ts +2 -0
  170. package/src/internal/session-kernel.ts +143 -55
  171. package/src/internal/sql-oauth-connected-model.ts +145 -0
  172. package/src/internal/sql-oauth-model.ts +263 -0
  173. package/src/internal/sql-query.ts +16 -13
  174. package/src/internal/sql-storage-validation.ts +64 -0
  175. package/src/internal/storage-mapping.ts +0 -37
  176. package/src/internal/storage-plans.ts +218 -0
  177. package/src/internal/storage-tables.ts +0 -20
  178. package/src/internal/storage-validation.ts +58 -0
  179. package/src/internal/transaction-kernel.ts +6 -2
  180. package/dist/internal/password-attempts.mjs +0 -197
  181. package/dist/internal/password-attempts.mjs.map +0 -1
  182. package/src/internal/password-attempts.ts +0 -466
@@ -3,12 +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
10
  export interface PasswordSubjectTable<Subject extends TableModel, _NativeSubjectId> {
13
11
  readonly table: Subject["table"];
14
12
  readonly id: ColumnKey<Subject>;
@@ -84,43 +82,6 @@ export interface PasswordCredentialTable<Subject extends TableModel, Identifier
84
82
  readonly credential: Credential["select"];
85
83
  }) => Effect.Effect<PasswordCredentialSnapshot, PersistenceMappingError>;
86
84
  }
87
- export interface PasswordAttemptRecord {
88
- readonly moduleId: string;
89
- readonly action: PasswordAttemptAction;
90
- readonly attemptId: PasswordAttemptId;
91
- readonly identifier: LoginIdentifier;
92
- readonly subjectId?: string;
93
- readonly credentialId?: string;
94
- readonly securityRevision?: SecurityRevision;
95
- readonly credentialRevision?: SecurityRevision;
96
- readonly verifierVersion?: SecurityRevision;
97
- readonly identifierBindingRevision?: SecurityRevision;
98
- readonly admittedAtMillis: number;
99
- readonly deadlineMillis: number;
100
- readonly retentionUntilMillis: number;
101
- }
102
- export interface PasswordAttemptTable<Attempt extends TableModel, NativeSubjectId> {
103
- readonly table: Attempt["table"];
104
- readonly moduleId: ColumnKey<Attempt>;
105
- readonly action: ColumnKey<Attempt>;
106
- readonly attemptId: ColumnKey<Attempt>;
107
- readonly identifierNamespace: ColumnKey<Attempt>;
108
- readonly identifierValue: ColumnKey<Attempt>;
109
- readonly subjectId: ColumnKey<Attempt>;
110
- readonly credentialId: ColumnKey<Attempt>;
111
- readonly securityRevision: ColumnKey<Attempt>;
112
- readonly credentialRevision: ColumnKey<Attempt>;
113
- readonly verifierVersion: ColumnKey<Attempt>;
114
- readonly identifierBindingRevision: ColumnKey<Attempt>;
115
- readonly admittedAt: ColumnKey<Attempt>;
116
- readonly deadline: ColumnKey<Attempt>;
117
- readonly retentionUntil: ColumnKey<Attempt>;
118
- readonly state: ColumnKey<Attempt>;
119
- readonly encodeInsert: (record: PasswordAttemptRecord, input: {
120
- readonly nativeSubjectId?: NativeSubjectId;
121
- readonly state: "pending";
122
- }) => Attempt["insert"];
123
- }
124
85
  export interface PasswordCommandTable<Command extends TableModel> {
125
86
  readonly table: Command["table"];
126
87
  readonly moduleId: ColumnKey<Command>;
@@ -143,7 +104,6 @@ export interface RequiredPasswordConstraints {
143
104
  readonly authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)";
144
105
  readonly credentialSubject: "unique(credential.moduleId,credential.subjectId)";
145
106
  readonly credentialId: "unique(credential.moduleId,credential.credentialId)";
146
- readonly attempt: "unique(attempt.moduleId,attempt.attemptId)";
147
107
  readonly command: "unique(command.moduleId,command.commandId)";
148
108
  }
149
109
  export declare const requiredPasswordConstraints: RequiredPasswordConstraints;
@@ -157,30 +117,28 @@ export interface PasswordD1Clock<Expression extends SqlExpression = SqlExpressio
157
117
  readonly engineInstantMinus: (millis: number) => Expression;
158
118
  readonly engineInstantPlus: (millis: number) => Expression;
159
119
  }
160
- export interface PasswordPersistenceMapping<Subject extends TableModel, Identifier extends TableModel, Credential extends TableModel, AuthorityCredential extends TableModel, Attempt 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 {
161
121
  readonly subject: PasswordSubjectTable<Subject, NativeSubjectId>;
162
122
  readonly identifier: PasswordIdentifierTable<Identifier, NativeSubjectId, Expression>;
163
123
  readonly credential: PasswordCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;
164
124
  /** Every factor revision named by action evidence, including non-password factors. */
165
125
  readonly authorityCredential: PasswordAuthorityCredentialTable<AuthorityCredential, NativeSubjectId>;
166
- readonly attempt: PasswordAttemptTable<Attempt, NativeSubjectId>;
167
126
  readonly command: PasswordCommandTable<Command>;
168
127
  readonly subjectId: SubjectIdCodec<NativeSubjectId>;
169
128
  readonly constraints: RequiredPasswordConstraints;
170
129
  readonly encodeInstant: (epochMillis: number) => unknown;
171
130
  readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;
172
- readonly allocateAttemptId?: Effect.Effect<PasswordAttemptId, PersistenceMappingError>;
173
- readonly allocateAttemptIdSync?: () => PasswordAttemptId;
174
131
  readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;
175
132
  readonly allocateCredentialIdSync?: () => string;
176
133
  readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;
177
134
  readonly allocateRevisionSync?: () => SecurityRevision;
178
135
  readonly commandRetentionMillis: number;
179
- /** All semantic replacements still bump subject revision. This flag only declares bearer invalidation latency. */
136
+ /** All semantic replacements still bump subject revision. This flag declares
137
+ * authoritative verification's invalidation latency; cookie exposure is separate. */
180
138
  readonly sessionInvalidation: "same-authority-immediate" | "original-absolute-expiry";
181
139
  readonly d1?: PasswordD1Clock<Expression>;
182
140
  }
183
- export type D1PasswordPersistenceMapping<Subject extends TableModel, Identifier extends TableModel, Credential extends TableModel, AuthorityCredential extends TableModel, Attempt extends TableModel, Command extends TableModel, NativeSubjectId, Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<Subject, Identifier, Credential, AuthorityCredential, Attempt, Command, NativeSubjectId, Expression> & {
141
+ 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> & {
184
142
  readonly d1: PasswordD1Clock<Expression>;
185
143
  readonly subject: PasswordSubjectTable<Subject, NativeSubjectId> & {
186
144
  readonly d1ActiveStatusValue: unknown;
@@ -272,7 +230,7 @@ export type PasswordRegistrationMapping<Registration, Subject extends TableModel
272
230
  readonly allocateRecoveryReference?: Effect.Effect<typeof RecoveryReference.Type, PersistenceMappingError>;
273
231
  readonly allocateRecoveryReferenceSync?: () => typeof RecoveryReference.Type;
274
232
  });
275
- export type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, unknown, Expression>;
233
+ export type AnyPasswordPersistenceMapping<Expression extends SqlExpression = SqlExpression> = PasswordPersistenceMapping<AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, unknown, Expression>;
276
234
  export type AnyPasswordRegistrationMapping<Registration = unknown, Expression extends SqlExpression = SqlExpression> = PasswordRegistrationMapping<Registration, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, AnyTableModel, unknown, Expression>;
277
235
  //#endregion
278
236
  //# sourceMappingURL=password-model.d.mts.map
@@ -5,7 +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
8
  command: "unique(command.moduleId,command.commandId)"
10
9
  };
11
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 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 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 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 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 Attempt 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 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 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 Command extends Table,\n NativeSubjectId,\n Expression extends SqlExpression = SqlExpression,\n> = PasswordPersistenceMapping<\n Subject,\n Identifier,\n Credential,\n AuthorityCredential,\n Attempt,\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 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":";;AAgMA,MAAa,8BAA2D;CACtE,YAAY;CACZ,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;CACd,SAAS;CACT,SAAS;AACX;AAwJA,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 declares\n * authoritative verification's invalidation latency; cookie exposure is separate. */\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;AAmJA,MAAa,0CAAmF;CAC9F,SAAS;CACT,mBAAmB;CACnB,YAAY;CACZ,mBAAmB;CACnB,qBAAqB;AACvB"}
@@ -1,4 +1,5 @@
1
1
  import "./mapping-error.mjs";
2
+ import { PhysicalTextColumn } from "./storage-validation.mjs";
2
3
  import { Effect } from "effect";
3
4
  import * as Statement$1 from "effect/sql/Statement";
4
5
  import { SqlClient } from "effect/sql/SqlClient";
@@ -10,6 +11,9 @@ export interface SqlTable {
10
11
  /** Alias reads only; writes continue to target the original physical table. */
11
12
  readonly as: (alias: string) => SqlTable;
12
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;
13
17
  /** Project every column under an ordinal alias, using a distinct prefix per table. */
14
18
  readonly fields: (prefix: string) => Statement$1.Fragment;
15
19
  readonly decode: (row: Readonly<Record<string, unknown>>, prefix: string) => Record<string, unknown>;
@@ -59,6 +59,13 @@ const directTable = (client, physical) => {
59
59
  name: alias === void 0 ? name : client`${name} AS ${reference}`,
60
60
  as: bind,
61
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,
62
69
  value,
63
70
  fields: (prefix) => client.join(", ", false)(columns.map(([key], index) => client`${column(key)} AS ${quote(nativeSqlAlias(prefix, index))}`)),
64
71
  decode: (row, prefix) => Object.fromEntries(columns.map(([key, field], index) => {
@@ -1 +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\";\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 /** 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 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":"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"}
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":"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"}
@@ -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";