effect 4.0.0-beta.44 → 4.0.0-beta.46
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
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 4.0.0
|
|
3
3
|
*/
|
|
4
|
+
import * as Cache from "../../Cache.ts"
|
|
4
5
|
import * as Context from "../../Context.ts"
|
|
5
6
|
import * as Data from "../../Data.ts"
|
|
6
|
-
import * as Deferred from "../../Deferred.ts"
|
|
7
7
|
import * as Effect from "../../Effect.ts"
|
|
8
|
-
import * as Exit from "../../Exit.ts"
|
|
9
8
|
import * as Layer from "../../Layer.ts"
|
|
9
|
+
import * as Predicate from "../../Predicate.ts"
|
|
10
10
|
import * as Queue from "../../Queue.ts"
|
|
11
|
-
import * as
|
|
12
|
-
import * as
|
|
13
|
-
import * as Schema from "../../Schema.ts"
|
|
11
|
+
import * as Redacted from "../../Redacted.ts"
|
|
12
|
+
import type * as Schema from "../../Schema.ts"
|
|
14
13
|
import type * as Scope from "../../Scope.ts"
|
|
15
|
-
import * as
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import type {
|
|
19
|
-
import {
|
|
14
|
+
import * as RpcClient from "../rpc/RpcClient.ts"
|
|
15
|
+
import type { RpcClientError } from "../rpc/RpcClientError.ts"
|
|
16
|
+
import type * as RpcGroup from "../rpc/RpcGroup.ts"
|
|
17
|
+
import type { Entry, RemoteEntry, RemoteId } from "./EventJournal.ts"
|
|
18
|
+
import { type Identity, Registry } from "./EventLog.ts"
|
|
19
|
+
import { EventLogEncryption, layerSubtle } from "./EventLogEncryption.ts"
|
|
20
|
+
import {
|
|
21
|
+
Authenticate,
|
|
22
|
+
ChangesRpc,
|
|
23
|
+
ChunkedMessage,
|
|
24
|
+
type EventLogProtocolError,
|
|
25
|
+
EventLogRemoteRpcs,
|
|
26
|
+
type HelloResponse,
|
|
27
|
+
type StoreId,
|
|
28
|
+
WriteEntries,
|
|
29
|
+
WriteEntriesUnencrypted
|
|
30
|
+
} from "./EventLogMessage.ts"
|
|
31
|
+
import { encodeSessionAuthPayload, signSessionAuthPayloadBytes } from "./EventLogSessionAuth.ts"
|
|
32
|
+
import { makeGetIdentityRootSecretMaterial } from "./internal/identityRootSecretDerivation.ts"
|
|
20
33
|
|
|
21
34
|
/**
|
|
22
35
|
* @since 4.0.0
|
|
@@ -24,217 +37,21 @@ import { EncryptedEntry, EncryptedRemoteEntry, EventLogEncryption, layerSubtle }
|
|
|
24
37
|
*/
|
|
25
38
|
export class EventLogRemote extends Context.Service<EventLogRemote, {
|
|
26
39
|
readonly id: RemoteId
|
|
27
|
-
readonly changes: (
|
|
28
|
-
identity: Identity["Service"]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
readonly changes: (options: {
|
|
41
|
+
readonly identity: Identity["Service"]
|
|
42
|
+
readonly storeId: StoreId
|
|
43
|
+
readonly startSequence: number
|
|
44
|
+
}) => Effect.Effect<Queue.Dequeue<RemoteEntry, EventLogRemoteError>, never, Scope.Scope>
|
|
45
|
+
readonly write: (options: {
|
|
46
|
+
readonly identity: Identity["Service"]
|
|
47
|
+
readonly storeId: StoreId
|
|
48
|
+
readonly entries: ReadonlyArray<Entry>
|
|
49
|
+
}) => Effect.Effect<void, EventLogRemoteError>
|
|
50
|
+
readonly whenAuthenticated: <A, E, R>(
|
|
51
|
+
effect: Effect.Effect<A, E, R>
|
|
52
|
+
) => Effect.Effect<A, E | EventLogRemoteError, R | Identity>
|
|
32
53
|
}>()("effect/eventlog/EventLogRemote") {}
|
|
33
54
|
|
|
34
|
-
/**
|
|
35
|
-
* @since 4.0.0
|
|
36
|
-
* @category protocol
|
|
37
|
-
*/
|
|
38
|
-
export class Hello extends Schema.Class<Hello>("effect/eventlog/EventLogRemote/Hello")({
|
|
39
|
-
_tag: Schema.tag("Hello"),
|
|
40
|
-
remoteId: RemoteId
|
|
41
|
-
}) {}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @since 4.0.0
|
|
45
|
-
* @category protocol
|
|
46
|
-
*/
|
|
47
|
-
export class ChunkedMessage extends Schema.Class<ChunkedMessage>("effect/eventlog/EventLogRemote/ChunkedMessage")({
|
|
48
|
-
_tag: Schema.tag("ChunkedMessage"),
|
|
49
|
-
id: Schema.Number,
|
|
50
|
-
part: Schema.Tuple([Schema.Number, Schema.Number]),
|
|
51
|
-
data: Schema.Uint8Array
|
|
52
|
-
}) {
|
|
53
|
-
/**
|
|
54
|
-
* @since 4.0.0
|
|
55
|
-
*/
|
|
56
|
-
static split(id: number, data: Uint8Array): ReadonlyArray<ChunkedMessage> {
|
|
57
|
-
const parts = Math.ceil(data.byteLength / constChunkSize)
|
|
58
|
-
const result: Array<ChunkedMessage> = new Array(parts)
|
|
59
|
-
for (let i = 0; i < parts; i++) {
|
|
60
|
-
const start = i * constChunkSize
|
|
61
|
-
const end = Math.min((i + 1) * constChunkSize, data.byteLength)
|
|
62
|
-
result[i] = new ChunkedMessage({
|
|
63
|
-
_tag: "ChunkedMessage",
|
|
64
|
-
id,
|
|
65
|
-
part: [i, parts],
|
|
66
|
-
data: data.subarray(start, end)
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
return result
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @since 4.0.0
|
|
74
|
-
*/
|
|
75
|
-
static join(
|
|
76
|
-
map: Map<number, {
|
|
77
|
-
readonly parts: Array<Uint8Array>
|
|
78
|
-
count: number
|
|
79
|
-
bytes: number
|
|
80
|
-
}>,
|
|
81
|
-
part: ChunkedMessage
|
|
82
|
-
): Uint8Array | undefined {
|
|
83
|
-
const [index, total] = part.part
|
|
84
|
-
let entry = map.get(part.id)
|
|
85
|
-
if (!entry) {
|
|
86
|
-
entry = {
|
|
87
|
-
parts: new Array(total),
|
|
88
|
-
count: 0,
|
|
89
|
-
bytes: 0
|
|
90
|
-
}
|
|
91
|
-
map.set(part.id, entry)
|
|
92
|
-
}
|
|
93
|
-
entry.parts[index] = part.data
|
|
94
|
-
entry.count++
|
|
95
|
-
entry.bytes += part.data.byteLength
|
|
96
|
-
if (entry.count !== total) {
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
const data = new Uint8Array(entry.bytes)
|
|
100
|
-
let offset = 0
|
|
101
|
-
for (const part of entry.parts) {
|
|
102
|
-
data.set(part, offset)
|
|
103
|
-
offset += part.byteLength
|
|
104
|
-
}
|
|
105
|
-
map.delete(part.id)
|
|
106
|
-
return data
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @since 4.0.0
|
|
112
|
-
* @category protocol
|
|
113
|
-
*/
|
|
114
|
-
export class WriteEntries extends Schema.Class<WriteEntries>("effect/eventlog/EventLogRemote/WriteEntries")({
|
|
115
|
-
_tag: Schema.tag("WriteEntries"),
|
|
116
|
-
publicKey: Schema.String,
|
|
117
|
-
id: Schema.Number,
|
|
118
|
-
iv: Schema.Uint8Array,
|
|
119
|
-
encryptedEntries: Schema.Array(EncryptedEntry)
|
|
120
|
-
}) {}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* @since 4.0.0
|
|
124
|
-
* @category protocol
|
|
125
|
-
*/
|
|
126
|
-
export class Ack extends Schema.Class<Ack>("effect/eventlog/EventLogRemote/Ack")({
|
|
127
|
-
_tag: Schema.tag("Ack"),
|
|
128
|
-
id: Schema.Number,
|
|
129
|
-
sequenceNumbers: Schema.Array(Schema.Number)
|
|
130
|
-
}) {}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* @since 4.0.0
|
|
134
|
-
* @category protocol
|
|
135
|
-
*/
|
|
136
|
-
export class RequestChanges extends Schema.Class<RequestChanges>("effect/eventlog/EventLogRemote/RequestChanges")({
|
|
137
|
-
_tag: Schema.tag("RequestChanges"),
|
|
138
|
-
publicKey: Schema.String,
|
|
139
|
-
startSequence: Schema.Number
|
|
140
|
-
}) {}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* @since 4.0.0
|
|
144
|
-
* @category protocol
|
|
145
|
-
*/
|
|
146
|
-
export class Changes extends Schema.Class<Changes>("effect/eventlog/EventLogRemote/Changes")({
|
|
147
|
-
_tag: Schema.tag("Changes"),
|
|
148
|
-
publicKey: Schema.String,
|
|
149
|
-
entries: Schema.Array(EncryptedRemoteEntry)
|
|
150
|
-
}) {}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @since 4.0.0
|
|
154
|
-
* @category protocol
|
|
155
|
-
*/
|
|
156
|
-
export class StopChanges extends Schema.Class<StopChanges>("effect/eventlog/EventLogRemote/StopChanges")({
|
|
157
|
-
_tag: Schema.tag("StopChanges"),
|
|
158
|
-
publicKey: Schema.String
|
|
159
|
-
}) {}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* @since 4.0.0
|
|
163
|
-
* @category protocol
|
|
164
|
-
*/
|
|
165
|
-
export class Ping extends Schema.Class<Ping>("effect/eventlog/EventLogRemote/Ping")({
|
|
166
|
-
_tag: Schema.tag("Ping"),
|
|
167
|
-
id: Schema.Number
|
|
168
|
-
}) {}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* @since 4.0.0
|
|
172
|
-
* @category protocol
|
|
173
|
-
*/
|
|
174
|
-
export class Pong extends Schema.Class<Pong>("effect/eventlog/EventLogRemote/Pong")({
|
|
175
|
-
_tag: Schema.tag("Pong"),
|
|
176
|
-
id: Schema.Number
|
|
177
|
-
}) {}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* @since 4.0.0
|
|
181
|
-
* @category protocol
|
|
182
|
-
*/
|
|
183
|
-
export const ProtocolRequest = Schema.Union([WriteEntries, RequestChanges, StopChanges, ChunkedMessage, Ping])
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* @since 4.0.0
|
|
187
|
-
* @category protocol
|
|
188
|
-
*/
|
|
189
|
-
export const ProtocolRequestMsgpack = Msgpack.schema(ProtocolRequest)
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* @since 4.0.0
|
|
193
|
-
* @category protocol
|
|
194
|
-
*/
|
|
195
|
-
export const decodeRequest = Schema.decodeUnknownEffect(ProtocolRequestMsgpack)
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* @since 4.0.0
|
|
199
|
-
* @category protocol
|
|
200
|
-
*/
|
|
201
|
-
export const encodeRequest = Schema.encodeUnknownEffect(ProtocolRequestMsgpack)
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* @since 4.0.0
|
|
205
|
-
* @category protocol
|
|
206
|
-
*/
|
|
207
|
-
export const ProtocolResponse = Schema.Union([Hello, Ack, Changes, ChunkedMessage, Pong])
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* @since 4.0.0
|
|
211
|
-
* @category protocol
|
|
212
|
-
*/
|
|
213
|
-
export const ProtocolResponseMsgpack = Msgpack.schema(ProtocolResponse)
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* @since 4.0.0
|
|
217
|
-
* @category protocol
|
|
218
|
-
*/
|
|
219
|
-
export const decodeResponse = Schema.decodeUnknownEffect(ProtocolResponseMsgpack)
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* @since 4.0.0
|
|
223
|
-
* @category protocol
|
|
224
|
-
*/
|
|
225
|
-
export const encodeResponse = Schema.encodeUnknownEffect(ProtocolResponseMsgpack)
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* @since 4.0.0
|
|
229
|
-
* @category change
|
|
230
|
-
*/
|
|
231
|
-
export class RemoteAdditions extends Schema.Class<RemoteAdditions>("effect/eventlog/EventLogRemote/RemoteAdditions")({
|
|
232
|
-
_tag: Schema.tag("RemoteAdditions"),
|
|
233
|
-
entries: Schema.Array(RemoteEntry)
|
|
234
|
-
}) {}
|
|
235
|
-
|
|
236
|
-
const constChunkSize = 512_000
|
|
237
|
-
|
|
238
55
|
/**
|
|
239
56
|
* @since 4.0.0
|
|
240
57
|
* @category errors
|
|
@@ -244,230 +61,266 @@ export class EventLogRemoteError extends Data.TaggedError("EventLogRemoteError")
|
|
|
244
61
|
readonly cause: unknown
|
|
245
62
|
}> {}
|
|
246
63
|
|
|
64
|
+
const getIdentityRootSecretMaterial = makeGetIdentityRootSecretMaterial(globalThis.crypto)
|
|
65
|
+
|
|
66
|
+
const makeAuthenticate = Effect.fnUntraced(function*(options: {
|
|
67
|
+
readonly identity: Identity["Service"]
|
|
68
|
+
readonly hello: HelloResponse
|
|
69
|
+
}) {
|
|
70
|
+
const rootSecretMaterial = yield* getIdentityRootSecretMaterial(options.identity)
|
|
71
|
+
const payload = yield* encodeSessionAuthPayload({
|
|
72
|
+
remoteId: options.hello.remoteId,
|
|
73
|
+
challenge: options.hello.challenge,
|
|
74
|
+
publicKey: options.identity.publicKey,
|
|
75
|
+
signingPublicKey: rootSecretMaterial.signingPublicKey
|
|
76
|
+
})
|
|
77
|
+
const signature = yield* signSessionAuthPayloadBytes({
|
|
78
|
+
payload,
|
|
79
|
+
signingPrivateKey: Redacted.value(rootSecretMaterial.signingPrivateKey)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return new Authenticate({
|
|
83
|
+
publicKey: options.identity.publicKey,
|
|
84
|
+
signingPublicKey: rootSecretMaterial.signingPublicKey,
|
|
85
|
+
signature,
|
|
86
|
+
algorithm: "Ed25519"
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
247
90
|
/**
|
|
248
91
|
* @since 4.0.0
|
|
249
|
-
* @category
|
|
92
|
+
* @category RpcClient
|
|
250
93
|
*/
|
|
251
|
-
export
|
|
94
|
+
export class EventLogRemoteClient extends Context.Service<
|
|
95
|
+
EventLogRemoteClient,
|
|
96
|
+
RpcClient.RpcClient<RpcGroup.Rpcs<typeof EventLogRemoteRpcs>, RpcClientError>
|
|
97
|
+
>()(
|
|
98
|
+
"effect/unstable/eventlog/EventLogRemote/EventLogRemoteClient"
|
|
99
|
+
) {
|
|
100
|
+
static readonly layer = Layer.effect(
|
|
101
|
+
EventLogRemoteClient,
|
|
102
|
+
RpcClient.make(EventLogRemoteRpcs, {
|
|
103
|
+
disableTracing: true
|
|
104
|
+
})
|
|
105
|
+
)
|
|
106
|
+
}
|
|
252
107
|
|
|
253
108
|
/**
|
|
254
109
|
* @since 4.0.0
|
|
255
110
|
* @category constructors
|
|
256
111
|
*/
|
|
257
|
-
export const
|
|
258
|
-
readonly
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
112
|
+
export const makeWith = Effect.fnUntraced(function*({ encodeWrite, decodeChanges }: {
|
|
113
|
+
readonly encodeWrite: (options: {
|
|
114
|
+
readonly identity: Identity["Service"]
|
|
115
|
+
readonly entries: ReadonlyArray<Entry>
|
|
116
|
+
readonly storeId: StoreId
|
|
117
|
+
}) => Effect.Effect<Uint8Array<ArrayBuffer>, Schema.SchemaError>
|
|
118
|
+
readonly decodeChanges: (
|
|
119
|
+
identity: Identity["Service"],
|
|
120
|
+
data: Uint8Array<ArrayBuffer>
|
|
121
|
+
) => Effect.Effect<ReadonlyArray<RemoteEntry>, Schema.SchemaError>
|
|
122
|
+
}): Effect.fn.Return<EventLogRemote["Service"], EventLogRemoteError, Scope.Scope | EventLogRemoteClient | Registry> {
|
|
123
|
+
const client = yield* EventLogRemoteClient
|
|
124
|
+
const registry = yield* Registry
|
|
125
|
+
|
|
126
|
+
let hello: HelloResponse | null = yield* client["EventLog.Hello"]().pipe(
|
|
127
|
+
Effect.mapError((cause) => new EventLogRemoteError({ method: "hello", cause }))
|
|
128
|
+
)
|
|
264
129
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
130
|
+
const identities = new Map<string, Identity["Service"]>()
|
|
131
|
+
const ensureIdentity = (identity: Identity["Service"]) => {
|
|
132
|
+
let entry = identities.get(identity.publicKey)
|
|
133
|
+
if (!entry) {
|
|
134
|
+
entry = identity
|
|
135
|
+
identities.set(identity.publicKey, entry)
|
|
136
|
+
}
|
|
137
|
+
return entry
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const authCache = yield* Cache.make({
|
|
141
|
+
lookup: Effect.fnUntraced(function*(publicKey: string) {
|
|
142
|
+
const identity = identities.get(publicKey)!
|
|
143
|
+
hello ??= yield* client["EventLog.Hello"]().pipe(
|
|
144
|
+
Effect.mapError((cause) => new EventLogRemoteError({ method: "hello", cause }))
|
|
145
|
+
)
|
|
146
|
+
const authenticate = yield* makeAuthenticate({
|
|
147
|
+
identity,
|
|
148
|
+
hello
|
|
275
149
|
})
|
|
150
|
+
yield* client["EventLog.Authenticate"](authenticate)
|
|
151
|
+
}, Effect.mapError((cause) => new EventLogRemoteError({ method: "authenticate", cause }))),
|
|
152
|
+
capacity: Number.MAX_SAFE_INTEGER
|
|
153
|
+
})
|
|
276
154
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
readonly publicKey: string
|
|
282
|
-
}>()
|
|
283
|
-
const chunks = new Map<number, {
|
|
284
|
-
readonly parts: Array<Uint8Array>
|
|
285
|
-
count: number
|
|
286
|
-
bytes: number
|
|
287
|
-
}>()
|
|
155
|
+
const ensureAuthenticated = (identity: Identity["Service"]) => {
|
|
156
|
+
ensureIdentity(identity)
|
|
157
|
+
return Cache.get(authCache, identity.publicKey)
|
|
158
|
+
}
|
|
288
159
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
160
|
+
const retryForbidden = <A, E, R>(
|
|
161
|
+
effect: Effect.Effect<A, E, R>,
|
|
162
|
+
options: {
|
|
163
|
+
readonly identity: Identity["Service"]
|
|
164
|
+
}
|
|
165
|
+
) =>
|
|
166
|
+
Effect.retry(effect, {
|
|
167
|
+
while(e) {
|
|
168
|
+
hello = null
|
|
169
|
+
const isForbidden = Predicate.isTagged(e, "EventLogProtocolError") &&
|
|
170
|
+
(e as any as EventLogProtocolError).code === "Forbidden"
|
|
171
|
+
return Cache.invalidate(authCache, options.identity.publicKey).pipe(
|
|
172
|
+
Effect.as(isForbidden)
|
|
297
173
|
)
|
|
174
|
+
},
|
|
175
|
+
times: 5
|
|
298
176
|
})
|
|
299
|
-
const identities = new Map<string, Identity["Service"]>()
|
|
300
|
-
const badPing = yield* Deferred.make<never, Error>()
|
|
301
|
-
const remoteId = yield* Deferred.make<RemoteId>()
|
|
302
177
|
|
|
303
|
-
|
|
304
|
-
let latestPong = 0
|
|
178
|
+
let chunkedIdCounter = 0
|
|
305
179
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
180
|
+
const remote = EventLogRemote.of({
|
|
181
|
+
id: hello.remoteId,
|
|
182
|
+
write: Effect.fnUntraced(
|
|
183
|
+
function*(options) {
|
|
184
|
+
yield* ensureAuthenticated(options.identity)
|
|
185
|
+
const encoded = yield* encodeWrite(options)
|
|
186
|
+
if (encoded.byteLength <= ChunkedMessage.chunkSize) {
|
|
187
|
+
return yield* client["EventLog.WriteSingle"]({ data: encoded })
|
|
188
|
+
}
|
|
189
|
+
for (const part of ChunkedMessage.split(chunkedIdCounter++, encoded)) {
|
|
190
|
+
yield* client["EventLog.WriteChunked"](part)
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
retryForbidden,
|
|
194
|
+
Effect.mapError((cause) => new EventLogRemoteError({ method: "write", cause }))
|
|
195
|
+
),
|
|
196
|
+
changes: Effect.fnUntraced(function*(options) {
|
|
197
|
+
const outgoing = yield* Queue.make<RemoteEntry, EventLogRemoteError>()
|
|
198
|
+
|
|
199
|
+
yield* Effect.gen(function*() {
|
|
200
|
+
yield* ensureAuthenticated(options.identity)
|
|
201
|
+
|
|
202
|
+
const chunkedState = ChunkedMessage.initialJoinState()
|
|
203
|
+
const incoming = yield* client["EventLog.Changes"]({
|
|
204
|
+
publicKey: options.identity.publicKey,
|
|
205
|
+
storeId: options.storeId,
|
|
206
|
+
startSequence: options.startSequence
|
|
207
|
+
}, { asQueue: true })
|
|
208
|
+
|
|
209
|
+
while (true) {
|
|
210
|
+
const parts = yield* Queue.takeAll(incoming)
|
|
211
|
+
for (let i = 0; i < parts.length; i++) {
|
|
212
|
+
const part = parts[i]
|
|
213
|
+
if (part._tag === "Single") {
|
|
214
|
+
yield* Queue.offerAll(outgoing, yield* decodeChanges(options.identity, part.data))
|
|
215
|
+
continue
|
|
216
|
+
}
|
|
217
|
+
const data = ChunkedMessage.join(chunkedState, part)
|
|
218
|
+
if (!data) continue
|
|
219
|
+
yield* Queue.offerAll(outgoing, yield* decodeChanges(options.identity, data))
|
|
220
|
+
}
|
|
310
221
|
}
|
|
311
|
-
return writeRequest(new Ping({ id: ++latestPing }))
|
|
312
222
|
}).pipe(
|
|
313
|
-
|
|
314
|
-
Effect.
|
|
315
|
-
|
|
316
|
-
|
|
223
|
+
(effect) => retryForbidden(effect, options),
|
|
224
|
+
Effect.mapError((cause) => {
|
|
225
|
+
if (cause._tag === "EventLogRemoteError") {
|
|
226
|
+
return cause
|
|
227
|
+
}
|
|
228
|
+
return new EventLogRemoteError({
|
|
229
|
+
method: "changes",
|
|
230
|
+
cause
|
|
231
|
+
})
|
|
232
|
+
}),
|
|
233
|
+
Effect.catchCause((cause) => Queue.failCause(outgoing, cause)),
|
|
317
234
|
Effect.forkScoped
|
|
318
235
|
)
|
|
319
|
-
}
|
|
320
236
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
case "Ack": {
|
|
327
|
-
return Effect.gen(function*() {
|
|
328
|
-
const entry = pending.get(res.id)
|
|
329
|
-
if (!entry) return
|
|
330
|
-
pending.delete(res.id)
|
|
331
|
-
const { deferred, entries, publicKey } = entry
|
|
332
|
-
const remoteEntries = res.sequenceNumbers.map((sequenceNumber, i) => {
|
|
333
|
-
const entry = entries[i]
|
|
334
|
-
return new RemoteEntry({
|
|
335
|
-
remoteSequence: sequenceNumber,
|
|
336
|
-
entry
|
|
337
|
-
})
|
|
338
|
-
})
|
|
339
|
-
const queue = yield* RcMap.get(subscriptions, publicKey)
|
|
340
|
-
yield* Queue.offerAll(queue, remoteEntries)
|
|
341
|
-
yield* Deferred.done(deferred, Exit.void)
|
|
342
|
-
}).pipe(Effect.scoped)
|
|
343
|
-
}
|
|
344
|
-
case "Pong": {
|
|
345
|
-
latestPong = res.id
|
|
346
|
-
if (res.id === latestPing) {
|
|
347
|
-
return Effect.void
|
|
348
|
-
}
|
|
349
|
-
return Deferred.fail(badPing, new Error("Pong id mismatch")).pipe(
|
|
350
|
-
Effect.asVoid
|
|
351
|
-
)
|
|
352
|
-
}
|
|
353
|
-
case "Changes": {
|
|
354
|
-
return Effect.gen(function*() {
|
|
355
|
-
const queue = yield* RcMap.get(subscriptions, res.publicKey)
|
|
356
|
-
const identity = identities.get(res.publicKey)
|
|
357
|
-
if (!identity) {
|
|
358
|
-
return
|
|
359
|
-
}
|
|
360
|
-
const entries = yield* encryption.decrypt(identity, res.entries)
|
|
361
|
-
yield* Queue.offerAll(queue, entries)
|
|
362
|
-
}).pipe(Effect.scoped)
|
|
363
|
-
}
|
|
364
|
-
case "ChunkedMessage": {
|
|
365
|
-
const data = ChunkedMessage.join(chunks, res)
|
|
366
|
-
if (!data) return Effect.void
|
|
367
|
-
return Effect.scoped(
|
|
368
|
-
Effect.flatMap(decodeResponse(data), handleMessage)
|
|
369
|
-
)
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
237
|
+
return outgoing
|
|
238
|
+
}),
|
|
239
|
+
whenAuthenticated: (effect) =>
|
|
240
|
+
IdentityService.use((identity) => Effect.flatMap(ensureAuthenticated(identity), () => effect))
|
|
241
|
+
})
|
|
373
242
|
|
|
374
|
-
|
|
375
|
-
Effect.raceFirst(Deferred.await(badPing)),
|
|
376
|
-
Effect.tapCause(Effect.logDebug),
|
|
377
|
-
Effect.retry({
|
|
378
|
-
schedule: Schedule.exponential(100).pipe(
|
|
379
|
-
Schedule.either(Schedule.spaced(5000))
|
|
380
|
-
)
|
|
381
|
-
}),
|
|
382
|
-
Effect.annotateLogs({
|
|
383
|
-
service: "EventLogRemote",
|
|
384
|
-
method: "fromSocket"
|
|
385
|
-
}),
|
|
386
|
-
Effect.forkScoped,
|
|
387
|
-
Effect.interruptible
|
|
388
|
-
)
|
|
243
|
+
yield* registry.registerRemote(remote)
|
|
389
244
|
|
|
390
|
-
|
|
245
|
+
return remote
|
|
246
|
+
})
|
|
391
247
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
Effect.gen(function*() {
|
|
396
|
-
const encrypted = yield* encryption.encrypt(identity, entries)
|
|
397
|
-
const deferred = yield* Deferred.make<void>()
|
|
398
|
-
const id = pendingCounter++
|
|
399
|
-
pending.set(id, {
|
|
400
|
-
entries,
|
|
401
|
-
deferred,
|
|
402
|
-
publicKey: identity.publicKey
|
|
403
|
-
})
|
|
404
|
-
yield* Effect.orDie(writeRequest(
|
|
405
|
-
new WriteEntries({
|
|
406
|
-
publicKey: identity.publicKey,
|
|
407
|
-
id,
|
|
408
|
-
iv: encrypted.iv,
|
|
409
|
-
encryptedEntries: encrypted.encryptedEntries.map((encryptedEntry, i) => ({
|
|
410
|
-
entryId: entries[i].id,
|
|
411
|
-
encryptedEntry
|
|
412
|
-
}))
|
|
413
|
-
})
|
|
414
|
-
))
|
|
415
|
-
yield* Deferred.await(deferred)
|
|
416
|
-
}),
|
|
417
|
-
changes: (identity, startSequence) =>
|
|
418
|
-
Effect.gen(function*() {
|
|
419
|
-
const queue = yield* RcMap.get(subscriptions, identity.publicKey)
|
|
420
|
-
identities.set(identity.publicKey, identity)
|
|
421
|
-
yield* Effect.orDie(writeRequest(
|
|
422
|
-
new RequestChanges({
|
|
423
|
-
publicKey: identity.publicKey,
|
|
424
|
-
startSequence
|
|
425
|
-
})
|
|
426
|
-
))
|
|
427
|
-
return queue
|
|
428
|
-
})
|
|
429
|
-
}
|
|
430
|
-
})
|
|
248
|
+
class IdentityService extends Context.Service<Identity, Identity["Service"]>()(
|
|
249
|
+
"effect/eventlog/EventLog/Identity" satisfies Identity["key"]
|
|
250
|
+
) {}
|
|
431
251
|
|
|
432
252
|
/**
|
|
433
253
|
* @since 4.0.0
|
|
434
254
|
* @category constructors
|
|
435
255
|
*/
|
|
436
|
-
export const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
256
|
+
export const makeEncrypted = Effect.gen(function*(): Effect.fn.Return<
|
|
257
|
+
EventLogRemote["Service"],
|
|
258
|
+
EventLogRemoteError,
|
|
259
|
+
Scope.Scope | EventLogRemoteClient | EventLogEncryption | Registry
|
|
260
|
+
> {
|
|
261
|
+
const encryption = yield* EventLogEncryption
|
|
262
|
+
|
|
263
|
+
return yield* makeWith({
|
|
264
|
+
encodeWrite: (options) =>
|
|
265
|
+
encryption.encrypt(options.identity, options.entries).pipe(
|
|
266
|
+
Effect.flatMap((msg) =>
|
|
267
|
+
new WriteEntries({
|
|
268
|
+
publicKey: options.identity.publicKey,
|
|
269
|
+
storeId: options.storeId,
|
|
270
|
+
iv: msg.iv,
|
|
271
|
+
encryptedEntries: msg.encryptedEntries.map((entry, i) => ({
|
|
272
|
+
entryId: options.entries[i].id,
|
|
273
|
+
encryptedEntry: entry
|
|
274
|
+
}))
|
|
275
|
+
}).encoded
|
|
276
|
+
)
|
|
277
|
+
),
|
|
278
|
+
decodeChanges: (identity, data) =>
|
|
279
|
+
ChangesRpc.decodeEncrypted(data).pipe(
|
|
280
|
+
Effect.flatMap((entries) => encryption.decrypt(identity, entries))
|
|
281
|
+
)
|
|
447
282
|
})
|
|
283
|
+
})
|
|
448
284
|
|
|
449
285
|
/**
|
|
450
286
|
* @since 4.0.0
|
|
451
|
-
* @category
|
|
287
|
+
* @category constructors
|
|
452
288
|
*/
|
|
453
|
-
export const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
289
|
+
export const makeUnencrypted: Effect.Effect<
|
|
290
|
+
EventLogRemote["Service"],
|
|
291
|
+
EventLogRemoteError,
|
|
292
|
+
Scope.Scope | EventLogRemoteClient | Registry
|
|
293
|
+
> = makeWith({
|
|
294
|
+
encodeWrite: (options) =>
|
|
295
|
+
new WriteEntriesUnencrypted({
|
|
296
|
+
publicKey: options.identity.publicKey,
|
|
297
|
+
storeId: options.storeId,
|
|
298
|
+
entries: options.entries
|
|
299
|
+
}).encoded,
|
|
300
|
+
decodeChanges: (_identity, data) => ChangesRpc.decodeUnencrypted(data)
|
|
301
|
+
})
|
|
460
302
|
|
|
461
303
|
/**
|
|
462
304
|
* @since 4.0.0
|
|
463
|
-
* @category
|
|
305
|
+
* @category Layers
|
|
464
306
|
*/
|
|
465
|
-
export const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
307
|
+
export const layerEncrypted: Layer.Layer<
|
|
308
|
+
EventLogRemote,
|
|
309
|
+
EventLogRemoteError,
|
|
310
|
+
RpcClient.Protocol | Registry
|
|
311
|
+
> = Layer.effect(EventLogRemote, makeEncrypted).pipe(
|
|
312
|
+
Layer.provide(EventLogRemoteClient.layer),
|
|
313
|
+
Layer.provide(layerSubtle)
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @since 4.0.0
|
|
318
|
+
* @category Layers
|
|
319
|
+
*/
|
|
320
|
+
export const layerUnencrypted: Layer.Layer<
|
|
321
|
+
EventLogRemote,
|
|
322
|
+
EventLogRemoteError,
|
|
323
|
+
RpcClient.Protocol | Registry
|
|
324
|
+
> = Layer.effect(EventLogRemote, makeUnencrypted).pipe(
|
|
325
|
+
Layer.provide(EventLogRemoteClient.layer)
|
|
326
|
+
)
|