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,304 +1,212 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 4.0.0
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import type { NonEmptyReadonlyArray } from "../../Array.ts"
|
|
5
|
+
import * as Arr from "../../Array.ts"
|
|
6
|
+
import * as Cache from "../../Cache.ts"
|
|
6
7
|
import * as Context from "../../Context.ts"
|
|
8
|
+
import * as Data from "../../Data.ts"
|
|
7
9
|
import * as Effect from "../../Effect.ts"
|
|
8
|
-
import * as
|
|
10
|
+
import * as Equal from "../../Equal.ts"
|
|
11
|
+
import * as Hash from "../../Hash.ts"
|
|
9
12
|
import * as Layer from "../../Layer.ts"
|
|
10
|
-
import * as
|
|
11
|
-
import * as
|
|
12
|
-
import * as
|
|
13
|
-
import * as
|
|
14
|
-
import type * as
|
|
15
|
-
import type
|
|
16
|
-
import * as
|
|
17
|
-
import * as HttpServerResponse from "../http/HttpServerResponse.ts"
|
|
18
|
-
import type * as Socket from "../socket/Socket.ts"
|
|
19
|
-
import { EntryId, makeRemoteIdUnsafe, type RemoteId } from "./EventJournal.ts"
|
|
20
|
-
import type { EncryptedRemoteEntry } from "./EventLogEncryption.ts"
|
|
13
|
+
import * as Option from "../../Option.ts"
|
|
14
|
+
import * as Redacted from "../../Redacted.ts"
|
|
15
|
+
import * as Stream from "../../Stream.ts"
|
|
16
|
+
import type * as Rpc from "../rpc/Rpc.ts"
|
|
17
|
+
import type * as RpcGroup from "../rpc/RpcGroup.ts"
|
|
18
|
+
import type { RemoteId } from "./EventJournal.ts"
|
|
19
|
+
import * as EventLog from "./EventLog.ts"
|
|
21
20
|
import {
|
|
22
|
-
Ack,
|
|
23
|
-
Changes,
|
|
24
21
|
ChunkedMessage,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type
|
|
31
|
-
} from "./
|
|
22
|
+
EventLogAuthentication,
|
|
23
|
+
EventLogProtocolError,
|
|
24
|
+
EventLogRemoteRpcs,
|
|
25
|
+
HelloResponse,
|
|
26
|
+
SingleMessage,
|
|
27
|
+
type StoreId
|
|
28
|
+
} from "./EventLogMessage.ts"
|
|
29
|
+
import * as EventLogSessionAuth from "./EventLogSessionAuth.ts"
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
/**
|
|
32
|
+
* @since 4.0.0
|
|
33
|
+
* @category Layers
|
|
34
|
+
*/
|
|
35
|
+
export const layerAuthMiddleware: Layer.Layer<
|
|
36
|
+
EventLogAuthentication
|
|
37
|
+
> = Layer.succeed(EventLogAuthentication, (effect, { client, rpc }) => {
|
|
38
|
+
const identity = Context.getOrUndefined(client.annotations, EventLog.Identity)
|
|
39
|
+
if (identity) return Effect.provideService(effect, EventLog.Identity, identity)
|
|
40
|
+
return Effect.fail(
|
|
41
|
+
new EventLogProtocolError({
|
|
42
|
+
requestTag: rpc._tag,
|
|
43
|
+
publicKey: undefined,
|
|
44
|
+
code: "Forbidden",
|
|
45
|
+
message: "Unauthenticated request"
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
})
|
|
34
49
|
|
|
35
50
|
/**
|
|
36
51
|
* @since 4.0.0
|
|
37
|
-
* @category
|
|
52
|
+
* @category Layers
|
|
38
53
|
*/
|
|
39
|
-
export const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
export const layerRpcHandlers = (options: {
|
|
55
|
+
readonly remoteId: RemoteId
|
|
56
|
+
readonly getOrCreateSessionAuthBinding: (
|
|
57
|
+
publicKey: string,
|
|
58
|
+
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
59
|
+
) => Effect.Effect<Uint8Array<ArrayBuffer>>
|
|
60
|
+
readonly onWrite: (
|
|
61
|
+
data: Uint8Array<ArrayBuffer>
|
|
62
|
+
) => Effect.Effect<void, EventLogProtocolError>
|
|
63
|
+
readonly changes: (options: {
|
|
64
|
+
readonly publicKey: string
|
|
65
|
+
readonly storeId: StoreId
|
|
66
|
+
readonly startSequence: number
|
|
67
|
+
}) => Stream.Stream<Uint8Array<ArrayBuffer>, unknown>
|
|
68
|
+
}): Layer.Layer<
|
|
69
|
+
Rpc.ToHandler<RpcGroup.Rpcs<typeof EventLogRemoteRpcs>> | EventLogAuthentication
|
|
70
|
+
> =>
|
|
71
|
+
EventLogRemoteRpcs.toLayer(Effect.gen(function*() {
|
|
72
|
+
const clientChallenges = yield* Cache.make({
|
|
73
|
+
lookup: (_clientId: number) => Effect.orDie(EventLogSessionAuth.makeSessionAuthChallenge),
|
|
74
|
+
capacity: Number.MAX_SAFE_INTEGER,
|
|
75
|
+
timeToLive: EventLogSessionAuth.SessionAuthChallengeTimeToLiveMillis
|
|
76
|
+
})
|
|
77
|
+
let chunkedIdCounter = 0
|
|
47
78
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
const persistedSigningPublicKeys = yield* Cache.make({
|
|
80
|
+
lookup: (key: SessionAuthCacheKey) =>
|
|
81
|
+
options.getOrCreateSessionAuthBinding(key.publicKey, key.signingPublicKey).pipe(
|
|
82
|
+
Effect.catchCause((_) =>
|
|
83
|
+
Effect.fail(
|
|
84
|
+
new EventLogProtocolError({
|
|
85
|
+
requestTag: "Authenticate",
|
|
86
|
+
publicKey: key.publicKey,
|
|
87
|
+
code: "Forbidden",
|
|
88
|
+
message: "Session auth binding lookup failed"
|
|
89
|
+
})
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
),
|
|
93
|
+
capacity: 4096
|
|
94
|
+
})
|
|
61
95
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
96
|
+
return EventLogRemoteRpcs.of({
|
|
97
|
+
"EventLog.Hello": Effect.fnUntraced(function*(_, { client }) {
|
|
98
|
+
const challenge = yield* Cache.get(clientChallenges, client.id)
|
|
99
|
+
return new HelloResponse({
|
|
100
|
+
remoteId: options.remoteId,
|
|
101
|
+
challenge
|
|
102
|
+
})
|
|
103
|
+
}),
|
|
104
|
+
"EventLog.Authenticate": Effect.fnUntraced(function*(request, { client }) {
|
|
105
|
+
const challenge = Option.getOrNull(yield* Cache.getOption(clientChallenges, client.id))
|
|
106
|
+
if (!challenge) {
|
|
107
|
+
return new EventLogProtocolError({
|
|
108
|
+
requestTag: "Authenticate",
|
|
109
|
+
publicKey: request.publicKey,
|
|
110
|
+
code: "Forbidden",
|
|
111
|
+
message: "Session auth challenge has expired"
|
|
112
|
+
})
|
|
70
113
|
}
|
|
71
|
-
|
|
114
|
+
yield* Cache.invalidate(clientChallenges, client.id)
|
|
115
|
+
const signingPublicKey = yield* Cache.get(
|
|
116
|
+
persistedSigningPublicKeys,
|
|
117
|
+
new SessionAuthCacheKey({
|
|
118
|
+
publicKey: request.publicKey,
|
|
119
|
+
signingPublicKey: request.signingPublicKey
|
|
120
|
+
})
|
|
121
|
+
)
|
|
122
|
+
const verified = yield* EventLogSessionAuth.verifySessionAuthenticateRequest({
|
|
123
|
+
remoteId: options.remoteId,
|
|
124
|
+
challenge,
|
|
125
|
+
publicKey: request.publicKey,
|
|
126
|
+
signingPublicKey,
|
|
127
|
+
signature: request.signature,
|
|
128
|
+
algorithm: request.algorithm
|
|
129
|
+
}).pipe(
|
|
130
|
+
Effect.catch(() => Effect.succeed(false))
|
|
131
|
+
)
|
|
72
132
|
|
|
73
|
-
|
|
133
|
+
if (!verified) {
|
|
134
|
+
return yield* new EventLogProtocolError({
|
|
135
|
+
requestTag: "Authenticate",
|
|
136
|
+
publicKey: request.publicKey,
|
|
137
|
+
code: "Forbidden",
|
|
138
|
+
message: "Session auth signature verification failed"
|
|
139
|
+
})
|
|
140
|
+
}
|
|
74
141
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
142
|
+
client
|
|
143
|
+
.annotate(EventLog.Identity, {
|
|
144
|
+
publicKey: request.publicKey,
|
|
145
|
+
privateKey: constEmptyPrivateKey
|
|
146
|
+
})
|
|
147
|
+
.annotate(ChunkedMessageState, new Map())
|
|
148
|
+
}),
|
|
149
|
+
"EventLog.WriteSingle": Effect.fnUntraced(function*(request) {
|
|
150
|
+
yield* options.onWrite(request.data)
|
|
151
|
+
}),
|
|
152
|
+
"EventLog.WriteChunked": Effect.fnUntraced(function*(request, { client }) {
|
|
153
|
+
const state = Context.get(client.annotations, ChunkedMessageState)
|
|
154
|
+
const data = ChunkedMessage.join(state, request)
|
|
155
|
+
if (!data) return
|
|
156
|
+
yield* options.onWrite(data)
|
|
157
|
+
}),
|
|
158
|
+
"EventLog.Changes": (request) =>
|
|
159
|
+
options.changes({
|
|
160
|
+
publicKey: request.publicKey,
|
|
161
|
+
storeId: request.storeId,
|
|
162
|
+
startSequence: request.startSequence
|
|
163
|
+
}).pipe(
|
|
164
|
+
Stream.mapArray(Arr.flatMap((data): NonEmptyReadonlyArray<SingleMessage | ChunkedMessage> => {
|
|
165
|
+
if (data.byteLength <= ChunkedMessage.chunkSize) {
|
|
166
|
+
return [new SingleMessage({ data })]
|
|
90
167
|
}
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return yield* Effect.orDie(
|
|
102
|
-
write(
|
|
103
|
-
new Ack({
|
|
104
|
-
id: request.id,
|
|
105
|
-
sequenceNumbers: encrypted.map((entry) => entry.sequence)
|
|
106
|
-
})
|
|
107
|
-
)
|
|
108
|
-
)
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
case "RequestChanges": {
|
|
112
|
-
return Effect.gen(function*() {
|
|
113
|
-
const changes = yield* storage.changes(request.publicKey, request.startSequence)
|
|
114
|
-
return yield* Queue.takeAll(changes).pipe(
|
|
115
|
-
Effect.flatMap((entries) => {
|
|
116
|
-
const latestEntries: Array<EncryptedRemoteEntry> = []
|
|
117
|
-
for (const entry of entries) {
|
|
118
|
-
if (entry.sequence <= latestSequence) continue
|
|
119
|
-
latestEntries.push(entry)
|
|
120
|
-
latestSequence = entry.sequence
|
|
121
|
-
}
|
|
122
|
-
if (latestEntries.length === 0) return Effect.void
|
|
123
|
-
return Effect.orDie(
|
|
124
|
-
write(
|
|
125
|
-
new Changes({
|
|
126
|
-
publicKey: request.publicKey,
|
|
127
|
-
entries: latestEntries
|
|
128
|
-
})
|
|
129
|
-
)
|
|
130
|
-
)
|
|
131
|
-
}),
|
|
132
|
-
Effect.forever
|
|
133
|
-
)
|
|
134
|
-
}).pipe(
|
|
135
|
-
Effect.scoped,
|
|
136
|
-
FiberMap.run(subscriptions, request.publicKey)
|
|
168
|
+
return ChunkedMessage.split(chunkedIdCounter++, data)
|
|
169
|
+
})),
|
|
170
|
+
Stream.catchCause((_) =>
|
|
171
|
+
Stream.fail(
|
|
172
|
+
new EventLogProtocolError({
|
|
173
|
+
requestTag: "Changes",
|
|
174
|
+
publicKey: request.publicKey,
|
|
175
|
+
code: "InternalServerError",
|
|
176
|
+
message: "Decoding failure"
|
|
177
|
+
})
|
|
137
178
|
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return FiberMap.remove(subscriptions, request.publicKey)
|
|
141
|
-
}
|
|
142
|
-
case "ChunkedMessage": {
|
|
143
|
-
const data = ChunkedMessage.join(chunks, request)
|
|
144
|
-
if (!data) return Effect.void
|
|
145
|
-
return Effect.flatMap(Effect.orDie(decodeRequest(data)), handleRequest)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
yield* socket.run((data) => Effect.flatMap(Effect.orDie(decodeRequest(data)), handleRequest)).pipe(
|
|
151
|
-
Effect.catchCause((cause) => Effect.logDebug(cause))
|
|
152
|
-
)
|
|
153
|
-
},
|
|
154
|
-
Effect.scoped,
|
|
155
|
-
Effect.annotateLogs({
|
|
156
|
-
module: "EventLogServer"
|
|
179
|
+
)
|
|
180
|
+
)
|
|
157
181
|
})
|
|
182
|
+
})).pipe(
|
|
183
|
+
Layer.merge(layerAuthMiddleware)
|
|
158
184
|
)
|
|
159
|
-
})
|
|
160
185
|
|
|
161
186
|
/**
|
|
162
187
|
* @since 4.0.0
|
|
163
|
-
* @category
|
|
188
|
+
* @category ChunkedMessage state
|
|
164
189
|
*/
|
|
165
|
-
export
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const handler = yield* makeHandler
|
|
175
|
-
|
|
176
|
-
// @effect-diagnostics-next-line returnEffectInGen:off
|
|
177
|
-
return Effect.gen(function*() {
|
|
178
|
-
const request = yield* HttpServerRequest.HttpServerRequest
|
|
179
|
-
const socket = yield* request.upgrade
|
|
180
|
-
yield* handler(socket)
|
|
181
|
-
return HttpServerResponse.empty()
|
|
182
|
-
}).pipe(Effect.annotateLogs({
|
|
183
|
-
module: "EventLogServer"
|
|
184
|
-
}))
|
|
185
|
-
})
|
|
190
|
+
export class ChunkedMessageState extends Context.Reference<
|
|
191
|
+
Map<number, {
|
|
192
|
+
readonly parts: Array<Uint8Array>
|
|
193
|
+
count: number
|
|
194
|
+
bytes: number
|
|
195
|
+
}>
|
|
196
|
+
>("effect/eventlog/EventLogServer/ChunkedMessageState", {
|
|
197
|
+
defaultValue: () => new Map()
|
|
198
|
+
}) {}
|
|
186
199
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
)({
|
|
194
|
-
entryId: EntryId,
|
|
195
|
-
iv: Schema.Uint8Array,
|
|
196
|
-
encryptedEntry: Schema.Uint8Array
|
|
197
|
-
}) {
|
|
198
|
-
/**
|
|
199
|
-
* @since 4.0.0
|
|
200
|
-
*/
|
|
201
|
-
get entryIdString(): string {
|
|
202
|
-
return Uuid.stringify(this.entryId)
|
|
200
|
+
class SessionAuthCacheKey extends Data.Class<{
|
|
201
|
+
readonly publicKey: string
|
|
202
|
+
readonly signingPublicKey: Uint8Array<ArrayBuffer>
|
|
203
|
+
}> {
|
|
204
|
+
[Equal.symbol](that: SessionAuthCacheKey) {
|
|
205
|
+
return this.publicKey === that.publicKey
|
|
203
206
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* @since 4.0.0
|
|
208
|
-
* @category storage
|
|
209
|
-
*/
|
|
210
|
-
export class Storage extends Context.Service<Storage, {
|
|
211
|
-
readonly getId: Effect.Effect<RemoteId>
|
|
212
|
-
readonly write: (
|
|
213
|
-
publicKey: string,
|
|
214
|
-
entries: ReadonlyArray<PersistedEntry>
|
|
215
|
-
) => Effect.Effect<ReadonlyArray<EncryptedRemoteEntry>>
|
|
216
|
-
readonly entries: (
|
|
217
|
-
publicKey: string,
|
|
218
|
-
startSequence: number
|
|
219
|
-
) => Effect.Effect<ReadonlyArray<EncryptedRemoteEntry>>
|
|
220
|
-
readonly changes: (
|
|
221
|
-
publicKey: string,
|
|
222
|
-
startSequence: number
|
|
223
|
-
) => Effect.Effect<Queue.Dequeue<EncryptedRemoteEntry, Cause.Done>, never, Scope.Scope>
|
|
224
|
-
}>()("effect/eventlog/EventLogServer/Storage") {}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* @since 4.0.0
|
|
228
|
-
* @category storage
|
|
229
|
-
*/
|
|
230
|
-
export const makeStorageMemory: Effect.Effect<Storage["Service"], never, Scope.Scope> = Effect.gen(function*() {
|
|
231
|
-
const knownIds = new Map<string, number>()
|
|
232
|
-
const journals = new Map<string, Array<EncryptedRemoteEntry>>()
|
|
233
|
-
const remoteId = makeRemoteIdUnsafe()
|
|
234
|
-
const ensureJournal = (publicKey: string) => {
|
|
235
|
-
let journal = journals.get(publicKey)
|
|
236
|
-
if (journal) return journal
|
|
237
|
-
journal = []
|
|
238
|
-
journals.set(publicKey, journal)
|
|
239
|
-
return journal
|
|
207
|
+
[Hash.symbol]() {
|
|
208
|
+
return Hash.string(this.publicKey)
|
|
240
209
|
}
|
|
241
|
-
|
|
242
|
-
lookup: (_publicKey: string) =>
|
|
243
|
-
Effect.acquireRelease(
|
|
244
|
-
PubSub.unbounded<EncryptedRemoteEntry>(),
|
|
245
|
-
PubSub.shutdown
|
|
246
|
-
),
|
|
247
|
-
idleTimeToLive: 60000
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
return Storage.of({
|
|
251
|
-
getId: Effect.succeed(remoteId),
|
|
252
|
-
write: (publicKey, entries) =>
|
|
253
|
-
Effect.gen(function*() {
|
|
254
|
-
const active = yield* RcMap.keys(pubsubs)
|
|
255
|
-
let pubsub: PubSub.PubSub<EncryptedRemoteEntry> | undefined
|
|
256
|
-
for (const key of active) {
|
|
257
|
-
if (key === publicKey) {
|
|
258
|
-
pubsub = yield* RcMap.get(pubsubs, publicKey)
|
|
259
|
-
break
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
const journal = ensureJournal(publicKey)
|
|
263
|
-
const encryptedEntries: Array<EncryptedRemoteEntry> = []
|
|
264
|
-
for (const entry of entries) {
|
|
265
|
-
const idString = entry.entryIdString
|
|
266
|
-
if (knownIds.has(idString)) continue
|
|
267
|
-
const encrypted: EncryptedRemoteEntry = {
|
|
268
|
-
sequence: journal.length,
|
|
269
|
-
entryId: entry.entryId,
|
|
270
|
-
iv: entry.iv,
|
|
271
|
-
encryptedEntry: entry.encryptedEntry
|
|
272
|
-
}
|
|
273
|
-
encryptedEntries.push(encrypted)
|
|
274
|
-
knownIds.set(idString, encrypted.sequence)
|
|
275
|
-
journal.push(encrypted)
|
|
276
|
-
if (pubsub) {
|
|
277
|
-
yield* PubSub.publish(pubsub, encrypted)
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return encryptedEntries
|
|
281
|
-
}).pipe(Effect.scoped),
|
|
282
|
-
entries: (publicKey, startSequence) => Effect.sync(() => ensureJournal(publicKey).slice(startSequence)),
|
|
283
|
-
changes: (publicKey, startSequence) =>
|
|
284
|
-
Effect.gen(function*() {
|
|
285
|
-
const queue = yield* Queue.make<EncryptedRemoteEntry>()
|
|
286
|
-
const pubsub = yield* RcMap.get(pubsubs, publicKey)
|
|
287
|
-
const subscription = yield* PubSub.subscribe(pubsub)
|
|
288
|
-
yield* Queue.offerAll(queue, ensureJournal(publicKey).slice(startSequence))
|
|
289
|
-
yield* PubSub.takeAll(subscription).pipe(
|
|
290
|
-
Effect.flatMap((chunk) => Queue.offerAll(queue, chunk)),
|
|
291
|
-
Effect.forever,
|
|
292
|
-
Effect.forkScoped
|
|
293
|
-
)
|
|
294
|
-
yield* Effect.addFinalizer(() => Queue.shutdown(queue))
|
|
295
|
-
return Queue.asDequeue(queue)
|
|
296
|
-
})
|
|
297
|
-
})
|
|
298
|
-
})
|
|
210
|
+
}
|
|
299
211
|
|
|
300
|
-
|
|
301
|
-
* @since 4.0.0
|
|
302
|
-
* @category storage
|
|
303
|
-
*/
|
|
304
|
-
export const layerStorageMemory: Layer.Layer<Storage> = Layer.effect(Storage)(makeStorageMemory)
|
|
212
|
+
const constEmptyPrivateKey = Redacted.make(new Uint8Array(32))
|