effect 4.0.0-beta.44 → 4.0.0-beta.45
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/dist/Equal.d.ts.map +1 -1
- package/dist/Equal.js +16 -0
- package/dist/Equal.js.map +1 -1
- package/dist/Hash.js +1 -1
- package/dist/Hash.js.map +1 -1
- package/dist/Semaphore.d.ts +1 -1
- package/dist/Semaphore.d.ts.map +1 -1
- package/dist/Semaphore.js +1 -3
- package/dist/Semaphore.js.map +1 -1
- package/dist/unstable/ai/McpServer.d.ts.map +1 -1
- package/dist/unstable/ai/McpServer.js +24 -21
- package/dist/unstable/ai/McpServer.js.map +1 -1
- package/dist/unstable/eventlog/Event.d.ts +0 -6
- package/dist/unstable/eventlog/Event.d.ts.map +1 -1
- package/dist/unstable/eventlog/Event.js +0 -5
- package/dist/unstable/eventlog/Event.js.map +1 -1
- package/dist/unstable/eventlog/EventGroup.d.ts +0 -2
- package/dist/unstable/eventlog/EventGroup.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventGroup.js +0 -2
- package/dist/unstable/eventlog/EventGroup.js.map +1 -1
- package/dist/unstable/eventlog/EventJournal.d.ts +22 -5
- package/dist/unstable/eventlog/EventJournal.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventJournal.js +126 -67
- package/dist/unstable/eventlog/EventJournal.js.map +1 -1
- package/dist/unstable/eventlog/EventLog.d.ts +88 -34
- package/dist/unstable/eventlog/EventLog.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventLog.js +215 -141
- package/dist/unstable/eventlog/EventLog.js.map +1 -1
- package/dist/unstable/eventlog/EventLogEncryption.d.ts +9 -7
- package/dist/unstable/eventlog/EventLogEncryption.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventLogEncryption.js +13 -15
- package/dist/unstable/eventlog/EventLogEncryption.js.map +1 -1
- package/dist/unstable/eventlog/EventLogMessage.d.ts +228 -0
- package/dist/unstable/eventlog/EventLogMessage.d.ts.map +1 -0
- package/dist/unstable/eventlog/EventLogMessage.js +214 -0
- package/dist/unstable/eventlog/EventLogMessage.js.map +1 -0
- package/dist/unstable/eventlog/EventLogRemote.d.ts +109 -194
- package/dist/unstable/eventlog/EventLogRemote.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventLogRemote.js +165 -320
- package/dist/unstable/eventlog/EventLogRemote.js.map +1 -1
- package/dist/unstable/eventlog/EventLogServer.d.ts +25 -47
- package/dist/unstable/eventlog/EventLogServer.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventLogServer.js +127 -198
- package/dist/unstable/eventlog/EventLogServer.js.map +1 -1
- package/dist/unstable/eventlog/EventLogServerEncrypted.d.ts +60 -0
- package/dist/unstable/eventlog/EventLogServerEncrypted.d.ts.map +1 -0
- package/dist/unstable/eventlog/EventLogServerEncrypted.js +166 -0
- package/dist/unstable/eventlog/EventLogServerEncrypted.js.map +1 -0
- package/dist/unstable/eventlog/EventLogServerUnencrypted.d.ts +183 -0
- package/dist/unstable/eventlog/EventLogServerUnencrypted.d.ts.map +1 -0
- package/dist/unstable/eventlog/EventLogServerUnencrypted.js +461 -0
- package/dist/unstable/eventlog/EventLogServerUnencrypted.js.map +1 -0
- package/dist/unstable/eventlog/EventLogSessionAuth.d.ts +117 -0
- package/dist/unstable/eventlog/EventLogSessionAuth.d.ts.map +1 -0
- package/dist/unstable/eventlog/EventLogSessionAuth.js +284 -0
- package/dist/unstable/eventlog/EventLogSessionAuth.js.map +1 -0
- package/dist/unstable/eventlog/{SqlEventLogJournal.d.ts → SqlEventJournal.d.ts} +2 -2
- package/dist/unstable/eventlog/SqlEventJournal.d.ts.map +1 -0
- package/dist/unstable/eventlog/{SqlEventLogJournal.js → SqlEventJournal.js} +20 -14
- package/dist/unstable/eventlog/SqlEventJournal.js.map +1 -0
- package/dist/unstable/eventlog/{SqlEventLogServer.d.ts → SqlEventLogServerEncrypted.d.ts} +5 -5
- package/dist/unstable/eventlog/SqlEventLogServerEncrypted.d.ts.map +1 -0
- package/dist/unstable/eventlog/{SqlEventLogServer.js → SqlEventLogServerEncrypted.js} +65 -24
- package/dist/unstable/eventlog/SqlEventLogServerEncrypted.js.map +1 -0
- package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.d.ts +25 -0
- package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.d.ts.map +1 -0
- package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.js +354 -0
- package/dist/unstable/eventlog/SqlEventLogServerUnencrypted.js.map +1 -0
- package/dist/unstable/eventlog/index.d.ts +22 -2
- package/dist/unstable/eventlog/index.d.ts.map +1 -1
- package/dist/unstable/eventlog/index.js +22 -2
- package/dist/unstable/eventlog/index.js.map +1 -1
- package/dist/unstable/eventlog/internal/identityRootSecretDerivation.d.ts +2 -0
- package/dist/unstable/eventlog/internal/identityRootSecretDerivation.d.ts.map +1 -0
- package/dist/unstable/eventlog/internal/identityRootSecretDerivation.js +89 -0
- package/dist/unstable/eventlog/internal/identityRootSecretDerivation.js.map +1 -0
- package/dist/unstable/reactivity/AtomHttpApi.d.ts +1 -2
- package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomHttpApi.js +2 -2
- package/dist/unstable/reactivity/AtomHttpApi.js.map +1 -1
- package/dist/unstable/reactivity/AtomRpc.d.ts +1 -2
- package/dist/unstable/reactivity/AtomRpc.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomRpc.js +3 -3
- package/dist/unstable/reactivity/AtomRpc.js.map +1 -1
- package/dist/unstable/rpc/Rpc.d.ts +25 -4
- package/dist/unstable/rpc/Rpc.d.ts.map +1 -1
- package/dist/unstable/rpc/Rpc.js +26 -0
- package/dist/unstable/rpc/Rpc.js.map +1 -1
- package/dist/unstable/rpc/RpcClient.d.ts +3 -13
- package/dist/unstable/rpc/RpcClient.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcClient.js +47 -23
- package/dist/unstable/rpc/RpcClient.js.map +1 -1
- package/dist/unstable/rpc/RpcGroup.d.ts +1 -1
- package/dist/unstable/rpc/RpcGroup.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcMiddleware.d.ts +2 -2
- package/dist/unstable/rpc/RpcMiddleware.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcServer.js +3 -2
- package/dist/unstable/rpc/RpcServer.js.map +1 -1
- package/dist/unstable/rpc/Utils.d.ts +6 -0
- package/dist/unstable/rpc/Utils.d.ts.map +1 -1
- package/dist/unstable/rpc/Utils.js +44 -0
- package/dist/unstable/rpc/Utils.js.map +1 -1
- package/dist/unstable/schema/Model.d.ts +2 -2
- package/dist/unstable/schema/Model.d.ts.map +1 -1
- package/dist/unstable/schema/Model.js +2 -4
- package/dist/unstable/schema/Model.js.map +1 -1
- package/dist/unstable/schema/VariantSchema.d.ts +1 -1
- package/dist/unstable/schema/VariantSchema.d.ts.map +1 -1
- package/dist/unstable/schema/VariantSchema.js +1 -12
- package/dist/unstable/schema/VariantSchema.js.map +1 -1
- package/dist/unstable/workers/Transferable.d.ts +1 -1
- package/dist/unstable/workers/Transferable.d.ts.map +1 -1
- package/dist/unstable/workers/Transferable.js +1 -1
- package/dist/unstable/workers/Transferable.js.map +1 -1
- package/package.json +1 -1
- package/src/Equal.ts +17 -0
- package/src/Hash.ts +2 -2
- package/src/Semaphore.ts +2 -4
- package/src/unstable/ai/McpServer.ts +24 -22
- package/src/unstable/eventlog/Event.ts +0 -8
- package/src/unstable/eventlog/EventGroup.ts +0 -4
- package/src/unstable/eventlog/EventJournal.ts +144 -76
- package/src/unstable/eventlog/EventLog.ts +342 -221
- package/src/unstable/eventlog/EventLogEncryption.ts +16 -30
- package/src/unstable/eventlog/EventLogMessage.ts +277 -0
- package/src/unstable/eventlog/EventLogRemote.ts +261 -408
- package/src/unstable/eventlog/EventLogServer.ts +182 -274
- package/src/unstable/eventlog/EventLogServerEncrypted.ts +206 -0
- package/src/unstable/eventlog/EventLogServerUnencrypted.ts +749 -0
- package/src/unstable/eventlog/EventLogSessionAuth.ts +437 -0
- package/src/unstable/eventlog/{SqlEventLogJournal.ts → SqlEventJournal.ts} +26 -18
- package/src/unstable/eventlog/{SqlEventLogServer.ts → SqlEventLogServerEncrypted.ts} +102 -40
- package/src/unstable/eventlog/SqlEventLogServerUnencrypted.ts +500 -0
- package/src/unstable/eventlog/index.ts +27 -2
- package/src/unstable/eventlog/internal/identityRootSecretDerivation.ts +153 -0
- package/src/unstable/reactivity/AtomHttpApi.ts +23 -8
- package/src/unstable/reactivity/AtomRpc.ts +16 -5
- package/src/unstable/rpc/Rpc.ts +42 -4
- package/src/unstable/rpc/RpcClient.ts +59 -24
- package/src/unstable/rpc/RpcGroup.ts +1 -1
- package/src/unstable/rpc/RpcMiddleware.ts +2 -2
- package/src/unstable/rpc/RpcServer.ts +5 -3
- package/src/unstable/rpc/Utils.ts +59 -0
- package/src/unstable/schema/Model.ts +4 -6
- package/src/unstable/schema/VariantSchema.ts +4 -17
- package/src/unstable/workers/Transferable.ts +9 -11
- package/dist/unstable/eventlog/SqlEventLogJournal.d.ts.map +0 -1
- package/dist/unstable/eventlog/SqlEventLogJournal.js.map +0 -1
- package/dist/unstable/eventlog/SqlEventLogServer.d.ts.map +0 -1
- package/dist/unstable/eventlog/SqlEventLogServer.js.map +0 -1
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 4.0.0
|
|
3
|
+
*/
|
|
4
|
+
import * as Arr from "../../Array.ts"
|
|
5
|
+
import * as Effect from "../../Effect.ts"
|
|
6
|
+
import * as Layer from "../../Layer.ts"
|
|
7
|
+
import * as PubSub from "../../PubSub.ts"
|
|
8
|
+
import * as RcMap from "../../RcMap.ts"
|
|
9
|
+
import * as Schema from "../../Schema.ts"
|
|
10
|
+
import type * as Scope from "../../Scope.ts"
|
|
11
|
+
import * as Stream from "../../Stream.ts"
|
|
12
|
+
import * as SqlClient from "../sql/SqlClient.ts"
|
|
13
|
+
import * as SqlError from "../sql/SqlError.ts"
|
|
14
|
+
import { Entry, EntryId, makeRemoteIdUnsafe, RemoteEntry, type RemoteId } from "./EventJournal.ts"
|
|
15
|
+
import * as EventLogServerUnencrypted from "./EventLogServerUnencrypted.ts"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @since 4.0.0
|
|
19
|
+
* @category constructors
|
|
20
|
+
*/
|
|
21
|
+
export const makeStorage = (options?: {
|
|
22
|
+
readonly entryTablePrefix?: string
|
|
23
|
+
readonly remoteIdTable?: string
|
|
24
|
+
readonly insertBatchSize?: number
|
|
25
|
+
}): Effect.Effect<
|
|
26
|
+
EventLogServerUnencrypted.Storage["Service"],
|
|
27
|
+
SqlError.SqlError,
|
|
28
|
+
SqlClient.SqlClient | Scope.Scope
|
|
29
|
+
> =>
|
|
30
|
+
Effect.gen(function*() {
|
|
31
|
+
const sql = (yield* SqlClient.SqlClient).withoutTransforms()
|
|
32
|
+
|
|
33
|
+
const entriesTable = options?.entryTablePrefix ?? "effect_events"
|
|
34
|
+
const remoteIdTable = options?.remoteIdTable ?? "effect_remote_id"
|
|
35
|
+
const insertBatchSize = options?.insertBatchSize ?? 200
|
|
36
|
+
const storesTable = `${entriesTable}_stores`
|
|
37
|
+
const sessionAuthBindingsTable = `${entriesTable}_session_auth_bindings`
|
|
38
|
+
|
|
39
|
+
const remoteIdTableSql = sql(remoteIdTable)
|
|
40
|
+
const entriesTableSql = sql(entriesTable)
|
|
41
|
+
const storesTableSql = sql(storesTable)
|
|
42
|
+
const sessionAuthBindingsTableSql = sql(sessionAuthBindingsTable)
|
|
43
|
+
|
|
44
|
+
yield* sql.onDialectOrElse({
|
|
45
|
+
pg: () =>
|
|
46
|
+
sql`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS ${remoteIdTableSql} (
|
|
48
|
+
singleton INT PRIMARY KEY,
|
|
49
|
+
remote_id BYTEA NOT NULL
|
|
50
|
+
)`,
|
|
51
|
+
mysql: () =>
|
|
52
|
+
sql`
|
|
53
|
+
CREATE TABLE IF NOT EXISTS ${remoteIdTableSql} (
|
|
54
|
+
singleton INT PRIMARY KEY,
|
|
55
|
+
remote_id BINARY(16) NOT NULL
|
|
56
|
+
)`,
|
|
57
|
+
mssql: () =>
|
|
58
|
+
sql`
|
|
59
|
+
CREATE TABLE IF NOT EXISTS ${remoteIdTableSql} (
|
|
60
|
+
singleton INT PRIMARY KEY,
|
|
61
|
+
remote_id VARBINARY(16) NOT NULL
|
|
62
|
+
)`,
|
|
63
|
+
orElse: () =>
|
|
64
|
+
sql`
|
|
65
|
+
CREATE TABLE IF NOT EXISTS ${remoteIdTableSql} (
|
|
66
|
+
singleton INTEGER PRIMARY KEY,
|
|
67
|
+
remote_id BLOB NOT NULL
|
|
68
|
+
)`
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
yield* sql.onDialectOrElse({
|
|
72
|
+
pg: () =>
|
|
73
|
+
sql`
|
|
74
|
+
CREATE TABLE IF NOT EXISTS ${entriesTableSql} (
|
|
75
|
+
store_id TEXT NOT NULL,
|
|
76
|
+
sequence BIGINT NOT NULL,
|
|
77
|
+
entry_id BYTEA NOT NULL,
|
|
78
|
+
event TEXT NOT NULL,
|
|
79
|
+
primary_key TEXT NOT NULL,
|
|
80
|
+
payload BYTEA NOT NULL,
|
|
81
|
+
PRIMARY KEY (store_id, sequence),
|
|
82
|
+
UNIQUE (store_id, entry_id)
|
|
83
|
+
)`,
|
|
84
|
+
mysql: () =>
|
|
85
|
+
sql`
|
|
86
|
+
CREATE TABLE IF NOT EXISTS ${entriesTableSql} (
|
|
87
|
+
store_id VARCHAR(191) NOT NULL,
|
|
88
|
+
sequence BIGINT NOT NULL,
|
|
89
|
+
entry_id BINARY(16) NOT NULL,
|
|
90
|
+
event TEXT NOT NULL,
|
|
91
|
+
primary_key TEXT NOT NULL,
|
|
92
|
+
payload BLOB NOT NULL,
|
|
93
|
+
PRIMARY KEY (store_id, sequence),
|
|
94
|
+
UNIQUE (store_id, entry_id)
|
|
95
|
+
)`,
|
|
96
|
+
mssql: () =>
|
|
97
|
+
sql`
|
|
98
|
+
CREATE TABLE IF NOT EXISTS ${entriesTableSql} (
|
|
99
|
+
store_id NVARCHAR(191) NOT NULL,
|
|
100
|
+
sequence BIGINT NOT NULL,
|
|
101
|
+
entry_id VARBINARY(16) NOT NULL,
|
|
102
|
+
event NVARCHAR(MAX) NOT NULL,
|
|
103
|
+
primary_key NVARCHAR(MAX) NOT NULL,
|
|
104
|
+
payload VARBINARY(MAX) NOT NULL,
|
|
105
|
+
PRIMARY KEY (store_id, sequence),
|
|
106
|
+
UNIQUE (store_id, entry_id)
|
|
107
|
+
)`,
|
|
108
|
+
orElse: () =>
|
|
109
|
+
sql`
|
|
110
|
+
CREATE TABLE IF NOT EXISTS ${entriesTableSql} (
|
|
111
|
+
store_id TEXT NOT NULL,
|
|
112
|
+
sequence INTEGER NOT NULL,
|
|
113
|
+
entry_id BLOB NOT NULL,
|
|
114
|
+
event TEXT NOT NULL,
|
|
115
|
+
primary_key TEXT NOT NULL,
|
|
116
|
+
payload BLOB NOT NULL,
|
|
117
|
+
PRIMARY KEY (store_id, sequence),
|
|
118
|
+
UNIQUE (store_id, entry_id)
|
|
119
|
+
)`
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
yield* sql.onDialectOrElse({
|
|
123
|
+
pg: () =>
|
|
124
|
+
sql`
|
|
125
|
+
CREATE TABLE IF NOT EXISTS ${storesTableSql} (
|
|
126
|
+
store_id TEXT PRIMARY KEY,
|
|
127
|
+
next_sequence BIGINT NOT NULL
|
|
128
|
+
)`,
|
|
129
|
+
mysql: () =>
|
|
130
|
+
sql`
|
|
131
|
+
CREATE TABLE IF NOT EXISTS ${storesTableSql} (
|
|
132
|
+
store_id VARCHAR(191) PRIMARY KEY,
|
|
133
|
+
next_sequence BIGINT NOT NULL
|
|
134
|
+
)`,
|
|
135
|
+
mssql: () =>
|
|
136
|
+
sql`
|
|
137
|
+
CREATE TABLE IF NOT EXISTS ${storesTableSql} (
|
|
138
|
+
store_id NVARCHAR(191) PRIMARY KEY,
|
|
139
|
+
next_sequence BIGINT NOT NULL
|
|
140
|
+
)`,
|
|
141
|
+
orElse: () =>
|
|
142
|
+
sql`
|
|
143
|
+
CREATE TABLE IF NOT EXISTS ${storesTableSql} (
|
|
144
|
+
store_id TEXT PRIMARY KEY,
|
|
145
|
+
next_sequence INTEGER NOT NULL
|
|
146
|
+
)`
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
yield* sql.onDialectOrElse({
|
|
150
|
+
pg: () =>
|
|
151
|
+
sql`
|
|
152
|
+
CREATE TABLE IF NOT EXISTS ${sessionAuthBindingsTableSql} (
|
|
153
|
+
public_key TEXT PRIMARY KEY,
|
|
154
|
+
signing_public_key BYTEA NOT NULL
|
|
155
|
+
)`,
|
|
156
|
+
mysql: () =>
|
|
157
|
+
sql`
|
|
158
|
+
CREATE TABLE IF NOT EXISTS ${sessionAuthBindingsTableSql} (
|
|
159
|
+
public_key VARCHAR(191) PRIMARY KEY,
|
|
160
|
+
signing_public_key BINARY(32) NOT NULL
|
|
161
|
+
)`,
|
|
162
|
+
mssql: () =>
|
|
163
|
+
sql`
|
|
164
|
+
CREATE TABLE IF NOT EXISTS ${sessionAuthBindingsTableSql} (
|
|
165
|
+
public_key NVARCHAR(191) PRIMARY KEY,
|
|
166
|
+
signing_public_key VARBINARY(32) NOT NULL
|
|
167
|
+
)`,
|
|
168
|
+
orElse: () =>
|
|
169
|
+
sql`
|
|
170
|
+
CREATE TABLE IF NOT EXISTS ${sessionAuthBindingsTableSql} (
|
|
171
|
+
public_key TEXT PRIMARY KEY,
|
|
172
|
+
signing_public_key BLOB NOT NULL
|
|
173
|
+
)`
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const selectRemoteId = sql<{ remote_id: Uint8Array }>`
|
|
177
|
+
SELECT remote_id
|
|
178
|
+
FROM ${remoteIdTableSql}
|
|
179
|
+
WHERE singleton = 1
|
|
180
|
+
`
|
|
181
|
+
|
|
182
|
+
const remoteId = yield* selectRemoteId.pipe(
|
|
183
|
+
Effect.flatMap((rows) => {
|
|
184
|
+
const existing = rows[0]
|
|
185
|
+
if (existing !== undefined) {
|
|
186
|
+
return Effect.succeed(existing.remote_id as RemoteId)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const created = makeRemoteIdUnsafe()
|
|
190
|
+
return sql`
|
|
191
|
+
INSERT INTO ${remoteIdTableSql} (singleton, remote_id)
|
|
192
|
+
VALUES (1, ${created})
|
|
193
|
+
`.pipe(
|
|
194
|
+
Effect.catchIf(
|
|
195
|
+
(error: SqlError.SqlError) => error.reason._tag === "ConstraintError",
|
|
196
|
+
() => Effect.void
|
|
197
|
+
),
|
|
198
|
+
Effect.andThen(selectRemoteId),
|
|
199
|
+
Effect.map((rows) => rows[0]?.remote_id as RemoteId | undefined),
|
|
200
|
+
Effect.map((persisted) => persisted ?? created)
|
|
201
|
+
)
|
|
202
|
+
})
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
const pubsubs = yield* RcMap.make({
|
|
206
|
+
lookup: (_storeId: string) =>
|
|
207
|
+
Effect.acquireRelease(
|
|
208
|
+
PubSub.unbounded<RemoteEntry>(),
|
|
209
|
+
PubSub.shutdown
|
|
210
|
+
),
|
|
211
|
+
idleTimeToLive: "5 minutes"
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
const ensureStore = (storeId: string) =>
|
|
215
|
+
sql.onDialectOrElse({
|
|
216
|
+
pg: () =>
|
|
217
|
+
sql`
|
|
218
|
+
INSERT INTO ${storesTableSql} (store_id, next_sequence)
|
|
219
|
+
VALUES (${storeId}, 1)
|
|
220
|
+
ON CONFLICT (store_id) DO NOTHING
|
|
221
|
+
`,
|
|
222
|
+
mysql: () =>
|
|
223
|
+
sql`
|
|
224
|
+
INSERT INTO ${storesTableSql} (store_id, next_sequence)
|
|
225
|
+
VALUES (${storeId}, 1)
|
|
226
|
+
ON DUPLICATE KEY UPDATE store_id = store_id
|
|
227
|
+
`,
|
|
228
|
+
mssql: () =>
|
|
229
|
+
sql`
|
|
230
|
+
MERGE ${storesTableSql} WITH (HOLDLOCK) AS target
|
|
231
|
+
USING (SELECT ${storeId} AS store_id, 1 AS next_sequence) AS source
|
|
232
|
+
ON target.store_id = source.store_id
|
|
233
|
+
WHEN NOT MATCHED THEN
|
|
234
|
+
INSERT (store_id, next_sequence)
|
|
235
|
+
VALUES (source.store_id, source.next_sequence);
|
|
236
|
+
`,
|
|
237
|
+
orElse: () =>
|
|
238
|
+
sql`
|
|
239
|
+
INSERT INTO ${storesTableSql} (store_id, next_sequence)
|
|
240
|
+
VALUES (${storeId}, 1)
|
|
241
|
+
ON CONFLICT DO NOTHING
|
|
242
|
+
`
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
const lockStore = (storeId: string) =>
|
|
246
|
+
sql.onDialectOrElse({
|
|
247
|
+
pg: () =>
|
|
248
|
+
sql`
|
|
249
|
+
SELECT next_sequence
|
|
250
|
+
FROM ${storesTableSql}
|
|
251
|
+
WHERE store_id = ${storeId}
|
|
252
|
+
FOR UPDATE
|
|
253
|
+
`,
|
|
254
|
+
mysql: () =>
|
|
255
|
+
sql`
|
|
256
|
+
SELECT next_sequence
|
|
257
|
+
FROM ${storesTableSql}
|
|
258
|
+
WHERE store_id = ${storeId}
|
|
259
|
+
FOR UPDATE
|
|
260
|
+
`,
|
|
261
|
+
mssql: () =>
|
|
262
|
+
sql`
|
|
263
|
+
SELECT next_sequence
|
|
264
|
+
FROM ${storesTableSql} WITH (UPDLOCK, HOLDLOCK)
|
|
265
|
+
WHERE store_id = ${storeId}
|
|
266
|
+
`,
|
|
267
|
+
orElse: () =>
|
|
268
|
+
sql`
|
|
269
|
+
UPDATE ${storesTableSql}
|
|
270
|
+
SET next_sequence = next_sequence
|
|
271
|
+
WHERE store_id = ${storeId}
|
|
272
|
+
RETURNING next_sequence
|
|
273
|
+
`
|
|
274
|
+
}).pipe(
|
|
275
|
+
Effect.flatMap(decodeStoreSequence)
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
const setNextSequence = (storeId: string, nextSequence: number) =>
|
|
279
|
+
sql`
|
|
280
|
+
UPDATE ${storesTableSql}
|
|
281
|
+
SET next_sequence = ${nextSequence}
|
|
282
|
+
WHERE store_id = ${storeId}
|
|
283
|
+
`
|
|
284
|
+
|
|
285
|
+
const selectEntriesAfter = (storeId: string, startSequence: number) =>
|
|
286
|
+
sql`
|
|
287
|
+
SELECT sequence, entry_id, event, primary_key, payload
|
|
288
|
+
FROM ${entriesTableSql}
|
|
289
|
+
WHERE store_id = ${storeId} AND sequence >= ${startSequence}
|
|
290
|
+
ORDER BY sequence ASC
|
|
291
|
+
`.pipe(
|
|
292
|
+
Effect.flatMap(decodeRemoteEntries)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
const getSessionAuthBinding = (publicKey: string) =>
|
|
296
|
+
sql`
|
|
297
|
+
SELECT public_key, signing_public_key
|
|
298
|
+
FROM ${sessionAuthBindingsTableSql}
|
|
299
|
+
WHERE public_key = ${publicKey}
|
|
300
|
+
`.pipe(
|
|
301
|
+
Effect.flatMap(decodeSessionAuthBindings),
|
|
302
|
+
Effect.map((rows) => {
|
|
303
|
+
const row = rows[0]
|
|
304
|
+
return row === undefined ? undefined : row.signing_public_key as Uint8Array<ArrayBuffer>
|
|
305
|
+
}),
|
|
306
|
+
Effect.orDie
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
return EventLogServerUnencrypted.Storage.of({
|
|
310
|
+
getId: Effect.succeed(remoteId),
|
|
311
|
+
getOrCreateSessionAuthBinding: Effect.fnUntraced(
|
|
312
|
+
function*(publicKey, signingPublicKey) {
|
|
313
|
+
const existing = yield* getSessionAuthBinding(publicKey)
|
|
314
|
+
if (existing !== undefined) {
|
|
315
|
+
return existing
|
|
316
|
+
}
|
|
317
|
+
return yield* sql`
|
|
318
|
+
INSERT INTO ${sessionAuthBindingsTableSql} (public_key, signing_public_key)
|
|
319
|
+
VALUES (${publicKey}, ${signingPublicKey})
|
|
320
|
+
`.pipe(
|
|
321
|
+
Effect.as(signingPublicKey)
|
|
322
|
+
)
|
|
323
|
+
},
|
|
324
|
+
sql.withTransaction,
|
|
325
|
+
Effect.orDie
|
|
326
|
+
),
|
|
327
|
+
entriesAfter: (storeId, entry) =>
|
|
328
|
+
sql`
|
|
329
|
+
SELECT sequence, entry_id, event, primary_key, payload
|
|
330
|
+
FROM ${entriesTableSql}
|
|
331
|
+
WHERE store_id = ${storeId} AND entry_id >= ${entry.id}
|
|
332
|
+
ORDER BY sequence ASC
|
|
333
|
+
`.pipe(
|
|
334
|
+
Effect.flatMap(decodeRemoteEntries),
|
|
335
|
+
Effect.map(Arr.map((r) => r.entry)),
|
|
336
|
+
Effect.orDie
|
|
337
|
+
),
|
|
338
|
+
write: Effect.fnUntraced(
|
|
339
|
+
function*(storeId, entries) {
|
|
340
|
+
if (entries.length === 0) {
|
|
341
|
+
return []
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
yield* ensureStore(storeId)
|
|
345
|
+
const currentNextSequence = yield* lockStore(storeId)
|
|
346
|
+
|
|
347
|
+
const committed: Array<RemoteEntry> = []
|
|
348
|
+
let rowsForInsert: Array<{
|
|
349
|
+
readonly store_id: string
|
|
350
|
+
readonly sequence: number
|
|
351
|
+
readonly entry_id: Uint8Array
|
|
352
|
+
readonly event: string
|
|
353
|
+
readonly primary_key: string
|
|
354
|
+
readonly payload: Uint8Array
|
|
355
|
+
}> = []
|
|
356
|
+
|
|
357
|
+
for (let index = 0; index < entries.length; index++) {
|
|
358
|
+
const entry = entries[index]
|
|
359
|
+
const remoteSequence = currentNextSequence + index
|
|
360
|
+
committed.push(
|
|
361
|
+
new RemoteEntry({
|
|
362
|
+
remoteSequence,
|
|
363
|
+
entry
|
|
364
|
+
}, { disableChecks: true })
|
|
365
|
+
)
|
|
366
|
+
rowsForInsert.push({
|
|
367
|
+
store_id: storeId,
|
|
368
|
+
sequence: remoteSequence,
|
|
369
|
+
entry_id: entry.id,
|
|
370
|
+
event: entry.event,
|
|
371
|
+
primary_key: entry.primaryKey,
|
|
372
|
+
payload: entry.payload
|
|
373
|
+
})
|
|
374
|
+
if (rowsForInsert.length >= insertBatchSize) {
|
|
375
|
+
yield* sql`INSERT INTO ${entriesTableSql} ${sql.insert(rowsForInsert)}`
|
|
376
|
+
rowsForInsert = []
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (rowsForInsert.length > 0) {
|
|
380
|
+
yield* sql`INSERT INTO ${entriesTableSql} ${sql.insert(rowsForInsert)}`
|
|
381
|
+
}
|
|
382
|
+
const nextSequence = currentNextSequence + entries.length
|
|
383
|
+
yield* setNextSequence(storeId, nextSequence)
|
|
384
|
+
|
|
385
|
+
const pubsub = yield* RcMap.get(pubsubs, storeId)
|
|
386
|
+
yield* PubSub.publishAll(pubsub, committed)
|
|
387
|
+
|
|
388
|
+
return committed
|
|
389
|
+
},
|
|
390
|
+
Effect.scoped,
|
|
391
|
+
sql.withTransaction,
|
|
392
|
+
Effect.orDie
|
|
393
|
+
),
|
|
394
|
+
changes: Effect.fnUntraced(
|
|
395
|
+
function*({ storeId, startSequence, compactors }) {
|
|
396
|
+
const pubsub = yield* RcMap.get(pubsubs, storeId)
|
|
397
|
+
const subscription = yield* PubSub.subscribe(pubsub)
|
|
398
|
+
const backlog = yield* EventLogServerUnencrypted.compactBacklog({
|
|
399
|
+
compactors,
|
|
400
|
+
remoteEntries: yield* selectEntriesAfter(storeId, startSequence)
|
|
401
|
+
})
|
|
402
|
+
let watermark = backlog.length > 0 ? backlog[backlog.length - 1]!.remoteSequence : startSequence
|
|
403
|
+
|
|
404
|
+
return Stream.fromArray(backlog).pipe(
|
|
405
|
+
Stream.concat(
|
|
406
|
+
Stream.fromSubscription(subscription).pipe(
|
|
407
|
+
Stream.filter((entry) => entry.remoteSequence > watermark)
|
|
408
|
+
)
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
},
|
|
412
|
+
Effect.orDie,
|
|
413
|
+
Stream.unwrap
|
|
414
|
+
),
|
|
415
|
+
withTransaction: (effect) =>
|
|
416
|
+
sql.withTransaction(effect).pipe(
|
|
417
|
+
Effect.catchIf(SqlError.isSqlError, Effect.die)
|
|
418
|
+
)
|
|
419
|
+
})
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* @since 4.0.0
|
|
424
|
+
* @category layers
|
|
425
|
+
*/
|
|
426
|
+
export const layerStorage = (options?: {
|
|
427
|
+
readonly entryTablePrefix?: string
|
|
428
|
+
readonly remoteIdTable?: string
|
|
429
|
+
readonly insertBatchSize?: number
|
|
430
|
+
}): Layer.Layer<EventLogServerUnencrypted.Storage, SqlError.SqlError, SqlClient.SqlClient> =>
|
|
431
|
+
Layer.effect(EventLogServerUnencrypted.Storage)(makeStorage(options))
|
|
432
|
+
|
|
433
|
+
const EntrySql = Schema.Struct({
|
|
434
|
+
entry_id: EntryId,
|
|
435
|
+
event: Schema.String,
|
|
436
|
+
primary_key: Schema.String,
|
|
437
|
+
payload: Schema.Uint8Array
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
type EntrySql = Schema.Schema.Type<typeof EntrySql>
|
|
441
|
+
|
|
442
|
+
const SqlNumber = Schema.Union([Schema.Number, Schema.NumberFromString])
|
|
443
|
+
|
|
444
|
+
const RemoteEntrySql = Schema.Struct({
|
|
445
|
+
...EntrySql.fields,
|
|
446
|
+
sequence: SqlNumber
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
type RemoteEntrySql = Schema.Schema.Type<typeof RemoteEntrySql>
|
|
450
|
+
|
|
451
|
+
const StoreSequenceSql = Schema.Struct({
|
|
452
|
+
next_sequence: SqlNumber
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
const SessionAuthBindingSql = Schema.Struct({
|
|
456
|
+
public_key: Schema.String,
|
|
457
|
+
signing_public_key: Schema.Uint8Array
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
type SessionAuthBindingSql = Schema.Schema.Type<typeof SessionAuthBindingSql>
|
|
461
|
+
|
|
462
|
+
const decodeRemoteEntryRows = Schema.decodeUnknownEffect(Schema.mutable(Schema.Array(RemoteEntrySql)))
|
|
463
|
+
const decodeStoreSequenceRows = Schema.decodeUnknownEffect(Schema.Array(StoreSequenceSql))
|
|
464
|
+
const decodeSessionAuthBindingRows = Schema.decodeUnknownEffect(Schema.Array(SessionAuthBindingSql))
|
|
465
|
+
|
|
466
|
+
const toEntry = (row: EntrySql): Entry =>
|
|
467
|
+
new Entry({
|
|
468
|
+
id: row.entry_id,
|
|
469
|
+
event: row.event,
|
|
470
|
+
primaryKey: row.primary_key,
|
|
471
|
+
payload: row.payload
|
|
472
|
+
}, { disableChecks: true })
|
|
473
|
+
|
|
474
|
+
const toRemoteEntry = (row: RemoteEntrySql): RemoteEntry =>
|
|
475
|
+
new RemoteEntry({
|
|
476
|
+
remoteSequence: row.sequence,
|
|
477
|
+
entry: toEntry(row)
|
|
478
|
+
}, { disableChecks: true })
|
|
479
|
+
|
|
480
|
+
const decodeRemoteEntries = (
|
|
481
|
+
rows: unknown
|
|
482
|
+
): Effect.Effect<Array<RemoteEntry>, Schema.SchemaError> =>
|
|
483
|
+
decodeRemoteEntryRows(rows).pipe(
|
|
484
|
+
Effect.map((rows) => rows.map(toRemoteEntry))
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
const decodeStoreSequence = (rows: unknown): Effect.Effect<number, Schema.SchemaError> =>
|
|
488
|
+
decodeStoreSequenceRows(rows).pipe(
|
|
489
|
+
Effect.flatMap((rows) => {
|
|
490
|
+
const row = rows[0]
|
|
491
|
+
if (row === undefined) {
|
|
492
|
+
return Effect.die("SqlEventLogServerUnencrypted missing store sequence row")
|
|
493
|
+
}
|
|
494
|
+
return Effect.succeed(row.next_sequence)
|
|
495
|
+
})
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
const decodeSessionAuthBindings = (
|
|
499
|
+
rows: unknown
|
|
500
|
+
): Effect.Effect<ReadonlyArray<SessionAuthBindingSql>, Schema.SchemaError> => decodeSessionAuthBindingRows(rows)
|
|
@@ -29,6 +29,11 @@ export * as EventLog from "./EventLog.ts"
|
|
|
29
29
|
*/
|
|
30
30
|
export * as EventLogEncryption from "./EventLogEncryption.ts"
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @since 4.0.0
|
|
34
|
+
*/
|
|
35
|
+
export * as EventLogMessage from "./EventLogMessage.ts"
|
|
36
|
+
|
|
32
37
|
/**
|
|
33
38
|
* @since 4.0.0
|
|
34
39
|
*/
|
|
@@ -42,9 +47,29 @@ export * as EventLogServer from "./EventLogServer.ts"
|
|
|
42
47
|
/**
|
|
43
48
|
* @since 4.0.0
|
|
44
49
|
*/
|
|
45
|
-
export * as
|
|
50
|
+
export * as EventLogServerEncrypted from "./EventLogServerEncrypted.ts"
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @since 4.0.0
|
|
54
|
+
*/
|
|
55
|
+
export * as EventLogServerUnencrypted from "./EventLogServerUnencrypted.ts"
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @since 4.0.0
|
|
59
|
+
*/
|
|
60
|
+
export * as EventLogSessionAuth from "./EventLogSessionAuth.ts"
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @since 4.0.0
|
|
64
|
+
*/
|
|
65
|
+
export * as SqlEventJournal from "./SqlEventJournal.ts"
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @since 4.0.0
|
|
69
|
+
*/
|
|
70
|
+
export * as SqlEventLogServerEncrypted from "./SqlEventLogServerEncrypted.ts"
|
|
46
71
|
|
|
47
72
|
/**
|
|
48
73
|
* @since 4.0.0
|
|
49
74
|
*/
|
|
50
|
-
export * as
|
|
75
|
+
export * as SqlEventLogServerUnencrypted from "./SqlEventLogServerUnencrypted.ts"
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as Effect from "../../../Effect.ts"
|
|
2
|
+
import * as Redacted from "../../../Redacted.ts"
|
|
3
|
+
import type { Identity } from "../EventLog.ts"
|
|
4
|
+
|
|
5
|
+
const textEncoder = new TextEncoder()
|
|
6
|
+
|
|
7
|
+
const Ed25519PublicKeyLength = 32
|
|
8
|
+
|
|
9
|
+
const Ed25519Pkcs8SeedPrefix = Uint8Array.from([
|
|
10
|
+
0x30,
|
|
11
|
+
0x2e,
|
|
12
|
+
0x02,
|
|
13
|
+
0x01,
|
|
14
|
+
0x00,
|
|
15
|
+
0x30,
|
|
16
|
+
0x05,
|
|
17
|
+
0x06,
|
|
18
|
+
0x03,
|
|
19
|
+
0x2b,
|
|
20
|
+
0x65,
|
|
21
|
+
0x70,
|
|
22
|
+
0x04,
|
|
23
|
+
0x22,
|
|
24
|
+
0x04,
|
|
25
|
+
0x20
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
/** @internal */
|
|
29
|
+
export const EncryptionDerivationLabelV1 = "effect/eventlog/identity/v1/encryption"
|
|
30
|
+
|
|
31
|
+
/** @internal */
|
|
32
|
+
export const SigningDerivationLabelV1 = "effect/eventlog/identity/v1/signing"
|
|
33
|
+
|
|
34
|
+
/** @internal */
|
|
35
|
+
export interface IdentityRootSecretMaterial {
|
|
36
|
+
readonly encryptionKeyMaterial: Uint8Array<ArrayBuffer>
|
|
37
|
+
readonly encryptionKey: CryptoKey
|
|
38
|
+
readonly signingPublicKey: Uint8Array<ArrayBuffer>
|
|
39
|
+
readonly signingPrivateKey: Redacted.Redacted<Uint8Array<ArrayBuffer>>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const toArrayBuffer = (data: Uint8Array): ArrayBuffer => {
|
|
43
|
+
const copy = new Uint8Array(data.byteLength)
|
|
44
|
+
copy.set(data)
|
|
45
|
+
return copy.buffer
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const decodeBase64Url = (value: string): Uint8Array<ArrayBuffer> => {
|
|
49
|
+
const normalized = value.replaceAll("-", "+").replaceAll("_", "/")
|
|
50
|
+
const remainder = normalized.length % 4
|
|
51
|
+
const padded = remainder === 0 ? normalized : `${normalized}${"=".repeat(4 - remainder)}`
|
|
52
|
+
const decoded = atob(padded)
|
|
53
|
+
const bytes = new Uint8Array(decoded.length)
|
|
54
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
55
|
+
bytes[i] = decoded.charCodeAt(i)
|
|
56
|
+
}
|
|
57
|
+
return bytes
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const makeEd25519Pkcs8FromSeed = (seed: Uint8Array): Uint8Array<ArrayBuffer> => {
|
|
61
|
+
const key = new Uint8Array(Ed25519Pkcs8SeedPrefix.byteLength + seed.byteLength)
|
|
62
|
+
key.set(Ed25519Pkcs8SeedPrefix, 0)
|
|
63
|
+
key.set(seed, Ed25519Pkcs8SeedPrefix.byteLength)
|
|
64
|
+
return key
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const deriveSecretBytes = Effect.fnUntraced(function*(options: {
|
|
68
|
+
readonly crypto: Crypto
|
|
69
|
+
readonly rootSecret: Uint8Array
|
|
70
|
+
readonly label: string
|
|
71
|
+
}) {
|
|
72
|
+
const labelBytes = textEncoder.encode(options.label)
|
|
73
|
+
const derivationInput = new Uint8Array(labelBytes.byteLength + 1 + options.rootSecret.byteLength)
|
|
74
|
+
derivationInput.set(labelBytes, 0)
|
|
75
|
+
derivationInput[labelBytes.byteLength] = 0
|
|
76
|
+
derivationInput.set(options.rootSecret, labelBytes.byteLength + 1)
|
|
77
|
+
|
|
78
|
+
const digest = yield* Effect.promise(() => options.crypto.subtle.digest("SHA-256", toArrayBuffer(derivationInput)))
|
|
79
|
+
|
|
80
|
+
return new Uint8Array(digest)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
/** @internal */
|
|
84
|
+
export const deriveIdentityRootSecretMaterial = Effect.fnUntraced(function*(options: {
|
|
85
|
+
readonly crypto: Crypto
|
|
86
|
+
readonly rootSecret: Uint8Array
|
|
87
|
+
}) {
|
|
88
|
+
const encryptionKeyMaterial = yield* deriveSecretBytes({
|
|
89
|
+
crypto: options.crypto,
|
|
90
|
+
rootSecret: options.rootSecret,
|
|
91
|
+
label: EncryptionDerivationLabelV1
|
|
92
|
+
})
|
|
93
|
+
const signingSeed = yield* deriveSecretBytes({
|
|
94
|
+
crypto: options.crypto,
|
|
95
|
+
rootSecret: options.rootSecret,
|
|
96
|
+
label: SigningDerivationLabelV1
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const signingPrivateKeyBytes = makeEd25519Pkcs8FromSeed(signingSeed)
|
|
100
|
+
|
|
101
|
+
const encryptionKey = yield* Effect.promise(() =>
|
|
102
|
+
options.crypto.subtle.importKey("raw", toArrayBuffer(encryptionKeyMaterial), "AES-GCM", true, [
|
|
103
|
+
"encrypt",
|
|
104
|
+
"decrypt"
|
|
105
|
+
])
|
|
106
|
+
)
|
|
107
|
+
const signingPrivateKey = yield* Effect.promise(() =>
|
|
108
|
+
options.crypto.subtle.importKey("pkcs8", toArrayBuffer(signingPrivateKeyBytes), "Ed25519", true, ["sign"])
|
|
109
|
+
)
|
|
110
|
+
const signingJwk = yield* Effect.promise(() => options.crypto.subtle.exportKey("jwk", signingPrivateKey))
|
|
111
|
+
|
|
112
|
+
if (typeof signingJwk.x !== "string") {
|
|
113
|
+
return yield* Effect.die(new Error("Unable to export deterministic Ed25519 public key"))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const signingPublicKey = decodeBase64Url(signingJwk.x)
|
|
117
|
+
|
|
118
|
+
if (signingPublicKey.byteLength !== Ed25519PublicKeyLength) {
|
|
119
|
+
return yield* Effect.die(
|
|
120
|
+
new Error(`Expected derived signing public key to be ${Ed25519PublicKeyLength} bytes`)
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
encryptionKeyMaterial,
|
|
126
|
+
encryptionKey,
|
|
127
|
+
signingPublicKey,
|
|
128
|
+
signingPrivateKey: Redacted.make(signingPrivateKeyBytes)
|
|
129
|
+
} satisfies IdentityRootSecretMaterial
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
/** @internal */
|
|
133
|
+
export const makeGetIdentityRootSecretMaterial = (crypto: Crypto) => {
|
|
134
|
+
const cache = new WeakMap<Identity["Service"], IdentityRootSecretMaterial>()
|
|
135
|
+
|
|
136
|
+
return Effect.fnUntraced(function*(identity: Identity["Service"]) {
|
|
137
|
+
const cached = cache.get(identity)
|
|
138
|
+
if (cached !== undefined) {
|
|
139
|
+
return cached
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const derived = yield* deriveIdentityRootSecretMaterial({
|
|
143
|
+
crypto,
|
|
144
|
+
rootSecret: Redacted.value(identity.privateKey)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
yield* Effect.sync(() => {
|
|
148
|
+
cache.set(identity, derived)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
return derived
|
|
152
|
+
})
|
|
153
|
+
}
|