@evolu/nodejs 1.0.1-preview.8 → 2.0.0

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,7 +1,22 @@
1
- import { ConsoleDep } from "@evolu/common";
1
+ import { ConsoleDep, CreateSqliteDriverDep, Result, SqliteError } from "@evolu/common";
2
2
  import { Relay, RelayConfig } from "@evolu/common/evolu";
3
3
  export interface NodeJsRelayConfig extends RelayConfig {
4
+ /** The port number for the HTTP server. */
4
5
  readonly port?: number;
5
6
  }
6
- export declare const createNodeJsRelay: (deps: ConsoleDep) => (config: NodeJsRelayConfig) => Promise<Relay>;
7
+ /**
8
+ * Creates an Evolu relay server.
9
+ *
10
+ * This implementation uses Node.js and better-sqlite3. Additional relay
11
+ * implementations will be provided for other platforms (Bun, Deno, Cloudflare
12
+ * Workers, Vercel Edge, etc.).
13
+ */
14
+ export declare const createNodeJsRelay: (deps: ConsoleDep) => (config: NodeJsRelayConfig) => Promise<Result<Relay, SqliteError>>;
15
+ /**
16
+ * Creates an Evolu relay server with a custom SQLite driver.
17
+ *
18
+ * Use this when you need to provide a different SQLite driver implementation
19
+ * (e.g., using alternative SQLite libraries).
20
+ */
21
+ export declare const createNodeJsRelayWithSqliteDriver: (deps: ConsoleDep & CreateSqliteDriverDep) => (config: NodeJsRelayConfig) => Promise<Result<Relay, SqliteError>>;
7
22
  //# sourceMappingURL=Relay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../src/Evolu/Relay.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAQX,MAAM,eAAe,CAAC;AACvB,OAAO,EAKL,KAAK,EACL,WAAW,EAEZ,MAAM,qBAAqB,CAAC;AAK7B,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,iBAAiB,GAC3B,MAAM,UAAU,MACV,QAAQ,iBAAiB,KAAG,OAAO,CAAC,KAAK,CA+I/C,CAAC"}
1
+ {"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../src/Evolu/Relay.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,qBAAqB,EAKrB,MAAM,EAEN,WAAW,EAGZ,MAAM,eAAe,CAAC;AACvB,OAAO,EASL,KAAK,EACL,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAO7B,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC3B,MAAM,UAAU,MAChB,QAAQ,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAInD,CAAC;AAEf;;;;;GAKG;AACH,eAAO,MAAM,iCAAiC,GAC3C,MAAM,UAAU,GAAG,qBAAqB,MACxC,QAAQ,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAKnD,CAAC"}
@@ -1,57 +1,105 @@
1
- import { createManyToManyMap, createRandom, createSqlite, getOrThrow, SimpleName, Uint8Array, } from "@evolu/common";
2
- import { applyProtocolMessageAsRelay, createRelayStorage, maxProtocolMessageSize, } from "@evolu/common/evolu";
1
+ import { createRelation, createRandom, createSqlite, isAsync, ok, SimpleName, Uint8Array, } from "@evolu/common";
2
+ import { applyProtocolMessageAsRelay, createBaseSqliteStorageTables, createRelayLogger, createRelaySqliteStorage, createRelayStorageTables, defaultProtocolMessageMaxSize, parseOwnerIdFromOwnerWebSocketTransportUrl, } from "@evolu/common/evolu";
3
+ import { existsSync } from "fs";
4
+ import { createServer } from "http";
3
5
  import { WebSocket, WebSocketServer } from "ws";
4
6
  import { createBetterSqliteDriver } from "../BetterSqliteDriver.js";
5
7
  import { createTimingSafeEqual } from "../Crypto.js";
