@evolu/nodejs 1.0.1-preview.6 → 1.0.1-preview.8

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 +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,CAuG/C,CAAC"}
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"}
@@ -4,7 +4,7 @@ import { WebSocket, WebSocketServer } from "ws";
4
4
  import { createBetterSqliteDriver } from "../BetterSqliteDriver.js";
5
5
  import { createTimingSafeEqual } from "../Crypto.js";
6
6
  export const createNodeJsRelay = (deps) => async (config) => {
7
- const { port = 443, name = getOrThrow(SimpleName.from("evolu-relay")), enableLogging = false, } = config;
7
+ const { port = 443, name = SimpleName.orThrow("evolu-relay"), enableLogging = false, } = config;
8
8
  deps.console.enabled = true;
9
9
  deps.console.log(`Evolu Relay started on port ${port}`);
10
10
  deps.console.enabled = enableLogging;
@@ -19,7 +19,7 @@ export const createNodeJsRelay = (deps) => async (config) => {
19
19
  };
20
20
  const storage = getOrThrow(createRelayStorage(relaySqliteStorageDeps)({
21
21
  onStorageError: (error) => {
22
- deps.console.error("[relay]", "[storage]", error);
22
+ deps.console.error("[relay]", "storage", error);
23
23
  },
24
24
  }));
25
25
  const wss = new WebSocketServer({
@@ -28,34 +28,73 @@ export const createNodeJsRelay = (deps) => async (config) => {
28
28
  });
29
29
  const ownerSocketsMap = createManyToManyMap();
30
30
  wss.on("connection", (ws) => {
31
- ws.on("error", deps.console.error);
31
+ deps.console.log("[relay]", "connection", {
32
+ clientCount: wss.clients.size,
33
+ });
34
+ ws.on("error", (error) => {
35
+ deps.console.warn("[relay]", "error", { error });
36
+ deps.console.error(error);
37
+ });
32
38
  const options = {
33
39
  subscribe: (ownerId) => {
34
40
  ownerSocketsMap.add(ownerId, ws);
41
+ deps.console.log("[relay]", "subscribe", {
42
+ ownerId,
43
+ subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
44
+ });
45
+ },
46
+ unsubscribe: (ownerId) => {
47
+ ownerSocketsMap.remove(ownerId, ws);
48
+ deps.console.log("[relay]", "unsubscribe", {
49
+ ownerId,
50
+ subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
51
+ });
35
52
  },
36
53
  broadcast: (ownerId, message) => {
37
54
  const sockets = ownerSocketsMap.getValues(ownerId);
55
+ if (!sockets)
56
+ return;
57
+ let broadcastCount = 0;
38
58
  for (const socket of sockets) {
39
59
  if (socket !== ws && socket.readyState === WebSocket.OPEN) {
40
60
  socket.send(message, { binary: true });
61
+ broadcastCount++;
41
62
  }
42
63
  }
64
+ deps.console.log("[relay]", "broadcast", {
65
+ ownerId,
66
+ broadcastCount,
67
+ totalSubscribers: sockets.size,
68
+ });
43
69
  },
44
70
  };
45
71
  ws.on("message", (message) => {
46
72
  if (!Uint8Array.is(message))
47
73
  return;
48
- const response = applyProtocolMessageAsRelay({ storage })(message, options);
49
- if (!response.ok) {
50
- deps.console.warn(response.error.type);
51
- return;
52
- }
53
- if (response.value) {
54
- ws.send(response.value, { binary: true });
55
- }
74
+ deps.console.log("[relay]", "on message", {
75
+ messageSize: message.length,
76
+ });
77
+ applyProtocolMessageAsRelay({ storage })(message, options)
78
+ .then((response) => {
79
+ if (!response.ok) {
80
+ deps.console.error("[relay]", "protocol", response.error);
81
+ deps.console.error(response.error);
82
+ return;
83
+ }
84
+ ws.send(response.value.message, { binary: true });
85
+ deps.console.log("[relay]", "response", {
86
+ responseSize: response.value.message.length,
87
+ });
88
+ })
89
+ .catch((error) => {
90
+ deps.console.error("[relay]", "applyProtocolMessageAsRelay", error);
91
+ });
56
92
  });
57
93
  ws.on("close", () => {
58
94
  ownerSocketsMap.deleteValue(ws);
95
+ deps.console.log("[relay]", "close", {
96
+ clientCount: wss.clients.size,
97
+ });
59
98
  });
60
99
  });
61
100
  const disposeWss = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evolu/nodejs",
3
- "version": "1.0.1-preview.6",
3
+ "version": "1.0.1-preview.8",
4
4
  "description": "Evolu for Node.js",
5
5
  "author": "Daniel Steigerwald <daniel@steigerwald.cz>",
6
6
  "license": "MIT",
@@ -25,14 +25,16 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/better-sqlite3": "^7.6.13",
28
- "@types/node": "^22.15.31",
29
- "typescript": "^5.8.3",
30
- "vitest": "^3.2.3",
31
- "@evolu/common": "6.0.1-preview.14",
28
+ "@types/node": "^22.17.1",
29
+ "@types/ws": "^8.18.1",
30
+ "shx": "^0.4.0",
31
+ "typescript": "^5.9.2",
32
+ "vitest": "^4.0.4",
33
+ "@evolu/common": "6.0.1-preview.20",
32
34
  "@evolu/tsconfig": "0.0.2"
33
35
  },
34
36
  "peerDependencies": {
35
- "@evolu/common": "^6.0.1-preview.14"
37
+ "@evolu/common": "^6.0.1-preview.20"
36
38
  },
37
39
  "engines": {
38
40
  "node": ">=22.0.0"
@@ -30,7 +30,7 @@ export const createNodeJsRelay =
30
30
  async (config: NodeJsRelayConfig): Promise<Relay> => {
31
31
  const {
32
32
  port = 443,
33
- name = getOrThrow(SimpleName.from("evolu-relay")),
33
+ name = SimpleName.orThrow("evolu-relay"),
34
34
  enableLogging = false,
35
35
  } = config;
36
36
 
@@ -54,7 +54,7 @@ export const createNodeJsRelay =
54
54
  const storage = getOrThrow(
55
55
  createRelayStorage(relaySqliteStorageDeps)({
56
56
  onStorageError: (error) => {
57
- deps.console.error("[relay]", "[storage]", error);
57
+ deps.console.error("[relay]", "storage", error);
58
58
  },
59
59
  }),
60
60
  );
@@ -67,42 +67,82 @@ export const createNodeJsRelay =
67
67
  const ownerSocketsMap = createManyToManyMap<OwnerId, WebSocket>();
68
68
 
69
69
  wss.on("connection", (ws) => {
70
- ws.on("error", deps.console.error);
70
+ deps.console.log("[relay]", "connection", {
71
+ clientCount: wss.clients.size,
72
+ });
73
+
74
+ ws.on("error", (error) => {
75
+ deps.console.warn("[relay]", "error", { error });
76
+ deps.console.error(error);
77
+ });
71
78
 
72
79
  const options: ApplyProtocolMessageAsRelayOptions = {
73
80
  subscribe: (ownerId) => {
74
81
  ownerSocketsMap.add(ownerId, ws);
82
+ deps.console.log("[relay]", "subscribe", {
83
+ ownerId,
84
+ subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
85
+ });
75
86
  },
87
+
88
+ unsubscribe: (ownerId) => {
89
+ ownerSocketsMap.remove(ownerId, ws);
90
+ deps.console.log("[relay]", "unsubscribe", {
91
+ ownerId,
92
+ subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
93
+ });
94
+ },
95
+
76
96
  broadcast: (ownerId, message) => {
77
- const sockets = ownerSocketsMap.getValues(ownerId)!;
97
+ const sockets = ownerSocketsMap.getValues(ownerId);
98
+ if (!sockets) return;
99
+
100
+ let broadcastCount = 0;
78
101
  for (const socket of sockets) {
79
102
  if (socket !== ws && socket.readyState === WebSocket.OPEN) {
80
103
  socket.send(message, { binary: true });
104
+ broadcastCount++;
81
105
  }
82
106
  }
107
+
108
+ deps.console.log("[relay]", "broadcast", {
109
+ ownerId,
110
+ broadcastCount,
111
+ totalSubscribers: sockets.size,
112
+ });
83
113
  },
84
114
  };
85
115
 
86
116
  ws.on("message", (message) => {
87
117
  if (!Uint8Array.is(message)) return;
88
118
 
89
- const response = applyProtocolMessageAsRelay({ storage })(
90
- message,
91
- options,
92
- );
119
+ deps.console.log("[relay]", "on message", {
120
+ messageSize: message.length,
121
+ });
93
122
 
94
- if (!response.ok) {
95
- deps.console.warn(response.error.type);
96
- return;
97
- }
123
+ applyProtocolMessageAsRelay({ storage })(message, options)
124
+ .then((response) => {
125
+ if (!response.ok) {
126
+ deps.console.error("[relay]", "protocol", response.error);
127
+ deps.console.error(response.error);
128
+ return;
129
+ }
98
130
 
99
- if (response.value) {
100
- ws.send(response.value, { binary: true });
101
- }
131
+ ws.send(response.value.message, { binary: true });
132
+ deps.console.log("[relay]", "response", {
133
+ responseSize: response.value.message.length,
134
+ });
135
+ })
136
+ .catch((error: unknown) => {
137
+ deps.console.error("[relay]", "applyProtocolMessageAsRelay", error);
138
+ });
102
139
  });
103
140
 
104
141
  ws.on("close", () => {
105
142
  ownerSocketsMap.deleteValue(ws);
143
+ deps.console.log("[relay]", "close", {
144
+ clientCount: wss.clients.size,
145
+ });
106
146
  });
107
147
  });
108
148