rivetkit 2.0.7 → 2.0.9

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 (105) hide show
  1. package/dist/tsup/{chunk-OSK2VSJF.cjs → chunk-2MJYYF2Q.cjs} +12 -12
  2. package/dist/tsup/{chunk-OSK2VSJF.cjs.map → chunk-2MJYYF2Q.cjs.map} +1 -1
  3. package/dist/tsup/{chunk-NUA6LOOJ.cjs → chunk-4PSLOAXR.cjs} +216 -204
  4. package/dist/tsup/chunk-4PSLOAXR.cjs.map +1 -0
  5. package/dist/tsup/{chunk-F7YL5G7Q.cjs → chunk-4YV6RDZL.cjs} +255 -229
  6. package/dist/tsup/chunk-4YV6RDZL.cjs.map +1 -0
  7. package/dist/tsup/{chunk-3ALZ7EGX.cjs → chunk-7OMMIAWP.cjs} +11 -11
  8. package/dist/tsup/{chunk-3ALZ7EGX.cjs.map → chunk-7OMMIAWP.cjs.map} +1 -1
  9. package/dist/tsup/{chunk-GWJTWY3G.cjs → chunk-A44TWAS5.cjs} +6 -6
  10. package/dist/tsup/{chunk-GWJTWY3G.cjs.map → chunk-A44TWAS5.cjs.map} +1 -1
  11. package/dist/tsup/{chunk-B6N6VM37.js → chunk-APHV6WXU.js} +2 -2
  12. package/dist/tsup/{chunk-ETDWYT2P.cjs → chunk-DL7TPF63.cjs} +7 -7
  13. package/dist/tsup/{chunk-ETDWYT2P.cjs.map → chunk-DL7TPF63.cjs.map} +1 -1
  14. package/dist/tsup/{chunk-YL4VZMMT.js → chunk-DLPIL3VC.js} +2 -2
  15. package/dist/tsup/{chunk-VAF63BEI.cjs → chunk-DZZQG7VH.cjs} +3 -3
  16. package/dist/tsup/{chunk-VAF63BEI.cjs.map → chunk-DZZQG7VH.cjs.map} +1 -1
  17. package/dist/tsup/{chunk-RLBM6D4L.js → chunk-E63WU5PL.js} +3 -3
  18. package/dist/tsup/chunk-E63WU5PL.js.map +1 -0
  19. package/dist/tsup/{chunk-DIHKN7NM.js → chunk-F2YZNUPU.js} +3 -3
  20. package/dist/tsup/{chunk-KHRZPP5T.js → chunk-FZP2IBIX.js} +94 -68
  21. package/dist/tsup/chunk-FZP2IBIX.js.map +1 -0
  22. package/dist/tsup/{chunk-NII4KKHD.js → chunk-KHZ2QSQ4.js} +28 -16
  23. package/dist/tsup/chunk-KHZ2QSQ4.js.map +1 -0
  24. package/dist/tsup/{chunk-4EXJ4ITR.cjs → chunk-QGRYH6TU.cjs} +3 -3
  25. package/dist/tsup/{chunk-4EXJ4ITR.cjs.map → chunk-QGRYH6TU.cjs.map} +1 -1
  26. package/dist/tsup/{chunk-NRELKXIX.js → chunk-R7OP5N25.js} +56 -46
  27. package/dist/tsup/chunk-R7OP5N25.js.map +1 -0
  28. package/dist/tsup/{chunk-NDCVQZBS.cjs → chunk-SDXTJDDR.cjs} +62 -52
  29. package/dist/tsup/chunk-SDXTJDDR.cjs.map +1 -0
  30. package/dist/tsup/{chunk-7OOBMCQI.cjs → chunk-SOC4HWCG.cjs} +23 -22
  31. package/dist/tsup/chunk-SOC4HWCG.cjs.map +1 -0
  32. package/dist/tsup/{chunk-LXAVET4A.cjs → chunk-U2IXX6DY.cjs} +3 -3
  33. package/dist/tsup/{chunk-LXAVET4A.cjs.map → chunk-U2IXX6DY.cjs.map} +1 -1
  34. package/dist/tsup/{chunk-2NL3KGJ7.js → chunk-VVCL5DXN.js} +5 -4
  35. package/dist/tsup/chunk-VVCL5DXN.js.map +1 -0
  36. package/dist/tsup/{chunk-54MAHBLL.js → chunk-WBSPHV5V.js} +2 -2
  37. package/dist/tsup/{chunk-WAT5AE7S.js → chunk-WRSWUDFA.js} +5 -5
  38. package/dist/tsup/{chunk-PD6HCAJE.js → chunk-YR2VY4XS.js} +2 -2
  39. package/dist/tsup/client/mod.cjs +9 -9
  40. package/dist/tsup/client/mod.d.cts +2 -2
  41. package/dist/tsup/client/mod.d.ts +2 -2
  42. package/dist/tsup/client/mod.js +8 -8
  43. package/dist/tsup/common/log.cjs +3 -3
  44. package/dist/tsup/common/log.js +2 -2
  45. package/dist/tsup/common/websocket.cjs +4 -4
  46. package/dist/tsup/common/websocket.js +3 -3
  47. package/dist/tsup/{conn-DCSQgIlw.d.ts → conn-Bt8rkUzm.d.ts} +19 -1
  48. package/dist/tsup/{conn-DdzHTm2E.d.cts → conn-CEh3WKbA.d.cts} +19 -1
  49. package/dist/tsup/driver-helpers/mod.cjs +7 -5
  50. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  51. package/dist/tsup/driver-helpers/mod.d.cts +4 -2
  52. package/dist/tsup/driver-helpers/mod.d.ts +4 -2
  53. package/dist/tsup/driver-helpers/mod.js +7 -5
  54. package/dist/tsup/driver-test-suite/mod.cjs +103 -113
  55. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  56. package/dist/tsup/driver-test-suite/mod.d.cts +3 -1
  57. package/dist/tsup/driver-test-suite/mod.d.ts +3 -1
  58. package/dist/tsup/driver-test-suite/mod.js +45 -55
  59. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  60. package/dist/tsup/inspector/mod.cjs +6 -6
  61. package/dist/tsup/inspector/mod.d.cts +2 -2
  62. package/dist/tsup/inspector/mod.d.ts +2 -2
  63. package/dist/tsup/inspector/mod.js +5 -5
  64. package/dist/tsup/mod.cjs +10 -10
  65. package/dist/tsup/mod.d.cts +5 -5
  66. package/dist/tsup/mod.d.ts +5 -5
  67. package/dist/tsup/mod.js +9 -9
  68. package/dist/tsup/test/mod.cjs +11 -11
  69. package/dist/tsup/test/mod.d.cts +1 -1
  70. package/dist/tsup/test/mod.d.ts +1 -1
  71. package/dist/tsup/test/mod.js +10 -10
  72. package/dist/tsup/utils.cjs +2 -2
  73. package/dist/tsup/utils.js +1 -1
  74. package/package.json +2 -2
  75. package/src/actor/instance.ts +20 -7
  76. package/src/actor/router-endpoints.ts +2 -1
  77. package/src/actor/router.ts +27 -24
  78. package/src/client/actor-conn.ts +5 -1
  79. package/src/client/config.ts +2 -0
  80. package/src/driver-helpers/mod.ts +1 -0
  81. package/src/driver-test-suite/mod.ts +11 -2
  82. package/src/driver-test-suite/tests/actor-schedule.ts +14 -37
  83. package/src/driver-test-suite/tests/actor-sleep.ts +18 -18
  84. package/src/drivers/engine/actor-driver.ts +39 -10
  85. package/src/drivers/file-system/manager.ts +5 -1
  86. package/src/manager/driver.ts +1 -1
  87. package/src/manager/router.ts +49 -41
  88. package/src/registry/mod.ts +11 -2
  89. package/src/remote-manager-driver/mod.ts +3 -2
  90. package/src/serde.ts +15 -0
  91. package/dist/tsup/chunk-2NL3KGJ7.js.map +0 -1
  92. package/dist/tsup/chunk-7OOBMCQI.cjs.map +0 -1
  93. package/dist/tsup/chunk-F7YL5G7Q.cjs.map +0 -1
  94. package/dist/tsup/chunk-KHRZPP5T.js.map +0 -1
  95. package/dist/tsup/chunk-NDCVQZBS.cjs.map +0 -1
  96. package/dist/tsup/chunk-NII4KKHD.js.map +0 -1
  97. package/dist/tsup/chunk-NRELKXIX.js.map +0 -1
  98. package/dist/tsup/chunk-NUA6LOOJ.cjs.map +0 -1
  99. package/dist/tsup/chunk-RLBM6D4L.js.map +0 -1
  100. /package/dist/tsup/{chunk-B6N6VM37.js.map → chunk-APHV6WXU.js.map} +0 -0
  101. /package/dist/tsup/{chunk-YL4VZMMT.js.map → chunk-DLPIL3VC.js.map} +0 -0
  102. /package/dist/tsup/{chunk-DIHKN7NM.js.map → chunk-F2YZNUPU.js.map} +0 -0
  103. /package/dist/tsup/{chunk-54MAHBLL.js.map → chunk-WBSPHV5V.js.map} +0 -0
  104. /package/dist/tsup/{chunk-WAT5AE7S.js.map → chunk-WRSWUDFA.js.map} +0 -0
  105. /package/dist/tsup/{chunk-PD6HCAJE.js.map → chunk-YR2VY4XS.js.map} +0 -0
