rivetkit 2.0.8 → 2.0.10

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 (125) hide show
  1. package/dist/tsup/{chunk-2FAWAPRT.js → chunk-346X2XU4.js} +2 -2
  2. package/dist/tsup/{chunk-SFRRXLRM.js → chunk-7E5K3375.js} +2 -2
  3. package/dist/tsup/{chunk-3WRAGTDC.cjs → chunk-CA3X5M6H.cjs} +92 -39
  4. package/dist/tsup/{chunk-PVKV2O2E.js.map → chunk-CA3X5M6H.cjs.map} +1 -1
  5. package/dist/tsup/{chunk-L5MHM6JJ.cjs → chunk-DVPXSB4B.cjs} +12 -12
  6. package/dist/tsup/{chunk-L5MHM6JJ.cjs.map → chunk-DVPXSB4B.cjs.map} +1 -1
  7. package/dist/tsup/{chunk-DQVVH5ZK.cjs → chunk-GIFHYL7A.cjs} +5 -6
  8. package/dist/tsup/chunk-GIFHYL7A.cjs.map +1 -0
  9. package/dist/tsup/{chunk-N7OVEOMU.js → chunk-H7E2UU23.js} +38 -15
  10. package/dist/tsup/chunk-H7E2UU23.js.map +1 -0
  11. package/dist/tsup/{chunk-A6TV3QU6.js → chunk-HI55LHM3.js} +5 -6
  12. package/dist/tsup/chunk-HI55LHM3.js.map +1 -0
  13. package/dist/tsup/{chunk-FGOZELKN.cjs → chunk-I3FB346I.cjs} +112 -58
  14. package/dist/tsup/chunk-I3FB346I.cjs.map +1 -0
  15. package/dist/tsup/{chunk-DOZBWJRI.js → chunk-KGDZYQYE.js} +2 -2
  16. package/dist/tsup/{chunk-KYEEAVJO.cjs → chunk-KH5WFDUK.cjs} +6 -6
  17. package/dist/tsup/{chunk-KYEEAVJO.cjs.map → chunk-KH5WFDUK.cjs.map} +1 -1
  18. package/dist/tsup/{chunk-WP7YG7S5.js → chunk-KL4V2ULR.js} +5 -4
  19. package/dist/tsup/chunk-KL4V2ULR.js.map +1 -0
  20. package/dist/tsup/{chunk-S6EAEZQA.js → chunk-MLQIYKAZ.js} +106 -52
  21. package/dist/tsup/chunk-MLQIYKAZ.js.map +1 -0
  22. package/dist/tsup/{chunk-3ZMJUIL3.js → chunk-N3A5GYJU.js} +3 -3
  23. package/dist/tsup/{chunk-CKSA7NOS.cjs → chunk-PDFL7FBL.cjs} +717 -380
  24. package/dist/tsup/chunk-PDFL7FBL.cjs.map +1 -0
  25. package/dist/tsup/{chunk-ESD2JX3L.cjs → chunk-PPLR53PP.cjs} +3 -3
  26. package/dist/tsup/{chunk-ESD2JX3L.cjs.map → chunk-PPLR53PP.cjs.map} +1 -1
  27. package/dist/tsup/{chunk-6INXQCH7.cjs → chunk-PSCDCEXM.cjs} +17 -12
  28. package/dist/tsup/chunk-PSCDCEXM.cjs.map +1 -0
  29. package/dist/tsup/{chunk-PVKV2O2E.js → chunk-QRFXXTLG.js} +96 -43
  30. package/dist/tsup/chunk-QRFXXTLG.js.map +1 -0
  31. package/dist/tsup/{chunk-RM2V2IRK.js → chunk-R2S45MO6.js} +14 -9
  32. package/dist/tsup/chunk-R2S45MO6.js.map +1 -0
  33. package/dist/tsup/{chunk-QGUQB3NC.cjs → chunk-SIWYIRXP.cjs} +7 -6
  34. package/dist/tsup/chunk-SIWYIRXP.cjs.map +1 -0
  35. package/dist/tsup/{chunk-E77RVI3P.js → chunk-VJRXZPTT.js} +601 -264
  36. package/dist/tsup/chunk-VJRXZPTT.js.map +1 -0
  37. package/dist/tsup/{chunk-KDNB2BQX.cjs → chunk-VZMXAZKC.cjs} +229 -206
  38. package/dist/tsup/chunk-VZMXAZKC.cjs.map +1 -0
  39. package/dist/tsup/{chunk-TPJNKVFB.cjs → chunk-YKVTF7MP.cjs} +7 -7
  40. package/dist/tsup/{chunk-TPJNKVFB.cjs.map → chunk-YKVTF7MP.cjs.map} +1 -1
  41. package/dist/tsup/client/mod.cjs +9 -9
  42. package/dist/tsup/client/mod.d.cts +2 -2
  43. package/dist/tsup/client/mod.d.ts +2 -2
  44. package/dist/tsup/client/mod.js +8 -8
  45. package/dist/tsup/common/log.cjs +3 -3
  46. package/dist/tsup/common/log.js +2 -2
  47. package/dist/tsup/common/websocket.cjs +4 -4
  48. package/dist/tsup/common/websocket.js +3 -3
  49. package/dist/tsup/{conn-ChAuuTr0.d.cts → conn-Cc9WHuN4.d.cts} +196 -185
  50. package/dist/tsup/{conn-CjUkMEcm.d.ts → conn-DfPG71FA.d.ts} +196 -185
  51. package/dist/tsup/driver-helpers/mod.cjs +7 -5
  52. package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
  53. package/dist/tsup/driver-helpers/mod.d.cts +4 -2
  54. package/dist/tsup/driver-helpers/mod.d.ts +4 -2
  55. package/dist/tsup/driver-helpers/mod.js +9 -7
  56. package/dist/tsup/driver-test-suite/mod.cjs +116 -102
  57. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  58. package/dist/tsup/driver-test-suite/mod.d.cts +3 -2
  59. package/dist/tsup/driver-test-suite/mod.d.ts +3 -2
  60. package/dist/tsup/driver-test-suite/mod.js +61 -47
  61. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  62. package/dist/tsup/inspector/mod.cjs +6 -6
  63. package/dist/tsup/inspector/mod.d.cts +6 -6
  64. package/dist/tsup/inspector/mod.d.ts +6 -6
  65. package/dist/tsup/inspector/mod.js +5 -5
  66. package/dist/tsup/mod.cjs +10 -10
  67. package/dist/tsup/mod.d.cts +8 -39
  68. package/dist/tsup/mod.d.ts +8 -39
  69. package/dist/tsup/mod.js +9 -9
  70. package/dist/tsup/test/mod.cjs +11 -11
  71. package/dist/tsup/test/mod.d.cts +1 -1
  72. package/dist/tsup/test/mod.d.ts +1 -1
  73. package/dist/tsup/test/mod.js +10 -10
  74. package/dist/tsup/utils.cjs +2 -2
  75. package/dist/tsup/utils.d.cts +2 -1
  76. package/dist/tsup/utils.d.ts +2 -1
  77. package/dist/tsup/utils.js +1 -1
  78. package/package.json +4 -5
  79. package/src/actor/driver.ts +2 -2
  80. package/src/actor/instance.ts +4 -4
  81. package/src/actor/protocol/serde.ts +75 -3
  82. package/src/actor/router-endpoints.ts +6 -6
  83. package/src/actor/router.ts +2 -2
  84. package/src/client/actor-conn.ts +24 -3
  85. package/src/client/config.ts +18 -25
  86. package/src/driver-helpers/mod.ts +5 -1
  87. package/src/driver-test-suite/mod.ts +65 -43
  88. package/src/driver-test-suite/utils.ts +4 -1
  89. package/src/drivers/default.ts +11 -9
  90. package/src/drivers/engine/actor-driver.ts +40 -39
  91. package/src/drivers/engine/config.ts +9 -22
  92. package/src/drivers/engine/mod.ts +9 -8
  93. package/src/drivers/file-system/global-state.ts +4 -4
  94. package/src/engine-process/log.ts +5 -0
  95. package/src/engine-process/mod.ts +316 -0
  96. package/src/inspector/utils.ts +6 -4
  97. package/src/manager/driver.ts +3 -3
  98. package/src/manager/gateway.ts +29 -11
  99. package/src/manager/router-schema.ts +20 -0
  100. package/src/manager/router.ts +139 -58
  101. package/src/registry/mod.ts +146 -120
  102. package/src/registry/run-config.ts +116 -47
  103. package/src/registry/serve.ts +3 -1
  104. package/src/remote-manager-driver/mod.ts +3 -2
  105. package/src/serde.ts +18 -3
  106. package/src/test/config.ts +2 -2
  107. package/src/test/mod.ts +6 -3
  108. package/src/utils.ts +2 -0
  109. package/dist/tsup/chunk-3WRAGTDC.cjs.map +0 -1
  110. package/dist/tsup/chunk-6INXQCH7.cjs.map +0 -1
  111. package/dist/tsup/chunk-A6TV3QU6.js.map +0 -1
  112. package/dist/tsup/chunk-CKSA7NOS.cjs.map +0 -1
  113. package/dist/tsup/chunk-DQVVH5ZK.cjs.map +0 -1
  114. package/dist/tsup/chunk-E77RVI3P.js.map +0 -1
  115. package/dist/tsup/chunk-FGOZELKN.cjs.map +0 -1
  116. package/dist/tsup/chunk-KDNB2BQX.cjs.map +0 -1
  117. package/dist/tsup/chunk-N7OVEOMU.js.map +0 -1
  118. package/dist/tsup/chunk-QGUQB3NC.cjs.map +0 -1
  119. package/dist/tsup/chunk-RM2V2IRK.js.map +0 -1
  120. package/dist/tsup/chunk-S6EAEZQA.js.map +0 -1
  121. package/dist/tsup/chunk-WP7YG7S5.js.map +0 -1
  122. /package/dist/tsup/{chunk-2FAWAPRT.js.map → chunk-346X2XU4.js.map} +0 -0
  123. /package/dist/tsup/{chunk-SFRRXLRM.js.map → chunk-7E5K3375.js.map} +0 -0
  124. /package/dist/tsup/{chunk-DOZBWJRI.js.map → chunk-KGDZYQYE.js.map} +0 -0
  125. /package/dist/tsup/{chunk-3ZMJUIL3.js.map → chunk-N3A5GYJU.js.map} +0 -0
