@yielded/auth-persistence 0.1.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/Adapter.d.mts +30 -0
- package/dist/Adapter.mjs +25 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +7 -0
- package/dist/internal/PasswordPreparedPostconditions.d.mts +22 -0
- package/dist/internal/PasswordPreparedPostconditions.mjs +12 -0
- package/dist/internal/PasswordPreparedPostconditions.mjs.map +1 -0
- package/dist/internal/configuration.d.mts +174 -0
- package/dist/internal/configuration.mjs +7 -0
- package/dist/internal/configuration.mjs.map +1 -0
- package/dist/internal/email-kernel.d.mts +275 -0
- package/dist/internal/email-kernel.mjs +487 -0
- package/dist/internal/email-kernel.mjs.map +1 -0
- package/dist/internal/mapping-error.d.mts +10 -0
- package/dist/internal/mapping-error.mjs +30 -0
- package/dist/internal/mapping-error.mjs.map +1 -0
- package/dist/internal/models/common.d.mts +12 -0
- package/dist/internal/models/email-model.d.mts +353 -0
- package/dist/internal/models/email-model.mjs +21 -0
- package/dist/internal/models/email-model.mjs.map +1 -0
- package/dist/internal/models/passkey-model.d.mts +266 -0
- package/dist/internal/models/passkey-model.mjs +34 -0
- package/dist/internal/models/passkey-model.mjs.map +1 -0
- package/dist/internal/models/passkey-registration-ceremony-model.d.mts +49 -0
- package/dist/internal/models/passkey-registration-ceremony-model.mjs +18 -0
- package/dist/internal/models/passkey-registration-ceremony-model.mjs.map +1 -0
- package/dist/internal/models/passkey-write-model.d.mts +189 -0
- package/dist/internal/models/passkey-write-model.mjs +13 -0
- package/dist/internal/models/passkey-write-model.mjs.map +1 -0
- package/dist/internal/models/password-model.d.mts +328 -0
- package/dist/internal/models/password-model.mjs +23 -0
- package/dist/internal/models/password-model.mjs.map +1 -0
- package/dist/internal/models/proof-model.d.mts +285 -0
- package/dist/internal/models/proof-model.mjs +17 -0
- package/dist/internal/models/proof-model.mjs.map +1 -0
- package/dist/internal/models/session-model.d.mts +199 -0
- package/dist/internal/models/session-model.mjs +20 -0
- package/dist/internal/models/session-model.mjs.map +1 -0
- package/dist/internal/models/step-up-model.d.mts +66 -0
- package/dist/internal/models/step-up-model.mjs +9 -0
- package/dist/internal/models/step-up-model.mjs.map +1 -0
- package/dist/internal/oauth-app.d.mts +11 -0
- package/dist/internal/oauth-app.mjs +57 -0
- package/dist/internal/oauth-app.mjs.map +1 -0
- package/dist/internal/oauth-server.d.mts +10 -0
- package/dist/internal/oauth-server.mjs +66 -0
- package/dist/internal/oauth-server.mjs.map +1 -0
- package/dist/internal/passkey/admission.d.mts +6 -0
- package/dist/internal/passkey/admission.mjs +216 -0
- package/dist/internal/passkey/admission.mjs.map +1 -0
- package/dist/internal/passkey/credentials.d.mts +14 -0
- package/dist/internal/passkey/credentials.mjs +249 -0
- package/dist/internal/passkey/credentials.mjs.map +1 -0
- package/dist/internal/passkey/enrollment.mjs +138 -0
- package/dist/internal/passkey/enrollment.mjs.map +1 -0
- package/dist/internal/passkey/flow.d.mts +21 -0
- package/dist/internal/passkey/flow.mjs +452 -0
- package/dist/internal/passkey/flow.mjs.map +1 -0
- package/dist/internal/passkey/management.mjs +231 -0
- package/dist/internal/passkey/management.mjs.map +1 -0
- package/dist/internal/passkey/registration-ceremony.d.mts +9 -0
- package/dist/internal/passkey/registration-ceremony.mjs +129 -0
- package/dist/internal/passkey/registration-ceremony.mjs.map +1 -0
- package/dist/internal/passkey/registration-custody.d.mts +2 -0
- package/dist/internal/passkey/registration-custody.mjs +52 -0
- package/dist/internal/passkey/registration-custody.mjs.map +1 -0
- package/dist/internal/passkey/registration-write.mjs +211 -0
- package/dist/internal/passkey/registration-write.mjs.map +1 -0
- package/dist/internal/passkey/state.d.mts +10 -0
- package/dist/internal/passkey/state.mjs +234 -0
- package/dist/internal/passkey/state.mjs.map +1 -0
- package/dist/internal/passkey/target.d.mts +19 -0
- package/dist/internal/passkey/target.mjs +190 -0
- package/dist/internal/passkey/target.mjs.map +1 -0
- package/dist/internal/passkey/write-state.d.mts +17 -0
- package/dist/internal/passkey/write-state.mjs +345 -0
- package/dist/internal/passkey/write-state.mjs.map +1 -0
- package/dist/internal/passkey/write-target.mjs +192 -0
- package/dist/internal/passkey/write-target.mjs.map +1 -0
- package/dist/internal/passkey-kernel.d.mts +5592 -0
- package/dist/internal/passkey-kernel.mjs +49 -0
- package/dist/internal/passkey-kernel.mjs.map +1 -0
- package/dist/internal/passkeys.d.mts +7 -0
- package/dist/internal/passkeys.mjs +368 -0
- package/dist/internal/passkeys.mjs.map +1 -0
- package/dist/internal/password-kernel.d.mts +290 -0
- package/dist/internal/password-kernel.mjs +704 -0
- package/dist/internal/password-kernel.mjs.map +1 -0
- package/dist/internal/persistence.d.mts +25 -0
- package/dist/internal/persistence.mjs +291 -0
- package/dist/internal/persistence.mjs.map +1 -0
- package/dist/internal/phone-kernel.d.mts +162 -0
- package/dist/internal/phone-kernel.mjs +434 -0
- package/dist/internal/phone-kernel.mjs.map +1 -0
- package/dist/internal/proof-kernel.d.mts +93 -0
- package/dist/internal/proof-kernel.mjs +619 -0
- package/dist/internal/proof-kernel.mjs.map +1 -0
- package/dist/internal/query-operations.d.mts +61 -0
- package/dist/internal/registration-contract.d.mts +16 -0
- package/dist/internal/registration.mjs +66 -0
- package/dist/internal/registration.mjs.map +1 -0
- package/dist/internal/session-kernel.d.mts +48 -0
- package/dist/internal/session-kernel.mjs +737 -0
- package/dist/internal/session-kernel.mjs.map +1 -0
- package/dist/internal/sql-persistence.d.mts +10 -0
- package/dist/internal/sql-persistence.mjs +37 -0
- package/dist/internal/sql-persistence.mjs.map +1 -0
- package/dist/internal/sql-query.mjs +207 -0
- package/dist/internal/sql-query.mjs.map +1 -0
- package/dist/internal/sql-table.d.mts +36 -0
- package/dist/internal/sql-table.mjs +81 -0
- package/dist/internal/sql-table.mjs.map +1 -0
- package/dist/internal/standalone.d.mts +9 -0
- package/dist/internal/standalone.mjs +13 -0
- package/dist/internal/standalone.mjs.map +1 -0
- package/dist/internal/step-up-state.d.mts +49 -0
- package/dist/internal/step-up-state.mjs +32 -0
- package/dist/internal/step-up-state.mjs.map +1 -0
- package/dist/internal/storage-mapping.mjs +686 -0
- package/dist/internal/storage-mapping.mjs.map +1 -0
- package/dist/internal/storage-tables.d.mts +913 -0
- package/dist/internal/storage-tables.mjs +387 -0
- package/dist/internal/storage-tables.mjs.map +1 -0
- package/dist/internal/storage-validation.mjs +58 -0
- package/dist/internal/storage-validation.mjs.map +1 -0
- package/dist/internal/transaction-execution-kernel.d.mts +38 -0
- package/dist/internal/transaction-execution-kernel.mjs +116 -0
- package/dist/internal/transaction-execution-kernel.mjs.map +1 -0
- package/dist/internal/transaction-kernel.d.mts +77 -0
- package/dist/internal/transaction-kernel.mjs +260 -0
- package/dist/internal/transaction-kernel.mjs.map +1 -0
- package/package.json +1 -0
- package/src/Adapter.ts +291 -0
- package/src/index.ts +6 -0
- package/src/internal/PasswordPreparedPostconditions.ts +30 -0
- package/src/internal/configuration.ts +282 -0
- package/src/internal/email-kernel.ts +1535 -0
- package/src/internal/mapping-error.ts +36 -0
- package/src/internal/models/common.ts +11 -0
- package/src/internal/models/email-model.ts +559 -0
- package/src/internal/models/passkey-model.ts +390 -0
- package/src/internal/models/passkey-registration-ceremony-model.ts +72 -0
- package/src/internal/models/passkey-write-model.ts +297 -0
- package/src/internal/models/password-model.ts +513 -0
- package/src/internal/models/proof-model.ts +424 -0
- package/src/internal/models/session-model.ts +375 -0
- package/src/internal/models/step-up-model.ts +135 -0
- package/src/internal/oauth-app.ts +82 -0
- package/src/internal/oauth-server.ts +89 -0
- package/src/internal/passkey/admission.ts +361 -0
- package/src/internal/passkey/credentials.ts +511 -0
- package/src/internal/passkey/enrollment.ts +326 -0
- package/src/internal/passkey/flow.ts +1062 -0
- package/src/internal/passkey/management.ts +421 -0
- package/src/internal/passkey/registration-ceremony.ts +283 -0
- package/src/internal/passkey/registration-custody.ts +91 -0
- package/src/internal/passkey/registration-write.ts +426 -0
- package/src/internal/passkey/state.ts +353 -0
- package/src/internal/passkey/target.ts +586 -0
- package/src/internal/passkey/write-state.ts +681 -0
- package/src/internal/passkey/write-target.ts +452 -0
- package/src/internal/passkey-kernel.ts +104 -0
- package/src/internal/passkeys.ts +606 -0
- package/src/internal/password-kernel.ts +2124 -0
- package/src/internal/persistence.ts +588 -0
- package/src/internal/phone-kernel.ts +846 -0
- package/src/internal/proof-kernel.ts +1954 -0
- package/src/internal/query-operations.ts +81 -0
- package/src/internal/registration-contract.ts +22 -0
- package/src/internal/registration.ts +161 -0
- package/src/internal/session-kernel.ts +2217 -0
- package/src/internal/sql-persistence.ts +45 -0
- package/src/internal/sql-query.ts +298 -0
- package/src/internal/sql-table.ts +104 -0
- package/src/internal/standalone.ts +30 -0
- package/src/internal/step-up-state.ts +139 -0
- package/src/internal/storage-mapping.ts +708 -0
- package/src/internal/storage-tables.ts +408 -0
- package/src/internal/storage-validation.ts +117 -0
- package/src/internal/transaction-execution-kernel.ts +313 -0
- package/src/internal/transaction-kernel.ts +593 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Cause, Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
export class PersistenceMappingError extends Schema.TaggedError<PersistenceMappingError>()(
|
|
4
|
+
"PersistenceMappingError",
|
|
5
|
+
{ operation: Schema.NonEmptyString, cause: Schema.Defect() },
|
|
6
|
+
) {}
|
|
7
|
+
|
|
8
|
+
export const isMappedConstraintConflict = (
|
|
9
|
+
classify: (cause: unknown) => boolean,
|
|
10
|
+
failure: unknown,
|
|
11
|
+
): boolean => {
|
|
12
|
+
const seen = new Set<unknown>();
|
|
13
|
+
const pending: Array<unknown> = [failure];
|
|
14
|
+
|
|
15
|
+
for (let inspected = 0; inspected < 24 && pending.length > 0; inspected++) {
|
|
16
|
+
const current = pending.shift();
|
|
17
|
+
|
|
18
|
+
if (current === undefined || current === null || seen.has(current)) continue;
|
|
19
|
+
seen.add(current);
|
|
20
|
+
if (classify(current)) return true;
|
|
21
|
+
if (Cause.isCause(current)) {
|
|
22
|
+
for (const reason of current.reasons) {
|
|
23
|
+
if (Cause.isFailReason(reason)) pending.push(reason.error);
|
|
24
|
+
else if (Cause.isDieReason(reason)) pending.push(reason.defect);
|
|
25
|
+
}
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (typeof current !== "object") continue;
|
|
29
|
+
const wrapped = current as { readonly cause?: unknown; readonly reason?: unknown };
|
|
30
|
+
|
|
31
|
+
if (wrapped.cause !== undefined) pending.push(wrapped.cause);
|
|
32
|
+
if (wrapped.reason !== undefined) pending.push(wrapped.reason);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return false;
|
|
36
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SubjectId } from "@yielded/auth/Schema";
|
|
2
|
+
import type { Effect } from "effect";
|
|
3
|
+
|
|
4
|
+
import type { PersistenceMappingError } from "../mapping-error";
|
|
5
|
+
export type { PersistenceMappingError } from "../mapping-error";
|
|
6
|
+
|
|
7
|
+
export interface SubjectIdCodec<NativeId> {
|
|
8
|
+
readonly toNative: (id: SubjectId) => Effect.Effect<NativeId, PersistenceMappingError>;
|
|
9
|
+
readonly toSubject: (id: NativeId) => Effect.Effect<SubjectId, PersistenceMappingError>;
|
|
10
|
+
readonly equals: (left: NativeId, right: NativeId) => boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
import type { EmailAction, EmailRegistrationDecision } from "@yielded/auth/Email";
|
|
2
|
+
import type { LoginIdentifier } from "@yielded/auth/Identity";
|
|
3
|
+
import type { ProofBinding, ProofContinuationId, ProofPurpose } from "@yielded/auth/Proofs";
|
|
4
|
+
import type { TokenDigest } from "@yielded/auth/Schema";
|
|
5
|
+
import type { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
6
|
+
import type { Effect } from "effect";
|
|
7
|
+
|
|
8
|
+
import type { AnyTableModel, TableModel as Table, SqlExpression } from "../query-operations";
|
|
9
|
+
import type { PersistenceMappingError, SubjectIdCodec } from "./common";
|
|
10
|
+
|
|
11
|
+
type ColumnKey<T extends Table> = T["column"];
|
|
12
|
+
|
|
13
|
+
export interface EmailSubjectReadTable<Subject extends Table> {
|
|
14
|
+
readonly table: Subject["table"];
|
|
15
|
+
readonly id: ColumnKey<Subject>;
|
|
16
|
+
readonly status: ColumnKey<Subject>;
|
|
17
|
+
readonly securityRevision: ColumnKey<Subject>;
|
|
18
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
19
|
+
readonly d1ActiveStatusValue?: unknown;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface EmailSubjectTable<Subject extends Table> extends EmailSubjectReadTable<Subject> {
|
|
23
|
+
readonly decodeActionRequirement: (
|
|
24
|
+
row: Subject["select"],
|
|
25
|
+
action: EmailAction,
|
|
26
|
+
) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;
|
|
27
|
+
readonly nextSecurityRevision?: (
|
|
28
|
+
current: SecurityRevision,
|
|
29
|
+
) => Effect.Effect<SecurityRevision, PersistenceMappingError>;
|
|
30
|
+
readonly nextSecurityRevisionSync?: (current: SecurityRevision) => SecurityRevision;
|
|
31
|
+
readonly d1ActiveStatusValue?: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface EmailIdentifierReadTable<Identifier extends Table> {
|
|
35
|
+
readonly table: Identifier["table"];
|
|
36
|
+
readonly namespace: ColumnKey<Identifier>;
|
|
37
|
+
readonly value: ColumnKey<Identifier>;
|
|
38
|
+
readonly subjectId: ColumnKey<Identifier>;
|
|
39
|
+
readonly verifiedAt: ColumnKey<Identifier>;
|
|
40
|
+
readonly bindingRevision: ColumnKey<Identifier>;
|
|
41
|
+
readonly isCurrent: (row: Identifier["select"]) => boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface EmailIdentifierTable<
|
|
45
|
+
Identifier extends Table,
|
|
46
|
+
NativeSubjectId,
|
|
47
|
+
Expression extends SqlExpression = SqlExpression,
|
|
48
|
+
> extends EmailIdentifierReadTable<Identifier> {
|
|
49
|
+
/** True only for an active, unverified binding. Confirming it preserves existing sessions. */
|
|
50
|
+
readonly isMutableTarget: (row: Identifier["select"]) => boolean;
|
|
51
|
+
readonly encodeVerifiedInsert: (input: {
|
|
52
|
+
readonly identifier: LoginIdentifier;
|
|
53
|
+
readonly subjectId: NativeSubjectId;
|
|
54
|
+
readonly verifiedAtMillis: number;
|
|
55
|
+
readonly bindingRevision: SecurityRevision;
|
|
56
|
+
}) => Identifier["insert"];
|
|
57
|
+
readonly encodeVerification: (input: {
|
|
58
|
+
readonly verifiedAtMillis: number;
|
|
59
|
+
readonly bindingRevision: SecurityRevision;
|
|
60
|
+
}) => Partial<Identifier["insert"]>;
|
|
61
|
+
/** Must make the selected source unavailable to sign-in. */
|
|
62
|
+
readonly encodeRetirement: (input: {
|
|
63
|
+
readonly source: LoginIdentifier;
|
|
64
|
+
readonly bindingRevision: SecurityRevision;
|
|
65
|
+
}) => Partial<Identifier["insert"]>;
|
|
66
|
+
readonly d1CurrentCondition?: (input: {
|
|
67
|
+
readonly identifier: LoginIdentifier;
|
|
68
|
+
readonly nativeSubjectId: NativeSubjectId;
|
|
69
|
+
readonly bindingRevision: SecurityRevision;
|
|
70
|
+
}) => Expression;
|
|
71
|
+
readonly d1MutableTargetCondition?: (input: {
|
|
72
|
+
readonly identifier: LoginIdentifier;
|
|
73
|
+
readonly nativeSubjectId: NativeSubjectId;
|
|
74
|
+
}) => Expression;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface EmailCredentialReadTable<
|
|
78
|
+
Subject extends Table,
|
|
79
|
+
Identifier extends Table,
|
|
80
|
+
Credential extends Table,
|
|
81
|
+
_NativeSubjectId,
|
|
82
|
+
> {
|
|
83
|
+
readonly table: Credential["table"];
|
|
84
|
+
readonly moduleId: ColumnKey<Credential>;
|
|
85
|
+
readonly subjectId: ColumnKey<Credential>;
|
|
86
|
+
readonly credentialId: ColumnKey<Credential>;
|
|
87
|
+
readonly identifierNamespace: ColumnKey<Credential>;
|
|
88
|
+
readonly identifierValue: ColumnKey<Credential>;
|
|
89
|
+
readonly credentialRevision: ColumnKey<Credential>;
|
|
90
|
+
readonly status: ColumnKey<Credential>;
|
|
91
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
92
|
+
readonly decode: (input: {
|
|
93
|
+
readonly moduleId: string;
|
|
94
|
+
readonly subject: Subject["select"];
|
|
95
|
+
readonly identifier: Identifier["select"];
|
|
96
|
+
readonly credential: Credential["select"];
|
|
97
|
+
}) => Effect.Effect<
|
|
98
|
+
import("@yielded/auth/Email").EmailCredentialSnapshot,
|
|
99
|
+
PersistenceMappingError
|
|
100
|
+
>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface EmailCredentialTable<
|
|
104
|
+
Subject extends Table,
|
|
105
|
+
Identifier extends Table,
|
|
106
|
+
Credential extends Table,
|
|
107
|
+
NativeSubjectId,
|
|
108
|
+
> extends EmailCredentialReadTable<Subject, Identifier, Credential, NativeSubjectId> {
|
|
109
|
+
readonly encodeVerifiedInsert: (input: {
|
|
110
|
+
readonly moduleId: string;
|
|
111
|
+
readonly subjectId: NativeSubjectId;
|
|
112
|
+
readonly credentialId: string;
|
|
113
|
+
readonly identifier: LoginIdentifier;
|
|
114
|
+
readonly credentialRevision: SecurityRevision;
|
|
115
|
+
}) => Credential["insert"];
|
|
116
|
+
readonly encodeActivation: (input: {
|
|
117
|
+
readonly identifier: LoginIdentifier;
|
|
118
|
+
readonly credentialRevision: SecurityRevision;
|
|
119
|
+
}) => Partial<Credential["insert"]>;
|
|
120
|
+
readonly encodeRetirement: (input: {
|
|
121
|
+
readonly source: LoginIdentifier;
|
|
122
|
+
readonly credentialRevision: SecurityRevision;
|
|
123
|
+
}) => Partial<Credential["insert"]>;
|
|
124
|
+
readonly d1ActiveStatusValue?: unknown;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface EmailAuthorityCredentialTable<Credential extends Table, NativeSubjectId> {
|
|
128
|
+
readonly table: Credential["table"];
|
|
129
|
+
readonly subjectId: ColumnKey<Credential>;
|
|
130
|
+
readonly credentialId: ColumnKey<Credential>;
|
|
131
|
+
readonly revision: ColumnKey<Credential>;
|
|
132
|
+
readonly status: ColumnKey<Credential>;
|
|
133
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
134
|
+
readonly encodeInsert: (input: {
|
|
135
|
+
readonly subjectId: NativeSubjectId;
|
|
136
|
+
readonly credentialId: string;
|
|
137
|
+
readonly revision: SecurityRevision;
|
|
138
|
+
}) => Credential["insert"];
|
|
139
|
+
readonly encodeActivation: (revision: SecurityRevision) => Partial<Credential["insert"]>;
|
|
140
|
+
readonly encodeRetirement: (revision: SecurityRevision) => Partial<Credential["insert"]>;
|
|
141
|
+
readonly d1ActiveStatusValue?: unknown;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface EmailCommandTable<Command extends Table> {
|
|
145
|
+
readonly table: Command["table"];
|
|
146
|
+
readonly moduleId: ColumnKey<Command>;
|
|
147
|
+
readonly commandId: ColumnKey<Command>;
|
|
148
|
+
readonly action: ColumnKey<Command>;
|
|
149
|
+
readonly bindingDigest: ColumnKey<Command>;
|
|
150
|
+
readonly retentionUntil: ColumnKey<Command>;
|
|
151
|
+
readonly encodeInsert: (input: {
|
|
152
|
+
readonly moduleId: string;
|
|
153
|
+
readonly commandId: string;
|
|
154
|
+
readonly action: EmailAction;
|
|
155
|
+
readonly bindingDigest: TokenDigest;
|
|
156
|
+
readonly retentionUntilMillis: number;
|
|
157
|
+
}) => Command["insert"];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface RequiredEmailSignInConstraints {
|
|
161
|
+
readonly identifier: "unique(identifier.namespace,identifier.value)";
|
|
162
|
+
readonly credentialId: "unique(emailCredential.moduleId,emailCredential.credentialId)";
|
|
163
|
+
readonly credentialIdentifier: "unique(emailCredential.moduleId,emailCredential.identifierNamespace,emailCredential.identifierValue)";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export const requiredEmailSignInConstraints: RequiredEmailSignInConstraints = {
|
|
167
|
+
identifier: "unique(identifier.namespace,identifier.value)",
|
|
168
|
+
credentialId: "unique(emailCredential.moduleId,emailCredential.credentialId)",
|
|
169
|
+
credentialIdentifier:
|
|
170
|
+
"unique(emailCredential.moduleId,emailCredential.identifierNamespace,emailCredential.identifierValue)",
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export interface EmailSignInMapping<
|
|
174
|
+
Subject extends Table,
|
|
175
|
+
Identifier extends Table,
|
|
176
|
+
Credential extends Table,
|
|
177
|
+
NativeSubjectId,
|
|
178
|
+
> {
|
|
179
|
+
readonly subject: EmailSubjectReadTable<Subject>;
|
|
180
|
+
readonly identifier: EmailIdentifierReadTable<Identifier>;
|
|
181
|
+
readonly credential: EmailCredentialReadTable<Subject, Identifier, Credential, NativeSubjectId>;
|
|
182
|
+
readonly subjectId: SubjectIdCodec<NativeSubjectId>;
|
|
183
|
+
readonly constraints: RequiredEmailSignInConstraints;
|
|
184
|
+
readonly decodeInstant: (native: unknown) => Effect.Effect<number, PersistenceMappingError>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface RequiredEmailAddressConstraints extends RequiredEmailSignInConstraints {
|
|
188
|
+
readonly authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)";
|
|
189
|
+
readonly command: "unique(emailCommand.moduleId,emailCommand.commandId)";
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const requiredEmailAddressConstraints: RequiredEmailAddressConstraints = {
|
|
193
|
+
...requiredEmailSignInConstraints,
|
|
194
|
+
authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)",
|
|
195
|
+
command: "unique(emailCommand.moduleId,emailCommand.commandId)",
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export interface EmailD1Clock<Expression extends SqlExpression = SqlExpression> {
|
|
199
|
+
readonly engineNow: Expression;
|
|
200
|
+
readonly engineNowMillis: Expression;
|
|
201
|
+
readonly engineInstantPlus: (millis: number) => Expression;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface EmailAddressMapping<
|
|
205
|
+
Subject extends Table,
|
|
206
|
+
Identifier extends Table,
|
|
207
|
+
Credential extends Table,
|
|
208
|
+
AuthorityCredential extends Table,
|
|
209
|
+
Command extends Table,
|
|
210
|
+
NativeSubjectId,
|
|
211
|
+
Expression extends SqlExpression = SqlExpression,
|
|
212
|
+
> extends EmailSignInMapping<Subject, Identifier, Credential, NativeSubjectId> {
|
|
213
|
+
readonly subject: EmailSubjectTable<Subject>;
|
|
214
|
+
readonly identifier: EmailIdentifierTable<Identifier, NativeSubjectId, Expression>;
|
|
215
|
+
readonly credential: EmailCredentialTable<Subject, Identifier, Credential, NativeSubjectId>;
|
|
216
|
+
readonly authorityCredential: EmailAuthorityCredentialTable<AuthorityCredential, NativeSubjectId>;
|
|
217
|
+
readonly command: EmailCommandTable<Command>;
|
|
218
|
+
readonly constraints: RequiredEmailAddressConstraints;
|
|
219
|
+
readonly addressCardinality: "single" | "multiple";
|
|
220
|
+
readonly changeDisposition: "retire-source";
|
|
221
|
+
readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;
|
|
222
|
+
readonly allocateCredentialIdSync?: () => string;
|
|
223
|
+
readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;
|
|
224
|
+
readonly allocateRevisionSync?: () => SecurityRevision;
|
|
225
|
+
readonly encodeInstant: (epochMillis: number) => unknown;
|
|
226
|
+
readonly commandRetentionMillis: number;
|
|
227
|
+
readonly sessionInvalidation: "same-authority-immediate" | "original-absolute-expiry";
|
|
228
|
+
readonly isCommandConflict: (cause: unknown) => boolean;
|
|
229
|
+
readonly isIdentifierConflict: (cause: unknown) => boolean;
|
|
230
|
+
readonly isCredentialConflict: (cause: unknown) => boolean;
|
|
231
|
+
readonly d1?: EmailD1Clock<Expression>;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export type D1EmailAddressMapping<
|
|
235
|
+
Subject extends Table,
|
|
236
|
+
Identifier extends Table,
|
|
237
|
+
Credential extends Table,
|
|
238
|
+
AuthorityCredential extends Table,
|
|
239
|
+
Command extends Table,
|
|
240
|
+
NativeSubjectId,
|
|
241
|
+
Expression extends SqlExpression = SqlExpression,
|
|
242
|
+
> = EmailAddressMapping<
|
|
243
|
+
Subject,
|
|
244
|
+
Identifier,
|
|
245
|
+
Credential,
|
|
246
|
+
AuthorityCredential,
|
|
247
|
+
Command,
|
|
248
|
+
NativeSubjectId,
|
|
249
|
+
Expression
|
|
250
|
+
> & {
|
|
251
|
+
readonly d1: EmailD1Clock<Expression>;
|
|
252
|
+
readonly subject: EmailSubjectTable<Subject> & {
|
|
253
|
+
readonly d1ActiveStatusValue: unknown;
|
|
254
|
+
};
|
|
255
|
+
readonly identifier: EmailIdentifierTable<Identifier, NativeSubjectId, Expression> & {
|
|
256
|
+
readonly d1CurrentCondition: NonNullable<
|
|
257
|
+
EmailIdentifierTable<Identifier, NativeSubjectId, Expression>["d1CurrentCondition"]
|
|
258
|
+
>;
|
|
259
|
+
readonly d1MutableTargetCondition: NonNullable<
|
|
260
|
+
EmailIdentifierTable<Identifier, NativeSubjectId, Expression>["d1MutableTargetCondition"]
|
|
261
|
+
>;
|
|
262
|
+
};
|
|
263
|
+
readonly credential: EmailCredentialTable<Subject, Identifier, Credential, NativeSubjectId> & {
|
|
264
|
+
readonly d1ActiveStatusValue: unknown;
|
|
265
|
+
};
|
|
266
|
+
readonly authorityCredential: EmailAuthorityCredentialTable<
|
|
267
|
+
AuthorityCredential,
|
|
268
|
+
NativeSubjectId
|
|
269
|
+
> & {
|
|
270
|
+
readonly d1ActiveStatusValue: unknown;
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
export type EmailRegistrationState = "pending" | "registered";
|
|
275
|
+
|
|
276
|
+
export interface EmailRegistrationIntent<Registration> {
|
|
277
|
+
readonly moduleId: string;
|
|
278
|
+
readonly commandId: string;
|
|
279
|
+
readonly identifier: LoginIdentifier;
|
|
280
|
+
readonly registration: Registration;
|
|
281
|
+
readonly fingerprint: TokenDigest;
|
|
282
|
+
readonly completion: {
|
|
283
|
+
readonly moduleId: string;
|
|
284
|
+
readonly purpose: ProofPurpose;
|
|
285
|
+
readonly continuationId: ProofContinuationId;
|
|
286
|
+
readonly binding: ProofBinding;
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface EmailRegistrationTable<Registration, Request extends Table, NativeSubjectId> {
|
|
291
|
+
readonly table: Request["table"];
|
|
292
|
+
readonly moduleId: ColumnKey<Request>;
|
|
293
|
+
readonly commandId: ColumnKey<Request>;
|
|
294
|
+
readonly fingerprint: ColumnKey<Request>;
|
|
295
|
+
readonly state: ColumnKey<Request>;
|
|
296
|
+
readonly subjectId: ColumnKey<Request>;
|
|
297
|
+
readonly pendingReference: ColumnKey<Request>;
|
|
298
|
+
readonly retentionUntil: ColumnKey<Request>;
|
|
299
|
+
readonly encodeInsert: (
|
|
300
|
+
input: EmailRegistrationIntent<Registration>,
|
|
301
|
+
state: {
|
|
302
|
+
readonly state: EmailRegistrationState;
|
|
303
|
+
readonly nativeSubjectId?: NativeSubjectId;
|
|
304
|
+
readonly pendingReference?: string;
|
|
305
|
+
readonly retentionUntilMillis: number;
|
|
306
|
+
},
|
|
307
|
+
) => Request["insert"];
|
|
308
|
+
readonly decodeReplay: (row: Request["select"]) => Effect.Effect<
|
|
309
|
+
Exclude<
|
|
310
|
+
EmailRegistrationDecision,
|
|
311
|
+
{
|
|
312
|
+
readonly _tag: "Registered";
|
|
313
|
+
}
|
|
314
|
+
>,
|
|
315
|
+
PersistenceMappingError
|
|
316
|
+
>;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export interface EmailRegistrationProvisioning<
|
|
320
|
+
Registration,
|
|
321
|
+
Subject extends Table,
|
|
322
|
+
NativeSubjectId,
|
|
323
|
+
> {
|
|
324
|
+
readonly encodeSubjectInsert: (
|
|
325
|
+
input: EmailRegistrationIntent<Registration>,
|
|
326
|
+
values: {
|
|
327
|
+
readonly nativeSubjectId: NativeSubjectId | undefined;
|
|
328
|
+
readonly securityRevision: SecurityRevision;
|
|
329
|
+
},
|
|
330
|
+
) => Subject["insert"];
|
|
331
|
+
readonly allocateSubjectId?: Effect.Effect<NativeSubjectId, PersistenceMappingError>;
|
|
332
|
+
readonly allocateSubjectIdSync?: () => NativeSubjectId;
|
|
333
|
+
readonly decodeGeneratedId?: (
|
|
334
|
+
rows: ReadonlyArray<unknown>,
|
|
335
|
+
) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export interface EmailRegistrationIdentifierTable<
|
|
339
|
+
Identifier extends Table,
|
|
340
|
+
NativeSubjectId,
|
|
341
|
+
Expression extends SqlExpression = SqlExpression,
|
|
342
|
+
> {
|
|
343
|
+
readonly table: Identifier["table"];
|
|
344
|
+
readonly namespace: ColumnKey<Identifier>;
|
|
345
|
+
readonly value: ColumnKey<Identifier>;
|
|
346
|
+
readonly subjectId: ColumnKey<Identifier>;
|
|
347
|
+
readonly verifiedAt: ColumnKey<Identifier>;
|
|
348
|
+
readonly bindingRevision: ColumnKey<Identifier>;
|
|
349
|
+
readonly isCurrent: (row: Identifier["select"]) => boolean;
|
|
350
|
+
readonly d1CurrentCondition?: (input: {
|
|
351
|
+
readonly identifier: LoginIdentifier;
|
|
352
|
+
readonly nativeSubjectId: NativeSubjectId;
|
|
353
|
+
readonly bindingRevision: SecurityRevision;
|
|
354
|
+
}) => Expression;
|
|
355
|
+
readonly encodeVerifiedInsert: (input: {
|
|
356
|
+
readonly identifier: LoginIdentifier;
|
|
357
|
+
readonly subjectId: NativeSubjectId;
|
|
358
|
+
readonly verifiedAtMillis: number;
|
|
359
|
+
readonly bindingRevision: SecurityRevision;
|
|
360
|
+
}) => Identifier["insert"];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export interface EmailRegistrationCredentialTable<Credential extends Table, NativeSubjectId> {
|
|
364
|
+
readonly table: Credential["table"];
|
|
365
|
+
readonly moduleId: ColumnKey<Credential>;
|
|
366
|
+
readonly subjectId: ColumnKey<Credential>;
|
|
367
|
+
readonly credentialId: ColumnKey<Credential>;
|
|
368
|
+
readonly identifierNamespace: ColumnKey<Credential>;
|
|
369
|
+
readonly identifierValue: ColumnKey<Credential>;
|
|
370
|
+
readonly credentialRevision: ColumnKey<Credential>;
|
|
371
|
+
readonly status: ColumnKey<Credential>;
|
|
372
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
373
|
+
readonly d1ActiveStatusValue?: unknown;
|
|
374
|
+
readonly encodeVerifiedInsert: (input: {
|
|
375
|
+
readonly moduleId: string;
|
|
376
|
+
readonly subjectId: NativeSubjectId;
|
|
377
|
+
readonly credentialId: string;
|
|
378
|
+
readonly identifier: LoginIdentifier;
|
|
379
|
+
readonly credentialRevision: SecurityRevision;
|
|
380
|
+
}) => Credential["insert"];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export interface EmailRegistrationAuthorityCredentialTable<
|
|
384
|
+
Credential extends Table,
|
|
385
|
+
NativeSubjectId,
|
|
386
|
+
> {
|
|
387
|
+
readonly table: Credential["table"];
|
|
388
|
+
readonly subjectId: ColumnKey<Credential>;
|
|
389
|
+
readonly credentialId: ColumnKey<Credential>;
|
|
390
|
+
readonly revision: ColumnKey<Credential>;
|
|
391
|
+
readonly status: ColumnKey<Credential>;
|
|
392
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
393
|
+
readonly d1ActiveStatusValue?: unknown;
|
|
394
|
+
readonly encodeInsert: (input: {
|
|
395
|
+
readonly subjectId: NativeSubjectId;
|
|
396
|
+
readonly credentialId: string;
|
|
397
|
+
readonly revision: SecurityRevision;
|
|
398
|
+
}) => Credential["insert"];
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface RequiredEmailRegistrationConstraints extends RequiredEmailSignInConstraints {
|
|
402
|
+
readonly authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)";
|
|
403
|
+
readonly request: "unique(emailRegistration.moduleId,emailRegistration.commandId)";
|
|
404
|
+
readonly pendingReference: "unique(emailRegistration.pendingReference)";
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export const requiredEmailRegistrationConstraints: RequiredEmailRegistrationConstraints = {
|
|
408
|
+
...requiredEmailSignInConstraints,
|
|
409
|
+
authorityCredential: "unique(authorityCredential.subjectId,authorityCredential.credentialId)",
|
|
410
|
+
request: "unique(emailRegistration.moduleId,emailRegistration.commandId)",
|
|
411
|
+
pendingReference: "unique(emailRegistration.pendingReference)",
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
type EmailRegistrationBase<Registration, Request extends Table, NativeSubjectId> = {
|
|
415
|
+
readonly registration: EmailRegistrationTable<Registration, Request, NativeSubjectId>;
|
|
416
|
+
readonly constraints: Pick<RequiredEmailRegistrationConstraints, "request" | "pendingReference">;
|
|
417
|
+
readonly inspect: (input: {
|
|
418
|
+
readonly identifier: LoginIdentifier;
|
|
419
|
+
readonly registration: Registration;
|
|
420
|
+
}) => Effect.Effect<
|
|
421
|
+
{
|
|
422
|
+
readonly fingerprint: TokenDigest;
|
|
423
|
+
readonly eligible: boolean;
|
|
424
|
+
},
|
|
425
|
+
PersistenceMappingError
|
|
426
|
+
>;
|
|
427
|
+
/** Projects one detached value of the factory-specific Registration Type. */
|
|
428
|
+
readonly snapshotRegistration: (
|
|
429
|
+
registration: Registration,
|
|
430
|
+
) => Effect.Effect<Registration, PersistenceMappingError>;
|
|
431
|
+
/** Required by synchronous transaction-bound services. */
|
|
432
|
+
readonly snapshotRegistrationSync?: (registration: Registration) => Registration;
|
|
433
|
+
/** Required by synchronous Durable Object transaction-bound services. */
|
|
434
|
+
readonly inspectSync?: (input: {
|
|
435
|
+
readonly identifier: LoginIdentifier;
|
|
436
|
+
readonly registration: Registration;
|
|
437
|
+
}) => {
|
|
438
|
+
readonly fingerprint: TokenDigest;
|
|
439
|
+
readonly eligible: boolean;
|
|
440
|
+
};
|
|
441
|
+
readonly allocatePendingReference?: Effect.Effect<string, PersistenceMappingError>;
|
|
442
|
+
readonly allocatePendingReferenceSync?: () => string;
|
|
443
|
+
readonly encodeInstant: (epochMillis: number) => unknown;
|
|
444
|
+
readonly retentionMillis: number;
|
|
445
|
+
readonly isRequestConflict: (cause: unknown) => boolean;
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
export type EmailRegistrationMapping<
|
|
449
|
+
Registration,
|
|
450
|
+
Subject extends Table,
|
|
451
|
+
Identifier extends Table,
|
|
452
|
+
Credential extends Table,
|
|
453
|
+
AuthorityCredential extends Table,
|
|
454
|
+
Request extends Table,
|
|
455
|
+
NativeSubjectId,
|
|
456
|
+
Expression extends SqlExpression = SqlExpression,
|
|
457
|
+
> = EmailRegistrationBase<Registration, Request, NativeSubjectId> &
|
|
458
|
+
(
|
|
459
|
+
| {
|
|
460
|
+
readonly mode: "atomic";
|
|
461
|
+
readonly subject: EmailSubjectReadTable<Subject>;
|
|
462
|
+
readonly identifier: EmailRegistrationIdentifierTable<
|
|
463
|
+
Identifier,
|
|
464
|
+
NativeSubjectId,
|
|
465
|
+
Expression
|
|
466
|
+
>;
|
|
467
|
+
readonly credential: EmailRegistrationCredentialTable<Credential, NativeSubjectId>;
|
|
468
|
+
readonly authorityCredential: EmailRegistrationAuthorityCredentialTable<
|
|
469
|
+
AuthorityCredential,
|
|
470
|
+
NativeSubjectId
|
|
471
|
+
>;
|
|
472
|
+
readonly subjectId: SubjectIdCodec<NativeSubjectId>;
|
|
473
|
+
readonly constraints: RequiredEmailRegistrationConstraints;
|
|
474
|
+
readonly allocateCredentialId?: Effect.Effect<string, PersistenceMappingError>;
|
|
475
|
+
readonly allocateCredentialIdSync?: () => string;
|
|
476
|
+
readonly allocateRevision?: Effect.Effect<SecurityRevision, PersistenceMappingError>;
|
|
477
|
+
readonly allocateRevisionSync?: () => SecurityRevision;
|
|
478
|
+
readonly isIdentifierConflict: (cause: unknown) => boolean;
|
|
479
|
+
readonly isCredentialConflict: (cause: unknown) => boolean;
|
|
480
|
+
readonly provisioning: EmailRegistrationProvisioning<
|
|
481
|
+
Registration,
|
|
482
|
+
Subject,
|
|
483
|
+
NativeSubjectId
|
|
484
|
+
> &
|
|
485
|
+
(
|
|
486
|
+
| {
|
|
487
|
+
readonly idMode: "allocated";
|
|
488
|
+
readonly allocateSubjectId: Effect.Effect<NativeSubjectId, PersistenceMappingError>;
|
|
489
|
+
}
|
|
490
|
+
| {
|
|
491
|
+
readonly idMode: "synchronous";
|
|
492
|
+
readonly allocateSubjectIdSync: () => NativeSubjectId;
|
|
493
|
+
}
|
|
494
|
+
| {
|
|
495
|
+
readonly idMode: "generated";
|
|
496
|
+
readonly decodeGeneratedId: (
|
|
497
|
+
rows: ReadonlyArray<unknown>,
|
|
498
|
+
) => Effect.Effect<NativeSubjectId, PersistenceMappingError>;
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
| {
|
|
503
|
+
readonly mode: "pending";
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
export type AnyEmailSignInMapping = EmailSignInMapping<
|
|
508
|
+
AnyTableModel,
|
|
509
|
+
AnyTableModel,
|
|
510
|
+
AnyTableModel,
|
|
511
|
+
unknown
|
|
512
|
+
>;
|
|
513
|
+
|
|
514
|
+
export type AnyEmailAddressMapping<Expression extends SqlExpression = SqlExpression> =
|
|
515
|
+
EmailAddressMapping<
|
|
516
|
+
AnyTableModel,
|
|
517
|
+
AnyTableModel,
|
|
518
|
+
AnyTableModel,
|
|
519
|
+
AnyTableModel,
|
|
520
|
+
AnyTableModel,
|
|
521
|
+
unknown,
|
|
522
|
+
Expression
|
|
523
|
+
>;
|
|
524
|
+
|
|
525
|
+
export type AnyEmailRegistrationMapping<
|
|
526
|
+
Registration = unknown,
|
|
527
|
+
Expression extends SqlExpression = SqlExpression,
|
|
528
|
+
> = EmailRegistrationMapping<
|
|
529
|
+
Registration,
|
|
530
|
+
AnyTableModel,
|
|
531
|
+
AnyTableModel,
|
|
532
|
+
AnyTableModel,
|
|
533
|
+
AnyTableModel,
|
|
534
|
+
AnyTableModel,
|
|
535
|
+
unknown,
|
|
536
|
+
Expression
|
|
537
|
+
>;
|
|
538
|
+
|
|
539
|
+
export type D1EmailRegistrationMapping<
|
|
540
|
+
Registration,
|
|
541
|
+
Subject extends Table,
|
|
542
|
+
Identifier extends Table,
|
|
543
|
+
Credential extends Table,
|
|
544
|
+
AuthorityCredential extends Table,
|
|
545
|
+
Request extends Table,
|
|
546
|
+
NativeSubjectId,
|
|
547
|
+
Expression extends SqlExpression = SqlExpression,
|
|
548
|
+
> = EmailRegistrationMapping<
|
|
549
|
+
Registration,
|
|
550
|
+
Subject,
|
|
551
|
+
Identifier,
|
|
552
|
+
Credential,
|
|
553
|
+
AuthorityCredential,
|
|
554
|
+
Request,
|
|
555
|
+
NativeSubjectId,
|
|
556
|
+
Expression
|
|
557
|
+
> & {
|
|
558
|
+
readonly d1: EmailD1Clock<Expression>;
|
|
559
|
+
};
|