@rivetkit/engine-runner 0.0.0-main.d6a0ba8

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/mod.d.cts ADDED
@@ -0,0 +1,324 @@
1
+ import * as protocol from '@rivetkit/engine-runner-protocol';
2
+ import { GatewayId, RequestId } from '@rivetkit/engine-runner-protocol';
3
+ import { Logger } from 'pino';
4
+ import WebSocket from 'ws';
5
+ import { UniversalWebSocket } from '@rivetkit/virtual-websocket';
6
+
7
+ interface PendingRequest {
8
+ resolve: (response: Response) => void;
9
+ reject: (error: Error) => void;
10
+ streamController?: ReadableStreamDefaultController<Uint8Array>;
11
+ actorId?: string;
12
+ gatewayId?: GatewayId;
13
+ requestId?: RequestId;
14
+ clientMessageIndex: number;
15
+ }
16
+ interface HibernatingWebSocketMetadata {
17
+ gatewayId: GatewayId;
18
+ requestId: RequestId;
19
+ clientMessageIndex: number;
20
+ serverMessageIndex: number;
21
+ path: string;
22
+ headers: Record<string, string>;
23
+ }
24
+ declare class Tunnel {
25
+ #private;
26
+ get log(): Logger | undefined;
27
+ constructor(runner: Runner);
28
+ start(): void;
29
+ resendBufferedEvents(): void;
30
+ shutdown(): void;
31
+ restoreHibernatingRequests(actorId: string, metaEntries: HibernatingWebSocketMetadata[]): Promise<void>;
32
+ addRequestToActor(gatewayId: GatewayId, requestId: RequestId, actorId: string): void;
33
+ getRequestActor(gatewayId: GatewayId, requestId: RequestId): RunnerActor | undefined;
34
+ getAndWaitForRequestActor(gatewayId: GatewayId, requestId: RequestId): Promise<RunnerActor | undefined>;
35
+ closeActiveRequests(actor: RunnerActor): void;
36
+ handleTunnelMessage(message: protocol.ToClientTunnelMessage): Promise<void>;
37
+ sendHibernatableWebSocketMessageAck(gatewayId: ArrayBuffer, requestId: ArrayBuffer, clientMessageIndex: number): void;
38
+ }
39
+
40
+ /**
41
+ * Polyfill for Promise.withResolvers().
42
+ *
43
+ * This is specifically for Cloudflare Workers. Their implementation of Promise.withResolvers does not work correctly.
44
+ */
45
+ declare function promiseWithResolvers<T>(): {
46
+ promise: Promise<T>;
47
+ resolve: (value: T | PromiseLike<T>) => void;
48
+ reject: (reason?: any) => void;
49
+ };
50
+ declare function idToStr(id: ArrayBuffer): string;
51
+
52
+ declare const HIBERNATABLE_SYMBOL: unique symbol;
53
+ declare class WebSocketTunnelAdapter {
54
+ #private;
55
+ readonly request: Request;
56
+ get [HIBERNATABLE_SYMBOL](): boolean;
57
+ constructor(tunnel: Tunnel, actorId: string, requestId: string, serverMessageIndex: number, hibernatable: boolean, isRestoringHibernatable: boolean, request: Request, sendCallback: (data: ArrayBuffer | string, isBinary: boolean) => void, closeCallback: (code?: number, reason?: string) => void);
58
+ get websocket(): UniversalWebSocket;
59
+ _handleOpen(requestId: ArrayBuffer): void;
60
+ _handleMessage(requestId: ArrayBuffer, data: string | Uint8Array, serverMessageIndex: number, isBinary: boolean): boolean;
61
+ _handleClose(_requestId: ArrayBuffer, code?: number, reason?: string): void;
62
+ _closeWithoutCallback(code?: number, reason?: string): void;
63
+ close(code?: number, reason?: string): void;
64
+ }
65
+
66
+ interface ActorConfig {
67
+ name: string;
68
+ key: string | null;
69
+ createTs: bigint;
70
+ input: Uint8Array | null;
71
+ }
72
+ declare class RunnerActor {
73
+ /**
74
+ * List of hibernating requests provided by the gateway on actor start.
75
+ * This represents the WebSocket connections that the gateway knows about.
76
+ **/
77
+ hibernatingRequests: readonly protocol.HibernatingRequest[];
78
+ actorId: string;
79
+ generation: number;
80
+ config: ActorConfig;
81
+ pendingRequests: Array<{
82
+ gatewayId: protocol.GatewayId;
83
+ requestId: protocol.RequestId;
84
+ request: PendingRequest;
85
+ }>;
86
+ webSockets: Array<{
87
+ gatewayId: protocol.GatewayId;
88
+ requestId: protocol.RequestId;
89
+ ws: WebSocketTunnelAdapter;
90
+ }>;
91
+ actorStartPromise: ReturnType<typeof promiseWithResolvers<void>>;
92
+ lastCommandIdx: bigint;
93
+ nextEventIdx: bigint;
94
+ eventHistory: protocol.EventWrapper[];
95
+ /**
96
+ * If restoreHibernatingRequests has been called. This is used to assert
97
+ * that the caller is implemented correctly.
98
+ **/
99
+ hibernationRestored: boolean;
100
+ /**
101
+ * Set when the actor has explicitly requested to stop (e.g. c.destroy()).
102
+ * Used to send StopCode.Ok (graceful) vs StopCode.Error (ungraceful) so
103
+ * the engine crash policy handles sleepable actors correctly.
104
+ **/
105
+ stopIntentSent: boolean;
106
+ constructor(actorId: string, generation: number, config: ActorConfig,
107
+ /**
108
+ * List of hibernating requests provided by the gateway on actor start.
109
+ * This represents the WebSocket connections that the gateway knows about.
110
+ **/
111
+ hibernatingRequests: readonly protocol.HibernatingRequest[]);
112
+ getPendingRequest(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): PendingRequest | undefined;
113
+ createPendingRequest(gatewayId: protocol.GatewayId, requestId: protocol.RequestId, clientMessageIndex: number): void;
114
+ createPendingRequestWithStreamController(gatewayId: protocol.GatewayId, requestId: protocol.RequestId, clientMessageIndex: number, streamController: ReadableStreamDefaultController<Uint8Array>): void;
115
+ deletePendingRequest(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): void;
116
+ getWebSocket(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): WebSocketTunnelAdapter | undefined;
117
+ setWebSocket(gatewayId: protocol.GatewayId, requestId: protocol.RequestId, ws: WebSocketTunnelAdapter): void;
118
+ deleteWebSocket(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): void;
119
+ handleAckEvents(lastEventIdx: bigint): void;
120
+ recordEvent(eventWrapper: protocol.EventWrapper): void;
121
+ }
122
+
123
+ declare class RunnerShutdownError extends Error {
124
+ constructor();
125
+ }
126
+ interface RunnerConfig {
127
+ logger?: Logger;
128
+ version: number;
129
+ endpoint: string;
130
+ token?: string;
131
+ pegboardEndpoint?: string;
132
+ pegboardRelayEndpoint?: string;
133
+ namespace: string;
134
+ totalSlots: number;
135
+ runnerName: string;
136
+ prepopulateActorNames: Record<string, {
137
+ metadata: Record<string, any>;
138
+ }>;
139
+ metadata?: Record<string, any>;
140
+ onConnected: () => void;
141
+ onDisconnected: (code: number, reason: string) => void;
142
+ onShutdown: () => void;
143
+ /** Called when receiving a network request. */
144
+ fetch: (runner: Runner, actorId: string, gatewayId: protocol.GatewayId, requestId: protocol.RequestId, request: Request) => Promise<Response>;
145
+ /**
146
+ * Called when receiving a WebSocket connection.
147
+ *
148
+ * All event listeners must be added synchronously inside this function or
149
+ * else events may be missed. The open event will fire immediately after
150
+ * this function finishes.
151
+ *
152
+ * Any errors thrown here will disconnect the WebSocket immediately.
153
+ *
154
+ * While `path` and `headers` are partially redundant to the data in the
155
+ * `Request`, they may vary slightly from the actual content of `Request`.
156
+ * Prefer to persist the `path` and `headers` properties instead of the
157
+ * `Request` itself.
158
+ *
159
+ * ## Hibernating Web Sockets
160
+ *
161
+ * ### Implementation Requirements
162
+ *
163
+ * **Requirement 1: Persist HWS Immediately**
164
+ *
165
+ * This is responsible for persisting hibernatable WebSockets immediately
166
+ * (do not wait for open event). It is not time sensitive to flush the
167
+ * connection state. If this fails to persist the HWS, the client's
168
+ * WebSocket will be disconnected on next wake in the call to
169
+ * `Tunnel::restoreHibernatingRequests` since the connection entry will not
170
+ * exist.
171
+ *
172
+ * **Requirement 2: Persist Message Index On `message`**
173
+ *
174
+ * In the `message` event listener, this handler must persist the message
175
+ * index from the event. The request ID is available at
176
+ * `event.rivetRequestId` and message index at `event.rivetMessageIndex`.
177
+ *
178
+ * The message index should not be flushed immediately. Instead, this
179
+ * should:
180
+ *
181
+ * - Debounce calls to persist the message index
182
+ * - After each persist, call
183
+ * `Runner::sendHibernatableWebSocketMessageAck` to acknowledge the
184
+ * message
185
+ *
186
+ * This mechanism allows us to buffer messages on the gateway so we can
187
+ * batch-persist events on our end on a given interval.
188
+ *
189
+ * If this fails to persist, then the gateway will replay unacked
190
+ * messages when the actor starts again.
191
+ *
192
+ * **Requirement 3: Remove HWS From Storage On `close`**
193
+ *
194
+ * This handler should add an event listener for `close` to remove the
195
+ * connection from storage.
196
+ *
197
+ * If the connection remove fails to persist, the close event will be
198
+ * called again on the next actor start in
199
+ * `Tunnel::restoreHibernatingRequests` since there will be no request for
200
+ * the given connection.
201
+ *
202
+ * ### Restoring Connections
203
+ *
204
+ * The user of this library is responsible for:
205
+ * 1. Loading all persisted hibernatable WebSocket metadata for an actor
206
+ * 2. Calling `Runner::restoreHibernatingRequests` with this metadata at
207
+ * the end of `onActorStart`
208
+ *
209
+ * `restoreHibernatingRequests` will restore all connections and attach
210
+ * the appropriate event listeners.
211
+ *
212
+ * ### No Open Event On Restoration
213
+ *
214
+ * When restoring a HWS, the open event will not be called again. It will
215
+ * go straight to the message or close event.
216
+ */
217
+ websocket: (runner: Runner, actorId: string, ws: any, gatewayId: protocol.GatewayId, requestId: protocol.RequestId, request: Request, path: string, headers: Record<string, string>, isHibernatable: boolean, isRestoringHibernatable: boolean) => Promise<void>;
218
+ hibernatableWebSocket: {
219
+ /**
220
+ * Determines if a WebSocket can continue to live while an actor goes to
221
+ * sleep.
222
+ */
223
+ canHibernate: (actorId: string, gatewayId: ArrayBuffer, requestId: ArrayBuffer, request: Request) => boolean;
224
+ };
225
+ /**
226
+ * Called when an actor starts.
227
+ *
228
+ * This callback is responsible for:
229
+ * 1. Initializing the actor instance
230
+ * 2. Loading all persisted hibernatable WebSocket metadata for this actor
231
+ * 3. Calling `Runner::restoreHibernatingRequests` with the loaded metadata
232
+ * to restore hibernatable WebSocket connections
233
+ *
234
+ * The actor should not be marked as "ready" until after
235
+ * `restoreHibernatingRequests` completes to ensure all hibernatable
236
+ * connections are fully restored before the actor processes new requests.
237
+ */
238
+ onActorStart: (actorId: string, generation: number, config: ActorConfig) => Promise<void>;
239
+ onActorStop: (actorId: string, generation: number) => Promise<void>;
240
+ noAutoShutdown?: boolean;
241
+ /**
242
+ * Debug option to inject artificial latency (in ms) into WebSocket
243
+ * communication. Messages are queued and delivered in order after the
244
+ * configured delay.
245
+ *
246
+ * @experimental For testing only.
247
+ */
248
+ debugLatencyMs?: number;
249
+ }
250
+ interface KvListOptions {
251
+ reverse?: boolean;
252
+ limit?: number;
253
+ }
254
+ declare class Runner {
255
+ #private;
256
+ get config(): RunnerConfig;
257
+ runnerId?: string;
258
+ get log(): Logger | undefined;
259
+ constructor(config: RunnerConfig);
260
+ sleepActor(actorId: string, generation?: number): void;
261
+ stopActor(actorId: string, generation?: number): Promise<void>;
262
+ /**
263
+ * Like stopActor but marks the actor for graceful destruction.
264
+ * This ensures the engine destroys the actor instead of sleeping it.
265
+ *
266
+ * NOTE: If a drain (GoingAway) occurs after this is called but before the
267
+ * stop completes, the engine's going_away flag overrides graceful_exit and
268
+ * the actor will sleep instead of being destroyed. The destroy intent is
269
+ * lost in this race. This is acceptable since the actor will be rescheduled
270
+ * elsewhere and can be destroyed on the next wake.
271
+ */
272
+ destroyActor(actorId: string, generation?: number): void;
273
+ forceStopActor(actorId: string, generation?: number): Promise<void>;
274
+ getActor(actorId: string, generation?: number): RunnerActor | undefined;
275
+ getAndWaitForActor(actorId: string, generation?: number): Promise<RunnerActor | undefined>;
276
+ hasActor(actorId: string, generation?: number): boolean;
277
+ get actors(): Map<string, RunnerActor>;
278
+ start(): Promise<void>;
279
+ shutdown(immediate: boolean, exit?: boolean): Promise<void>;
280
+ get pegboardEndpoint(): string;
281
+ get pegboardUrl(): string;
282
+ kvGet(actorId: string, keys: Uint8Array[]): Promise<(Uint8Array | null)[]>;
283
+ kvListAll(actorId: string, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
284
+ kvListRange(actorId: string, start: Uint8Array, end: Uint8Array, exclusive?: boolean, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
285
+ kvListPrefix(actorId: string, prefix: Uint8Array, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
286
+ kvPut(actorId: string, entries: [Uint8Array, Uint8Array][]): Promise<void>;
287
+ kvDelete(actorId: string, keys: Uint8Array[]): Promise<void>;
288
+ kvDeleteRange(actorId: string, start: Uint8Array, end: Uint8Array): Promise<void>;
289
+ kvDrop(actorId: string): Promise<void>;
290
+ setAlarm(actorId: string, alarmTs: number | null, generation?: number): void;
291
+ clearAlarm(actorId: string, generation?: number): void;
292
+ /** Asserts WebSocket exists and is ready. */
293
+ getPegboardWebSocketIfReady(): WebSocket | undefined;
294
+ __sendToServer(message: protocol.ToServer): void;
295
+ sendHibernatableWebSocketMessageAck(gatewayId: ArrayBuffer, requestId: ArrayBuffer, index: number): void;
296
+ /**
297
+ * Restores hibernatable WebSocket connections for an actor.
298
+ *
299
+ * This method should be called at the end of `onActorStart` after the
300
+ * actor instance is fully initialized.
301
+ *
302
+ * This method will:
303
+ * - Restore all provided hibernatable WebSocket connections
304
+ * - Attach event listeners to the restored WebSockets
305
+ * - Close any WebSocket connections that failed to restore
306
+ *
307
+ * The provided metadata list should include all hibernatable WebSockets
308
+ * that were persisted for this actor. The gateway will automatically
309
+ * close any connections that are not restored (i.e., not included in
310
+ * this list).
311
+ *
312
+ * **Important:** This method must be called after `onActorStart` completes
313
+ * and before marking the actor as "ready" to ensure all hibernatable
314
+ * connections are fully restored.
315
+ *
316
+ * @param actorId - The ID of the actor to restore connections for
317
+ * @param metaEntries - Array of hibernatable WebSocket metadata to restore
318
+ */
319
+ restoreHibernatingRequests(actorId: string, metaEntries: HibernatingWebSocketMetadata[]): Promise<void>;
320
+ getServerlessInitPacket(): string | undefined;
321
+ getProtocolMetadata(): protocol.ProtocolMetadata | undefined;
322
+ }
323
+
324
+ export { type ActorConfig, type HibernatingWebSocketMetadata, type KvListOptions, Runner, RunnerActor, type RunnerConfig, RunnerShutdownError, idToStr };
package/dist/mod.d.ts ADDED
@@ -0,0 +1,324 @@
1
+ import * as protocol from '@rivetkit/engine-runner-protocol';
2
+ import { GatewayId, RequestId } from '@rivetkit/engine-runner-protocol';
3
+ import { Logger } from 'pino';
4
+ import WebSocket from 'ws';
5
+ import { UniversalWebSocket } from '@rivetkit/virtual-websocket';
6
+
7
+ interface PendingRequest {
8
+ resolve: (response: Response) => void;
9
+ reject: (error: Error) => void;
10
+ streamController?: ReadableStreamDefaultController<Uint8Array>;
11
+ actorId?: string;
12
+ gatewayId?: GatewayId;
13
+ requestId?: RequestId;
14
+ clientMessageIndex: number;
15
+ }
16
+ interface HibernatingWebSocketMetadata {
17
+ gatewayId: GatewayId;
18
+ requestId: RequestId;
19
+ clientMessageIndex: number;
20
+ serverMessageIndex: number;
21
+ path: string;
22
+ headers: Record<string, string>;
23
+ }
24
+ declare class Tunnel {
25
+ #private;
26
+ get log(): Logger | undefined;
27
+ constructor(runner: Runner);
28
+ start(): void;
29
+ resendBufferedEvents(): void;
30
+ shutdown(): void;
31
+ restoreHibernatingRequests(actorId: string, metaEntries: HibernatingWebSocketMetadata[]): Promise<void>;
32
+ addRequestToActor(gatewayId: GatewayId, requestId: RequestId, actorId: string): void;
33
+ getRequestActor(gatewayId: GatewayId, requestId: RequestId): RunnerActor | undefined;
34
+ getAndWaitForRequestActor(gatewayId: GatewayId, requestId: RequestId): Promise<RunnerActor | undefined>;
35
+ closeActiveRequests(actor: RunnerActor): void;
36
+ handleTunnelMessage(message: protocol.ToClientTunnelMessage): Promise<void>;
37
+ sendHibernatableWebSocketMessageAck(gatewayId: ArrayBuffer, requestId: ArrayBuffer, clientMessageIndex: number): void;
38
+ }
39
+
40
+ /**
41
+ * Polyfill for Promise.withResolvers().
42
+ *
43
+ * This is specifically for Cloudflare Workers. Their implementation of Promise.withResolvers does not work correctly.
44
+ */
45
+ declare function promiseWithResolvers<T>(): {
46
+ promise: Promise<T>;
47
+ resolve: (value: T | PromiseLike<T>) => void;
48
+ reject: (reason?: any) => void;
49
+ };
50
+ declare function idToStr(id: ArrayBuffer): string;
51
+
52
+ declare const HIBERNATABLE_SYMBOL: unique symbol;
53
+ declare class WebSocketTunnelAdapter {
54
+ #private;
55
+ readonly request: Request;
56
+ get [HIBERNATABLE_SYMBOL](): boolean;
57
+ constructor(tunnel: Tunnel, actorId: string, requestId: string, serverMessageIndex: number, hibernatable: boolean, isRestoringHibernatable: boolean, request: Request, sendCallback: (data: ArrayBuffer | string, isBinary: boolean) => void, closeCallback: (code?: number, reason?: string) => void);
58
+ get websocket(): UniversalWebSocket;
59
+ _handleOpen(requestId: ArrayBuffer): void;
60
+ _handleMessage(requestId: ArrayBuffer, data: string | Uint8Array, serverMessageIndex: number, isBinary: boolean): boolean;
61
+ _handleClose(_requestId: ArrayBuffer, code?: number, reason?: string): void;
62
+ _closeWithoutCallback(code?: number, reason?: string): void;
63
+ close(code?: number, reason?: string): void;
64
+ }
65
+
66
+ interface ActorConfig {
67
+ name: string;
68
+ key: string | null;
69
+ createTs: bigint;
70
+ input: Uint8Array | null;
71
+ }
72
+ declare class RunnerActor {
73
+ /**
74
+ * List of hibernating requests provided by the gateway on actor start.
75
+ * This represents the WebSocket connections that the gateway knows about.
76
+ **/
77
+ hibernatingRequests: readonly protocol.HibernatingRequest[];
78
+ actorId: string;
79
+ generation: number;
80
+ config: ActorConfig;
81
+ pendingRequests: Array<{
82
+ gatewayId: protocol.GatewayId;
83
+ requestId: protocol.RequestId;
84
+ request: PendingRequest;
85
+ }>;
86
+ webSockets: Array<{
87
+ gatewayId: protocol.GatewayId;
88
+ requestId: protocol.RequestId;
89
+ ws: WebSocketTunnelAdapter;
90
+ }>;
91
+ actorStartPromise: ReturnType<typeof promiseWithResolvers<void>>;
92
+ lastCommandIdx: bigint;
93
+ nextEventIdx: bigint;
94
+ eventHistory: protocol.EventWrapper[];
95
+ /**
96
+ * If restoreHibernatingRequests has been called. This is used to assert
97
+ * that the caller is implemented correctly.
98
+ **/
99
+ hibernationRestored: boolean;
100
+ /**
101
+ * Set when the actor has explicitly requested to stop (e.g. c.destroy()).
102
+ * Used to send StopCode.Ok (graceful) vs StopCode.Error (ungraceful) so
103
+ * the engine crash policy handles sleepable actors correctly.
104
+ **/
105
+ stopIntentSent: boolean;
106
+ constructor(actorId: string, generation: number, config: ActorConfig,
107
+ /**
108
+ * List of hibernating requests provided by the gateway on actor start.
109
+ * This represents the WebSocket connections that the gateway knows about.
110
+ **/
111
+ hibernatingRequests: readonly protocol.HibernatingRequest[]);
112
+ getPendingRequest(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): PendingRequest | undefined;
113
+ createPendingRequest(gatewayId: protocol.GatewayId, requestId: protocol.RequestId, clientMessageIndex: number): void;
114
+ createPendingRequestWithStreamController(gatewayId: protocol.GatewayId, requestId: protocol.RequestId, clientMessageIndex: number, streamController: ReadableStreamDefaultController<Uint8Array>): void;
115
+ deletePendingRequest(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): void;
116
+ getWebSocket(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): WebSocketTunnelAdapter | undefined;
117
+ setWebSocket(gatewayId: protocol.GatewayId, requestId: protocol.RequestId, ws: WebSocketTunnelAdapter): void;
118
+ deleteWebSocket(gatewayId: protocol.GatewayId, requestId: protocol.RequestId): void;
119
+ handleAckEvents(lastEventIdx: bigint): void;
120
+ recordEvent(eventWrapper: protocol.EventWrapper): void;
121
+ }
122
+
123
+ declare class RunnerShutdownError extends Error {
124
+ constructor();
125
+ }
126
+ interface RunnerConfig {
127
+ logger?: Logger;
128
+ version: number;
129
+ endpoint: string;
130
+ token?: string;
131
+ pegboardEndpoint?: string;
132
+ pegboardRelayEndpoint?: string;
133
+ namespace: string;
134
+ totalSlots: number;
135
+ runnerName: string;
136
+ prepopulateActorNames: Record<string, {
137
+ metadata: Record<string, any>;
138
+ }>;
139
+ metadata?: Record<string, any>;
140
+ onConnected: () => void;
141
+ onDisconnected: (code: number, reason: string) => void;
142
+ onShutdown: () => void;
143
+ /** Called when receiving a network request. */
144
+ fetch: (runner: Runner, actorId: string, gatewayId: protocol.GatewayId, requestId: protocol.RequestId, request: Request) => Promise<Response>;
145
+ /**
146
+ * Called when receiving a WebSocket connection.
147
+ *
148
+ * All event listeners must be added synchronously inside this function or
149
+ * else events may be missed. The open event will fire immediately after
150
+ * this function finishes.
151
+ *
152
+ * Any errors thrown here will disconnect the WebSocket immediately.
153
+ *
154
+ * While `path` and `headers` are partially redundant to the data in the
155
+ * `Request`, they may vary slightly from the actual content of `Request`.
156
+ * Prefer to persist the `path` and `headers` properties instead of the
157
+ * `Request` itself.
158
+ *
159
+ * ## Hibernating Web Sockets
160
+ *
161
+ * ### Implementation Requirements
162
+ *
163
+ * **Requirement 1: Persist HWS Immediately**
164
+ *
165
+ * This is responsible for persisting hibernatable WebSockets immediately
166
+ * (do not wait for open event). It is not time sensitive to flush the
167
+ * connection state. If this fails to persist the HWS, the client's
168
+ * WebSocket will be disconnected on next wake in the call to
169
+ * `Tunnel::restoreHibernatingRequests` since the connection entry will not
170
+ * exist.
171
+ *
172
+ * **Requirement 2: Persist Message Index On `message`**
173
+ *
174
+ * In the `message` event listener, this handler must persist the message
175
+ * index from the event. The request ID is available at
176
+ * `event.rivetRequestId` and message index at `event.rivetMessageIndex`.
177
+ *
178
+ * The message index should not be flushed immediately. Instead, this
179
+ * should:
180
+ *
181
+ * - Debounce calls to persist the message index
182
+ * - After each persist, call
183
+ * `Runner::sendHibernatableWebSocketMessageAck` to acknowledge the
184
+ * message
185
+ *
186
+ * This mechanism allows us to buffer messages on the gateway so we can
187
+ * batch-persist events on our end on a given interval.
188
+ *
189
+ * If this fails to persist, then the gateway will replay unacked
190
+ * messages when the actor starts again.
191
+ *
192
+ * **Requirement 3: Remove HWS From Storage On `close`**
193
+ *
194
+ * This handler should add an event listener for `close` to remove the
195
+ * connection from storage.
196
+ *
197
+ * If the connection remove fails to persist, the close event will be
198
+ * called again on the next actor start in
199
+ * `Tunnel::restoreHibernatingRequests` since there will be no request for
200
+ * the given connection.
201
+ *
202
+ * ### Restoring Connections
203
+ *
204
+ * The user of this library is responsible for:
205
+ * 1. Loading all persisted hibernatable WebSocket metadata for an actor
206
+ * 2. Calling `Runner::restoreHibernatingRequests` with this metadata at
207
+ * the end of `onActorStart`
208
+ *
209
+ * `restoreHibernatingRequests` will restore all connections and attach
210
+ * the appropriate event listeners.
211
+ *
212
+ * ### No Open Event On Restoration
213
+ *
214
+ * When restoring a HWS, the open event will not be called again. It will
215
+ * go straight to the message or close event.
216
+ */
217
+ websocket: (runner: Runner, actorId: string, ws: any, gatewayId: protocol.GatewayId, requestId: protocol.RequestId, request: Request, path: string, headers: Record<string, string>, isHibernatable: boolean, isRestoringHibernatable: boolean) => Promise<void>;
218
+ hibernatableWebSocket: {
219
+ /**
220
+ * Determines if a WebSocket can continue to live while an actor goes to
221
+ * sleep.
222
+ */
223
+ canHibernate: (actorId: string, gatewayId: ArrayBuffer, requestId: ArrayBuffer, request: Request) => boolean;
224
+ };
225
+ /**
226
+ * Called when an actor starts.
227
+ *
228
+ * This callback is responsible for:
229
+ * 1. Initializing the actor instance
230
+ * 2. Loading all persisted hibernatable WebSocket metadata for this actor
231
+ * 3. Calling `Runner::restoreHibernatingRequests` with the loaded metadata
232
+ * to restore hibernatable WebSocket connections
233
+ *
234
+ * The actor should not be marked as "ready" until after
235
+ * `restoreHibernatingRequests` completes to ensure all hibernatable
236
+ * connections are fully restored before the actor processes new requests.
237
+ */
238
+ onActorStart: (actorId: string, generation: number, config: ActorConfig) => Promise<void>;
239
+ onActorStop: (actorId: string, generation: number) => Promise<void>;
240
+ noAutoShutdown?: boolean;
241
+ /**
242
+ * Debug option to inject artificial latency (in ms) into WebSocket
243
+ * communication. Messages are queued and delivered in order after the
244
+ * configured delay.
245
+ *
246
+ * @experimental For testing only.
247
+ */
248
+ debugLatencyMs?: number;
249
+ }
250
+ interface KvListOptions {
251
+ reverse?: boolean;
252
+ limit?: number;
253
+ }
254
+ declare class Runner {
255
+ #private;
256
+ get config(): RunnerConfig;
257
+ runnerId?: string;
258
+ get log(): Logger | undefined;
259
+ constructor(config: RunnerConfig);
260
+ sleepActor(actorId: string, generation?: number): void;
261
+ stopActor(actorId: string, generation?: number): Promise<void>;
262
+ /**
263
+ * Like stopActor but marks the actor for graceful destruction.
264
+ * This ensures the engine destroys the actor instead of sleeping it.
265
+ *
266
+ * NOTE: If a drain (GoingAway) occurs after this is called but before the
267
+ * stop completes, the engine's going_away flag overrides graceful_exit and
268
+ * the actor will sleep instead of being destroyed. The destroy intent is
269
+ * lost in this race. This is acceptable since the actor will be rescheduled
270
+ * elsewhere and can be destroyed on the next wake.
271
+ */
272
+ destroyActor(actorId: string, generation?: number): void;
273
+ forceStopActor(actorId: string, generation?: number): Promise<void>;
274
+ getActor(actorId: string, generation?: number): RunnerActor | undefined;
275
+ getAndWaitForActor(actorId: string, generation?: number): Promise<RunnerActor | undefined>;
276
+ hasActor(actorId: string, generation?: number): boolean;
277
+ get actors(): Map<string, RunnerActor>;
278
+ start(): Promise<void>;
279
+ shutdown(immediate: boolean, exit?: boolean): Promise<void>;
280
+ get pegboardEndpoint(): string;
281
+ get pegboardUrl(): string;
282
+ kvGet(actorId: string, keys: Uint8Array[]): Promise<(Uint8Array | null)[]>;
283
+ kvListAll(actorId: string, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
284
+ kvListRange(actorId: string, start: Uint8Array, end: Uint8Array, exclusive?: boolean, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
285
+ kvListPrefix(actorId: string, prefix: Uint8Array, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
286
+ kvPut(actorId: string, entries: [Uint8Array, Uint8Array][]): Promise<void>;
287
+ kvDelete(actorId: string, keys: Uint8Array[]): Promise<void>;
288
+ kvDeleteRange(actorId: string, start: Uint8Array, end: Uint8Array): Promise<void>;
289
+ kvDrop(actorId: string): Promise<void>;
290
+ setAlarm(actorId: string, alarmTs: number | null, generation?: number): void;
291
+ clearAlarm(actorId: string, generation?: number): void;
292
+ /** Asserts WebSocket exists and is ready. */
293
+ getPegboardWebSocketIfReady(): WebSocket | undefined;
294
+ __sendToServer(message: protocol.ToServer): void;
295
+ sendHibernatableWebSocketMessageAck(gatewayId: ArrayBuffer, requestId: ArrayBuffer, index: number): void;
296
+ /**
297
+ * Restores hibernatable WebSocket connections for an actor.
298
+ *
299
+ * This method should be called at the end of `onActorStart` after the
300
+ * actor instance is fully initialized.
301
+ *
302
+ * This method will:
303
+ * - Restore all provided hibernatable WebSocket connections
304
+ * - Attach event listeners to the restored WebSockets
305
+ * - Close any WebSocket connections that failed to restore
306
+ *
307
+ * The provided metadata list should include all hibernatable WebSockets
308
+ * that were persisted for this actor. The gateway will automatically
309
+ * close any connections that are not restored (i.e., not included in
310
+ * this list).
311
+ *
312
+ * **Important:** This method must be called after `onActorStart` completes
313
+ * and before marking the actor as "ready" to ensure all hibernatable
314
+ * connections are fully restored.
315
+ *
316
+ * @param actorId - The ID of the actor to restore connections for
317
+ * @param metaEntries - Array of hibernatable WebSocket metadata to restore
318
+ */
319
+ restoreHibernatingRequests(actorId: string, metaEntries: HibernatingWebSocketMetadata[]): Promise<void>;
320
+ getServerlessInitPacket(): string | undefined;
321
+ getProtocolMetadata(): protocol.ProtocolMetadata | undefined;
322
+ }
323
+
324
+ export { type ActorConfig, type HibernatingWebSocketMetadata, type KvListOptions, Runner, RunnerActor, type RunnerConfig, RunnerShutdownError, idToStr };