@synnaxlabs/client 0.57.2 → 0.57.3

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.
Files changed (42) hide show
  1. package/dist/{client-BsVW3qAW.js → client-CX6CMvCc.js} +3617 -3528
  2. package/dist/client-CX6CMvCc.js.map +1 -0
  3. package/dist/client.js +1 -1
  4. package/dist/src/arc/client.d.ts.map +1 -1
  5. package/dist/src/channel/client.d.ts +1 -0
  6. package/dist/src/channel/client.d.ts.map +1 -1
  7. package/dist/src/device/client.d.ts.map +1 -1
  8. package/dist/src/framer/streamer.d.ts +34 -18
  9. package/dist/src/framer/streamer.d.ts.map +1 -1
  10. package/dist/src/query/indexes.d.ts +10 -4
  11. package/dist/src/query/indexes.d.ts.map +1 -1
  12. package/dist/src/query/table.d.ts +10 -3
  13. package/dist/src/query/table.d.ts.map +1 -1
  14. package/dist/src/rack/client.d.ts.map +1 -1
  15. package/dist/src/ranger/client.d.ts +9 -1
  16. package/dist/src/ranger/client.d.ts.map +1 -1
  17. package/dist/src/status/client.d.ts.map +1 -1
  18. package/dist/src/status/status.d.ts +2 -0
  19. package/dist/src/status/status.d.ts.map +1 -1
  20. package/dist/src/task/client.d.ts +19 -1
  21. package/dist/src/task/client.d.ts.map +1 -1
  22. package/dist/src/testutil/client.d.ts +2 -0
  23. package/dist/src/testutil/client.d.ts.map +1 -1
  24. package/dist/src/testutil/proxy.d.ts +8 -0
  25. package/dist/src/testutil/proxy.d.ts.map +1 -1
  26. package/dist/testutil.js +80 -60
  27. package/dist/testutil.js.map +1 -1
  28. package/package.json +3 -3
  29. package/src/arc/client.ts +2 -20
  30. package/src/channel/client.ts +11 -6
  31. package/src/device/client.ts +4 -3
  32. package/src/framer/streamer.ts +71 -6
  33. package/src/query/indexes.ts +19 -6
  34. package/src/query/table.ts +50 -8
  35. package/src/rack/client.ts +5 -4
  36. package/src/ranger/client.ts +39 -8
  37. package/src/status/client.ts +1 -3
  38. package/src/status/status.ts +14 -0
  39. package/src/task/client.ts +54 -19
  40. package/src/testutil/client.ts +5 -1
  41. package/src/testutil/proxy.ts +59 -6
  42. package/dist/client-BsVW3qAW.js.map +0 -1
@@ -35,12 +35,27 @@ export interface SeverableProxy {
35
35
  port: number;
36
36
  /** Drops every live connection and refuses new ones, as if the cluster died. */
37
37
  sever: () => Promise<void>;
38
+ /**
39
+ * Silently kills every live WebSocket connection, modeling a half-open socket (NAT
40
+ * timeout, VPN drop, laptop sleep): the cluster side is destroyed while the client
41
+ * side is held open with its writes discarded, so no close or reset ever reaches the
42
+ * client. New connections still forward. Returns how many connections were
43
+ * blackholed.
44
+ */
45
+ blackholeStreams: () => number;
38
46
  /** Accepts connections again on the same port. */
39
47
  restore: () => Promise<void>;
40
48
  /** Shuts the proxy down for good. */
41
49
  close: () => Promise<void>;
42
50
  }
43
51
 
52
+ interface ProxiedPair {
53
+ downstream: Socket;
54
+ upstream: Socket;
55
+ /** Whether a WebSocket upgrade was observed on this connection. */
56
+ ws: boolean;
57
+ }
58
+
44
59
  /**
45
60
  * Creates a TCP proxy in front of the live test cluster so specs can simulate
46
61
  * cluster downtime without touching the cluster itself. Connect a client to
@@ -50,7 +65,10 @@ export const createSeverableProxy = async (
50
65
  target: SeverableProxyTarget = {},
51
66
  ): Promise<SeverableProxy> => {
52
67
  const { host, port } = { ...DEFAULT_TARGET, ...target };
53
- const sockets = new Set<Socket>();
68
+ const pairs = new Set<ProxiedPair>();
69
+ // Client-side sockets of blackholed connections: held open, silent, until the proxy
70
+ // is severed or closed.
71
+ const zombies = new Set<Socket>();
54
72
  let severed = false;
55
73
  const server = createServer((downstream) => {
56
74
  // A connection the kernel accepted before the sever is still delivered after it,
@@ -60,10 +78,16 @@ export const createSeverableProxy = async (
60
78
  return;
61
79
  }
62
80
  const upstream = connect(port, host);
63
- sockets.add(downstream).add(upstream);
81
+ const pair: ProxiedPair = { downstream, upstream, ws: false };
82
+ pairs.add(pair);
83
+ // The upgrade can arrive on any request of a pooled keep-alive connection, not just
84
+ // the first, so every chunk is sniffed until one is seen.
85
+ downstream.on("data", (chunk: Buffer) => {
86
+ if (!pair.ws && /upgrade:\s*websocket/i.test(chunk.toString("latin1")))
87
+ pair.ws = true;
88
+ });
64
89
  const destroy = (): void => {
65
- sockets.delete(downstream);
66
- sockets.delete(upstream);
90
+ pairs.delete(pair);
67
91
  downstream.destroy();
68
92
  upstream.destroy();
69
93
  };
@@ -90,13 +114,42 @@ export const createSeverableProxy = async (
90
114
  const sever = async (): Promise<void> => {
91
115
  severed = true;
92
116
  const closed = new Promise<void>((resolve) => server.close(() => resolve()));
93
- sockets.forEach((socket) => socket.destroy());
94
- sockets.clear();
117
+ pairs.forEach(({ downstream, upstream }) => {
118
+ downstream.destroy();
119
+ upstream.destroy();
120
+ });
121
+ pairs.clear();
122
+ zombies.forEach((socket) => socket.destroy());
123
+ zombies.clear();
95
124
  await closed;
96
125
  };
126
+ const blackholeStreams = (): number => {
127
+ let count = 0;
128
+ for (const pair of [...pairs]) {
129
+ if (!pair.ws) continue;
130
+ count += 1;
131
+ const { downstream, upstream } = pair;
132
+ downstream.unpipe(upstream);
133
+ upstream.unpipe(downstream);
134
+ for (const socket of [downstream, upstream]) {
135
+ socket.removeAllListeners("close");
136
+ socket.removeAllListeners("error");
137
+ socket.on("error", () => {});
138
+ }
139
+ // Discard anything the client still writes so backpressure cannot close the
140
+ // socket on the proxy's behalf.
141
+ downstream.on("data", () => {});
142
+ downstream.resume();
143
+ upstream.destroy();
144
+ pairs.delete(pair);
145
+ zombies.add(downstream);
146
+ }
147
+ return count;
148
+ };
97
149
  return {
98
150
  port: boundPort,
99
151
  sever,
152
+ blackholeStreams,
100
153
  restore: async () => {
101
154
  severed = false;
102
155
  await listen(boundPort);