@rivetkit/engine-runner 2.0.4-rc.1
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/LICENSE +203 -0
- package/dist/mod.cjs +2813 -0
- package/dist/mod.cjs.map +1 -0
- package/dist/mod.d.cts +298 -0
- package/dist/mod.d.ts +298 -0
- package/dist/mod.js +2813 -0
- package/dist/mod.js.map +1 -0
- package/package.json +43 -0
- package/src/actor.ts +210 -0
- package/src/log.ts +11 -0
- package/src/mod.ts +1862 -0
- package/src/stringify.ts +353 -0
- package/src/tunnel.ts +1169 -0
- package/src/utils.ts +175 -0
- package/src/websocket-tunnel-adapter.ts +201 -0
- package/src/websocket.ts +43 -0
package/src/stringify.ts
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import type * as protocol from "@rivetkit/engine-runner-protocol";
|
|
2
|
+
import { idToStr } from "./utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Helper function to stringify ArrayBuffer for logging
|
|
6
|
+
*/
|
|
7
|
+
function stringifyArrayBuffer(buffer: ArrayBuffer): string {
|
|
8
|
+
return `ArrayBuffer(${buffer.byteLength})`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Helper function to stringify bigint for logging
|
|
13
|
+
*/
|
|
14
|
+
function stringifyBigInt(value: bigint): string {
|
|
15
|
+
return `${value}n`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Helper function to stringify Map for logging
|
|
20
|
+
*/
|
|
21
|
+
function stringifyMap(map: ReadonlyMap<string, string>): string {
|
|
22
|
+
const entries = Array.from(map.entries())
|
|
23
|
+
.map(([k, v]) => `"${k}": "${v}"`)
|
|
24
|
+
.join(", ");
|
|
25
|
+
return `Map(${map.size}){${entries}}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Helper function to stringify MessageId for logging
|
|
30
|
+
*/
|
|
31
|
+
function stringifyMessageId(messageId: protocol.MessageId): string {
|
|
32
|
+
return `MessageId{gatewayId: ${idToStr(messageId.gatewayId)}, requestId: ${idToStr(messageId.requestId)}, messageIndex: ${messageId.messageIndex}}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Stringify ToServerTunnelMessageKind for logging
|
|
37
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
38
|
+
*/
|
|
39
|
+
export function stringifyToServerTunnelMessageKind(
|
|
40
|
+
kind: protocol.ToServerTunnelMessageKind,
|
|
41
|
+
): string {
|
|
42
|
+
switch (kind.tag) {
|
|
43
|
+
case "ToServerResponseStart": {
|
|
44
|
+
const { status, headers, body, stream } = kind.val;
|
|
45
|
+
const bodyStr = body === null ? "null" : stringifyArrayBuffer(body);
|
|
46
|
+
return `ToServerResponseStart{status: ${status}, headers: ${stringifyMap(headers)}, body: ${bodyStr}, stream: ${stream}}`;
|
|
47
|
+
}
|
|
48
|
+
case "ToServerResponseChunk": {
|
|
49
|
+
const { body, finish } = kind.val;
|
|
50
|
+
return `ToServerResponseChunk{body: ${stringifyArrayBuffer(body)}, finish: ${finish}}`;
|
|
51
|
+
}
|
|
52
|
+
case "ToServerResponseAbort":
|
|
53
|
+
return "ToServerResponseAbort";
|
|
54
|
+
case "ToServerWebSocketOpen": {
|
|
55
|
+
const { canHibernate } = kind.val;
|
|
56
|
+
return `ToServerWebSocketOpen{canHibernate: ${canHibernate}}`;
|
|
57
|
+
}
|
|
58
|
+
case "ToServerWebSocketMessage": {
|
|
59
|
+
const { data, binary } = kind.val;
|
|
60
|
+
return `ToServerWebSocketMessage{data: ${stringifyArrayBuffer(data)}, binary: ${binary}}`;
|
|
61
|
+
}
|
|
62
|
+
case "ToServerWebSocketMessageAck": {
|
|
63
|
+
const { index } = kind.val;
|
|
64
|
+
return `ToServerWebSocketMessageAck{index: ${index}}`;
|
|
65
|
+
}
|
|
66
|
+
case "ToServerWebSocketClose": {
|
|
67
|
+
const { code, reason, hibernate } = kind.val;
|
|
68
|
+
const codeStr = code === null ? "null" : code.toString();
|
|
69
|
+
const reasonStr = reason === null ? "null" : `"${reason}"`;
|
|
70
|
+
return `ToServerWebSocketClose{code: ${codeStr}, reason: ${reasonStr}, hibernate: ${hibernate}}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Stringify ToClientTunnelMessageKind for logging
|
|
77
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
78
|
+
*/
|
|
79
|
+
export function stringifyToClientTunnelMessageKind(
|
|
80
|
+
kind: protocol.ToClientTunnelMessageKind,
|
|
81
|
+
): string {
|
|
82
|
+
switch (kind.tag) {
|
|
83
|
+
case "ToClientRequestStart": {
|
|
84
|
+
const { actorId, method, path, headers, body, stream } = kind.val;
|
|
85
|
+
const bodyStr = body === null ? "null" : stringifyArrayBuffer(body);
|
|
86
|
+
return `ToClientRequestStart{actorId: "${actorId}", method: "${method}", path: "${path}", headers: ${stringifyMap(headers)}, body: ${bodyStr}, stream: ${stream}}`;
|
|
87
|
+
}
|
|
88
|
+
case "ToClientRequestChunk": {
|
|
89
|
+
const { body, finish } = kind.val;
|
|
90
|
+
return `ToClientRequestChunk{body: ${stringifyArrayBuffer(body)}, finish: ${finish}}`;
|
|
91
|
+
}
|
|
92
|
+
case "ToClientRequestAbort":
|
|
93
|
+
return "ToClientRequestAbort";
|
|
94
|
+
case "ToClientWebSocketOpen": {
|
|
95
|
+
const { actorId, path, headers } = kind.val;
|
|
96
|
+
return `ToClientWebSocketOpen{actorId: "${actorId}", path: "${path}", headers: ${stringifyMap(headers)}}`;
|
|
97
|
+
}
|
|
98
|
+
case "ToClientWebSocketMessage": {
|
|
99
|
+
const { data, binary } = kind.val;
|
|
100
|
+
return `ToClientWebSocketMessage{data: ${stringifyArrayBuffer(data)}, binary: ${binary}}`;
|
|
101
|
+
}
|
|
102
|
+
case "ToClientWebSocketClose": {
|
|
103
|
+
const { code, reason } = kind.val;
|
|
104
|
+
const codeStr = code === null ? "null" : code.toString();
|
|
105
|
+
const reasonStr = reason === null ? "null" : `"${reason}"`;
|
|
106
|
+
return `ToClientWebSocketClose{code: ${codeStr}, reason: ${reasonStr}}`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Stringify Command for logging
|
|
113
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
114
|
+
*/
|
|
115
|
+
export function stringifyCommand(command: protocol.Command): string {
|
|
116
|
+
switch (command.tag) {
|
|
117
|
+
case "CommandStartActor": {
|
|
118
|
+
const { config, hibernatingRequests } = command.val;
|
|
119
|
+
const keyStr = config.key === null ? "null" : `"${config.key}"`;
|
|
120
|
+
const inputStr =
|
|
121
|
+
config.input === null
|
|
122
|
+
? "null"
|
|
123
|
+
: stringifyArrayBuffer(config.input);
|
|
124
|
+
const hibernatingRequestsStr =
|
|
125
|
+
hibernatingRequests.length > 0
|
|
126
|
+
? `[${hibernatingRequests.map((hr) => `{gatewayId: ${idToStr(hr.gatewayId)}, requestId: ${idToStr(hr.requestId)}}`).join(", ")}]`
|
|
127
|
+
: "[]";
|
|
128
|
+
return `CommandStartActor{config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}, hibernatingRequests: ${hibernatingRequestsStr}}`;
|
|
129
|
+
}
|
|
130
|
+
case "CommandStopActor": {
|
|
131
|
+
return `CommandStopActor`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Stringify CommandWrapper for logging
|
|
138
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
139
|
+
*/
|
|
140
|
+
export function stringifyCommandWrapper(
|
|
141
|
+
wrapper: protocol.CommandWrapper,
|
|
142
|
+
): string {
|
|
143
|
+
return `CommandWrapper{actorId: "${wrapper.checkpoint.actorId}", generation: "${wrapper.checkpoint.generation}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Stringify Event for logging
|
|
148
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
149
|
+
*/
|
|
150
|
+
export function stringifyEvent(event: protocol.Event): string {
|
|
151
|
+
switch (event.tag) {
|
|
152
|
+
case "EventActorIntent": {
|
|
153
|
+
const { intent } = event.val;
|
|
154
|
+
const intentStr =
|
|
155
|
+
intent.tag === "ActorIntentSleep"
|
|
156
|
+
? "Sleep"
|
|
157
|
+
: intent.tag === "ActorIntentStop"
|
|
158
|
+
? "Stop"
|
|
159
|
+
: "Unknown";
|
|
160
|
+
return `EventActorIntent{intent: ${intentStr}}`;
|
|
161
|
+
}
|
|
162
|
+
case "EventActorStateUpdate": {
|
|
163
|
+
const { state } = event.val;
|
|
164
|
+
let stateStr: string;
|
|
165
|
+
if (state.tag === "ActorStateRunning") {
|
|
166
|
+
stateStr = "Running";
|
|
167
|
+
} else if (state.tag === "ActorStateStopped") {
|
|
168
|
+
const { code, message } = state.val;
|
|
169
|
+
const messageStr = message === null ? "null" : `"${message}"`;
|
|
170
|
+
stateStr = `Stopped{code: ${code}, message: ${messageStr}}`;
|
|
171
|
+
} else {
|
|
172
|
+
stateStr = "Unknown";
|
|
173
|
+
}
|
|
174
|
+
return `EventActorStateUpdate{state: ${stateStr}}`;
|
|
175
|
+
}
|
|
176
|
+
case "EventActorSetAlarm": {
|
|
177
|
+
const { alarmTs } = event.val;
|
|
178
|
+
const alarmTsStr =
|
|
179
|
+
alarmTs === null ? "null" : stringifyBigInt(alarmTs);
|
|
180
|
+
return `EventActorSetAlarm{alarmTs: ${alarmTsStr}}`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Stringify EventWrapper for logging
|
|
187
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
188
|
+
*/
|
|
189
|
+
export function stringifyEventWrapper(wrapper: protocol.EventWrapper): string {
|
|
190
|
+
return `EventWrapper{actorId: ${wrapper.checkpoint.actorId}, generation: "${wrapper.checkpoint.generation}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Stringify ToServer for logging
|
|
195
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
196
|
+
*/
|
|
197
|
+
export function stringifyToServer(message: protocol.ToServer): string {
|
|
198
|
+
switch (message.tag) {
|
|
199
|
+
case "ToServerInit": {
|
|
200
|
+
const {
|
|
201
|
+
name,
|
|
202
|
+
version,
|
|
203
|
+
totalSlots,
|
|
204
|
+
prepopulateActorNames,
|
|
205
|
+
metadata,
|
|
206
|
+
} = message.val;
|
|
207
|
+
const prepopulateActorNamesStr =
|
|
208
|
+
prepopulateActorNames === null
|
|
209
|
+
? "null"
|
|
210
|
+
: `Map(${prepopulateActorNames.size})`;
|
|
211
|
+
const metadataStr = metadata === null ? "null" : `"${metadata}"`;
|
|
212
|
+
return `ToServerInit{name: "${name}", version: ${version}, totalSlots: ${totalSlots}, prepopulateActorNames: ${prepopulateActorNamesStr}, metadata: ${metadataStr}}`;
|
|
213
|
+
}
|
|
214
|
+
case "ToServerEvents": {
|
|
215
|
+
const events = message.val;
|
|
216
|
+
return `ToServerEvents{count: ${events.length}, events: [${events.map((e) => stringifyEventWrapper(e)).join(", ")}]}`;
|
|
217
|
+
}
|
|
218
|
+
case "ToServerAckCommands": {
|
|
219
|
+
const { lastCommandCheckpoints } = message.val;
|
|
220
|
+
const checkpointsStr =
|
|
221
|
+
lastCommandCheckpoints.length > 0
|
|
222
|
+
? `[${lastCommandCheckpoints.map((cp) => `{actorId: "${cp.actorId}", index: ${stringifyBigInt(cp.index)}}`).join(", ")}]`
|
|
223
|
+
: "[]";
|
|
224
|
+
return `ToServerAckCommands{lastCommandCheckpoints: ${checkpointsStr}}`;
|
|
225
|
+
}
|
|
226
|
+
case "ToServerStopping":
|
|
227
|
+
return "ToServerStopping";
|
|
228
|
+
case "ToServerPong": {
|
|
229
|
+
const { ts } = message.val;
|
|
230
|
+
return `ToServerPong{ts: ${stringifyBigInt(ts)}}`;
|
|
231
|
+
}
|
|
232
|
+
case "ToServerKvRequest": {
|
|
233
|
+
const { actorId, requestId, data } = message.val;
|
|
234
|
+
const dataStr = stringifyKvRequestData(data);
|
|
235
|
+
return `ToServerKvRequest{actorId: "${actorId}", requestId: ${requestId}, data: ${dataStr}}`;
|
|
236
|
+
}
|
|
237
|
+
case "ToServerTunnelMessage": {
|
|
238
|
+
const { messageId, messageKind } = message.val;
|
|
239
|
+
return `ToServerTunnelMessage{messageId: ${stringifyMessageId(messageId)}, messageKind: ${stringifyToServerTunnelMessageKind(messageKind)}}`;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Stringify ToClient for logging
|
|
246
|
+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
|
|
247
|
+
*/
|
|
248
|
+
export function stringifyToClient(message: protocol.ToClient): string {
|
|
249
|
+
switch (message.tag) {
|
|
250
|
+
case "ToClientInit": {
|
|
251
|
+
const { runnerId, metadata } = message.val;
|
|
252
|
+
const metadataStr = `{runnerLostThreshold: ${stringifyBigInt(metadata.runnerLostThreshold)}}`;
|
|
253
|
+
return `ToClientInit{runnerId: "${runnerId}", metadata: ${metadataStr}}`;
|
|
254
|
+
}
|
|
255
|
+
case "ToClientPing": {
|
|
256
|
+
const { ts } = message.val;
|
|
257
|
+
return `ToClientPing{ts: ${stringifyBigInt(ts)}}`;
|
|
258
|
+
}
|
|
259
|
+
case "ToClientCommands": {
|
|
260
|
+
const commands = message.val;
|
|
261
|
+
return `ToClientCommands{count: ${commands.length}, commands: [${commands.map((c) => stringifyCommandWrapper(c)).join(", ")}]}`;
|
|
262
|
+
}
|
|
263
|
+
case "ToClientAckEvents": {
|
|
264
|
+
const { lastEventCheckpoints } = message.val;
|
|
265
|
+
const checkpointsStr =
|
|
266
|
+
lastEventCheckpoints.length > 0
|
|
267
|
+
? `[${lastEventCheckpoints.map((cp) => `{actorId: "${cp.actorId}", index: ${stringifyBigInt(cp.index)}}`).join(", ")}]`
|
|
268
|
+
: "[]";
|
|
269
|
+
return `ToClientAckEvents{lastEventCheckpoints: ${checkpointsStr}}`;
|
|
270
|
+
}
|
|
271
|
+
case "ToClientKvResponse": {
|
|
272
|
+
const { requestId, data } = message.val;
|
|
273
|
+
const dataStr = stringifyKvResponseData(data);
|
|
274
|
+
return `ToClientKvResponse{requestId: ${requestId}, data: ${dataStr}}`;
|
|
275
|
+
}
|
|
276
|
+
case "ToClientTunnelMessage": {
|
|
277
|
+
const { messageId, messageKind } = message.val;
|
|
278
|
+
return `ToClientTunnelMessage{messageId: ${stringifyMessageId(messageId)}, messageKind: ${stringifyToClientTunnelMessageKind(messageKind)}}`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Stringify KvRequestData for logging
|
|
285
|
+
*/
|
|
286
|
+
function stringifyKvRequestData(data: protocol.KvRequestData): string {
|
|
287
|
+
switch (data.tag) {
|
|
288
|
+
case "KvGetRequest": {
|
|
289
|
+
const { keys } = data.val;
|
|
290
|
+
return `KvGetRequest{keys: ${keys.length}}`;
|
|
291
|
+
}
|
|
292
|
+
case "KvListRequest": {
|
|
293
|
+
const { query, reverse, limit } = data.val;
|
|
294
|
+
const reverseStr = reverse === null ? "null" : reverse.toString();
|
|
295
|
+
const limitStr = limit === null ? "null" : stringifyBigInt(limit);
|
|
296
|
+
return `KvListRequest{query: ${stringifyKvListQuery(query)}, reverse: ${reverseStr}, limit: ${limitStr}}`;
|
|
297
|
+
}
|
|
298
|
+
case "KvPutRequest": {
|
|
299
|
+
const { keys, values } = data.val;
|
|
300
|
+
return `KvPutRequest{keys: ${keys.length}, values: ${values.length}}`;
|
|
301
|
+
}
|
|
302
|
+
case "KvDeleteRequest": {
|
|
303
|
+
const { keys } = data.val;
|
|
304
|
+
return `KvDeleteRequest{keys: ${keys.length}}`;
|
|
305
|
+
}
|
|
306
|
+
case "KvDropRequest":
|
|
307
|
+
return "KvDropRequest";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Stringify KvListQuery for logging
|
|
313
|
+
*/
|
|
314
|
+
function stringifyKvListQuery(query: protocol.KvListQuery): string {
|
|
315
|
+
switch (query.tag) {
|
|
316
|
+
case "KvListAllQuery":
|
|
317
|
+
return "KvListAllQuery";
|
|
318
|
+
case "KvListRangeQuery": {
|
|
319
|
+
const { start, end, exclusive } = query.val;
|
|
320
|
+
return `KvListRangeQuery{start: ${stringifyArrayBuffer(start)}, end: ${stringifyArrayBuffer(end)}, exclusive: ${exclusive}}`;
|
|
321
|
+
}
|
|
322
|
+
case "KvListPrefixQuery": {
|
|
323
|
+
const { key } = query.val;
|
|
324
|
+
return `KvListPrefixQuery{key: ${stringifyArrayBuffer(key)}}`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Stringify KvResponseData for logging
|
|
331
|
+
*/
|
|
332
|
+
function stringifyKvResponseData(data: protocol.KvResponseData): string {
|
|
333
|
+
switch (data.tag) {
|
|
334
|
+
case "KvErrorResponse": {
|
|
335
|
+
const { message } = data.val;
|
|
336
|
+
return `KvErrorResponse{message: "${message}"}`;
|
|
337
|
+
}
|
|
338
|
+
case "KvGetResponse": {
|
|
339
|
+
const { keys, values, metadata } = data.val;
|
|
340
|
+
return `KvGetResponse{keys: ${keys.length}, values: ${values.length}, metadata: ${metadata.length}}`;
|
|
341
|
+
}
|
|
342
|
+
case "KvListResponse": {
|
|
343
|
+
const { keys, values, metadata } = data.val;
|
|
344
|
+
return `KvListResponse{keys: ${keys.length}, values: ${values.length}, metadata: ${metadata.length}}`;
|
|
345
|
+
}
|
|
346
|
+
case "KvPutResponse":
|
|
347
|
+
return "KvPutResponse";
|
|
348
|
+
case "KvDeleteResponse":
|
|
349
|
+
return "KvDeleteResponse";
|
|
350
|
+
case "KvDropResponse":
|
|
351
|
+
return "KvDropResponse";
|
|
352
|
+
}
|
|
353
|
+
}
|