rivetkit 2.0.2 → 2.0.4

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 (246) hide show
  1. package/README.md +3 -5
  2. package/dist/schemas/actor-persist/v1.ts +225 -0
  3. package/dist/schemas/client-protocol/v1.ts +435 -0
  4. package/dist/schemas/file-system-driver/v1.ts +102 -0
  5. package/dist/tsup/actor/errors.cjs +77 -0
  6. package/dist/tsup/actor/errors.cjs.map +1 -0
  7. package/dist/tsup/actor/errors.d.cts +156 -0
  8. package/dist/tsup/actor/errors.d.ts +156 -0
  9. package/dist/tsup/actor/errors.js +77 -0
  10. package/dist/tsup/actor/errors.js.map +1 -0
  11. package/dist/tsup/chunk-3F2YSRJL.js +117 -0
  12. package/dist/tsup/chunk-3F2YSRJL.js.map +1 -0
  13. package/dist/tsup/chunk-4CXBCT26.cjs +250 -0
  14. package/dist/tsup/chunk-4CXBCT26.cjs.map +1 -0
  15. package/dist/tsup/chunk-4R73YDN3.cjs +20 -0
  16. package/dist/tsup/chunk-4R73YDN3.cjs.map +1 -0
  17. package/dist/tsup/chunk-6LJT3QRL.cjs +539 -0
  18. package/dist/tsup/chunk-6LJT3QRL.cjs.map +1 -0
  19. package/dist/tsup/chunk-GICQ3YCU.cjs +1792 -0
  20. package/dist/tsup/chunk-GICQ3YCU.cjs.map +1 -0
  21. package/dist/tsup/chunk-H26RP6GD.js +251 -0
  22. package/dist/tsup/chunk-H26RP6GD.js.map +1 -0
  23. package/dist/tsup/chunk-HI3HWJRC.js +20 -0
  24. package/dist/tsup/chunk-HI3HWJRC.js.map +1 -0
  25. package/dist/tsup/chunk-HLLF4B4Q.js +1792 -0
  26. package/dist/tsup/chunk-HLLF4B4Q.js.map +1 -0
  27. package/dist/tsup/chunk-IH6CKNDW.cjs +117 -0
  28. package/dist/tsup/chunk-IH6CKNDW.cjs.map +1 -0
  29. package/dist/tsup/chunk-LV2S3OU3.js +250 -0
  30. package/dist/tsup/chunk-LV2S3OU3.js.map +1 -0
  31. package/dist/tsup/chunk-LWNKVZG5.cjs +251 -0
  32. package/dist/tsup/chunk-LWNKVZG5.cjs.map +1 -0
  33. package/dist/tsup/chunk-NFU2BBT5.js +374 -0
  34. package/dist/tsup/chunk-NFU2BBT5.js.map +1 -0
  35. package/dist/tsup/chunk-PQY7KKTL.js +539 -0
  36. package/dist/tsup/chunk-PQY7KKTL.js.map +1 -0
  37. package/dist/tsup/chunk-QK72M5JB.js +45 -0
  38. package/dist/tsup/chunk-QK72M5JB.js.map +1 -0
  39. package/dist/tsup/chunk-QNNXFOQV.cjs +45 -0
  40. package/dist/tsup/chunk-QNNXFOQV.cjs.map +1 -0
  41. package/dist/tsup/chunk-SBHHJ6QS.cjs +374 -0
  42. package/dist/tsup/chunk-SBHHJ6QS.cjs.map +1 -0
  43. package/dist/tsup/chunk-TQ62L3X7.js +325 -0
  44. package/dist/tsup/chunk-TQ62L3X7.js.map +1 -0
  45. package/dist/tsup/chunk-VO7ZRVVD.cjs +6293 -0
  46. package/dist/tsup/chunk-VO7ZRVVD.cjs.map +1 -0
  47. package/dist/tsup/chunk-WHBPJNGW.cjs +325 -0
  48. package/dist/tsup/chunk-WHBPJNGW.cjs.map +1 -0
  49. package/dist/tsup/chunk-XJQHKJ4P.js +6293 -0
  50. package/dist/tsup/chunk-XJQHKJ4P.js.map +1 -0
  51. package/dist/tsup/client/mod.cjs +32 -0
  52. package/dist/tsup/client/mod.cjs.map +1 -0
  53. package/dist/tsup/client/mod.d.cts +20 -0
  54. package/dist/tsup/client/mod.d.ts +20 -0
  55. package/dist/tsup/client/mod.js +32 -0
  56. package/dist/tsup/client/mod.js.map +1 -0
  57. package/dist/tsup/common/log.cjs +21 -0
  58. package/dist/tsup/common/log.cjs.map +1 -0
  59. package/dist/tsup/common/log.d.cts +26 -0
  60. package/dist/tsup/common/log.d.ts +26 -0
  61. package/dist/tsup/common/log.js +21 -0
  62. package/dist/tsup/common/log.js.map +1 -0
  63. package/dist/tsup/common/websocket.cjs +10 -0
  64. package/dist/tsup/common/websocket.cjs.map +1 -0
  65. package/dist/tsup/common/websocket.d.cts +3 -0
  66. package/dist/tsup/common/websocket.d.ts +3 -0
  67. package/dist/tsup/common/websocket.js +10 -0
  68. package/dist/tsup/common/websocket.js.map +1 -0
  69. package/dist/tsup/common-CXCe7s6i.d.cts +218 -0
  70. package/dist/tsup/common-CXCe7s6i.d.ts +218 -0
  71. package/dist/tsup/connection-BI-6UIBJ.d.ts +2087 -0
  72. package/dist/tsup/connection-Dyd4NLGW.d.cts +2087 -0
  73. package/dist/tsup/driver-helpers/mod.cjs +30 -0
  74. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  75. package/dist/tsup/driver-helpers/mod.d.cts +17 -0
  76. package/dist/tsup/driver-helpers/mod.d.ts +17 -0
  77. package/dist/tsup/driver-helpers/mod.js +30 -0
  78. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  79. package/dist/tsup/driver-test-suite/mod.cjs +3411 -0
  80. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  81. package/dist/tsup/driver-test-suite/mod.d.cts +63 -0
  82. package/dist/tsup/driver-test-suite/mod.d.ts +63 -0
  83. package/dist/tsup/driver-test-suite/mod.js +3411 -0
  84. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  85. package/dist/tsup/inspector/mod.cjs +51 -0
  86. package/dist/tsup/inspector/mod.cjs.map +1 -0
  87. package/dist/tsup/inspector/mod.d.cts +408 -0
  88. package/dist/tsup/inspector/mod.d.ts +408 -0
  89. package/dist/tsup/inspector/mod.js +51 -0
  90. package/dist/tsup/inspector/mod.js.map +1 -0
  91. package/dist/tsup/mod.cjs +67 -0
  92. package/dist/tsup/mod.cjs.map +1 -0
  93. package/dist/tsup/mod.d.cts +105 -0
  94. package/dist/tsup/mod.d.ts +105 -0
  95. package/dist/tsup/mod.js +67 -0
  96. package/dist/tsup/mod.js.map +1 -0
  97. package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +65 -0
  98. package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +65 -0
  99. package/dist/tsup/test/mod.cjs +17 -0
  100. package/dist/tsup/test/mod.cjs.map +1 -0
  101. package/dist/tsup/test/mod.d.cts +26 -0
  102. package/dist/tsup/test/mod.d.ts +26 -0
  103. package/dist/tsup/test/mod.js +17 -0
  104. package/dist/tsup/test/mod.js.map +1 -0
  105. package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
  106. package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
  107. package/dist/tsup/utils.cjs +26 -0
  108. package/dist/tsup/utils.cjs.map +1 -0
  109. package/dist/tsup/utils.d.cts +36 -0
  110. package/dist/tsup/utils.d.ts +36 -0
  111. package/dist/tsup/utils.js +26 -0
  112. package/dist/tsup/utils.js.map +1 -0
  113. package/package.json +208 -5
  114. package/src/actor/action.ts +178 -0
  115. package/src/actor/config.ts +497 -0
  116. package/src/actor/connection.ts +257 -0
  117. package/src/actor/context.ts +168 -0
  118. package/src/actor/database.ts +23 -0
  119. package/src/actor/definition.ts +82 -0
  120. package/src/actor/driver.ts +84 -0
  121. package/src/actor/errors.ts +422 -0
  122. package/src/actor/generic-conn-driver.ts +246 -0
  123. package/src/actor/instance.ts +1844 -0
  124. package/src/actor/keys.test.ts +266 -0
  125. package/src/actor/keys.ts +89 -0
  126. package/src/actor/log.ts +6 -0
  127. package/src/actor/mod.ts +108 -0
  128. package/src/actor/persisted.ts +42 -0
  129. package/src/actor/protocol/old.ts +297 -0
  130. package/src/actor/protocol/serde.ts +131 -0
  131. package/src/actor/router-endpoints.ts +688 -0
  132. package/src/actor/router.ts +265 -0
  133. package/src/actor/schedule.ts +17 -0
  134. package/src/actor/unstable-react.ts +110 -0
  135. package/src/actor/utils.ts +102 -0
  136. package/src/client/actor-common.ts +30 -0
  137. package/src/client/actor-conn.ts +865 -0
  138. package/src/client/actor-handle.ts +268 -0
  139. package/src/client/actor-query.ts +65 -0
  140. package/src/client/client.ts +554 -0
  141. package/src/client/config.ts +44 -0
  142. package/src/client/errors.ts +42 -0
  143. package/src/client/log.ts +5 -0
  144. package/src/client/mod.ts +60 -0
  145. package/src/client/raw-utils.ts +149 -0
  146. package/src/client/test.ts +44 -0
  147. package/src/client/utils.ts +152 -0
  148. package/src/common/eventsource-interface.ts +47 -0
  149. package/src/common/eventsource.ts +80 -0
  150. package/src/common/fake-event-source.ts +267 -0
  151. package/src/common/inline-websocket-adapter2.ts +454 -0
  152. package/src/common/log-levels.ts +27 -0
  153. package/src/common/log.ts +214 -0
  154. package/src/common/logfmt.ts +219 -0
  155. package/src/common/network.ts +2 -0
  156. package/src/common/router.ts +80 -0
  157. package/src/common/utils.ts +336 -0
  158. package/src/common/versioned-data.ts +95 -0
  159. package/src/common/websocket-interface.ts +49 -0
  160. package/src/common/websocket.ts +42 -0
  161. package/src/driver-helpers/mod.ts +22 -0
  162. package/src/driver-helpers/utils.ts +17 -0
  163. package/src/driver-test-suite/log.ts +5 -0
  164. package/src/driver-test-suite/mod.ts +239 -0
  165. package/src/driver-test-suite/tests/action-features.ts +136 -0
  166. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  167. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  168. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  169. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  170. package/src/driver-test-suite/tests/actor-handle.ts +292 -0
  171. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  172. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  173. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  174. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  175. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  176. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  177. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  178. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  179. package/src/driver-test-suite/tests/manager-driver.ts +367 -0
  180. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
  181. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  182. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  183. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
  184. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  185. package/src/driver-test-suite/tests/request-access.ts +230 -0
  186. package/src/driver-test-suite/utils.ts +71 -0
  187. package/src/drivers/default.ts +34 -0
  188. package/src/drivers/engine/actor-driver.ts +369 -0
  189. package/src/drivers/engine/config.ts +31 -0
  190. package/src/drivers/engine/kv.ts +3 -0
  191. package/src/drivers/engine/log.ts +5 -0
  192. package/src/drivers/engine/mod.ts +35 -0
  193. package/src/drivers/file-system/actor.ts +91 -0
  194. package/src/drivers/file-system/global-state.ts +686 -0
  195. package/src/drivers/file-system/log.ts +5 -0
  196. package/src/drivers/file-system/manager.ts +329 -0
  197. package/src/drivers/file-system/mod.ts +48 -0
  198. package/src/drivers/file-system/utils.ts +109 -0
  199. package/src/globals.d.ts +6 -0
  200. package/src/inspector/actor.ts +298 -0
  201. package/src/inspector/config.ts +88 -0
  202. package/src/inspector/log.ts +5 -0
  203. package/src/inspector/manager.ts +86 -0
  204. package/src/inspector/mod.ts +2 -0
  205. package/src/inspector/protocol/actor.ts +10 -0
  206. package/src/inspector/protocol/common.ts +196 -0
  207. package/src/inspector/protocol/manager.ts +10 -0
  208. package/src/inspector/protocol/mod.ts +2 -0
  209. package/src/inspector/utils.ts +76 -0
  210. package/src/manager/driver.ts +88 -0
  211. package/src/manager/hono-websocket-adapter.ts +342 -0
  212. package/src/manager/log.ts +5 -0
  213. package/src/manager/mod.ts +2 -0
  214. package/src/manager/protocol/mod.ts +24 -0
  215. package/src/manager/protocol/query.ts +89 -0
  216. package/src/manager/router.ts +412 -0
  217. package/src/manager-api/routes/actors-create.ts +16 -0
  218. package/src/manager-api/routes/actors-delete.ts +4 -0
  219. package/src/manager-api/routes/actors-get-by-id.ts +7 -0
  220. package/src/manager-api/routes/actors-get-or-create-by-id.ts +29 -0
  221. package/src/manager-api/routes/actors-get.ts +7 -0
  222. package/src/manager-api/routes/common.ts +18 -0
  223. package/src/mod.ts +18 -0
  224. package/src/registry/config.ts +32 -0
  225. package/src/registry/log.ts +5 -0
  226. package/src/registry/mod.ts +157 -0
  227. package/src/registry/run-config.ts +52 -0
  228. package/src/registry/serve.ts +52 -0
  229. package/src/remote-manager-driver/actor-http-client.ts +72 -0
  230. package/src/remote-manager-driver/actor-websocket-client.ts +63 -0
  231. package/src/remote-manager-driver/api-endpoints.ts +79 -0
  232. package/src/remote-manager-driver/api-utils.ts +43 -0
  233. package/src/remote-manager-driver/log.ts +5 -0
  234. package/src/remote-manager-driver/mod.ts +274 -0
  235. package/src/remote-manager-driver/ws-proxy.ts +180 -0
  236. package/src/schemas/actor-persist/mod.ts +1 -0
  237. package/src/schemas/actor-persist/versioned.ts +25 -0
  238. package/src/schemas/client-protocol/mod.ts +1 -0
  239. package/src/schemas/client-protocol/versioned.ts +63 -0
  240. package/src/schemas/file-system-driver/mod.ts +1 -0
  241. package/src/schemas/file-system-driver/versioned.ts +28 -0
  242. package/src/serde.ts +90 -0
  243. package/src/test/config.ts +16 -0
  244. package/src/test/log.ts +5 -0
  245. package/src/test/mod.ts +154 -0
  246. package/src/utils.ts +172 -0