@@ -1,7 +1,9 @@
1
+ import invariant from "invariant";
1
2
  import { type Client, createClientWithDriver } from "@/client/client";
2
3
  import { configureBaseLogger, configureDefaultLogger } from "@/common/log";
3
4
  import type { ActorDriver } from "@/driver-helpers/mod";
4
5
  import { chooseDefaultDriver } from "@/drivers/default";
6
+ import { ENGINE_ENDPOINT, ensureEngineProcess } from "@/engine-process/mod";
5
7
  import {
6
8
  configureInspectorAccessToken,
7
9
  getInspectorUrl,
@@ -18,12 +20,16 @@ import {
18
20
  import { logger } from "./log";
19
21
  import {
20
22
  type DriverConfig,
21
- type RunConfig,
22
- type RunConfigInput,
23
- RunConfigSchema,
23
+ type RunnerConfig,
24
+ type RunnerConfigInput,
25
+ RunnerConfigSchema,
24
26
  } from "./run-config";
25
27
  import { crossPlatformServe } from "./serve";
26
28
 
29
+ export type ServerlessActorDriverBuilder = (
30
+ updateConfig: (config: RunnerConfig) => void,
31
+ ) => ActorDriver;
32
+
27
33
  interface ServerOutput<A extends Registry<any>> {
28
34
  /** Client to communicate with the actors. */
29
35
  client: Client<A>;
@@ -45,8 +51,48 @@ export class Registry<A extends RegistryActors> {
45
51
  /**
46
52
  * Runs the registry for a server.
47
53
  */
48
- public start(inputConfig?: RunConfigInput): ServerOutput<this> {
49
- const config = RunConfigSchema.parse(inputConfig);
54
+ public start(inputConfig?: RunnerConfigInput): ServerOutput<this> {
55
+ const config = RunnerConfigSchema.parse(inputConfig);
56
+
57
+ // Validate autoConfigureServerless is only used with serverless runner
58
+ if (config.autoConfigureServerless && config.runnerKind !== "serverless") {
59
+ throw new Error(
60
+ "autoConfigureServerless can only be configured when runnerKind is 'serverless'",
61
+ );
62
+ }
63
+
64
+ // Promise for any async operations we need to wait to complete
65
+ const readyPromises = [];
66
+
67
+ // Start engine
68
+ if (config.runEngine) {
69
+ logger().debug({
70
+ msg: "run engine requested",
71
+ version: config.runEngineVersion,
72
+ });
73
+
74
+ // Set config to point to the engine
75
+ invariant(
76
+ config.endpoint === undefined,
77
+ "cannot specify 'endpoint' with 'runEngine'",
78
+ );
79
+ config.endpoint = ENGINE_ENDPOINT;
80
+ config.disableActorDriver = true;
81
+
82
+ // Start the engine
83
+ const engineProcessPromise = ensureEngineProcess({
84
+ version: config.runEngineVersion,
85
+ });
86
+
87
+ // Chain ready promise
88
+ readyPromises.push(engineProcessPromise);
89
+ }
90
+
91
+ // Configure for serverless
92
+ if (config.runnerKind === "serverless") {
93
+ config.defaultServerPort = 8080;
94
+ config.overrideServerAddress = config.endpoint;
95
+ }
50
96
 
51
97
  // Configure logger
52
98
  if (config.logging?.baseLogger) {
@@ -61,14 +107,18 @@ export class Registry<A extends RegistryActors> {
61
107
  // Choose the driver based on configuration
62
108
  const driver = chooseDefaultDriver(config);
63
109
 
64
- // TODO: Find cleaner way of disabling by default
110
+ // Set defaults based on the driver
65
111
  if (driver.name === "engine") {
66
112
  config.inspector.enabled = { manager: false, actor: true };
67
- config.disableServer = true;
113
+
114
+ // We need to leave the default server enabled for dev
115
+ if (config.runnerKind !== "serverless") {
116
+ config.disableDefaultServer = true;
117
+ }
68
118
  }
69
119
  if (driver.name === "cloudflare-workers") {
70
120
  config.inspector.enabled = { manager: false, actor: true };
71
- config.disableServer = true;
121
+ config.disableDefaultServer = true;
72
122
  config.disableActorDriver = true;
73
123
  config.noWelcome = true;
74
124
  }
@@ -102,13 +152,21 @@ export class Registry<A extends RegistryActors> {
102
152
  const displayInfo = managerDriver.displayInformation();
103
153
  console.log();
104
154
  console.log(` RivetKit ${pkg.version} (${displayInfo.name})`);
105
- console.log(` - Endpoint: http://127.0.0.1:6420`);
155
+ if (!config.disableDefaultServer) {
156
+ console.log(` - Endpoint: ${config.endpoint}`);
157
+ } else if (config.overrideServerAddress) {
158
+ console.log(` - Endpoint: ${config.overrideServerAddress}`);
159
+ }
160
+ if (config.runEngine) {
161
+ const padding = " ".repeat(Math.max(0, 13 - "Engine".length));
162
+ console.log(` - Engine:${padding}v${config.runEngineVersion}`);
163
+ }
106
164
  for (const [k, v] of Object.entries(displayInfo.properties)) {
107
165
  const padding = " ".repeat(Math.max(0, 13 - k.length));
108
166
  console.log(` - ${k}:${padding}${v}`);
109
167
  }
110
168
  if (isInspectorEnabled(config, "manager") && managerDriver.inspector) {
111
- console.log(` - Inspector: ${getInspectorUrl(config)}`);
169
+ console.log(` - Inspector: ${getInspectorUrl(config)}`);
112
170
  }
113
171
  console.log();
114
172
  }
@@ -116,27 +174,32 @@ export class Registry<A extends RegistryActors> {
116
174
  // HACK: We need to find a better way to let the driver itself decide when to start the actor driver
117
175
  // Create runner
118
176
  //
119
- // Even though we do not use the return value, this is required to start the code that will handle incoming actors
177
+ // Even though we do not use the returned ActorDriver, this is required to start the code that will handle incoming actors
120
178
  if (!config.disableActorDriver) {
121
- const _actorDriver = driver.actor(
122
- this.#config,
123
- config,
124
- managerDriver,
125
- client,
126
- );
179
+ Promise.all(readyPromises).then(async () => {
180
+ driver.actor(this.#config, config, managerDriver, client);
181
+ });
182
+ }
183
+
184
+ // Configure serverless runner if enabled when actor driver is disabled
185
+ if (config.runnerKind === "serverless" && config.autoConfigureServerless) {
186
+ Promise.all(readyPromises).then(async () => {
187
+ await configureServerlessRunner(config);
188
+ });
127
189
  }
128
190
 
129
191
  const { router: hono } = createManagerRouter(
130
192
  this.#config,
131
193
  config,
132
194
  managerDriver,
133
- undefined,
195
+ driver,
196
+ client,
134
197
  );
135
198
 
136
199
  // Start server
137
- if (!config.disableServer) {
200
+ if (!config.disableDefaultServer) {
138
201
  (async () => {
139
- const out = await crossPlatformServe(hono, undefined);
202
+ const out = await crossPlatformServe(config, hono, undefined);
140
203
  upgradeWebSocket = out.upgradeWebSocket;
141
204
  })();
142
205
  }
@@ -146,116 +209,79 @@ export class Registry<A extends RegistryActors> {
146
209
  fetch: hono.fetch.bind(hono),
147
210
  };
148
211
  }
212
+ }
149
213
 
150
- public startServerless(inputConfig?: RunConfigInput): ServerOutput<this> {
151
- const config = RunConfigSchema.parse(inputConfig);
152
-
153
- // Configure logger
154
- if (config.logging?.baseLogger) {
155
- // Use provided base logger
156
- configureBaseLogger(config.logging.baseLogger);
157
- } else {
158
- // Configure default logger with log level from config
159
- // getPinoLevel will handle env variable priority
160
- configureDefaultLogger(config.logging?.level);
214
+ async function configureServerlessRunner(config: RunnerConfig): Promise<void> {
215
+ try {
216
+ // Ensure we have required config values
217
+ if (!config.runnerName) {
218
+ throw new Error("runnerName is required for serverless configuration");
161
219
  }
162
-
163
- // Choose the driver based on configuration
164
- const driver = chooseDefaultDriver(config);
165
-
166
- // TODO: Find cleaner way of disabling by default
167
- if (driver.name === "engine") {
168
- config.inspector.enabled = false;
169
- config.disableServer = true;
170
- config.disableActorDriver = true;
220
+ if (!config.namespace) {
221
+ throw new Error("namespace is required for serverless configuration");
171
222
  }
172
- if (driver.name === "cloudflare-workers") {
173
- config.inspector.enabled = false;
174
- config.disableServer = true;
175
- config.disableActorDriver = true;
176
- config.noWelcome = true;
223
+ if (!config.endpoint) {
224
+ throw new Error("endpoint is required for serverless configuration");
177
225
  }
178
226
 
179
- // Configure getUpgradeWebSocket lazily so we can assign it in crossPlatformServe
180
- let upgradeWebSocket: any;
181
- if (!config.getUpgradeWebSocket) {
182
- config.getUpgradeWebSocket = () => upgradeWebSocket!;
183
- }
227
+ // Prepare the configuration
228
+ const customConfig =
229
+ typeof config.autoConfigureServerless === "object"
230
+ ? config.autoConfigureServerless
231
+ : {};
232
+
233
+ // Build the request body
234
+ const requestBody = {
235
+ serverless: {
236
+ url:
237
+ customConfig.url ||
238
+ `http://localhost:${config.defaultServerPort}/start`,
239
+ headers: customConfig.headers || {},
240
+ max_runners: customConfig.maxRunners ?? 100,
241
+ min_runners: customConfig.minRunners ?? 0,
242
+ request_lifespan: customConfig.requestLifespan ?? 15 * 60,
243
+ runners_margin: customConfig.runnersMargin ?? 0,
244
+ slots_per_runner:
245
+ customConfig.slotsPerRunner ?? config.totalSlots ?? 1000,
246
+ },
247
+ };
184
248
 
185
- // Create router
186
- const managerDriver = driver.manager(this.#config, config);
249
+ // Make the request to configure the serverless runner
250
+ const configUrl = `${config.endpoint}/runner-configs/${config.runnerName}?namespace=${config.namespace}`;
187
251
 
188
- // Create client
189
- const client = createClientWithDriver<this>(managerDriver, config);
190
-
191
- const driverLog = managerDriver.extraStartupLog?.() ?? {};
192
- logger().info({
193
- msg: "rivetkit ready",
194
- driver: driver.name,
195
- definitions: Object.keys(this.#config.use).length,
196
- ...driverLog,
252
+ logger().debug({
253
+ msg: "configuring serverless runner",
254
+ url: configUrl,
255
+ config: requestBody.serverless,
197
256
  });
198
- if (config.inspector?.enabled && managerDriver.inspector) {
199
- logger().info({ msg: "inspector ready", url: getInspectorUrl(config) });
200
- }
201
-
202
- // Print welcome information
203
- if (!config.noWelcome) {
204
- const displayInfo = managerDriver.displayInformation();
205
- console.log();
206
- console.log(` RivetKit ${pkg.version} (${displayInfo.name})`);
207
- console.log(` - Endpoint: http://127.0.0.1:6420`);
208
- for (const [k, v] of Object.entries(displayInfo.properties)) {
209
- const padding = " ".repeat(Math.max(0, 13 - k.length));
210
- console.log(` - ${k}:${padding}${v}`);
211
- }
212
- if (config.inspector?.enabled && managerDriver.inspector) {
213
- console.log(` - Inspector: ${getInspectorUrl(config)}`);
214
- }
215
- console.log();
216
- }
217
-
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
-
228
- return driver.actor(this.#config, config, managerDriver, client);
229
- };
230
-
231
- // HACK: We need to find a better way to let the driver itself decide when to start the actor driver
232
- // Create runner
233
- //
234
- // Even though we do not use the return value, this is required to start the code that will handle incoming actors
235
- if (!config.disableActorDriver) {
236
- const _actorDriver = serverlessActorDriverBuilder();
237
- serverlessActorDriverBuilder = undefined;
238
- }
239
257
 
240
- const { router: hono } = createManagerRouter(
241
- this.#config,
242
- config,
243
- managerDriver,
244
- serverlessActorDriverBuilder,
245
- );
258
+ const response = await fetch(configUrl, {
259
+ method: "PUT",
260
+ headers: {
261
+ "Content-Type": "application/json",
262
+ ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),
263
+ },
264
+ body: JSON.stringify(requestBody),
265
+ });
246
266
 
247
- // Start server
248
- if (!config.disableServer) {
249
- (async () => {
250
- const out = await crossPlatformServe(hono, undefined);
251
- upgradeWebSocket = out.upgradeWebSocket;
252
- })();
267
+ if (!response.ok) {
268
+ const errorText = await response.text();
269
+ throw new Error(
270
+ `failed to configure serverless runner: ${response.status} ${response.statusText} - ${errorText}`,
271
+ );
253
272
  }
254
273
 
255
- return {
256
- client,
257
- fetch: hono.fetch.bind(hono),
258
- };
274
+ logger().info({
275
+ msg: "serverless runner configured successfully",
276
+ runnerName: config.runnerName,
277
+ namespace: config.namespace,
278
+ });
279
+ } catch (error) {
280
+ logger().error({
281
+ msg: "failed to configure serverless runner",
282
+ error,
283
+ });
284
+ throw error;
259
285
  }
260
286
  }
261
287
 
@@ -269,8 +295,8 @@ export function setup<A extends RegistryActors>(
269
295
  export type {
270
296
  RegistryConfig,
271
297
  RegistryActors,
272
- RunConfig,
273
- RunConfigInput,
298
+ RunnerConfig as RunConfig,
299
+ RunnerConfigInput as RunConfigInput,
274
300
  DriverConfig,
275
301
  };
276
302
  export { RegistryConfigSchema };
@@ -2,10 +2,12 @@ import type { cors } from "hono/cors";
2
2
  import type { Logger } from "pino";
3
3
  import { z } from "zod";
4
4
  import type { ActorDriverBuilder } from "@/actor/driver";
5
- import { ClientConfigSchema } from "@/client/config";
6
5
  import { LogLevelSchema } from "@/common/log";
6
+ import { EngingConfigSchema as EngineConfigSchema } from "@/drivers/engine/config";
7
7
  import { InspectorConfigSchema } from "@/inspector/config";
8
8
  import type { ManagerDriverBuilder } from "@/manager/driver";
9
+ import type { GetUpgradeWebSocket } from "@/utils";
10
+ import { getEnvUniversal } from "@/utils";
9
11
 
10
12
  type CorsOptions = NonNullable<Parameters<typeof cors>[0]>;
11
13
 
@@ -19,49 +21,116 @@ export const DriverConfigSchema = z.object({
19
21
  export type DriverConfig = z.infer<typeof DriverConfigSchema>;
20
22
 
21
23
  /** Base config used for the actor config across all platforms. */
22
- export const RunConfigSchema = ClientConfigSchema.extend({
23
- driver: DriverConfigSchema.optional(),
24
-
25
- /** CORS configuration for the router. Uses Hono's CORS middleware options. */
26
- cors: z.custom<CorsOptions>().optional(),
27
-
28
- maxIncomingMessageSize: z.number().optional().default(65_536),
29
-
30
- inspector: InspectorConfigSchema,
31
-
32
- /** @experimental */
33
- disableServer: z.boolean().optional().default(false),
34
-
35
- /** @experimental */
36
- disableActorDriver: z.boolean().optional().default(false),
37
-
38
- /**
39
- * @experimental
40
- *
41
- * Base path for the router. This is used to prefix all routes.
42
- * For example, if the base path is `/api`, then the route `/actors` will be
43
- * available at `/api/actors`.
44
- */
45
- basePath: z.string().optional().default("/"),
46
-
47
- /**
48
- * @experimental
49
- *
50
- * Disable welcome message.
51
- * */
52
- noWelcome: z.boolean().optional().default(false),
53
-
54
- /**
55
- * @experimental
56
- * */
57
- logging: z
58
- .object({
59
- baseLogger: z.custom<Logger>().optional(),
60
- level: LogLevelSchema.optional(),
61
- })
62
- .optional()
63
- .default({}),
64
- }).default({});
65
-
66
- export type RunConfig = z.infer<typeof RunConfigSchema>;
67
- export type RunConfigInput = z.input<typeof RunConfigSchema>;
24
+ export const RunnerConfigSchema = z
25
+ .object({
26
+ driver: DriverConfigSchema.optional(),
27
+
28
+ /** CORS configuration for the router. Uses Hono's CORS middleware options. */
29
+ cors: z.custom<CorsOptions>().optional(),
30
+
31
+ /** @experimental */
32
+ maxIncomingMessageSize: z.number().optional().default(65_536),
33
+
34
+ /** @experimental */
35
+ inspector: InspectorConfigSchema,
36
+
37
+ /** @experimental */
38
+ disableDefaultServer: z.boolean().optional().default(false),
39
+
40
+ /** @experimental */
41
+ defaultServerPort: z.number().default(6420),
42
+
43
+ /** @experimental */
44
+ runEngine: z
45
+ .boolean()
46
+ .optional()
47
+ .default(() => getEnvUniversal("RIVET_RUN_ENGINE") === "1"),
48
+
49
+ /** @experimental */
50
+ runEngineVersion: z
51
+ .string()
52
+ .optional()
53
+ .default(() => getEnvUniversal("RIVET_RUN_ENGINE_VERSION") ?? "25.7.3"),
54
+
55
+ /** @experimental */
56
+ overrideServerAddress: z.string().optional(),
57
+
58
+ /** @experimental */
59
+ disableActorDriver: z.boolean().optional().default(false),
60
+
61
+ /**
62
+ * @experimental
63
+ *
64
+ * Whether to run runners normally or have them managed
65
+ * serverlessly (by the Rivet Engine for example).
66
+ */
67
+ runnerKind: z
68
+ .enum(["serverless", "normal"])
69
+ .optional()
70
+ .default(() =>
71
+ getEnvUniversal("RIVET_RUNNER_KIND") === "serverless"
72
+ ? "serverless"
73
+ : "normal",
74
+ ),
75
+ totalSlots: z.number().optional(),
76
+
77
+ /**
78
+ * @experimental
79
+ *
80
+ * Base path for the router. This is used to prefix all routes.
81
+ * For example, if the base path is `/api`, then the route `/actors` will be
82
+ * available at `/api/actors`.
83
+ */
84
+ basePath: z.string().optional().default("/"),
85
+
86
+ /**
87
+ * @experimental
88
+ *
89
+ * Disable welcome message.
90
+ * */
91
+ noWelcome: z.boolean().optional().default(false),
92
+
93
+ /**
94
+ * @experimental
95
+ * */
96
+ logging: z
97
+ .object({
98
+ baseLogger: z.custom<Logger>().optional(),
99
+ level: LogLevelSchema.optional(),
100
+ })
101
+ .optional()
102
+ .default({}),
103
+
104
+ /**
105
+ * @experimental
106
+ *
107
+ * Automatically configure serverless runners in the engine.
108
+ * Can only be used when runnerKind is "serverless".
109
+ * If true, uses default configuration. Can also provide custom configuration.
110
+ */
111
+ autoConfigureServerless: z
112
+ .union([
113
+ z.boolean(),
114
+ z.object({
115
+ url: z.string().optional(),
116
+ headers: z.record(z.string(), z.string()).optional(),
117
+ maxRunners: z.number().optional(),
118
+ minRunners: z.number().optional(),
119
+ requestLifespan: z.number().optional(),
120
+ runnersMargin: z.number().optional(),
121
+ slotsPerRunner: z.number().optional(),
122
+ }),
123
+ ])
124
+ .optional(),
125
+
126
+ // This is a function to allow for lazy configuration of upgradeWebSocket on the
127
+ // fly. This is required since the dependencies that upgradeWebSocket
128
+ // (specifically Node.js) can sometimes only be specified after the router is
129
+ // created or must be imported async using `await import(...)`
130
+ getUpgradeWebSocket: z.custom<GetUpgradeWebSocket>().optional(),
131
+ })
132
+ .merge(EngineConfigSchema.removeDefault())
133
+ .default({});
134
+
135
+ export type RunnerConfig = z.infer<typeof RunnerConfigSchema>;
136
+ export type RunnerConfigInput = z.input<typeof RunnerConfigSchema>;
@@ -1,7 +1,9 @@
1
1
  import { Hono } from "hono";
2
2
  import { logger } from "./log";
3
+ import type { RunnerConfig } from "./run-config";
3
4
 
4
5
  export async function crossPlatformServe(
6
+ runConfig: RunnerConfig,
5
7
  rivetKitRouter: Hono<any>,
6
8
  userRouter: Hono | undefined,
7
9
  ) {
@@ -47,7 +49,7 @@ export async function crossPlatformServe(
47
49
  });
48
50
 
49
51
  // Start server
50
- const port = 6420;
52
+ const port = runConfig.defaultServerPort;
51
53
  const server = serve({ fetch: app.fetch, port }, () =>
52
54
  logger().info({ msg: "server listening", port }),
53
55
  );
@@ -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
@@ -3,7 +3,22 @@ import invariant from "invariant";
3
3
  import { assertUnreachable } from "@/common/utils";
4
4
  import type { VersionedDataHandler } from "@/common/versioned-data";
5
5
  import type { Encoding } from "@/mod";
6
- import { jsonStringifyCompat } from "./actor/protocol/serde";
6
+ import { jsonParseCompat, jsonStringifyCompat } from "./actor/protocol/serde";
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
+ }
7
22
 
8
23
  export function encodingIsBinary(encoding: Encoding): boolean {
9
24
  if (encoding === "json") {
@@ -63,11 +78,11 @@ export function deserializeWithEncoding<T>(
63
78
  ): T {
64
79
  if (encoding === "json") {
65
80
  if (typeof buffer === "string") {
66
- return JSON.parse(buffer);
81
+ return jsonParseCompat(buffer);
67
82
  } else {
68
83
  const decoder = new TextDecoder("utf-8");
69
84
  const jsonString = decoder.decode(buffer);
70
- return JSON.parse(jsonString);
85
+ return jsonParseCompat(jsonString);
71
86
  }
72
87
  } else if (encoding === "cbor") {
73
88
  invariant(
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
- import { RunConfigSchema } from "@/registry/run-config";
2
+ import { RunnerConfigSchema } from "@/registry/run-config";
3
3
 
4
- export const ConfigSchema = RunConfigSchema.removeDefault()
4
+ export const ConfigSchema = RunnerConfigSchema.removeDefault()
5
5
  .extend({
6
6
  hostname: z
7
7
  .string()
package/src/test/mod.ts CHANGED
@@ -10,8 +10,9 @@ import {
10
10
  getInspectorUrl,
11
11
  } from "@/inspector/utils";
12
12
  import { createManagerRouter } from "@/manager/router";
13
+ import { createClientWithDriver } from "@/mod";
13
14
  import type { Registry } from "@/registry/mod";
14
- import { RunConfigSchema } from "@/registry/run-config";
15
+ import { RunnerConfigSchema } from "@/registry/run-config";
15
16
  import { ConfigSchema, type InputConfig } from "./config";
16
17
  import { logger } from "./log";
17
18
 
@@ -27,15 +28,17 @@ function serve(registry: Registry<any>, inputConfig?: InputConfig): ServerType {
27
28
  }
28
29
 
29
30
  // Create router
30
- const runConfig = RunConfigSchema.parse(inputConfig);
31
+ const runConfig = RunnerConfigSchema.parse(inputConfig);
31
32
  const driver = inputConfig.driver ?? createFileSystemOrMemoryDriver(false);
32
33
  const managerDriver = driver.manager(registry.config, config);
34
+ const client = createClientWithDriver(managerDriver);
33
35
  configureInspectorAccessToken(config, managerDriver);
34
36
  const { router } = createManagerRouter(
35
37
  registry.config,
36
38
  runConfig,
37
39
  managerDriver,
38
- undefined,
40
+ driver,
41
+ client,
39
42
  );
40
43
 
41
44
  // Inject WebSocket
package/src/utils.ts CHANGED
@@ -31,6 +31,8 @@ export type UpgradeWebSocket = (
31
31
  createEvents: (c: HonoContext) => any,
32
32
  ) => HonoHandler;
33
33
 
34
+ export type GetUpgradeWebSocket = () => UpgradeWebSocket;
35
+
34
36
  export function getEnvUniversal(key: string): string | undefined {
35
37
  if (typeof Deno !== "undefined") {
36
38
  return Deno.env.get(key);