@livestore/webmesh 0.3.0-dev.22 → 0.3.0-dev.24

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.
@@ -1,17 +1,18 @@
1
+ import type { HttpClient } from '@livestore/utils/effect'
1
2
  import {
2
3
  Deferred,
3
4
  Effect,
4
5
  Either,
5
6
  Exit,
7
+ Layer,
6
8
  Queue,
7
9
  Schedule,
8
10
  Schema,
9
11
  Scope,
12
+ Socket,
10
13
  Stream,
11
14
  WebChannel,
12
- WebSocket,
13
15
  } from '@livestore/utils/effect'
14
- import type * as NodeWebSocket from 'ws'
15
16
 
16
17
  import * as WebmeshSchema from './mesh-schema.js'
17
18
  import type { MeshNode } from './node.js'
@@ -41,41 +42,49 @@ export type SocketType =
41
42
  export const connectViaWebSocket = ({
42
43
  node,
43
44
  url,
44
- reconnect = Schedule.exponential(100),
45
45
  }: {
46
46
  node: MeshNode
47
47
  url: string
48
- reconnect?: Schedule.Schedule<unknown> | false
49
- }): Effect.Effect<void, never, Scope.Scope> =>
48
+ }): Effect.Effect<void, never, Scope.Scope | HttpClient.HttpClient> =>
50
49
  Effect.gen(function* () {
51
50
  const disconnected = yield* Deferred.make<void>()
52
51
 
53
- const socket = yield* WebSocket.makeWebSocket({ url, reconnect })
52
+ const socket = yield* Socket.makeWebSocket(url, { openTimeout: 50 })
54
53
 
55
- socket.addEventListener('close', () => Deferred.unsafeDone(disconnected, Exit.void))
54
+ const edgeChannel = yield* makeWebSocketEdge({
55
+ socket,
56
+ socketType: { _tag: 'leaf', from: node.nodeName },
57
+ })
56
58
 
57
- const edgeChannel = yield* makeWebSocketEdge(socket, { _tag: 'leaf', from: node.nodeName })
58
-
59
- yield* node.addEdge({ target: 'ws', edgeChannel: edgeChannel.webChannel, replaceIfExists: true })
59
+ yield* node
60
+ .addEdge({ target: 'ws', edgeChannel: edgeChannel.webChannel, replaceIfExists: true })
61
+ .pipe(Effect.acquireRelease(() => node.removeEdge('ws').pipe(Effect.orDie)))
60
62
 
61
63
  yield* disconnected
62
- }).pipe(Effect.scoped, Effect.forever, Effect.catchTag('WebSocketError', Effect.orDie))
64
+ }).pipe(Effect.scoped, Effect.forever, Effect.interruptible, Effect.provide(binaryWebSocketConstructorLayer))
65
+
66
+ const binaryWebSocketConstructorLayer = Layer.succeed(Socket.WebSocketConstructor, (url, protocols) => {
67
+ const socket = new globalThis.WebSocket(url, protocols)
68
+ socket.binaryType = 'arraybuffer'
69
+ return socket
70
+ })
63
71
 
64
- export const makeWebSocketEdge = (
65
- socket: globalThis.WebSocket | NodeWebSocket.WebSocket,
66
- socketType: SocketType,
67
- ): Effect.Effect<
72
+ export const makeWebSocketEdge = ({
73
+ socket,
74
+ socketType,
75
+ }: {
76
+ socket: Socket.Socket
77
+ socketType: SocketType
78
+ }): Effect.Effect<
68
79
  {
69
80
  webChannel: WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>
70
81
  from: string
71
82
  },
72
83
  never,
73
- Scope.Scope
84
+ Scope.Scope | HttpClient.HttpClient
74
85
  > =>