@@ -6,6 +6,8 @@ export function runActorScheduleTests(driverTestConfig: DriverTestConfig) {
6
6
  describe.skipIf(driverTestConfig.skip?.schedule)(
7
7
  "Actor Schedule Tests",
8
8
  () => {
9
+ // See alarm + actor sleeping test in actor-sleep.ts
10
+
9
11
  describe("Scheduled Alarms", () => {
10
12
  test("executes c.schedule.at() with specific timestamp", async (c) => {
11
13
  const { client } = await setupDriverTest(c, driverTestConfig);
@@ -13,12 +15,12 @@ export function runActorScheduleTests(driverTestConfig: DriverTestConfig) {
13
15
  // Create instance
14
16
  const scheduled = client.scheduled.getOrCreate();
15
17
 
16
- // Schedule a task to run in 100ms using timestamp
17
- const timestamp = Date.now() + 100;
18
+ // Schedule a task to run using timestamp
19
+ const timestamp = Date.now() + 250;
18
20
  await scheduled.scheduleTaskAt(timestamp);
19
21
 
20
22
  // Wait for longer than the scheduled time
21
- await waitFor(driverTestConfig, 200);
23
+ await waitFor(driverTestConfig, 500);
22
24
 
23
25
  // Verify the scheduled task ran
24
26
  const lastRun = await scheduled.getLastRun();
@@ -34,11 +36,11 @@ export function runActorScheduleTests(driverTestConfig: DriverTestConfig) {
34
36
  // Create instance
35
37
  const scheduled = client.scheduled.getOrCreate();
36
38
 
37
- // Schedule a task to run in 100ms using delay
38
- await scheduled.scheduleTaskAfter(100);
39
+ // Schedule a task to run using delay
40
+ await scheduled.scheduleTaskAfter(250);
39
41
 
40
42
  // Wait for longer than the scheduled time
41
- await waitFor(driverTestConfig, 200);
43
+ await waitFor(driverTestConfig, 500);
42
44
 
43
45
  // Verify the scheduled task ran
44
46
  const lastRun = await scheduled.getLastRun();
@@ -48,31 +50,6 @@ export function runActorScheduleTests(driverTestConfig: DriverTestConfig) {
48
50
  expect(scheduledCount).toBe(1);
49
51
  });
50
52
 
51
- test("scheduled tasks persist across actor restarts", async (c) => {
52
- const { client } = await setupDriverTest(c, driverTestConfig);
53
-
54
- // Create instance and schedule
55
- const scheduled = client.scheduled.getOrCreate();
56
- await scheduled.scheduleTaskAfter(200);
57
-
58
- // Wait a little so the schedule is stored but hasn't triggered yet
59
- await waitFor(driverTestConfig, 100);
60
-
61
- // Get a new reference to simulate actor restart
62
- const newInstance = client.scheduled.getOrCreate();
63
-
64
- // Verify the schedule still exists but hasn't run yet
65
- const initialCount = await newInstance.getScheduledCount();
66
- expect(initialCount).toBe(0);
67
-
68
- // Wait for the scheduled task to execute
69
- await waitFor(driverTestConfig, 200);
70
-
71
- // Verify the scheduled task ran after "restart"
72
- const scheduledCount = await newInstance.getScheduledCount();
73
- expect(scheduledCount).toBe(1);
74
- });
75
-
76
53
  test("multiple scheduled tasks execute in order", async (c) => {
77
54
  const { client } = await setupDriverTest(c, driverTestConfig);
78
55
 
@@ -83,22 +60,22 @@ export function runActorScheduleTests(driverTestConfig: DriverTestConfig) {
83
60
  await scheduled.clearHistory();
84
61
 
85
62
  // Schedule multiple tasks with different delays
86
- await scheduled.scheduleTaskAfterWithId("first", 100);
87
- await scheduled.scheduleTaskAfterWithId("second", 300);
88
- await scheduled.scheduleTaskAfterWithId("third", 500);
63
+ await scheduled.scheduleTaskAfterWithId("first", 250);
64
+ await scheduled.scheduleTaskAfterWithId("second", 750);
65
+ await scheduled.scheduleTaskAfterWithId("third", 1250);
89
66
 
90
67
  // Wait for first task only
91
- await waitFor(driverTestConfig, 200);
68
+ await waitFor(driverTestConfig, 500);
92
69
  const history1 = await scheduled.getTaskHistory();
93
70
  expect(history1).toEqual(["first"]);
94
71
 
95
72
  // Wait for second task
96
- await waitFor(driverTestConfig, 200);
73
+ await waitFor(driverTestConfig, 500);
97
74
  const history2 = await scheduled.getTaskHistory();
98
75
  expect(history2).toEqual(["first", "second"]);
99
76
 
100
77
  // Wait for third task
101
- await waitFor(driverTestConfig, 200);
78
+ await waitFor(driverTestConfig, 500);
102
79
  const history3 = await scheduled.getTaskHistory();
103
80
  expect(history3).toEqual(["first", "second", "third"]);
104
81
  });
@@ -29,7 +29,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
29
29
  await sleepActor.triggerSleep();
30
30
 
31
31
  // HACK: Wait for sleep to finish in background
32
- await waitFor(driverTestConfig, 100);
32
+ await waitFor(driverTestConfig, 250);
33
33
 
34
34
  // Get sleep count after restore
35
35
  {
@@ -59,7 +59,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
59
59
  await sleepActor.dispose();
60
60
 
61
61
  // HACK: Wait for sleep to finish in background
62
- await waitFor(driverTestConfig, 100);
62
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
63
63
 
64
64
  // Reconnect to get sleep count after restore
65
65
  const sleepActor2 = client.sleep.getOrCreate();
@@ -84,7 +84,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
84
84
  }
85
85
 
86
86
  // Wait for sleep
87
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
87
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
88
88
 
89
89
  // Get sleep count after restore
90
90
  {
@@ -111,7 +111,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
111
111
  await sleepActor.dispose();
112
112
 
113
113
  // Wait for sleep
114
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
114
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
115
115
 
116
116
  // Reconnect to get sleep count after restore
117
117
  const sleepActor2 = client.sleep.getOrCreate();
@@ -136,7 +136,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
136
136
  }
137
137
 
138
138
  // Wait almost until sleep timeout, then make RPC call
139
- await waitFor(driverTestConfig, SLEEP_TIMEOUT - 100);
139
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT - 250);
140
140
 
141
141
  // RPC call should reset the sleep timer
142
142
  {
@@ -146,7 +146,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
146
146
  }
147
147
 
148
148
  // Wait another partial timeout period - actor should still be awake
149
- await waitFor(driverTestConfig, SLEEP_TIMEOUT - 100);
149
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT - 250);
150
150
 
151
151
  // Actor should still be awake
152
152
  {
@@ -156,7 +156,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
156
156
  }
157
157
 
158
158
  // Now wait for full timeout without any RPC calls
159
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
159
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
160
160
 
161
161
  // Actor should have slept and restarted
162
162
  {
@@ -180,10 +180,10 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
180
180
  }
181
181
 
182
182
  // Set an alarm to keep the actor awake
183
- await sleepActor.setAlarm(SLEEP_TIMEOUT - 100);
183
+ await sleepActor.setAlarm(SLEEP_TIMEOUT - 250);
184
184
 
185
185
  // Wait until after SLEEPT_IMEOUT to validate the actor did not sleep
186
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
186
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
187
187
 
188
188
  // Actor should not have slept
189
189
  {
@@ -207,7 +207,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
207
207
  }
208
208
 
209
209
  // Set an alarm to keep the actor awake
210
- await sleepActor.setAlarm(SLEEP_TIMEOUT + 100);
210
+ await sleepActor.setAlarm(SLEEP_TIMEOUT + 250);
211
211
 
212
212
  // Wait until after SLEEPT_IMEOUT to validate the actor did not sleep
213
213
  await waitFor(driverTestConfig, SLEEP_TIMEOUT + 200);
@@ -239,7 +239,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
239
239
  );
240
240
  const longRunningPromise = sleepActor.longRunningRpc();
241
241
  await waitPromise;
242
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
242
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
243
243
  await sleepActor.finishLongRunningRpc();
244
244
  await longRunningPromise;
245
245
 
@@ -252,7 +252,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
252
252
  await sleepActor.dispose();
253
253
 
254
254
  // Now wait for the sleep timeout
255
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
255
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
256
256
 
257
257
  // Actor should have slept after the timeout
258
258
  const sleepActor2 = client.sleepWithLongRpc.getOrCreate();
@@ -298,7 +298,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
298
298
  });
299
299
 
300
300
  // Wait longer than sleep timeout while keeping WebSocket connected
301
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
301
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
302
302
 
303
303
  // Send a message to check if actor is still alive
304
304
  ws.send(JSON.stringify({ type: "getCounts" }));
@@ -320,7 +320,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
320
320
  ws.close();
321
321
 
322
322
  // Wait for sleep timeout after WebSocket closed
323
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
323
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
324
324
 
325
325
  // Actor should have slept after WebSocket closed
326
326
  {
@@ -347,7 +347,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
347
347
  }
348
348
 
349
349
  // Start a long-running fetch request
350
- const fetchDuration = SLEEP_TIMEOUT + 100;
350
+ const fetchDuration = SLEEP_TIMEOUT + 250;
351
351
  const fetchPromise = sleepActor.fetch(
352
352
  `long-request?duration=${fetchDuration}`,
353
353
  );
@@ -365,7 +365,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
365
365
  }
366
366
 
367
367
  // Wait for sleep timeout
368
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
368
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
369
369
 
370
370
  // Actor should have slept after timeout
371
371
  {
@@ -389,7 +389,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
389
389
  }
390
390
 
391
391
  // Wait longer than sleep timeout
392
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
392
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
393
393
 
394
394
  // Actor should NOT have slept due to noSleep option
395
395
  {
@@ -399,7 +399,7 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
399
399
  }
400
400
 
401
401
  // Wait even longer to be sure
402
- await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
402
+ await waitFor(driverTestConfig, SLEEP_TIMEOUT + 250);
403
403
 
404
404
  // Actor should still not have slept
405
405
  {
@@ -35,7 +35,11 @@ import {
35
35
  } from "@/driver-helpers/mod";
36
36
  import type { RegistryConfig } from "@/registry/config";
37
37
  import type { RunConfig } from "@/registry/run-config";
38
- import { promiseWithResolvers } from "@/utils";
38
+ import {
39
+ type LongTimeoutHandle,
40
+ promiseWithResolvers,
41
+ setLongTimeout,
42
+ } from "@/utils";
39
43
  import type { Config } from "./config";
40
44
  import { KEYS } from "./kv";
41
45
  import { logger } from "./log";
@@ -58,6 +62,7 @@ export class EngineActorDriver implements ActorDriver {
58
62
  #actors: Map<string, ActorHandler> = new Map();
59
63
  #actorRouter: ActorRouter;
60
64
  #version: number = 1; // Version for the runner protocol
65
+ #alarmTimeout?: LongTimeoutHandle;
61
66
 
62
67
  #runnerStarted: PromiseWithResolvers<undefined> = Promise.withResolvers();
63
68
  #runnerStopped: PromiseWithResolvers<undefined> = Promise.withResolvers();
@@ -74,17 +79,21 @@ export class EngineActorDriver implements ActorDriver {
74
79
  this.#managerDriver = managerDriver;
75
80
  this.#inlineClient = inlineClient;
76
81
  this.#config = config;
77
- this.#actorRouter = createActorRouter(runConfig, this);
82
+ this.#actorRouter = createActorRouter(
83
+ runConfig,
84
+ this,
85
+ registryConfig.test.enabled,
86
+ );
78
87
 
79
88
  // Create runner configuration
80
89
  let hasDisconnected = false;
81
90
  const runnerConfig: RunnerConfig = {
82
91
  version: this.#version,
83
92
  endpoint: config.endpoint,
84
- token: config.token,
93
+ token: runConfig.token ?? config.token,
85
94
  pegboardEndpoint: config.pegboardEndpoint,
86
95
  namespace: config.namespace,
87
- totalSlots: config.totalSlots,
96
+ totalSlots: runConfig.totalSlots ?? config.totalSlots,
88
97
  runnerName: config.runnerName,
89
98
  runnerKey: config.runnerKey,
90
99
  metadata: {
@@ -186,9 +195,29 @@ export class EngineActorDriver implements ActorDriver {
186
195
  }
187
196
 
188
197
  async setAlarm(actor: AnyActorInstance, timestamp: number): Promise<void> {
189
- // TODO: Set timeout
190
- // TODO: Use alarm on sleep
191
- // TODO: Send alarm to runner
198
+ // Clear prev timeout
199
+ if (this.#alarmTimeout) {
200
+ this.#alarmTimeout.abort();
201
+ this.#alarmTimeout = undefined;
202
+ }
203
+
204
+ // Set alarm
205
+ const delay = Math.max(0, timestamp - Date.now());
206
+ this.#alarmTimeout = setLongTimeout(() => {
207
+ actor._onAlarm();
208
+ this.#alarmTimeout = undefined;
209
+ }, delay);
210
+
211
+ // TODO: This call may not be needed on ActorInstance.start, but it does help ensure that the local state is synced with the alarm state
212
+ // Set alarm on Rivet
213
+ //
214
+ // This does not call an "alarm" event like Durable Objects.
215
+ // Instead, it just wakes the actor on the alarm (if not
216
+ // already awake).
217
+ //
218
+ // _onAlarm is automatically called on `ActorInstance.start` when waking
219
+ // again.
220
+ this.#runner.setAlarm(actor.id, timestamp);
192
221
  }
193
222
 
194
223
  async getDatabase(_actorId: string): Promise<unknown | undefined> {
@@ -382,9 +411,9 @@ export class EngineActorDriver implements ActorDriver {
382
411
 
383
412
  return streamSSE(c, async (stream) => {
384
413
  // Runner id should be set if the runner started
385
- const runnerId = this.#runner.runnerId;
386
- invariant(runnerId, "runnerId not set");
387
- stream.writeSSE({ data: runnerId });
414
+ const payload = this.#runner.getServerlessInitPacket();
415
+ invariant(payload, "runnerId not set");
416
+ stream.writeSSE({ data: payload });
388
417
 
389
418
  return this.#runnerStopped.promise;
390
419
  });
@@ -123,7 +123,11 @@ export class FileSystemManagerDriver implements ManagerDriver {
123
123
  this,
124
124
  inlineClient,
125
125
  );
126
- this.#actorRouter = createActorRouter(this.#runConfig, this.#actorDriver);
126
+ this.#actorRouter = createActorRouter(
127
+ this.#runConfig,
128
+ this.#actorDriver,
129
+ registryConfig.test.enabled,
130
+ );
127
131
  }
128
132
 
129
133
  async sendRequest(actorId: string, actorRequest: Request): Promise<Response> {
@@ -52,7 +52,7 @@ export interface ManagerDriver {
52
52
 
53
53
  /**
54
54
  * Get or create the inspector access token.
55
- * @internal
55
+ * @experimental
56
56
  * @returns creates or returns existing inspector access token
57
57
  */
58
58
  getOrCreateInspectorAccessToken: () => string;
@@ -2,9 +2,9 @@ import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
2
2
  import * as cbor from "cbor-x";
3
3
  import {
4
4
  Hono,
5
- Context as HonoContext,
5
+ type Context as HonoContext,
6
6
  type MiddlewareHandler,
7
- Next,
7
+ type Next,
8
8
  } from "hono";
9
9
  import { cors as corsMiddleware } from "hono/cors";
10
10
  import { createMiddleware } from "hono/factory";
@@ -80,45 +80,53 @@ export function createManagerRouter(
80
80
  runConfig: RunConfig,
81
81
  managerDriver: ManagerDriver,
82
82
  serverlessActorDriverBuilder: (() => ActorDriver) | undefined,
83
- ): { router: Hono; openapi: OpenAPIHono; cors: MiddlewareHandler } {
83
+ ): { router: Hono; openapi: OpenAPIHono } {
84
84
  const router = new OpenAPIHono({ strict: false }).basePath(
85
85
  runConfig.basePath,
86
86
  );
87
87
 
88
88
  router.use("*", loggerMiddleware(logger()));
89
89
 
90
- const cors = runConfig.cors
91
- ? corsMiddleware(runConfig.cors)
92
- : createMiddleware((_c, next) => next());
93
-
94
90
  if (serverlessActorDriverBuilder) {
95
- addServerlessRoutes(serverlessActorDriverBuilder, router, cors);
91
+ addServerlessRoutes(runConfig, serverlessActorDriverBuilder, router);
96
92
  } else {
97
- addManagerRoutes(registryConfig, runConfig, managerDriver, router, cors);
93
+ addManagerRoutes(registryConfig, runConfig, managerDriver, router);
98
94
  }
99
95
 
100
96
  // Error handling
101
97
  router.notFound(handleRouteNotFound);
102
98
  router.onError(handleRouteError);
103
99
 
104
- return { router: router as Hono, openapi: router, cors };
100
+ return { router: router as Hono, openapi: router };
105
101
  }
106
102
 
107
103
  function addServerlessRoutes(
108
- serverlessActorDriverBuilder: () => ActorDriver,
104
+ runConfig: RunConfig,
105
+ serverlessActorDriverBuilder: (
106
+ token: string | undefined,
107
+ totalSlots: number | undefined,
108
+ ) => ActorDriver,
109
109
  router: OpenAPIHono,
110
- cors: MiddlewareHandler,
111
110
  ) {
111
+ // Apply CORS
112
+ if (runConfig.cors) router.use("*", corsMiddleware(runConfig.cors));
113
+
112
114
  // GET /
113
- router.get("/", cors, (c) => {
115
+ router.get("/", (c) => {
114
116
  return c.text(
115
117
  "This is a RivetKit server.\n\nLearn more at https://rivetkit.org",
116
118
  );
117
119
  });
118
120
 
119
121
  // Serverless start endpoint
120
- router.get("/start", cors, async (c) => {
121
- const actorDriver = serverlessActorDriverBuilder();
122
+ router.get("/start", async (c) => {
123
+ const token = c.req.header("x-rivet-token");
124
+ let totalSlots: number | undefined = parseInt(
125
+ c.req.header("x-rivetkit-total-slots") as any,
126
+ );
127
+ if (isNaN(totalSlots)) totalSlots = undefined;
128
+
129
+ const actorDriver = serverlessActorDriverBuilder(token, totalSlots);
122
130
  invariant(
123
131
  actorDriver.serverlessHandleStart,
124
132
  "missing serverlessHandleStart on ActorDriver",
@@ -126,7 +134,7 @@ function addServerlessRoutes(
126
134
  return await actorDriver.serverlessHandleStart(c);
127
135
  });
128
136
 
129
- router.get("/health", cors, (c) => {
137
+ router.get("/health", (c) => {
130
138
  return c.text("ok");
131
139
  });
132
140
  }
@@ -136,13 +144,34 @@ function addManagerRoutes(
136
144
  runConfig: RunConfig,
137
145
  managerDriver: ManagerDriver,
138
146
  router: OpenAPIHono,
139
- cors: MiddlewareHandler,
140
147
  ) {
148
+ // Serve inspector BEFORE the rest of the routes, since this has a special
149
+ // CORS config that should take precedence for the `/inspector` path
150
+ if (isInspectorEnabled(runConfig, "manager")) {
151
+ if (!managerDriver.inspector) {
152
+ throw new Unsupported("inspector");
153
+ }
154
+ router.route(
155
+ "/inspect",
156
+ new Hono<{ Variables: { inspector: any } }>()
157
+ .use(corsMiddleware(runConfig.inspector.cors))
158
+ .use(secureInspector(runConfig))
159
+ .use((c, next) => {
160
+ c.set("inspector", managerDriver.inspector!);
161
+ return next();
162
+ })
163
+ .route("/", createManagerInspectorRouter()),
164
+ );
165
+ }
166
+
167
+ // Apply CORS
168
+ if (runConfig.cors) router.use("*", corsMiddleware(runConfig.cors));
169
+
141
170
  // Actor gateway
142
- router.use("*", cors, actorGateway.bind(undefined, runConfig, managerDriver));
171
+ router.use("*", actorGateway.bind(undefined, runConfig, managerDriver));
143
172
 
144
173
  // GET /
145
- router.get("/", cors, (c) => {
174
+ router.get("/", (c) => {
146
175
  return c.text(
147
176
  "This is a RivetKit server.\n\nLearn more at https://rivetkit.org",
148
177
  );
@@ -151,7 +180,6 @@ function addManagerRoutes(
151
180
  // GET /actors
152
181
  {
153
182
  const route = createRoute({
154
- middleware: [cors],
155
183
  method: "get",
156
184
  path: "/actors",
157
185
  request: {
@@ -224,7 +252,6 @@ function addManagerRoutes(
224
252
  // PUT /actors
225
253
  {
226
254
  const route = createRoute({
227
- middleware: [cors],
228
255
  method: "put",
229
256
  path: "/actors",
230
257
  request: {
@@ -277,7 +304,6 @@ function addManagerRoutes(
277
304
  // POST /actors
278
305
  {
279
306
  const route = createRoute({
280
- middleware: [cors],
281
307
  method: "post",
282
308
  path: "/actors",
283
309
  request: {
@@ -317,7 +343,6 @@ function addManagerRoutes(
317
343
  // // DELETE /actors/{actor_id}
318
344
  // {
319
345
  // const route = createRoute({
320
- // middleware: [cors],
321
346
  // method: "delete",
322
347
  // path: "/actors/{actor_id}",
323
348
  // request: {
@@ -538,7 +563,7 @@ function addManagerRoutes(
538
563
  });
539
564
  }
540
565
 
541
- router.get("/health", cors, (c) => {
566
+ router.get("/health", (c) => {
542
567
  return c.text("ok");
543
568
  });
544
569
 
@@ -546,23 +571,6 @@ function addManagerRoutes(
546
571
  registryConfig,
547
572
  router as unknown as Hono,
548
573
  );
549
-
550
- if (isInspectorEnabled(runConfig, "manager")) {
551
- if (!managerDriver.inspector) {
552
- throw new Unsupported("inspector");
553
- }
554
- router.route(
555
- "/inspect",
556
- new Hono<{ Variables: { inspector: any } }>()
557
- .use(corsMiddleware(runConfig.inspector.cors))
558
- .use(secureInspector(runConfig))
559
- .use((c, next) => {
560
- c.set("inspector", managerDriver.inspector!);
561
- return next();
562
- })
563
- .route("/", createManagerInspectorRouter()),
564
- );
565
- }
566
574
  }
567
575
 
568
576
  function createApiActor(actor: ActorOutput): ApiActor {
@@ -108,7 +108,7 @@ export class Registry<A extends RegistryActors> {
108
108
  console.log(` - ${k}:${padding}${v}`);
109
109
  }
110
110
  if (isInspectorEnabled(config, "manager") && managerDriver.inspector) {
111
- console.log(` - Inspector: ${getInspectorUrl(config)}`);
111
+ console.log(` - Inspector: ${getInspectorUrl(config)}`);
112
112
  }
113
113
  console.log();
114
114
  }
@@ -215,7 +215,16 @@ export class Registry<A extends RegistryActors> {
215
215
  console.log();
216
216
  }
217
217
 
218
- let serverlessActorDriverBuilder: (() => ActorDriver) | undefined = () => {
218
+ let serverlessActorDriverBuilder:
219
+ | ((token?: string, totalSlots?: number) => ActorDriver)
220
+ | undefined = (
221
+ token: string | undefined,
222
+ totalSlots: number | undefined,
223
+ ) => {
224
+ // Override config
225
+ if (token) config.token = token;
226
+ if (totalSlots) config.totalSlots = totalSlots;
227
+
219
228
  return driver.actor(this.#config, config, managerDriver, client);
220
229
  };
221
230
 
@@ -15,6 +15,7 @@ import type {
15
15
  ManagerDriver,
16
16
  } from "@/driver-helpers/mod";
17
17
  import type { Encoding, UniversalWebSocket } from "@/mod";
18
+ import { uint8ArrayToBase64 } from "@/serde";
18
19
  import { combineUrlPath } from "@/utils";
19
20
  import { sendHttpRequestToActor } from "./actor-http-client";
20
21
  import {
@@ -140,7 +141,7 @@ export class RemoteManagerDriver implements ManagerDriver {
140
141
  key: serializeActorKey(key),
141
142
  runner_name_selector: this.#config.runnerName,
142
143
  input: actorInput
143
- ? cbor.encode(actorInput).toString("base64")
144
+ ? uint8ArrayToBase64(cbor.encode(actorInput))
144
145
  : undefined,
145
146
  crash_policy: "sleep",
146
147
  });
@@ -175,7 +176,7 @@ export class RemoteManagerDriver implements ManagerDriver {
175
176
  name,
176
177
  runner_name_selector: this.#config.runnerName,
177
178
  key: serializeActorKey(key),
178
- input: input ? cbor.encode(input).toString("base64") : null,
179
+ input: input ? uint8ArrayToBase64(cbor.encode(input)) : undefined,
179
180
  crash_policy: "sleep",
180
181
  });
181
182
  const actorId = result.actor.actor_id;
package/src/serde.ts CHANGED
@@ -5,6 +5,21 @@ import type { VersionedDataHandler } from "@/common/versioned-data";
5
5
  import type { Encoding } from "@/mod";
6
6
  import { jsonStringifyCompat } from "./actor/protocol/serde";
7
7
 
8
+ export function uint8ArrayToBase64(uint8Array: Uint8Array): string {
9
+ // Check if Buffer is available (Node.js)
10
+ if (typeof Buffer !== "undefined") {
11
+ return Buffer.from(uint8Array).toString("base64");
12
+ }
13
+
14
+ // Browser environment - use btoa
15
+ let binary = "";
16
+ const len = uint8Array.byteLength;
17
+ for (let i = 0; i < len; i++) {
18
+ binary += String.fromCharCode(uint8Array[i]);
19
+ }
20
+ return btoa(binary);
21
+ }
22
+
8
23
  export function encodingIsBinary(encoding: Encoding): boolean {
9
24
  if (encoding === "json") {
10
25
  return false;