@@ -0,0 +1,154 @@
1
+ import { createServer } from "node:net";
2
+ import { serve as honoServe, type ServerType } from "@hono/node-server";
3
+ import { createNodeWebSocket } from "@hono/node-ws";
4
+ import { type TestContext, vi } from "vitest";
5
+ import { type Client, createClient } from "@/client/mod";
6
+ import { chooseDefaultDriver } from "@/drivers/default";
7
+ import { createFileSystemOrMemoryDriver } from "@/drivers/file-system/mod";
8
+ import { getInspectorUrl } from "@/inspector/utils";
9
+ import { createManagerRouter } from "@/manager/router";
10
+ import type { Registry } from "@/registry/mod";
11
+ import { RunConfigSchema } from "@/registry/run-config";
12
+ import { ConfigSchema, type InputConfig } from "./config";
13
+ import { logger } from "./log";
14
+
15
+ function serve(registry: Registry<any>, inputConfig?: InputConfig): ServerType {
16
+ // Configure default configuration
17
+ inputConfig ??= {};
18
+
19
+ const config = ConfigSchema.parse(inputConfig);
20
+
21
+ let upgradeWebSocket: any;
22
+ if (!config.getUpgradeWebSocket) {
23
+ config.getUpgradeWebSocket = () => upgradeWebSocket!;
24
+ }
25
+
26
+ // Create router
27
+ const runConfig = RunConfigSchema.parse(inputConfig);
28
+ const driver = inputConfig.driver ?? createFileSystemOrMemoryDriver(false);
29
+ const managerDriver = driver.manager(registry.config, config);
30
+ const { router } = createManagerRouter(
31
+ registry.config,
32
+ runConfig,
33
+ managerDriver,
34
+ false,
35
+ );
36
+
37
+ // Inject WebSocket
38
+ const nodeWebSocket = createNodeWebSocket({ app: router });
39
+ upgradeWebSocket = nodeWebSocket.upgradeWebSocket;
40
+
41
+ const server = honoServe({
42
+ fetch: router.fetch,
43
+ hostname: config.hostname,
44
+ port: config.port,
45
+ });
46
+ nodeWebSocket.injectWebSocket(server);
47
+
48
+ logger().info({
49
+ msg: "rivetkit started",
50
+ hostname: config.hostname,
51
+ port: config.port,
52
+ definitions: Object.keys(registry.config.use).length,
53
+ });
54
+
55
+ return server;
56
+ }
57
+
58
+ export interface SetupTestResult<A extends Registry<any>> {
59
+ client: Client<A>;
60
+ mockDriver: {
61
+ actorDriver: {
62
+ setCreateVarsContext: (ctx: any) => void;
63
+ };
64
+ };
65
+ }
66
+
67
+ // Must use `TestContext` since global hooks do not work when running concurrently
68
+ export async function setupTest<A extends Registry<any>>(
69
+ c: TestContext,
70
+ registry: A,
71
+ ): Promise<SetupTestResult<A>> {
72
+ vi.useFakeTimers();
73
+
74
+ // Set up mock driver for testing createVars context
75
+ const mockDriverContext: any = {};
76
+ const setDriverContextFn = (ctx: any) => {
77
+ mockDriverContext.current = ctx;
78
+ };
79
+
80
+ // We don't need to modify the driver context anymore since we're testing with the actual context
81
+
82
+ // Start server with a random port
83
+ const port = await getPort();
84
+ const server = serve(registry, { port });
85
+ c.onTestFinished(
86
+ async () => await new Promise((resolve) => server.close(() => resolve())),
87
+ );
88
+
89
+ throw "TODO: Fix engine port";
90
+
91
+ // // TODO: Figure out how to make this the correct endpoint
92
+ // // Create client
93
+ // const client = createClient<A>(`http://127.0.0.1:${port}`);
94
+ // c.onTestFinished(async () => await client.dispose());
95
+ //
96
+ // return {
97
+ // client,
98
+ // mockDriver: {
99
+ // actorDriver: {
100
+ // setCreateVarsContext: setDriverContextFn,
101
+ // },
102
+ // },
103
+ // };
104
+ }
105
+
106
+ export async function getPort(): Promise<number> {
107
+ // Pick random port between 10000 and 65535 (avoiding well-known and registered ports)
108
+ const MIN_PORT = 10000;
109
+ const MAX_PORT = 65535;
110
+ const getRandomPort = () =>
111
+ Math.floor(Math.random() * (MAX_PORT - MIN_PORT + 1)) + MIN_PORT;
112
+
113
+ let port = getRandomPort();
114
+ let maxAttempts = 10;
115
+
116
+ while (maxAttempts > 0) {
117
+ try {
118
+ // Try to create a server on the port to check if it's available
119
+ const server = await new Promise<any>((resolve, reject) => {
120
+ const server = createServer();
121
+
122
+ server.once("error", (err: Error & { code?: string }) => {
123
+ if (err.code === "EADDRINUSE") {
124
+ reject(new Error(`Port ${port} is in use`));
125
+ } else {
126
+ reject(err);
127
+ }
128
+ });
129
+
130
+ server.once("listening", () => {
131
+ resolve(server);
132
+ });
133
+
134
+ server.listen(port);
135
+ });
136
+
137
+ // Close the server since we're just checking availability
138
+ await new Promise<void>((resolve) => {
139
+ server.close(() => resolve());
140
+ });
141
+
142
+ return port;
143
+ } catch (err) {
144
+ // If port is in use, try a different one
145
+ maxAttempts--;
146
+ if (maxAttempts <= 0) {
147
+ break;
148
+ }
149
+ port = getRandomPort();
150
+ }
151
+ }
152
+
153
+ throw new Error("Could not find an available port after multiple attempts");
154
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,172 @@
1
+ export { stringifyError } from "@/common/utils";
2
+ export { assertUnreachable } from "./common/utils";
3
+
4
+ import type { Context as HonoContext, Handler as HonoHandler } from "hono";
5
+
6
+ import pkgJson from "../package.json" with { type: "json" };
7
+
8
+ export const VERSION = pkgJson.version;
9
+
10
+ let _userAgent: string | undefined;
11
+
12
+ export function httpUserAgent(): string {
13
+ // Return cached value if already initialized
14
+ if (_userAgent !== undefined) {
15
+ return _userAgent;
16
+ }
17
+
18
+ // Library
19
+ let userAgent = `RivetKit/${VERSION}`;
20
+
21
+ // Navigator
22
+ const navigatorObj = typeof navigator !== "undefined" ? navigator : undefined;
23
+ if (navigatorObj?.userAgent) userAgent += ` ${navigatorObj.userAgent}`;
24
+
25
+ _userAgent = userAgent;
26
+
27
+ return userAgent;
28
+ }
29
+
30
+ export type UpgradeWebSocket = (
31
+ createEvents: (c: HonoContext) => any,
32
+ ) => HonoHandler;
33
+
34
+ export function getEnvUniversal(key: string): string | undefined {
35
+ if (typeof Deno !== "undefined") {
36
+ return Deno.env.get(key);
37
+ } else if (typeof process !== "undefined") {
38
+ // Do this after Deno since `process` is sometimes polyfilled
39
+ return process.env[key];
40
+ }
41
+ }
42
+
43
+ export function dbg<T>(x: T): T {
44
+ console.trace(`=== DEBUG ===\n${x}`);
45
+ return x;
46
+ }
47
+
48
+ /**
49
+ * Converts various ArrayBuffer-like types to Uint8Array.
50
+ * Handles ArrayBuffer, ArrayBufferView (including typed arrays), and passes through existing Uint8Array.
51
+ *
52
+ * @param data - The ArrayBuffer or ArrayBufferView to convert
53
+ * @returns A Uint8Array view of the data
54
+ */
55
+ export function toUint8Array(data: ArrayBuffer | ArrayBufferView): Uint8Array {
56
+ if (data instanceof Uint8Array) {
57
+ return data;
58
+ } else if (data instanceof ArrayBuffer) {
59
+ return new Uint8Array(data);
60
+ } else if (ArrayBuffer.isView(data)) {
61
+ // Handle other ArrayBufferView types (Int8Array, Uint16Array, DataView, etc.)
62
+ return new Uint8Array(
63
+ data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength),
64
+ );
65
+ } else {
66
+ throw new TypeError("Input must be ArrayBuffer or ArrayBufferView");
67
+ }
68
+ }
69
+
70
+ // Long timeouts
71
+ //
72
+ // JavaScript timers use a signed 32-bit integer for delays, so values above 2^31-1 (~24.8 days)
73
+ // are not reliable and may fire immediately or overflow.
74
+ //
75
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#maximum_delay_value
76
+ const TIMEOUT_MAX = 2147483647; // 2^31-1
77
+
78
+ export type LongTimeoutHandle = { abort: () => void };
79
+
80
+ export function setLongTimeout(
81
+ listener: () => void,
82
+ after: number,
83
+ ): LongTimeoutHandle {
84
+ let timeout: ReturnType<typeof setTimeout> | undefined;
85
+
86
+ function start(remaining: number) {
87
+ if (remaining <= TIMEOUT_MAX) {
88
+ timeout = setTimeout(listener, remaining);
89
+ } else {
90
+ timeout = setTimeout(() => {
91
+ start(remaining - TIMEOUT_MAX);
92
+ }, TIMEOUT_MAX);
93
+ }
94
+ }
95
+
96
+ start(after);
97
+
98
+ return {
99
+ abort: () => {
100
+ if (timeout !== undefined) clearTimeout(timeout);
101
+ },
102
+ };
103
+ }
104
+
105
+ /**
106
+ * A tiny utility that coalesces/enqueues async operations so only the latest
107
+ * queued task runs per cycle, while callers receive a promise that resolves
108
+ * when the task for the cycle they joined has completed.
109
+ */
110
+ export class SinglePromiseQueue {
111
+ /** Next operation to execute in the queue. If attempting to enqueue another op, it will override the existing op. */
112
+ #queuedOp?: () => Promise<void>;
113
+
114
+ /** The currently running promise of #drainLoop. Do not await this, instead await `pending` to await the current cycle. */
115
+ runningDrainLoop?: Promise<void>;
116
+
117
+ /** Pending resolver fro the currently queued entry. */
118
+ #pending?: PromiseWithResolvers<void>;
119
+
120
+ /** Queue the next operation and return a promise that resolves when it flushes. */
121
+ enqueue(op: () => Promise<void>): Promise<void> {
122
+ // Replace any previously queued operation with the latest one
123
+ this.#queuedOp = op;
124
+
125
+ // Ensure a shared resolver exists for all callers in this cycle
126
+ if (!this.#pending) {
127
+ this.#pending = Promise.withResolvers<void>();
128
+ }
129
+
130
+ const waitForThisCycle = this.#pending.promise;
131
+
132
+ // Start runner if not already running
133
+ if (!this.runningDrainLoop) {
134
+ this.runningDrainLoop = this.#drainLoop();
135
+ }
136
+
137
+ return waitForThisCycle;
138
+ }
139
+
140
+ /** Drain queued operations sequentially until there is nothing left. */
141
+ async #drainLoop(): Promise<void> {
142
+ try {
143
+ while (this.#queuedOp) {
144
+ // Capture current cycle resolver then reset for the next cycle
145
+ const resolver = this.#pending;
146
+ this.#pending = undefined;
147
+
148
+ // Capture and clear the currently queued operation
149
+ const op = this.#queuedOp;
150
+ this.#queuedOp = undefined;
151
+
152
+ try {
153
+ await op();
154
+ } catch {
155
+ // Swallow errors: callers only await cycle completion, not success
156
+ }
157
+
158
+ // Notify all waiters for this cycle
159
+ resolver?.resolve();
160
+ }
161
+ } finally {
162
+ this.runningDrainLoop = undefined;
163
+ }
164
+ }
165
+ }
166
+
167
+ export function bufferToArrayBuffer(buf: Buffer | Uint8Array): ArrayBuffer {
168
+ return buf.buffer.slice(
169
+ buf.byteOffset,
170
+ buf.byteOffset + buf.byteLength,
171
+ ) as ArrayBuffer;
172
+ }