75
86
  Effect.scopeWithCloseable((scope) =>
76
87
  Effect.gen(function* () {
77
- socket.binaryType = 'arraybuffer'
78
-
79
88
  const fromDeferred = yield* Deferred.make<string>()
80
89
 
81
90
  const listenQueue = yield* Queue.unbounded<typeof WebmeshSchema.Packet.Type>().pipe(
@@ -84,11 +93,32 @@ export const makeWebSocketEdge = (
84
93
 
85
94
  const schema = WebChannel.mapSchema(WebmeshSchema.Packet)
86
95
 
87
- yield* Stream.fromEventListener<MessageEvent>(socket as any, 'message').pipe(
88
- Stream.map((msg) => Schema.decodeUnknownEither(MessageMsgPack)(new Uint8Array(msg.data))),
89
- Stream.flatten(),
90
- Stream.tap((msg) =>
91
- Effect.gen(function* () {
96
+ const isConnectedLatch = yield* Effect.makeLatch(true)
97
+
98
+ const closedDeferred = yield* Deferred.make<void>().pipe(Effect.acquireRelease(Deferred.done(Exit.void)))
99
+
100
+ const retryOpenTimeoutSchedule = Schedule.exponential(100).pipe(
101
+ Schedule.whileInput((_: Socket.SocketError) => _.reason === 'OpenTimeout'),
102
+ )
103
+
104
+ yield* Stream.never.pipe(
105
+ Stream.pipeThroughChannel(Socket.toChannel(socket)),
106
+ Stream.catchTag(
107
+ 'SocketError',
108
+ Effect.fn(function* (error) {
109
+ if (error.reason === 'Close') {
110
+ yield* isConnectedLatch.close
111
+ yield* Deferred.succeed(closedDeferred, undefined)
112
+ return yield* Effect.interrupt
113
+ } else {
114
+ return yield* Effect.fail(error)
115
+ }
116
+ }),
117
+ ),
118
+ Stream.retry(retryOpenTimeoutSchedule),
119
+ Stream.tap(
120
+ Effect.fn(function* (bytes) {
121
+ const msg = yield* Schema.decode(MessageMsgPack)(new Uint8Array(bytes))
92
122
  if (msg._tag === 'WSEdgeInit') {
93
123
  yield* Deferred.succeed(fromDeferred, msg.from)
94
124
  } else {
@@ -99,45 +129,33 @@ export const makeWebSocketEdge = (
99
129
  ),
100
130
  Stream.runDrain,
101
131
  Effect.interruptible,
132
+ Effect.withSpan('makeWebSocketEdge:listen'),
102
133
  Effect.tapCauseLogPretty,
103
134
  Effect.forkScoped,
104
135
  )
105
136
 
137
+ const sendToSocket = yield* socket.writer
138
+
106
139
  const initHandshake = (from: string) =>
107
- socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgeInit', from }))
140
+ sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgeInit', from }))
108
141
 
109
142
  if (socketType._tag === 'leaf') {
110
- initHandshake(socketType.from)
143
+ yield* initHandshake(socketType.from)
111
144
  }
112
145
 
113
146
  const deferredResult = yield* fromDeferred
114
147
  const from = socketType._tag === 'leaf' ? socketType.from : deferredResult
115
148
 
116
149
  if (socketType._tag === 'relay') {
117
- initHandshake(from)
150
+ yield* initHandshake(from)
118
151
  }
119
152
 
120
- const isConnectedLatch = yield* Effect.makeLatch(true)
121
-
122
- const closedDeferred = yield* Deferred.make<void>().pipe(Effect.acquireRelease(Deferred.done(Exit.void)))
123
-
124
- yield* Effect.eventListener<any>(
125
- socket,
126
- 'close',
127
- () =>
128
- Effect.gen(function* () {
129
- yield* isConnectedLatch.close
130
- yield* Deferred.succeed(closedDeferred, undefined)
131
- }),
132
- { once: true },
133
- )
134
-
135
153
  const send = (message: typeof WebmeshSchema.Packet.Type) =>
136
154
  Effect.gen(function* () {
137
155
  yield* isConnectedLatch.await
138
156
  const payload = yield* Schema.encode(schema.send)(message)
139
- socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgePayload', payload, from }))
140
- })
157
+ yield* sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgePayload', payload, from }))
158
+ }).pipe(Effect.orDie)
141
159
 
142
160
  const listen = Stream.fromQueue(listenQueue).pipe(
143
161
  Stream.map(Either.right),
@@ -155,5 +173,5 @@ export const makeWebSocketEdge = (
155
173
  } satisfies WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>
156
174
 
157
175
  return { webChannel, from }
158
- }).pipe(Effect.withSpanScoped('makeWebSocketEdge')),
176
+ }).pipe(Effect.withSpanScoped('makeWebSocketEdge'), Effect.orDie),
159
177
  )
package/tmp/pack.tgz CHANGED
Binary file
@@ -1,50 +0,0 @@
1
- import { Effect, Schedule, Schema, Scope, WebChannel } from '@livestore/utils/effect';
2
- import type * as NodeWebSocket from 'ws';
3
- import * as WebmeshSchema from './mesh-schema.js';
4
- import type { MeshNode } from './node.js';
5
- declare const WSConnectionInit_base: Schema.TaggedStruct<"WSConnectionInit", {
6
- from: typeof Schema.String;
7
- }>;
8
- export declare class WSConnectionInit extends WSConnectionInit_base {
9
- }
10
- declare const WSConnectionPayload_base: Schema.TaggedStruct<"WSConnectionPayload", {
11
- from: typeof Schema.String;
12
- payload: typeof Schema.Any;
13
- }>;
14
- export declare class WSConnectionPayload extends WSConnectionPayload_base {
15
- }
16
- declare const WSConnectionMessage_base: Schema.Union<[typeof WSConnectionInit, typeof WSConnectionPayload]>;
17
- export declare class WSConnectionMessage extends WSConnectionMessage_base {
18
- }
19
- export declare const MessageMsgPack: Schema.transform<typeof Schema.Uint8ArrayFromSelf, Schema.Schema<{
20
- readonly _tag: "WSConnectionInit";
21
- readonly from: string;
22
- } | {
23
- readonly _tag: "WSConnectionPayload";
24
- readonly payload: any;
25
- readonly from: string;
26
- }, {
27
- readonly _tag: "WSConnectionInit";
28
- readonly from: string;
29
- } | {
30
- readonly _tag: "WSConnectionPayload";
31
- readonly payload: any;
32
- readonly from: string;
33
- }, never>>;
34
- export type SocketType = {
35
- _tag: 'leaf';
36
- from: string;
37
- } | {
38
- _tag: 'relay';
39
- };
40
- export declare const connectViaWebSocket: ({ node, url, reconnect, }: {
41
- node: MeshNode;
42
- url: string;
43
- reconnect?: Schedule.Schedule<unknown> | false;
44
- }) => Effect.Effect<void, never, Scope.Scope>;
45
- export declare const makeWebSocketEdge: (socket: globalThis.WebSocket | NodeWebSocket.WebSocket, socketType: SocketType) => Effect.Effect<{
46
- webChannel: WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>;
47
- from: string;
48
- }, never, Scope.Scope>;
49
- export {};
50
- //# sourceMappingURL=websocket-connection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-connection.d.ts","sourceRoot":"","sources":["../src/websocket-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,MAAM,EAIN,QAAQ,EACR,MAAM,EACN,KAAK,EAEL,UAAU,EAEX,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,KAAK,aAAa,MAAM,IAAI,CAAA;AAExC,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;;;;AAEzC,qBAAa,gBAAiB,SAAQ,qBAEpC;CAAG;;;;;AAEL,qBAAa,mBAAoB,SAAQ,wBAGvC;CAAG;;AAEL,qBAAa,mBAAoB,SAAQ,wBAAmD;CAAG;AAE/F,eAAO,MAAM,cAAc;;;;;;;;;;;;;;UAAsC,CAAA;AAEjE,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAEL,eAAO,MAAM,mBAAmB,GAAI,2BAIjC;IACD,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,KAAK,CAAA;CAC/C,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAa+C,CAAA;AAEzF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,UAAU,CAAC,SAAS,GAAG,aAAa,CAAC,SAAS,EACtD,YAAY,UAAU,KACrB,MAAM,CAAC,MAAM,CACd;IACE,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACrG,IAAI,EAAE,MAAM,CAAA;CACb,EACD,KAAK,EACL,KAAK,CAAC,KAAK,CAsFV,CAAA"}
@@ -1,69 +0,0 @@
1
- import { Deferred, Effect, Either, Exit, Queue, Schedule, Schema, Scope, Stream, WebChannel, WebSocket, } from '@livestore/utils/effect';
2
- import * as WebmeshSchema from './mesh-schema.js';
3
- export class WSConnectionInit extends Schema.TaggedStruct('WSConnectionInit', {
4
- from: Schema.String,
5
- }) {
6
- }
7
- export class WSConnectionPayload extends Schema.TaggedStruct('WSConnectionPayload', {
8
- from: Schema.String,
9
- payload: Schema.Any,
10
- }) {
11
- }
12
- export class WSConnectionMessage extends Schema.Union(WSConnectionInit, WSConnectionPayload) {
13
- }
14
- export const MessageMsgPack = Schema.MsgPack(WSConnectionMessage);
15
- export const connectViaWebSocket = ({ node, url, reconnect = Schedule.exponential(100), }) => Effect.gen(function* () {
16
- const disconnected = yield* Deferred.make();
17
- const socket = yield* WebSocket.makeWebSocket({ url, reconnect });
18
- socket.addEventListener('close', () => Deferred.unsafeDone(disconnected, Exit.void));
19
- const edgeChannel = yield* makeWebSocketEdge(socket, { _tag: 'leaf', from: node.nodeName });
20
- yield* node.addEdge({ target: 'ws', edgeChannel: edgeChannel.webChannel, replaceIfExists: true });
21
- yield* disconnected;
22
- }).pipe(Effect.scoped, Effect.forever, Effect.catchTag('WebSocketError', Effect.orDie));
23
- export const makeWebSocketEdge = (socket, socketType) => Effect.scopeWithCloseable((scope) => Effect.gen(function* () {
24
- socket.binaryType = 'arraybuffer';
25
- const fromDeferred = yield* Deferred.make();
26
- const listenQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
27
- const schema = WebChannel.mapSchema(WebmeshSchema.Packet);
28
- yield* Stream.fromEventListener(socket, 'message').pipe(Stream.map((msg) => Schema.decodeUnknownEither(MessageMsgPack)(new Uint8Array(msg.data))), Stream.flatten(), Stream.tap((msg) => Effect.gen(function* () {
29
- if (msg._tag === 'WSConnectionInit') {
30
- yield* Deferred.succeed(fromDeferred, msg.from);
31
- }
32
- else {
33
- const decodedPayload = yield* Schema.decode(schema.listen)(msg.payload);
34
- yield* Queue.offer(listenQueue, decodedPayload);
35
- }
36
- })), Stream.runDrain, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
37
- const initHandshake = (from) => socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSConnectionInit', from }));
38
- if (socketType._tag === 'leaf') {
39
- initHandshake(socketType.from);
40
- }
41
- const deferredResult = yield* fromDeferred;
42
- const from = socketType._tag === 'leaf' ? socketType.from : deferredResult;
43
- if (socketType._tag === 'relay') {
44
- initHandshake(from);
45
- }
46
- const isConnectedLatch = yield* Effect.makeLatch(true);
47
- const closedDeferred = yield* Deferred.make().pipe(Effect.acquireRelease(Deferred.done(Exit.void)));
48
- yield* Effect.eventListener(socket, 'close', () => Effect.gen(function* () {
49
- yield* isConnectedLatch.close;
50
- yield* Deferred.succeed(closedDeferred, undefined);
51
- }), { once: true });
52
- const send = (message) => Effect.gen(function* () {
53
- yield* isConnectedLatch.await;
54
- const payload = yield* Schema.encode(schema.send)(message);
55
- socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSConnectionPayload', payload, from }));
56
- });
57
- const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right), WebChannel.listenToDebugPing('websocket-edge'));
58
- const webChannel = {
59
- [WebChannel.WebChannelSymbol]: WebChannel.WebChannelSymbol,
60
- send,
61
- listen,
62
- closedDeferred,
63
- schema,
64
- supportsTransferables: false,
65
- shutdown: Scope.close(scope, Exit.void),
66
- };
67
- return { webChannel, from };
68
- }).pipe(Effect.withSpanScoped('makeWebSocketEdge')));
69
- //# sourceMappingURL=websocket-connection.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-connection.js","sourceRoot":"","sources":["../src/websocket-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,MAAM,EACN,UAAU,EACV,SAAS,GACV,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AAGjD,MAAM,OAAO,gBAAiB,SAAQ,MAAM,CAAC,YAAY,CAAC,kBAAkB,EAAE;IAC5E,IAAI,EAAE,MAAM,CAAC,MAAM;CACpB,CAAC;CAAG;AAEL,MAAM,OAAO,mBAAoB,SAAQ,MAAM,CAAC,YAAY,CAAC,qBAAqB,EAAE;IAClF,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,OAAO,EAAE,MAAM,CAAC,GAAG;CACpB,CAAC;CAAG;AAEL,MAAM,OAAO,mBAAoB,SAAQ,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;CAAG;AAE/F,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAWjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,IAAI,EACJ,GAAG,EACH,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAKtC,EAA2C,EAAE,CAC5C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAA;IAEjD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAA;IAEjE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAEpF,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;IAE3F,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;IAEjG,KAAK,CAAC,CAAC,YAAY,CAAA;AACrB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;AAEzF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAsD,EACtD,UAAsB,EAQtB,EAAE,CACF,MAAM,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,EAAE,CAClC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,CAAC,UAAU,GAAG,aAAa,CAAA;IAEjC,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAU,CAAA;IAEnD,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,EAAoC,CAAC,IAAI,CACjF,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CACtC,CAAA;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;IAEzD,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAe,MAAa,EAAE,SAAS,CAAC,CAAC,IAAI,CAC1E,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EACzF,MAAM,CAAC,OAAO,EAAE,EAChB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACjB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACpC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACjD,CAAC;aAAM,CAAC;YACN,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACvE,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,cAAc,CAAC,CAAA;QACjD,CAAC;IACH,CAAC,CAAC,CACH,EACD,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,aAAa,EACpB,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,UAAU,CAClB,CAAA;IAED,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAEpF,IAAI,UAAU,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC/B,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,YAAY,CAAA;IAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAA;IAE1E,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAChC,aAAa,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;IAED,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAEtD,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAEzG,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CACzB,MAAM,EACN,OAAO,EACP,GAAG,EAAE,CACH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,KAAK,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAA;QAC7B,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;IACpD,CAAC,CAAC,EACJ,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAA;IAED,MAAM,IAAI,GAAG,CAAC,OAAyC,EAAE,EAAE,CACzD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,KAAK,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAA;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAA;QAC1D,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAChG,CAAC,CAAC,CAAA;IAEJ,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAC/C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EACxB,UAAU,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAC/C,CAAA;IAED,MAAM,UAAU,GAAG;QACjB,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC,gBAAgB;QAC1D,IAAI;QACJ,MAAM;QACN,cAAc;QACd,MAAM;QACN,qBAAqB,EAAE,KAAK;QAC5B,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC;KAC4D,CAAA;IAErG,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;AAC7B,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CACpD,CAAA"}
@@ -1,7 +0,0 @@
1
- import type { Scope } from '@livestore/utils/effect';
2
- import { Effect } from '@livestore/utils/effect';
3
- import * as WebSocket from 'ws';
4
- export declare const makeWebSocketServer: ({ relayNodeName, }: {
5
- relayNodeName: string;
6
- }) => Effect.Effect<WebSocket.WebSocketServer, never, Scope.Scope>;
7
- //# sourceMappingURL=websocket-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAY,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,SAAS,MAAM,IAAI,CAAA;AAK/B,eAAO,MAAM,mBAAmB,GAAI,oBAEjC;IACD,aAAa,EAAE,MAAM,CAAA;CACtB,KAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CA4C3D,CAAA"}
@@ -1,38 +0,0 @@
1
- import { UnexpectedError } from '@livestore/common';
2
- import { Effect, FiberSet } from '@livestore/utils/effect';
3
- import * as WebSocket from 'ws';
4
- import { makeMeshNode } from './node.js';
5
- import { makeWebSocketEdge } from './websocket-edge.js';
6
- export const makeWebSocketServer = ({ relayNodeName, }) => Effect.gen(function* () {
7
- const server = new WebSocket.WebSocketServer({ noServer: true });
8
- yield* Effect.addFinalizer(() => Effect.async((cb) => {
9
- server.close((cause) => {
10
- if (cause) {
11
- cb(Effect.fail(UnexpectedError.make({ cause })));
12
- }
13
- else {
14
- server.removeAllListeners();
15
- server.clients.forEach((client) => client.terminate());
16
- cb(Effect.succeed(undefined));
17
- }
18
- });
19
- }).pipe(Effect.orDie));
20
- const node = yield* makeMeshNode(relayNodeName);
21
- const runtime = yield* Effect.runtime();
22
- const fiberSet = yield* FiberSet.make();
23
- // TODO handle node disconnects (i.e. remove respective connection)
24
- server.on('connection', (socket) => {
25
- Effect.gen(function* () {
26
- const { webChannel, from } = yield* makeWebSocketEdge(socket, { _tag: 'relay' });
27
- yield* node.addEdge({ target: from, edgeChannel: webChannel, replaceIfExists: true });
28
- yield* Effect.log(`WS Relay ${relayNodeName}: added edge from '${from}'`);
29
- socket.addEventListener('close', () => Effect.gen(function* () {
30
- yield* node.removeEdge(from);
31
- yield* Effect.log(`WS Relay ${relayNodeName}: removed edge from '${from}'`);
32
- }).pipe(Effect.provide(runtime), Effect.tapCauseLogPretty, Effect.runFork));
33
- yield* Effect.never;
34
- }).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.provide(runtime), FiberSet.run(fiberSet), Effect.runFork);
35
- });
36
- return server;
37
- });
38
- //# sourceMappingURL=websocket-server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"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"}
@@ -1,57 +0,0 @@
1
- import { UnexpectedError } from '@livestore/common'
2
- import type { Scope } from '@livestore/utils/effect'
3
- import { Effect, FiberSet } from '@livestore/utils/effect'
4
- import * as WebSocket from 'ws'
5
-
6
- import { makeMeshNode } from './node.js'
7
- import { makeWebSocketEdge } from './websocket-edge.js'
8
-
9
- export const makeWebSocketServer = ({
10
- relayNodeName,
11
- }: {
12
- relayNodeName: string
13
- }): Effect.Effect<WebSocket.WebSocketServer, never, Scope.Scope> =>
14
- Effect.gen(function* () {
15
- const server = new WebSocket.WebSocketServer({ noServer: true })
16
-
17
- yield* Effect.addFinalizer(() =>
18
- Effect.async<void, UnexpectedError>((cb) => {
19
- server.close((cause) => {
20
- if (cause) {
21
- cb(Effect.fail(UnexpectedError.make({ cause })))
22
- } else {
23
- server.removeAllListeners()
24
- server.clients.forEach((client) => client.terminate())
25
- cb(Effect.succeed(undefined))
26
- }
27
- })
28
- }).pipe(Effect.orDie),
29
- )
30
-
31
- const node = yield* makeMeshNode(relayNodeName)
32
-
33
- const runtime = yield* Effect.runtime<never>()
34
-
35
- const fiberSet = yield* FiberSet.make()
36
-
37
- // TODO handle node disconnects (i.e. remove respective connection)
38
- server.on('connection', (socket) => {
39
- Effect.gen(function* () {
40
- const { webChannel, from } = yield* makeWebSocketEdge(socket, { _tag: 'relay' })
41
-
42
- yield* node.addEdge({ target: from, edgeChannel: webChannel, replaceIfExists: true })
43
- yield* Effect.log(`WS Relay ${relayNodeName}: added edge from '${from}'`)
44
-
45
- socket.addEventListener('close', () =>
46
- Effect.gen(function* () {
47
- yield* node.removeEdge(from)
48
- yield* Effect.log(`WS Relay ${relayNodeName}: removed edge from '${from}'`)
49
- }).pipe(Effect.provide(runtime), Effect.tapCauseLogPretty, Effect.runFork),
50
- )
51
-
52
- yield* Effect.never
53
- }).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.provide(runtime), FiberSet.run(fiberSet), Effect.runFork)
54
- })
55
-
56
- return server
57
- })