6
- export const createNodeJsRelay = (deps) => async (config) => {
7
- const { port = 443, name = SimpleName.orThrow("evolu-relay"), enableLogging = false, } = config;
8
- deps.console.enabled = true;
9
- deps.console.log(`Evolu Relay started on port ${port}`);
10
- deps.console.enabled = enableLogging;
11
- const sqlite = getOrThrow(await createSqlite({
12
- ...deps,
13
- createSqliteDriver: createBetterSqliteDriver,
14
- })(name));
15
- const relaySqliteStorageDeps = {
16
- sqlite,
17
- random: createRandom(),
18
- timingSafeEqual: createTimingSafeEqual(),
19
- };
20
- const storage = getOrThrow(createRelayStorage(relaySqliteStorageDeps)({
21
- onStorageError: (error) => {
22
- deps.console.error("[relay]", "storage", error);
23
- },
24
- }));
8
+ /**
9
+ * Creates an Evolu relay server.
10
+ *
11
+ * This implementation uses Node.js and better-sqlite3. Additional relay
12
+ * implementations will be provided for other platforms (Bun, Deno, Cloudflare
13
+ * Workers, Vercel Edge, etc.).
14
+ */
15
+ export const createNodeJsRelay = (deps) => (config) => createNodeJsRelayWithSqliteDriver({
16
+ ...deps,
17
+ createSqliteDriver: createBetterSqliteDriver,
18
+ })(config);
19
+ /**
20
+ * Creates an Evolu relay server with a custom SQLite driver.
21
+ *
22
+ * Use this when you need to provide a different SQLite driver implementation
23
+ * (e.g., using alternative SQLite libraries).
24
+ */
25
+ export const createNodeJsRelayWithSqliteDriver = (deps) => (config) => createNodeJsRelayWithDeps({
26
+ ...deps,
27
+ random: createRandom(),
28
+ timingSafeEqual: createTimingSafeEqual(),
29
+ })(config);
30
+ const createNodeJsRelayWithDeps = (deps) => async ({ port = 443, name = SimpleName.orThrow("evolu-relay"), enableLogging = false, isOwnerAllowed, isOwnerWithinQuota, }) => {
31
+ const log = createRelayLogger(deps);
32
+ log.started(enableLogging, port);
33
+ const dbFileExists = existsSync(`${name}.db`);
34
+ const sqlite = await createSqlite(deps)(name);
35
+ if (!sqlite.ok)
36
+ return sqlite;
37
+ const depsWithSqlite = { ...deps, sqlite: sqlite.value };
38
+ if (!dbFileExists) {
39
+ const baseTables = createBaseSqliteStorageTables(depsWithSqlite);
40
+ if (!baseTables.ok)
41
+ return baseTables;
42
+ const relayTables = createRelayStorageTables(depsWithSqlite);
43
+ if (!relayTables.ok)
44
+ return relayTables;
45
+ }
46
+ const storage = createRelaySqliteStorage(depsWithSqlite)({
47
+ onStorageError: log.storageError,
48
+ isOwnerWithinQuota,
49
+ });
50
+ const server = createServer();
25
51
  const wss = new WebSocketServer({
26
- maxPayload: maxProtocolMessageSize,
27
- port,
52
+ maxPayload: defaultProtocolMessageMaxSize,
53
+ noServer: true,
54
+ });
55
+ const ownerSocketRelation = createRelation();
56
+ server.on("upgrade", (request, socket, head) => {
57
+ socket.on("error", log.upgradeSocketError);
58
+ const completeUpgrade = () => {
59
+ socket.removeListener("error", log.upgradeSocketError);
60
+ wss.handleUpgrade(request, socket, head, (ws) => {
61
+ wss.emit("connection", ws, request);
62
+ });
63
+ };
64
+ if (!isOwnerAllowed) {
65
+ completeUpgrade();
66
+ return;
67
+ }
68
+ const ownerId = parseOwnerIdFromOwnerWebSocketTransportUrl(request.url ?? "");
69
+ if (!ownerId) {
70
+ log.invalidOrMissingOwnerIdInUrl(request.url);
71
+ socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
72
+ socket.destroy();
73
+ return;
74
+ }
75
+ void (async () => {
76
+ const result = isOwnerAllowed(ownerId);
77
+ const isAllowed = isAsync(result) ? await result : result;
78
+ if (!isAllowed) {
79
+ log.unauthorizedOwner(ownerId);
80
+ socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
81
+ socket.destroy();
82
+ return;
83
+ }
84
+ completeUpgrade();
85
+ })();
28
86
  });
29
- const ownerSocketsMap = createManyToManyMap();
30
87
  wss.on("connection", (ws) => {
31
- deps.console.log("[relay]", "connection", {
32
- clientCount: wss.clients.size,
33
- });
88
+ log.connectionEstablished(wss.clients.size);
34
89
  ws.on("error", (error) => {
35
- deps.console.warn("[relay]", "error", { error });
36
- deps.console.error(error);
90
+ log.connectionWebSocketError(error);
37
91
  });
38
92
  const options = {
39
93
  subscribe: (ownerId) => {
40
- ownerSocketsMap.add(ownerId, ws);
41
- deps.console.log("[relay]", "subscribe", {
42
- ownerId,
43
- subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
44
- });
94
+ ownerSocketRelation.add(ownerId, ws);
95
+ log.relayOptionSubscribe(ownerId, () => ownerSocketRelation.getB(ownerId)?.size ?? 0);
45
96
  },
46
97
  unsubscribe: (ownerId) => {
47
- ownerSocketsMap.remove(ownerId, ws);
48
- deps.console.log("[relay]", "unsubscribe", {
49
- ownerId,
50
- subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
51
- });
98
+ ownerSocketRelation.remove(ownerId, ws);
99
+ log.relayOptionUnsubscribe(ownerId, () => ownerSocketRelation.getB(ownerId)?.size ?? 0);
52
100
  },
53
101
  broadcast: (ownerId, message) => {
54
- const sockets = ownerSocketsMap.getValues(ownerId);
102
+ const sockets = ownerSocketRelation.getB(ownerId);
55
103
  if (!sockets)
56
104
  return;
57
105
  let broadcastCount = 0;
@@ -61,61 +109,53 @@ export const createNodeJsRelay = (deps) => async (config) => {
61
109
  broadcastCount++;
62
110
  }
63
111
  }
64
- deps.console.log("[relay]", "broadcast", {
65
- ownerId,
66
- broadcastCount,
67
- totalSubscribers: sockets.size,
68
- });
112
+ log.relayOptionBroadcast(ownerId, broadcastCount, sockets.size);
69
113
  },
70
114
  };
71
115
  ws.on("message", (message) => {
72
116
  if (!Uint8Array.is(message))
73
117
  return;
74
- deps.console.log("[relay]", "on message", {
75
- messageSize: message.length,
76
- });
118
+ log.messageLength(message.length);
77
119
  applyProtocolMessageAsRelay({ storage })(message, options)
78
120
  .then((response) => {
79
121
  if (!response.ok) {
80
- deps.console.error("[relay]", "protocol", response.error);
81
- deps.console.error(response.error);
122
+ log.applyProtocolMessageAsRelayError(response.error);
82
123
  return;
83
124
  }
84
125
  ws.send(response.value.message, { binary: true });
85
- deps.console.log("[relay]", "response", {
86
- responseSize: response.value.message.length,
87
- });
126
+ log.responseLength(response.value.message.length);
88
127
  })
89
- .catch((error) => {
90
- deps.console.error("[relay]", "applyProtocolMessageAsRelay", error);
91
- });
128
+ .catch(log.applyProtocolMessageAsRelayUnknownError);
92
129
  });
93
130
  ws.on("close", () => {
94
- ownerSocketsMap.deleteValue(ws);
95
- deps.console.log("[relay]", "close", {
96
- clientCount: wss.clients.size,
97
- });
131
+ ownerSocketRelation.deleteB(ws);
132
+ log.connectionClosed(wss.clients.size);
98
133
  });
99
134
  });
100
- const disposeWss = () => {
101
- deps.console.log("Shutting down Evolu Relay...");
135
+ server.listen(port);
136
+ const dispose = () => {
137
+ log.shuttingDown();
102
138
  wss.clients.forEach((client) => {
103
139
  if (client.readyState === WebSocket.OPEN) {
104
140
  client.close(1000, "Evolu Relay shutting down");
105
141
  }
106
142
  });
107
143
  wss.close(() => {
108
- deps.console.log("Evolu Relay disposed");
144
+ log.webSocketServerDisposed();
145
+ });
146
+ server.close(() => {
147
+ log.httpServerDisposed();
109
148
  });
110
149
  };
111
150
  let isDisposed = false;
112
- return {
151
+ const relay = {
113
152
  [Symbol.dispose]: () => {
114
153
  if (isDisposed)
115
154
  return;
116
155
  isDisposed = true;
117
- sqlite[Symbol.dispose]();
118
- disposeWss();
156
+ sqlite.value[Symbol.dispose]();
157
+ dispose();
119
158
  },
120
159
  };
160
+ return ok(relay);
121
161
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evolu/nodejs",
3
- "version": "1.0.1-preview.8",
3
+ "version": "2.0.0",
4
4
  "description": "Evolu for Node.js",
5
5
  "author": "Daniel Steigerwald <daniel@steigerwald.cz>",
6
6
  "license": "MIT",
@@ -30,11 +30,11 @@
30
30
  "shx": "^0.4.0",
31
31
  "typescript": "^5.9.2",
32
32
  "vitest": "^4.0.4",
33
- "@evolu/common": "6.0.1-preview.20",
33
+ "@evolu/common": "7.0.0",
34
34
  "@evolu/tsconfig": "0.0.2"
35
35
  },
36
36
  "peerDependencies": {
37
- "@evolu/common": "^6.0.1-preview.20"
37
+ "@evolu/common": "^7.0.0"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=22.0.0"
@@ -1,100 +1,177 @@
1
1
  import {
2
2
  ConsoleDep,
3
- createManyToManyMap,
3
+ createRelation,
4
4
  createRandom,
5
5
  createSqlite,
6
- getOrThrow,
6
+ CreateSqliteDriverDep,
7
+ isAsync,
8
+ ok,
7
9
  OwnerId,
10
+ RandomDep,
11
+ Result,
8
12
  SimpleName,
13
+ SqliteError,
14
+ TimingSafeEqualDep,
9
15
  Uint8Array,
10
16
  } from "@evolu/common";
11
17
  import {
12
18
  applyProtocolMessageAsRelay,
13
19
  ApplyProtocolMessageAsRelayOptions,
14
- createRelayStorage,
15
- maxProtocolMessageSize,
20
+ createBaseSqliteStorageTables,
21
+ createRelayLogger,
22
+ createRelaySqliteStorage,
23
+ createRelayStorageTables,
24
+ defaultProtocolMessageMaxSize,
25
+ parseOwnerIdFromOwnerWebSocketTransportUrl,
16
26
  Relay,
17
27
  RelayConfig,
18
- RelaySqliteStorageDeps,
19
28
  } from "@evolu/common/evolu";
29
+ import { existsSync } from "fs";
30
+ import { createServer } from "http";
20
31
  import { WebSocket, WebSocketServer } from "ws";
21
32
  import { createBetterSqliteDriver } from "../BetterSqliteDriver.js";
22
33
  import { createTimingSafeEqual } from "../Crypto.js";
23
34
 
24
35
  export interface NodeJsRelayConfig extends RelayConfig {
36
+ /** The port number for the HTTP server. */
25
37
  readonly port?: number;
26
38
  }
27
39
 
40
+ /**
41
+ * Creates an Evolu relay server.
42
+ *
43
+ * This implementation uses Node.js and better-sqlite3. Additional relay
44
+ * implementations will be provided for other platforms (Bun, Deno, Cloudflare
45
+ * Workers, Vercel Edge, etc.).
46
+ */
28
47
  export const createNodeJsRelay =
29
48
  (deps: ConsoleDep) =>
30
- async (config: NodeJsRelayConfig): Promise<Relay> => {
31
- const {
32
- port = 443,
33
- name = SimpleName.orThrow("evolu-relay"),
34
- enableLogging = false,
35
- } = config;
36
-
37
- deps.console.enabled = true;
38
- deps.console.log(`Evolu Relay started on port ${port}`);
39
- deps.console.enabled = enableLogging;
40
-
41
- const sqlite = getOrThrow(
42
- await createSqlite({
43
- ...deps,
44
- createSqliteDriver: createBetterSqliteDriver,
45
- })(name),
46
- );
47
-
48
- const relaySqliteStorageDeps: RelaySqliteStorageDeps = {
49
- sqlite,
49
+ (config: NodeJsRelayConfig): Promise<Result<Relay, SqliteError>> =>
50
+ createNodeJsRelayWithSqliteDriver({
51
+ ...deps,
52
+ createSqliteDriver: createBetterSqliteDriver,
53
+ })(config);
54
+
55
+ /**
56
+ * Creates an Evolu relay server with a custom SQLite driver.
57
+ *
58
+ * Use this when you need to provide a different SQLite driver implementation
59
+ * (e.g., using alternative SQLite libraries).
60
+ */
61
+ export const createNodeJsRelayWithSqliteDriver =
62
+ (deps: ConsoleDep & CreateSqliteDriverDep) =>
63
+ (config: NodeJsRelayConfig): Promise<Result<Relay, SqliteError>> =>
64
+ createNodeJsRelayWithDeps({
65
+ ...deps,
50
66
  random: createRandom(),
51
67
  timingSafeEqual: createTimingSafeEqual(),
52
- };
53
-
54
- const storage = getOrThrow(
55
- createRelayStorage(relaySqliteStorageDeps)({
56
- onStorageError: (error) => {
57
- deps.console.error("[relay]", "storage", error);
58
- },
59
- }),
60
- );
68
+ })(config);
69
+
70
+ const createNodeJsRelayWithDeps =
71
+ (deps: ConsoleDep & CreateSqliteDriverDep & RandomDep & TimingSafeEqualDep) =>
72
+ async ({
73
+ port = 443,
74
+ name = SimpleName.orThrow("evolu-relay"),
75
+ enableLogging = false,
76
+ isOwnerAllowed,
77
+ isOwnerWithinQuota,
78
+ }: NodeJsRelayConfig): Promise<Result<Relay, SqliteError>> => {
79
+ const log = createRelayLogger(deps);
80
+ log.started(enableLogging, port);
81
+
82
+ const dbFileExists = existsSync(`${name}.db`);
83
+
84
+ const sqlite = await createSqlite(deps)(name);
85
+ if (!sqlite.ok) return sqlite;
86
+
87
+ const depsWithSqlite = { ...deps, sqlite: sqlite.value };
88
+
89
+ if (!dbFileExists) {
90
+ const baseTables = createBaseSqliteStorageTables(depsWithSqlite);
91
+ if (!baseTables.ok) return baseTables;
92
+
93
+ const relayTables = createRelayStorageTables(depsWithSqlite);
94
+ if (!relayTables.ok) return relayTables;
95
+ }
96
+
97
+ const storage = createRelaySqliteStorage(depsWithSqlite)({
98
+ onStorageError: log.storageError,
99
+ isOwnerWithinQuota,
100
+ });
61
101
 
102
+ const server = createServer();
62
103
  const wss = new WebSocketServer({
63
- maxPayload: maxProtocolMessageSize,
64
- port,
104
+ maxPayload: defaultProtocolMessageMaxSize,
105
+ noServer: true,
65
106
  });
66
107
 
67
- const ownerSocketsMap = createManyToManyMap<OwnerId, WebSocket>();
108
+ const ownerSocketRelation = createRelation<OwnerId, WebSocket>();
109
+
110
+ server.on("upgrade", (request, socket, head) => {
111
+ socket.on("error", log.upgradeSocketError);
112
+
113
+ const completeUpgrade = () => {
114
+ socket.removeListener("error", log.upgradeSocketError);
115
+ wss.handleUpgrade(request, socket, head, (ws) => {
116
+ wss.emit("connection", ws, request);
117
+ });
118
+ };
119
+
120
+ if (!isOwnerAllowed) {
121
+ completeUpgrade();
122
+ return;
123
+ }
124
+
125
+ const ownerId = parseOwnerIdFromOwnerWebSocketTransportUrl(
126
+ request.url ?? "",
127
+ );
128
+
129
+ if (!ownerId) {
130
+ log.invalidOrMissingOwnerIdInUrl(request.url);
131
+ socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
132
+ socket.destroy();
133
+ return;
134
+ }
135
+
136
+ void (async () => {
137
+ const result = isOwnerAllowed(ownerId);
138
+ const isAllowed = isAsync(result) ? await result : result;
139
+ if (!isAllowed) {
140
+ log.unauthorizedOwner(ownerId);
141
+ socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
142
+ socket.destroy();
143
+ return;
144
+ }
145
+ completeUpgrade();
146
+ })();
147
+ });
68
148
 
69
149
  wss.on("connection", (ws) => {
70
- deps.console.log("[relay]", "connection", {
71
- clientCount: wss.clients.size,
72
- });
150
+ log.connectionEstablished(wss.clients.size);
73
151
 
74
152
  ws.on("error", (error) => {
75
- deps.console.warn("[relay]", "error", { error });
76
- deps.console.error(error);
153
+ log.connectionWebSocketError(error);
77
154
  });
78
155
 
79
156
  const options: ApplyProtocolMessageAsRelayOptions = {
80
157
  subscribe: (ownerId) => {
81
- ownerSocketsMap.add(ownerId, ws);
82
- deps.console.log("[relay]", "subscribe", {
158
+ ownerSocketRelation.add(ownerId, ws);
159
+ log.relayOptionSubscribe(
83
160
  ownerId,
84
- subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
85
- });
161
+ () => ownerSocketRelation.getB(ownerId)?.size ?? 0,
162
+ );
86
163
  },
87
164
 
88
165
  unsubscribe: (ownerId) => {
89
- ownerSocketsMap.remove(ownerId, ws);
90
- deps.console.log("[relay]", "unsubscribe", {
166
+ ownerSocketRelation.remove(ownerId, ws);
167
+ log.relayOptionUnsubscribe(
91
168
  ownerId,
92
- subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
93
- });
169
+ () => ownerSocketRelation.getB(ownerId)?.size ?? 0,
170
+ );
94
171
  },
95
172
 
96
173
  broadcast: (ownerId, message) => {
97
- const sockets = ownerSocketsMap.getValues(ownerId);
174
+ const sockets = ownerSocketRelation.getB(ownerId);
98
175
  if (!sockets) return;
99
176
 
100
177
  let broadcastCount = 0;
@@ -105,49 +182,36 @@ export const createNodeJsRelay =
105
182
  }
106
183
  }
107
184
 
108
- deps.console.log("[relay]", "broadcast", {
109
- ownerId,
110
- broadcastCount,
111
- totalSubscribers: sockets.size,
112
- });
185
+ log.relayOptionBroadcast(ownerId, broadcastCount, sockets.size);
113
186
  },
114
187
  };
115
188
 
116
189
  ws.on("message", (message) => {
117
190
  if (!Uint8Array.is(message)) return;
118
-
119
- deps.console.log("[relay]", "on message", {
120
- messageSize: message.length,
121
- });
191
+ log.messageLength(message.length);
122
192
 
123
193
  applyProtocolMessageAsRelay({ storage })(message, options)
124
194
  .then((response) => {
125
195
  if (!response.ok) {
126
- deps.console.error("[relay]", "protocol", response.error);
127
- deps.console.error(response.error);
196
+ log.applyProtocolMessageAsRelayError(response.error);
128
197
  return;
129
198
  }
130
-
131
199
  ws.send(response.value.message, { binary: true });
132
- deps.console.log("[relay]", "response", {
133
- responseSize: response.value.message.length,
134
- });
200
+ log.responseLength(response.value.message.length);
135
201
  })
136
- .catch((error: unknown) => {
137
- deps.console.error("[relay]", "applyProtocolMessageAsRelay", error);
138
- });
202
+ .catch(log.applyProtocolMessageAsRelayUnknownError);
139
203
  });
140
204
 
141
205
  ws.on("close", () => {
142
- ownerSocketsMap.deleteValue(ws);
143
- deps.console.log("[relay]", "close", {
144
- clientCount: wss.clients.size,
145
- });
206
+ ownerSocketRelation.deleteB(ws);
207
+ log.connectionClosed(wss.clients.size);
146
208
  });
147
209
  });
148
210
 
149
- const disposeWss = () => {
150
- deps.console.log("Shutting down Evolu Relay...");
211
+ server.listen(port);
212
+
213
+ const dispose = () => {
214
+ log.shuttingDown();
151
215
 
152
216
  wss.clients.forEach((client) => {
153
217
  if (client.readyState === WebSocket.OPEN) {
@@ -156,18 +220,24 @@ export const createNodeJsRelay =
156
220
  });
157
221
 
158
222
  wss.close(() => {
159
- deps.console.log("Evolu Relay disposed");
223
+ log.webSocketServerDisposed();
224
+ });
225
+
226
+ server.close(() => {
227
+ log.httpServerDisposed();
160
228
  });
161
229
  };
162
230
 
163
231
  let isDisposed = false;
164
232
 
165
- return {
233
+ const relay: Relay = {
166
234
  [Symbol.dispose]: () => {
167
235
  if (isDisposed) return;
168
236
  isDisposed = true;
169
- sqlite[Symbol.dispose]();
170
- disposeWss();
237
+ sqlite.value[Symbol.dispose]();
238
+ dispose();
171
239
  },
172
240
  };
241
+
242
+ return ok(relay);
173
243
  };