@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.
@@ -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
+ }