@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,81 @@
|
|
|
1
|
+
import type { Statement } from "effect/unstable/sql/Statement";
|
|
2
|
+
|
|
3
|
+
/** Adapter-owned table metadata. No driver or ORM type enters the shared models. */
|
|
4
|
+
export interface TableModel {
|
|
5
|
+
readonly table: object;
|
|
6
|
+
readonly column: string;
|
|
7
|
+
readonly select: Record<string, unknown>;
|
|
8
|
+
readonly insert: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Kernels erase the physical table handle after the adapter validates its
|
|
12
|
+
* mapping. Rows and insert values still pass through their declared codecs. */
|
|
13
|
+
export interface AnyTableModel extends TableModel {
|
|
14
|
+
// oxlint-disable-next-line no-explicit-any -- physical compiler handle, never a domain value or an Effect error.
|
|
15
|
+
readonly table: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Opaque compiler expression; only the owning compiler interprets its contents. */
|
|
19
|
+
export interface SqlExpression {
|
|
20
|
+
readonly getSQL: () => SqlExpression;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SqlFragment extends SqlExpression {
|
|
24
|
+
readonly mapWith: (decode: (value: unknown) => unknown) => SqlFragment;
|
|
25
|
+
readonly as: (name: string) => SqlExpression;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SqlColumn extends SqlExpression {
|
|
29
|
+
readonly mapToDriverValue: (value: unknown) => unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Native query failures stay in E until the owning kernel reports and redacts
|
|
33
|
+
* them. Drivers may carry a more specific tag; the cause remains available to
|
|
34
|
+
* the application's constraint classifier and is never public telemetry. */
|
|
35
|
+
export interface QueryFailure {
|
|
36
|
+
readonly _tag: string;
|
|
37
|
+
readonly cause: unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type Predicate<Fragment> = (
|
|
41
|
+
...parts: ReadonlyArray<SqlExpression | undefined>
|
|
42
|
+
) => Fragment | undefined;
|
|
43
|
+
type Comparison<Fragment> = (left: unknown, right: unknown) => Fragment;
|
|
44
|
+
|
|
45
|
+
/** Compiler operations shared by the SQL state machines; no driver is acquired here. */
|
|
46
|
+
export interface QueryOperations<
|
|
47
|
+
Fragment extends SqlFragment = SqlFragment,
|
|
48
|
+
Column extends SqlColumn = SqlColumn,
|
|
49
|
+
> {
|
|
50
|
+
readonly and: Predicate<Fragment>;
|
|
51
|
+
readonly or: Predicate<Fragment>;
|
|
52
|
+
readonly balancedD1And: Predicate<Fragment>;
|
|
53
|
+
readonly asc: (value: unknown) => Fragment;
|
|
54
|
+
readonly eq: Comparison<Fragment>;
|
|
55
|
+
readonly gt: Comparison<Fragment>;
|
|
56
|
+
readonly gte: Comparison<Fragment>;
|
|
57
|
+
readonly lte: Comparison<Fragment>;
|
|
58
|
+
readonly inArray: (value: unknown, values: ReadonlyArray<unknown>) => Fragment;
|
|
59
|
+
readonly isNull: (value: unknown) => Fragment;
|
|
60
|
+
readonly notExists: (value: SqlExpression) => Fragment;
|
|
61
|
+
readonly sql: {
|
|
62
|
+
(parts: TemplateStringsArray, ...values: ReadonlyArray<unknown>): Fragment;
|
|
63
|
+
readonly param: (value: unknown, column: SqlColumn) => unknown;
|
|
64
|
+
readonly join: (values: ReadonlyArray<unknown>, separator: SqlExpression) => Fragment;
|
|
65
|
+
};
|
|
66
|
+
readonly getTableColumns: (table: object) => Readonly<Record<string, Column>>;
|
|
67
|
+
readonly column: (table: object, key: string) => Column;
|
|
68
|
+
readonly updateValues: (
|
|
69
|
+
entries: ReadonlyArray<readonly [string, unknown]>,
|
|
70
|
+
) => Record<string, unknown>;
|
|
71
|
+
readonly compactD1GeneratedStatement: <A extends object>(
|
|
72
|
+
client: {
|
|
73
|
+
readonly unsafe: <Row extends object>(
|
|
74
|
+
sql: string,
|
|
75
|
+
params?: ReadonlyArray<unknown>,
|
|
76
|
+
) => Statement<Row>;
|
|
77
|
+
},
|
|
78
|
+
statement: Statement<A>,
|
|
79
|
+
invalid: () => unknown,
|
|
80
|
+
) => Statement<A>;
|
|
81
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PreparedCommit } from "@yielded/auth/Hooks";
|
|
2
|
+
import type { LoginIdentifier } from "@yielded/auth/Identity";
|
|
3
|
+
import type {
|
|
4
|
+
PasswordUnavailable,
|
|
5
|
+
PasswordReplacement,
|
|
6
|
+
PasswordRegistrationDecision,
|
|
7
|
+
PreparePasswordCommit,
|
|
8
|
+
} from "@yielded/auth/Password";
|
|
9
|
+
import type { Effect } from "effect";
|
|
10
|
+
|
|
11
|
+
export interface PasswordRegistrationAuthority<Registration> {
|
|
12
|
+
readonly register: <A>(
|
|
13
|
+
input: {
|
|
14
|
+
readonly moduleId: string;
|
|
15
|
+
readonly requestId: string;
|
|
16
|
+
readonly identifier: LoginIdentifier;
|
|
17
|
+
readonly registration: Registration;
|
|
18
|
+
readonly replacement: PasswordReplacement;
|
|
19
|
+
},
|
|
20
|
+
prepare: PreparePasswordCommit<PasswordRegistrationDecision, A>,
|
|
21
|
+
) => Effect.Effect<PreparedCommit<A>, PasswordUnavailable>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { randomId } from "@yielded/auth-crypto";
|
|
2
|
+
import { coordinateCommit, hasCommitScope, LifecycleHooks } from "@yielded/auth/Hooks";
|
|
3
|
+
import type { LoginIdentifier } from "@yielded/auth/Identity";
|
|
4
|
+
import { PasswordUnavailable } from "@yielded/auth/Password";
|
|
5
|
+
import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
6
|
+
import type { SubjectId } from "@yielded/auth/Schema";
|
|
7
|
+
import { SecurityRevision } from "@yielded/auth/Sessions";
|
|
8
|
+
import { Effect, Schema } from "effect";
|
|
9
|
+
|
|
10
|
+
import type { PasswordSqlDatabase } from "./password-kernel";
|
|
11
|
+
import type { QueryOperations } from "./query-operations";
|
|
12
|
+
import type { PasswordRegistrationAuthority } from "./registration-contract";
|
|
13
|
+
import type { makeMappings } from "./storage-mapping";
|
|
14
|
+
|
|
15
|
+
class IdentifierTaken extends Schema.TaggedError<IdentifierTaken>()("IdentifierTaken", {}) {}
|
|
16
|
+
|
|
17
|
+
export type CreateSubject = (input: {
|
|
18
|
+
readonly identifier: LoginIdentifier;
|
|
19
|
+
readonly registration: unknown;
|
|
20
|
+
}) => Effect.Effect<SubjectId, PasswordUnavailable>;
|
|
21
|
+
|
|
22
|
+
/** Registration reserves the command, provisions the application's subject, and
|
|
23
|
+
* creates the unverified identifier and password in one SQL transaction. Replays
|
|
24
|
+
* always suppress; a public request ID never recovers a private password intent.
|
|
25
|
+
*/
|
|
26
|
+
export const makeRegistrationAuthority = Effect.fn("makeRegistrationAuthority")(function* (
|
|
27
|
+
database: PasswordSqlDatabase,
|
|
28
|
+
mappings: ReturnType<typeof makeMappings>,
|
|
29
|
+
operations: QueryOperations,
|
|
30
|
+
standalone: Effect.Effect<void, PasswordUnavailable>,
|
|
31
|
+
createSubject: CreateSubject,
|
|
32
|
+
): Effect.fn.Return<PasswordRegistrationAuthority<unknown>, never, LifecycleHooks> {
|
|
33
|
+
const hooks = yield* LifecycleHooks;
|
|
34
|
+
const { and, eq, column } = operations;
|
|
35
|
+
const mapping = mappings.passwords();
|
|
36
|
+
const receipts = mappings.table("passwordRegistrations");
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
register: (input, prepare) =>
|
|
40
|
+
Effect.gen(function* () {
|
|
41
|
+
if (yield* hasCommitScope) return yield* PasswordUnavailable.make({});
|
|
42
|
+
yield* standalone;
|
|
43
|
+
|
|
44
|
+
const receipt = { moduleId: input.moduleId, requestId: input.requestId };
|
|
45
|
+
|
|
46
|
+
const suppress = coordinateCommit(
|
|
47
|
+
(journal) =>
|
|
48
|
+
database.transaction((tx) =>
|
|
49
|
+
Effect.gen(function* () {
|
|
50
|
+
yield* tx.insert(receipts).values(receipt).onConflictDoNothing();
|
|
51
|
+
|
|
52
|
+
return prepare({ _tag: "Suppressed" }, journal);
|
|
53
|
+
}),
|
|
54
|
+
),
|
|
55
|
+
{ mode: "interactive" },
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const committed = yield* coordinateCommit(
|
|
59
|
+
(journal) =>
|
|
60
|
+
database.transaction((tx) =>
|
|
61
|
+
Effect.gen(function* () {
|
|
62
|
+
const reserved = yield* tx
|
|
63
|
+
.insert(receipts)
|
|
64
|
+
.values(receipt)
|
|
65
|
+
.onConflictDoNothing()
|
|
66
|
+
.returning();
|
|
67
|
+
|
|
68
|
+
if (reserved.length === 0) return prepare({ _tag: "Suppressed" }, journal);
|
|
69
|
+
|
|
70
|
+
const identifiers = yield* tx
|
|
71
|
+
.select()
|
|
72
|
+
.from(mapping.identifier.table)
|
|
73
|
+
.where(
|
|
74
|
+
and(
|
|
75
|
+
eq(
|
|
76
|
+
column(mapping.identifier.table, mapping.identifier.namespace),
|
|
77
|
+
input.identifier.namespace,
|
|
78
|
+
),
|
|
79
|
+
eq(
|
|
80
|
+
column(mapping.identifier.table, mapping.identifier.value),
|
|
81
|
+
input.identifier.value,
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
.limit(1);
|
|
86
|
+
|
|
87
|
+
if (identifiers.length !== 0) return prepare({ _tag: "Suppressed" }, journal);
|
|
88
|
+
|
|
89
|
+
const subjectId = yield* createSubject({
|
|
90
|
+
identifier: input.identifier,
|
|
91
|
+
registration: input.registration,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const nativeId = yield* mapping.subjectId.toNative(subjectId);
|
|
95
|
+
|
|
96
|
+
const subjects = yield* tx
|
|
97
|
+
.select()
|
|
98
|
+
.from(mapping.subject.table)
|
|
99
|
+
.where(eq(column(mapping.subject.table, mapping.subject.id), nativeId))
|
|
100
|
+
.limit(1);
|
|
101
|
+
|
|
102
|
+
if (
|
|
103
|
+
subjects.length !== 1 ||
|
|
104
|
+
!mapping.subject.isActiveStatus(subjects[0][mapping.subject.status])
|
|
105
|
+
)
|
|
106
|
+
return yield* PasswordUnavailable.make({});
|
|
107
|
+
yield* Schema.decodeUnknownEffect(SecurityRevision)(
|
|
108
|
+
subjects[0][mapping.subject.securityRevision],
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const bound = yield* tx
|
|
112
|
+
.insert(mapping.identifier.table)
|
|
113
|
+
.values(
|
|
114
|
+
mapping.identifier.encodeInitialInsert(
|
|
115
|
+
input.identifier,
|
|
116
|
+
nativeId,
|
|
117
|
+
SecurityRevision.make(randomId()),
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
.onConflictDoNothing()
|
|
121
|
+
.returning();
|
|
122
|
+
|
|
123
|
+
// A concurrent registration won the identifier. Roll back the application
|
|
124
|
+
// subject too, then persist a non-authorizing receipt in a new transaction.
|
|
125
|
+
if (bound.length !== 1) return yield* new IdentifierTaken({});
|
|
126
|
+
|
|
127
|
+
const credentialId = randomId();
|
|
128
|
+
const credentialRevision = SecurityRevision.make(randomId());
|
|
129
|
+
|
|
130
|
+
yield* tx.insert(mapping.credential.table).values(
|
|
131
|
+
mapping.credential.encodeInsert({
|
|
132
|
+
moduleId: input.moduleId,
|
|
133
|
+
subjectId: nativeId,
|
|
134
|
+
credentialId,
|
|
135
|
+
credentialRevision,
|
|
136
|
+
verifierVersion: SecurityRevision.make(randomId()),
|
|
137
|
+
replacement: input.replacement,
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
140
|
+
yield* tx.insert(mapping.authorityCredential.table).values(
|
|
141
|
+
mapping.authorityCredential.encodeInsert({
|
|
142
|
+
subjectId: nativeId,
|
|
143
|
+
credentialId,
|
|
144
|
+
revision: credentialRevision,
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
return prepare({ _tag: "Created", subjectId }, journal);
|
|
149
|
+
}),
|
|
150
|
+
),
|
|
151
|
+
{ mode: "interactive" },
|
|
152
|
+
).pipe(Effect.catchTag("IdentifierTaken", () => suppress));
|
|
153
|
+
|
|
154
|
+
return committed.value;
|
|
155
|
+
}).pipe(
|
|
156
|
+
Effect.provideService(LifecycleHooks, hooks),
|
|
157
|
+
(work) => reportPersistenceFailure(work, Schema.is(PasswordUnavailable)),
|
|
158
|
+
Effect.mapError(() => PasswordUnavailable.make({})),
|
|
159
|
+
),
|
|
160
|
+
};
|
|
161
|
+
});
|