rivetkit 2.0.2 → 2.0.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.
- package/dist/schemas/actor-persist/v1.ts +228 -0
- package/dist/schemas/client-protocol/v1.ts +429 -0
- package/dist/schemas/file-system-driver/v1.ts +102 -0
- package/dist/tsup/actor/errors.cjs +69 -0
- package/dist/tsup/actor/errors.cjs.map +1 -0
- package/dist/tsup/actor/errors.d.cts +143 -0
- package/dist/tsup/actor/errors.d.ts +143 -0
- package/dist/tsup/actor/errors.js +69 -0
- package/dist/tsup/actor/errors.js.map +1 -0
- package/dist/tsup/chunk-2CRLFV6Z.cjs +202 -0
- package/dist/tsup/chunk-2CRLFV6Z.cjs.map +1 -0
- package/dist/tsup/chunk-3H7O2A7I.js +525 -0
- package/dist/tsup/chunk-3H7O2A7I.js.map +1 -0
- package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
- package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
- package/dist/tsup/chunk-4NSUQZ2H.js +1790 -0
- package/dist/tsup/chunk-4NSUQZ2H.js.map +1 -0
- package/dist/tsup/chunk-6PDXBYI5.js +132 -0
- package/dist/tsup/chunk-6PDXBYI5.js.map +1 -0
- package/dist/tsup/chunk-6WKQDDUD.cjs +1790 -0
- package/dist/tsup/chunk-6WKQDDUD.cjs.map +1 -0
- package/dist/tsup/chunk-CTBOSFUH.cjs +116 -0
- package/dist/tsup/chunk-CTBOSFUH.cjs.map +1 -0
- package/dist/tsup/chunk-EGVZZFE2.js +2857 -0
- package/dist/tsup/chunk-EGVZZFE2.js.map +1 -0
- package/dist/tsup/chunk-FCCPJNMA.cjs +132 -0
- package/dist/tsup/chunk-FCCPJNMA.cjs.map +1 -0
- package/dist/tsup/chunk-FLMTTN27.js +244 -0
- package/dist/tsup/chunk-FLMTTN27.js.map +1 -0
- package/dist/tsup/chunk-GIR3AFFI.cjs +315 -0
- package/dist/tsup/chunk-GIR3AFFI.cjs.map +1 -0
- package/dist/tsup/chunk-INGJP237.js +315 -0
- package/dist/tsup/chunk-INGJP237.js.map +1 -0
- package/dist/tsup/chunk-KJCJLKRM.js +116 -0
- package/dist/tsup/chunk-KJCJLKRM.js.map +1 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
- package/dist/tsup/chunk-O2MBYIXO.cjs +2857 -0
- package/dist/tsup/chunk-O2MBYIXO.cjs.map +1 -0
- package/dist/tsup/chunk-OGAPU3UG.cjs +525 -0
- package/dist/tsup/chunk-OGAPU3UG.cjs.map +1 -0
- package/dist/tsup/chunk-OV6AYD4S.js +4406 -0
- package/dist/tsup/chunk-OV6AYD4S.js.map +1 -0
- package/dist/tsup/chunk-PO4VLDWA.js +47 -0
- package/dist/tsup/chunk-PO4VLDWA.js.map +1 -0
- package/dist/tsup/chunk-R2OPSKIV.cjs +244 -0
- package/dist/tsup/chunk-R2OPSKIV.cjs.map +1 -0
- package/dist/tsup/chunk-TZJKSBUQ.cjs +47 -0
- package/dist/tsup/chunk-TZJKSBUQ.cjs.map +1 -0
- package/dist/tsup/chunk-UBUC5C3G.cjs +189 -0
- package/dist/tsup/chunk-UBUC5C3G.cjs.map +1 -0
- package/dist/tsup/chunk-UIM22YJL.cjs +4406 -0
- package/dist/tsup/chunk-UIM22YJL.cjs.map +1 -0
- package/dist/tsup/chunk-URVFQMYI.cjs +230 -0
- package/dist/tsup/chunk-URVFQMYI.cjs.map +1 -0
- package/dist/tsup/chunk-UVUPOS46.js +230 -0
- package/dist/tsup/chunk-UVUPOS46.js.map +1 -0
- package/dist/tsup/chunk-VRRHBNJC.js +189 -0
- package/dist/tsup/chunk-VRRHBNJC.js.map +1 -0
- package/dist/tsup/chunk-XFSS33EQ.js +202 -0
- package/dist/tsup/chunk-XFSS33EQ.js.map +1 -0
- package/dist/tsup/client/mod.cjs +32 -0
- package/dist/tsup/client/mod.cjs.map +1 -0
- package/dist/tsup/client/mod.d.cts +26 -0
- package/dist/tsup/client/mod.d.ts +26 -0
- package/dist/tsup/client/mod.js +32 -0
- package/dist/tsup/client/mod.js.map +1 -0
- package/dist/tsup/common/log.cjs +13 -0
- package/dist/tsup/common/log.cjs.map +1 -0
- package/dist/tsup/common/log.d.cts +20 -0
- package/dist/tsup/common/log.d.ts +20 -0
- package/dist/tsup/common/log.js +13 -0
- package/dist/tsup/common/log.js.map +1 -0
- package/dist/tsup/common/websocket.cjs +10 -0
- package/dist/tsup/common/websocket.cjs.map +1 -0
- package/dist/tsup/common/websocket.d.cts +3 -0
- package/dist/tsup/common/websocket.d.ts +3 -0
- package/dist/tsup/common/websocket.js +10 -0
- package/dist/tsup/common/websocket.js.map +1 -0
- package/dist/tsup/common-CpqORuCq.d.cts +218 -0
- package/dist/tsup/common-CpqORuCq.d.ts +218 -0
- package/dist/tsup/connection-BR_Ve4ku.d.cts +2117 -0
- package/dist/tsup/connection-BwUMoe6n.d.ts +2117 -0
- package/dist/tsup/driver-helpers/mod.cjs +33 -0
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
- package/dist/tsup/driver-helpers/mod.d.cts +18 -0
- package/dist/tsup/driver-helpers/mod.d.ts +18 -0
- package/dist/tsup/driver-helpers/mod.js +33 -0
- package/dist/tsup/driver-helpers/mod.js.map +1 -0
- package/dist/tsup/driver-test-suite/mod.cjs +4619 -0
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
- package/dist/tsup/driver-test-suite/mod.d.cts +57 -0
- package/dist/tsup/driver-test-suite/mod.d.ts +57 -0
- package/dist/tsup/driver-test-suite/mod.js +4619 -0
- package/dist/tsup/driver-test-suite/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +53 -0
- package/dist/tsup/inspector/mod.cjs.map +1 -0
- package/dist/tsup/inspector/mod.d.cts +408 -0
- package/dist/tsup/inspector/mod.d.ts +408 -0
- package/dist/tsup/inspector/mod.js +53 -0
- package/dist/tsup/inspector/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +73 -0
- package/dist/tsup/mod.cjs.map +1 -0
- package/dist/tsup/mod.d.cts +100 -0
- package/dist/tsup/mod.d.ts +100 -0
- package/dist/tsup/mod.js +73 -0
- package/dist/tsup/mod.js.map +1 -0
- package/dist/tsup/router-endpoints-AYkXG8Tl.d.cts +66 -0
- package/dist/tsup/router-endpoints-DAbqVFx2.d.ts +66 -0
- package/dist/tsup/test/mod.cjs +21 -0
- package/dist/tsup/test/mod.cjs.map +1 -0
- package/dist/tsup/test/mod.d.cts +27 -0
- package/dist/tsup/test/mod.d.ts +27 -0
- package/dist/tsup/test/mod.js +21 -0
- package/dist/tsup/test/mod.js.map +1 -0
- package/dist/tsup/utils-CT0cv4jd.d.cts +17 -0
- package/dist/tsup/utils-CT0cv4jd.d.ts +17 -0
- package/dist/tsup/utils.cjs +26 -0
- package/dist/tsup/utils.cjs.map +1 -0
- package/dist/tsup/utils.d.cts +36 -0
- package/dist/tsup/utils.d.ts +36 -0
- package/dist/tsup/utils.js +26 -0
- package/dist/tsup/utils.js.map +1 -0
- package/package.json +208 -5
- package/src/actor/action.ts +182 -0
- package/src/actor/config.ts +765 -0
- package/src/actor/connection.ts +260 -0
- package/src/actor/context.ts +171 -0
- package/src/actor/database.ts +23 -0
- package/src/actor/definition.ts +86 -0
- package/src/actor/driver.ts +84 -0
- package/src/actor/errors.ts +360 -0
- package/src/actor/generic-conn-driver.ts +234 -0
- package/src/actor/instance.ts +1800 -0
- package/src/actor/log.ts +15 -0
- package/src/actor/mod.ts +113 -0
- package/src/actor/persisted.ts +42 -0
- package/src/actor/protocol/old.ts +281 -0
- package/src/actor/protocol/serde.ts +131 -0
- package/src/actor/router-endpoints.ts +685 -0
- package/src/actor/router.ts +263 -0
- package/src/actor/schedule.ts +17 -0
- package/src/actor/unstable-react.ts +110 -0
- package/src/actor/utils.ts +98 -0
- package/src/client/actor-common.ts +30 -0
- package/src/client/actor-conn.ts +804 -0
- package/src/client/actor-handle.ts +208 -0
- package/src/client/client.ts +623 -0
- package/src/client/errors.ts +41 -0
- package/src/client/http-client-driver.ts +326 -0
- package/src/client/log.ts +7 -0
- package/src/client/mod.ts +56 -0
- package/src/client/raw-utils.ts +92 -0
- package/src/client/test.ts +44 -0
- package/src/client/utils.ts +150 -0
- package/src/common/eventsource-interface.ts +47 -0
- package/src/common/eventsource.ts +80 -0
- package/src/common/fake-event-source.ts +266 -0
- package/src/common/inline-websocket-adapter2.ts +445 -0
- package/src/common/log-levels.ts +27 -0
- package/src/common/log.ts +139 -0
- package/src/common/logfmt.ts +228 -0
- package/src/common/network.ts +2 -0
- package/src/common/router.ts +87 -0
- package/src/common/utils.ts +322 -0
- package/src/common/versioned-data.ts +95 -0
- package/src/common/websocket-interface.ts +49 -0
- package/src/common/websocket.ts +43 -0
- package/src/driver-helpers/mod.ts +22 -0
- package/src/driver-helpers/utils.ts +17 -0
- package/src/driver-test-suite/log.ts +7 -0
- package/src/driver-test-suite/mod.ts +213 -0
- package/src/driver-test-suite/test-inline-client-driver.ts +402 -0
- package/src/driver-test-suite/tests/action-features.ts +136 -0
- package/src/driver-test-suite/tests/actor-auth.ts +591 -0
- package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
- package/src/driver-test-suite/tests/actor-conn.ts +349 -0
- package/src/driver-test-suite/tests/actor-driver.ts +25 -0
- package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
- package/src/driver-test-suite/tests/actor-handle.ts +259 -0
- package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
- package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
- package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
- package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
- package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
- package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
- package/src/driver-test-suite/tests/actor-state.ts +54 -0
- package/src/driver-test-suite/tests/actor-vars.ts +93 -0
- package/src/driver-test-suite/tests/manager-driver.ts +365 -0
- package/src/driver-test-suite/tests/raw-http-direct-registry.ts +226 -0
- package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
- package/src/driver-test-suite/tests/raw-http.ts +347 -0
- package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +392 -0
- package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
- package/src/driver-test-suite/tests/request-access.ts +244 -0
- package/src/driver-test-suite/utils.ts +68 -0
- package/src/drivers/default.ts +31 -0
- package/src/drivers/engine/actor-driver.ts +360 -0
- package/src/drivers/engine/api-endpoints.ts +128 -0
- package/src/drivers/engine/api-utils.ts +70 -0
- package/src/drivers/engine/config.ts +39 -0
- package/src/drivers/engine/keys.test.ts +266 -0
- package/src/drivers/engine/keys.ts +89 -0
- package/src/drivers/engine/kv.ts +3 -0
- package/src/drivers/engine/log.ts +7 -0
- package/src/drivers/engine/manager-driver.ts +391 -0
- package/src/drivers/engine/mod.ts +36 -0
- package/src/drivers/engine/ws-proxy.ts +170 -0
- package/src/drivers/file-system/actor.ts +91 -0
- package/src/drivers/file-system/global-state.ts +673 -0
- package/src/drivers/file-system/log.ts +7 -0
- package/src/drivers/file-system/manager.ts +306 -0
- package/src/drivers/file-system/mod.ts +48 -0
- package/src/drivers/file-system/utils.ts +109 -0
- package/src/globals.d.ts +6 -0
- package/src/inline-client-driver/log.ts +7 -0
- package/src/inline-client-driver/mod.ts +385 -0
- package/src/inspector/actor.ts +298 -0
- package/src/inspector/config.ts +83 -0
- package/src/inspector/log.ts +5 -0
- package/src/inspector/manager.ts +86 -0
- package/src/inspector/mod.ts +2 -0
- package/src/inspector/protocol/actor.ts +10 -0
- package/src/inspector/protocol/common.ts +196 -0
- package/src/inspector/protocol/manager.ts +10 -0
- package/src/inspector/protocol/mod.ts +2 -0
- package/src/inspector/utils.ts +76 -0
- package/src/manager/auth.ts +121 -0
- package/src/manager/driver.ts +80 -0
- package/src/manager/hono-websocket-adapter.ts +333 -0
- package/src/manager/log.ts +7 -0
- package/src/manager/mod.ts +2 -0
- package/src/manager/protocol/mod.ts +24 -0
- package/src/manager/protocol/query.ts +89 -0
- package/src/manager/router.ts +1792 -0
- package/src/mod.ts +20 -0
- package/src/registry/config.ts +32 -0
- package/src/registry/log.ts +7 -0
- package/src/registry/mod.ts +124 -0
- package/src/registry/run-config.ts +54 -0
- package/src/registry/serve.ts +53 -0
- package/src/schemas/actor-persist/mod.ts +1 -0
- package/src/schemas/actor-persist/versioned.ts +25 -0
- package/src/schemas/client-protocol/mod.ts +1 -0
- package/src/schemas/client-protocol/versioned.ts +63 -0
- package/src/schemas/file-system-driver/mod.ts +1 -0
- package/src/schemas/file-system-driver/versioned.ts +28 -0
- package/src/serde.ts +84 -0
- package/src/test/config.ts +16 -0
- package/src/test/log.ts +7 -0
- package/src/test/mod.ts +153 -0
- package/src/utils.ts +172 -0
- package/README.md +0 -13
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import type { DriverTestConfig } from "../mod";
|
|
3
|
+
import { setupDriverTest } from "../utils";
|
|
4
|
+
|
|
5
|
+
export function runRawWebSocketTests(driverTestConfig: DriverTestConfig) {
|
|
6
|
+
describe("raw websocket", () => {
|
|
7
|
+
test("should establish raw WebSocket connection", async (c) => {
|
|
8
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
9
|
+
const actor = client.rawWebSocketActor.getOrCreate(["basic"]);
|
|
10
|
+
|
|
11
|
+
const ws = await actor.websocket();
|
|
12
|
+
|
|
13
|
+
// The WebSocket should already be open since openWebSocket waits for openPromise
|
|
14
|
+
// But we still need to ensure any buffered events are processed
|
|
15
|
+
await new Promise<void>((resolve) => {
|
|
16
|
+
// If already open, resolve immediately
|
|
17
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
18
|
+
resolve();
|
|
19
|
+
} else {
|
|
20
|
+
// Otherwise wait for open event
|
|
21
|
+
ws.addEventListener(
|
|
22
|
+
"open",
|
|
23
|
+
() => {
|
|
24
|
+
resolve();
|
|
25
|
+
},
|
|
26
|
+
{ once: true },
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Should receive welcome message
|
|
32
|
+
const welcomeMessage = await new Promise<any>((resolve, reject) => {
|
|
33
|
+
ws.addEventListener(
|
|
34
|
+
"message",
|
|
35
|
+
(event: any) => {
|
|
36
|
+
resolve(JSON.parse(event.data as string));
|
|
37
|
+
},
|
|
38
|
+
{ once: true },
|
|
39
|
+
);
|
|
40
|
+
ws.addEventListener("close", reject);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(welcomeMessage.type).toBe("welcome");
|
|
44
|
+
expect(welcomeMessage.connectionCount).toBe(1);
|
|
45
|
+
|
|
46
|
+
ws.close();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should echo messages", async (c) => {
|
|
50
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
51
|
+
const actor = client.rawWebSocketActor.getOrCreate(["echo"]);
|
|
52
|
+
|
|
53
|
+
const ws = await actor.websocket();
|
|
54
|
+
|
|
55
|
+
// Check if WebSocket is already open
|
|
56
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
57
|
+
await new Promise<void>((resolve, reject) => {
|
|
58
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
59
|
+
ws.addEventListener("close", reject);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Skip welcome message
|
|
64
|
+
await new Promise<void>((resolve, reject) => {
|
|
65
|
+
ws.addEventListener("message", () => resolve(), { once: true });
|
|
66
|
+
ws.addEventListener("close", reject);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Send and receive echo
|
|
70
|
+
const testMessage = { test: "data", timestamp: Date.now() };
|
|
71
|
+
ws.send(JSON.stringify(testMessage));
|
|
72
|
+
|
|
73
|
+
const echoMessage = await new Promise<any>((resolve, reject) => {
|
|
74
|
+
ws.addEventListener(
|
|
75
|
+
"message",
|
|
76
|
+
(event: any) => {
|
|
77
|
+
resolve(JSON.parse(event.data as string));
|
|
78
|
+
},
|
|
79
|
+
{ once: true },
|
|
80
|
+
);
|
|
81
|
+
ws.addEventListener("close", reject);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(echoMessage).toEqual(testMessage);
|
|
85
|
+
|
|
86
|
+
ws.close();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("should handle ping/pong protocol", async (c) => {
|
|
90
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
91
|
+
const actor = client.rawWebSocketActor.getOrCreate(["ping"]);
|
|
92
|
+
|
|
93
|
+
const ws = await actor.websocket();
|
|
94
|
+
|
|
95
|
+
// Check if WebSocket is already open
|
|
96
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
97
|
+
await new Promise<void>((resolve, reject) => {
|
|
98
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
99
|
+
ws.addEventListener("close", reject);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Skip welcome message
|
|
104
|
+
await new Promise<void>((resolve, reject) => {
|
|
105
|
+
ws.addEventListener("message", () => resolve(), { once: true });
|
|
106
|
+
ws.addEventListener("close", reject);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Send ping
|
|
110
|
+
ws.send(JSON.stringify({ type: "ping" }));
|
|
111
|
+
|
|
112
|
+
const pongMessage = await new Promise<any>((resolve, reject) => {
|
|
113
|
+
ws.addEventListener("message", (event: any) => {
|
|
114
|
+
const data = JSON.parse(event.data as string);
|
|
115
|
+
if (data.type === "pong") {
|
|
116
|
+
resolve(data);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
ws.addEventListener("close", reject);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(pongMessage.type).toBe("pong");
|
|
123
|
+
expect(pongMessage.timestamp).toBeDefined();
|
|
124
|
+
|
|
125
|
+
ws.close();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("should track stats across connections", async (c) => {
|
|
129
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
130
|
+
const actor1 = client.rawWebSocketActor.getOrCreate(["stats"]);
|
|
131
|
+
|
|
132
|
+
// Create first connection to ensure actor exists
|
|
133
|
+
const ws1 = await actor1.websocket();
|
|
134
|
+
const ws1MessagePromise = new Promise<void>((resolve, reject) => {
|
|
135
|
+
ws1.addEventListener("message", () => resolve(), { once: true });
|
|
136
|
+
ws1.addEventListener("close", reject);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Wait for first connection to establish before getting the actor
|
|
140
|
+
await ws1MessagePromise;
|
|
141
|
+
|
|
142
|
+
// Now get reference to same actor
|
|
143
|
+
const actor2 = client.rawWebSocketActor.get(["stats"]);
|
|
144
|
+
const ws2 = await actor2.websocket();
|
|
145
|
+
const ws2MessagePromise = new Promise<void>((resolve, reject) => {
|
|
146
|
+
ws2.addEventListener("message", () => resolve(), { once: true });
|
|
147
|
+
ws2.addEventListener("close", reject);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Wait for welcome messages
|
|
151
|
+
await Promise.all([ws1MessagePromise, ws2MessagePromise]);
|
|
152
|
+
|
|
153
|
+
// Send some messages
|
|
154
|
+
const pingPromise = new Promise<any>((resolve, reject) => {
|
|
155
|
+
ws2.addEventListener("message", (event: any) => {
|
|
156
|
+
const data = JSON.parse(event.data as string);
|
|
157
|
+
if (data.type === "pong") {
|
|
158
|
+
resolve(undefined);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
ws2.addEventListener("close", reject);
|
|
162
|
+
});
|
|
163
|
+
ws1.send(JSON.stringify({ data: "test1" }));
|
|
164
|
+
ws1.send(JSON.stringify({ data: "test3" }));
|
|
165
|
+
ws2.send(JSON.stringify({ type: "ping" }));
|
|
166
|
+
await pingPromise;
|
|
167
|
+
|
|
168
|
+
// Get stats
|
|
169
|
+
const statsPromise = new Promise<any>((resolve, reject) => {
|
|
170
|
+
ws1.addEventListener("message", (event: any) => {
|
|
171
|
+
const data = JSON.parse(event.data as string);
|
|
172
|
+
if (data.type === "stats") {
|
|
173
|
+
resolve(data);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
ws1.addEventListener("close", reject);
|
|
177
|
+
});
|
|
178
|
+
ws1.send(JSON.stringify({ type: "getStats" }));
|
|
179
|
+
const stats = await statsPromise;
|
|
180
|
+
expect(stats.connectionCount).toBe(2);
|
|
181
|
+
expect(stats.messageCount).toBe(4);
|
|
182
|
+
|
|
183
|
+
// Verify via action
|
|
184
|
+
const actionStats = await actor1.getStats();
|
|
185
|
+
expect(actionStats.connectionCount).toBe(2);
|
|
186
|
+
expect(actionStats.messageCount).toBe(4);
|
|
187
|
+
|
|
188
|
+
ws1.close();
|
|
189
|
+
ws2.close();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("should handle binary data", async (c) => {
|
|
193
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
194
|
+
const actor = client.rawWebSocketBinaryActor.getOrCreate(["binary"]);
|
|
195
|
+
|
|
196
|
+
const ws = await actor.websocket();
|
|
197
|
+
|
|
198
|
+
// Check if WebSocket is already open
|
|
199
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
200
|
+
await new Promise<void>((resolve, reject) => {
|
|
201
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
202
|
+
ws.addEventListener("close", reject);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Helper to receive and convert binary message
|
|
207
|
+
const receiveBinaryMessage = async (): Promise<Uint8Array> => {
|
|
208
|
+
const response = await new Promise<ArrayBuffer | Blob>(
|
|
209
|
+
(resolve, reject) => {
|
|
210
|
+
ws.addEventListener(
|
|
211
|
+
"message",
|
|
212
|
+
(event: any) => {
|
|
213
|
+
resolve(event.data);
|
|
214
|
+
},
|
|
215
|
+
{ once: true },
|
|
216
|
+
);
|
|
217
|
+
ws.addEventListener("close", reject);
|
|
218
|
+
},
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
// Convert Blob to ArrayBuffer if needed
|
|
222
|
+
const buffer =
|
|
223
|
+
response instanceof Blob ? await response.arrayBuffer() : response;
|
|
224
|
+
|
|
225
|
+
return new Uint8Array(buffer);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Test 1: Small binary data
|
|
229
|
+
const smallData = new Uint8Array([1, 2, 3, 4, 5]);
|
|
230
|
+
ws.send(smallData);
|
|
231
|
+
const smallReversed = await receiveBinaryMessage();
|
|
232
|
+
expect(Array.from(smallReversed)).toEqual([5, 4, 3, 2, 1]);
|
|
233
|
+
|
|
234
|
+
// Test 2: Large binary data (1KB)
|
|
235
|
+
const largeData = new Uint8Array(1024);
|
|
236
|
+
for (let i = 0; i < largeData.length; i++) {
|
|
237
|
+
largeData[i] = i % 256;
|
|
238
|
+
}
|
|
239
|
+
ws.send(largeData);
|
|
240
|
+
const largeReversed = await receiveBinaryMessage();
|
|
241
|
+
|
|
242
|
+
// Verify it's reversed correctly
|
|
243
|
+
for (let i = 0; i < largeData.length; i++) {
|
|
244
|
+
expect(largeReversed[i]).toBe(largeData[largeData.length - 1 - i]);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
ws.close();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test("should work with custom paths", async (c) => {
|
|
251
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
252
|
+
const actor = client.rawWebSocketActor.getOrCreate(["paths"]);
|
|
253
|
+
|
|
254
|
+
const ws = await actor.websocket("custom/path");
|
|
255
|
+
|
|
256
|
+
await new Promise<void>((resolve, reject) => {
|
|
257
|
+
ws.addEventListener("open", () => {
|
|
258
|
+
resolve();
|
|
259
|
+
});
|
|
260
|
+
ws.addEventListener("error", reject);
|
|
261
|
+
ws.addEventListener("close", reject);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Should still work
|
|
265
|
+
const welcomeMessage = await new Promise<any>((resolve) => {
|
|
266
|
+
ws.addEventListener(
|
|
267
|
+
"message",
|
|
268
|
+
(event: any) => {
|
|
269
|
+
resolve(JSON.parse(event.data as string));
|
|
270
|
+
},
|
|
271
|
+
{ once: true },
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(welcomeMessage.type).toBe("welcome");
|
|
276
|
+
|
|
277
|
+
ws.close();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("should pass connection parameters through subprotocols", async (c) => {
|
|
281
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
282
|
+
|
|
283
|
+
// Create actor with connection parameters
|
|
284
|
+
const testParams = { userId: "test123", role: "admin" };
|
|
285
|
+
const actor = client.rawWebSocketActor.getOrCreate(["params"], {
|
|
286
|
+
params: testParams,
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const ws = await actor.websocket();
|
|
290
|
+
|
|
291
|
+
await new Promise<void>((resolve) => {
|
|
292
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Send a request to echo the auth data (which should include conn params from auth)
|
|
296
|
+
ws.send(JSON.stringify({ type: "getAuthData" }));
|
|
297
|
+
|
|
298
|
+
const response = await new Promise<any>((resolve, reject) => {
|
|
299
|
+
ws.addEventListener("message", (event: any) => {
|
|
300
|
+
const data = JSON.parse(event.data as string);
|
|
301
|
+
if (data.type === "authData") {
|
|
302
|
+
resolve(data);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
ws.addEventListener("close", reject);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// For now, just verify we get a response
|
|
309
|
+
// The actual connection params handling needs to be implemented
|
|
310
|
+
expect(response).toBeDefined();
|
|
311
|
+
|
|
312
|
+
ws.close();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test("should handle connection close properly", async (c) => {
|
|
316
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
317
|
+
const actor = client.rawWebSocketActor.getOrCreate(["close-test"]);
|
|
318
|
+
|
|
319
|
+
const ws = await actor.websocket();
|
|
320
|
+
|
|
321
|
+
// Check if WebSocket is already open
|
|
322
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
323
|
+
await new Promise<void>((resolve, reject) => {
|
|
324
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
325
|
+
ws.addEventListener("close", reject);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Get initial stats
|
|
330
|
+
const initialStats = await actor.getStats();
|
|
331
|
+
expect(initialStats.connectionCount).toBe(1);
|
|
332
|
+
|
|
333
|
+
// Wait for close event on client side
|
|
334
|
+
const closePromise = new Promise<void>((resolve) => {
|
|
335
|
+
ws.addEventListener("close", () => resolve(), { once: true });
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Close connection
|
|
339
|
+
ws.close();
|
|
340
|
+
await closePromise;
|
|
341
|
+
|
|
342
|
+
// Poll getStats until connection count is 0
|
|
343
|
+
let finalStats: any;
|
|
344
|
+
for (let i = 0; i < 20; i++) {
|
|
345
|
+
finalStats = await actor.getStats();
|
|
346
|
+
if (finalStats.connectionCount === 0) {
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Check stats after close
|
|
353
|
+
expect(finalStats?.connectionCount).toBe(0);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("should properly handle onWebSocket open and close events", async (c) => {
|
|
357
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
358
|
+
const actor = client.rawWebSocketActor.getOrCreate(["open-close-test"]);
|
|
359
|
+
|
|
360
|
+
// Create first connection
|
|
361
|
+
const ws1 = await actor.websocket();
|
|
362
|
+
|
|
363
|
+
// Wait for open event
|
|
364
|
+
await new Promise<void>((resolve, reject) => {
|
|
365
|
+
ws1.addEventListener("open", () => resolve(), { once: true });
|
|
366
|
+
ws1.addEventListener("close", reject);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// Wait for welcome message which confirms onWebSocket was called
|
|
370
|
+
const welcome1 = await new Promise<any>((resolve, reject) => {
|
|
371
|
+
ws1.addEventListener(
|
|
372
|
+
"message",
|
|
373
|
+
(event: any) => {
|
|
374
|
+
resolve(JSON.parse(event.data as string));
|
|
375
|
+
},
|
|
376
|
+
{ once: true },
|
|
377
|
+
);
|
|
378
|
+
ws1.addEventListener("close", reject);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
expect(welcome1.type).toBe("welcome");
|
|
382
|
+
expect(welcome1.connectionCount).toBe(1);
|
|
383
|
+
|
|
384
|
+
// Create second connection to same actor
|
|
385
|
+
const ws2 = await actor.websocket();
|
|
386
|
+
|
|
387
|
+
await new Promise<void>((resolve, reject) => {
|
|
388
|
+
ws2.addEventListener("open", () => resolve(), { once: true });
|
|
389
|
+
ws2.addEventListener("close", reject);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const welcome2 = await new Promise<any>((resolve, reject) => {
|
|
393
|
+
ws2.addEventListener(
|
|
394
|
+
"message",
|
|
395
|
+
(event: any) => {
|
|
396
|
+
resolve(JSON.parse(event.data as string));
|
|
397
|
+
},
|
|
398
|
+
{ once: true },
|
|
399
|
+
);
|
|
400
|
+
ws2.addEventListener("close", reject);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
expect(welcome2.type).toBe("welcome");
|
|
404
|
+
expect(welcome2.connectionCount).toBe(2);
|
|
405
|
+
|
|
406
|
+
// Verify stats
|
|
407
|
+
const midStats = await actor.getStats();
|
|
408
|
+
expect(midStats.connectionCount).toBe(2);
|
|
409
|
+
|
|
410
|
+
// Close first connection
|
|
411
|
+
ws1.close();
|
|
412
|
+
await new Promise<void>((resolve) => {
|
|
413
|
+
ws1.addEventListener("close", () => resolve(), { once: true });
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// Poll getStats until connection count decreases to 1
|
|
417
|
+
let afterFirstClose: any;
|
|
418
|
+
for (let i = 0; i < 20; i++) {
|
|
419
|
+
afterFirstClose = await actor.getStats();
|
|
420
|
+
if (afterFirstClose.connectionCount === 1) {
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Verify connection count decreased
|
|
427
|
+
expect(afterFirstClose?.connectionCount).toBe(1);
|
|
428
|
+
|
|
429
|
+
// Close second connection
|
|
430
|
+
ws2.close();
|
|
431
|
+
await new Promise<void>((resolve) => {
|
|
432
|
+
ws2.addEventListener("close", () => resolve(), { once: true });
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// Poll getStats until connection count is 0
|
|
436
|
+
let finalStats: any;
|
|
437
|
+
for (let i = 0; i < 20; i++) {
|
|
438
|
+
finalStats = await actor.getStats();
|
|
439
|
+
if (finalStats.connectionCount === 0) {
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Verify final state
|
|
446
|
+
expect(finalStats?.connectionCount).toBe(0);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test("should handle query parameters in websocket paths", async (c) => {
|
|
450
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
451
|
+
const actor = client.rawWebSocketActor.getOrCreate(["query-params"]);
|
|
452
|
+
|
|
453
|
+
// Test WebSocket with query parameters
|
|
454
|
+
const ws = await actor.websocket("api/v1/stream?token=abc123&user=test");
|
|
455
|
+
|
|
456
|
+
await new Promise<void>((resolve, reject) => {
|
|
457
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
458
|
+
ws.addEventListener("error", reject);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
const requestInfoPromise = new Promise<any>((resolve, reject) => {
|
|
462
|
+
ws.addEventListener("message", (event: any) => {
|
|
463
|
+
const data = JSON.parse(event.data as string);
|
|
464
|
+
if (data.type === "requestInfo") {
|
|
465
|
+
resolve(data);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
ws.addEventListener("close", reject);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Send request to get the request info
|
|
472
|
+
ws.send(JSON.stringify({ type: "getRequestInfo" }));
|
|
473
|
+
|
|
474
|
+
const requestInfo = await requestInfoPromise;
|
|
475
|
+
|
|
476
|
+
// Verify the path and query parameters were preserved
|
|
477
|
+
expect(requestInfo.url).toContain("api/v1/stream");
|
|
478
|
+
expect(requestInfo.url).toContain("token=abc123");
|
|
479
|
+
expect(requestInfo.url).toContain("user=test");
|
|
480
|
+
|
|
481
|
+
ws.close();
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
}
|