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.
- package/dist/tsup/{chunk-2FAWAPRT.js → chunk-346X2XU4.js} +2 -2
- package/dist/tsup/{chunk-SFRRXLRM.js → chunk-7E5K3375.js} +2 -2
- package/dist/tsup/{chunk-3WRAGTDC.cjs → chunk-CA3X5M6H.cjs} +92 -39
- package/dist/tsup/{chunk-PVKV2O2E.js.map → chunk-CA3X5M6H.cjs.map} +1 -1
- package/dist/tsup/{chunk-L5MHM6JJ.cjs → chunk-DVPXSB4B.cjs} +12 -12
- package/dist/tsup/{chunk-L5MHM6JJ.cjs.map → chunk-DVPXSB4B.cjs.map} +1 -1
- package/dist/tsup/{chunk-DQVVH5ZK.cjs → chunk-GIFHYL7A.cjs} +5 -6
- package/dist/tsup/chunk-GIFHYL7A.cjs.map +1 -0
- package/dist/tsup/{chunk-N7OVEOMU.js → chunk-H7E2UU23.js} +38 -15
- package/dist/tsup/chunk-H7E2UU23.js.map +1 -0
- package/dist/tsup/{chunk-A6TV3QU6.js → chunk-HI55LHM3.js} +5 -6
- package/dist/tsup/chunk-HI55LHM3.js.map +1 -0
- package/dist/tsup/{chunk-FGOZELKN.cjs → chunk-I3FB346I.cjs} +112 -58
- package/dist/tsup/chunk-I3FB346I.cjs.map +1 -0
- package/dist/tsup/{chunk-DOZBWJRI.js → chunk-KGDZYQYE.js} +2 -2
- package/dist/tsup/{chunk-KYEEAVJO.cjs → chunk-KH5WFDUK.cjs} +6 -6
- package/dist/tsup/{chunk-KYEEAVJO.cjs.map → chunk-KH5WFDUK.cjs.map} +1 -1
- package/dist/tsup/{chunk-WP7YG7S5.js → chunk-KL4V2ULR.js} +5 -4
- package/dist/tsup/chunk-KL4V2ULR.js.map +1 -0
- package/dist/tsup/{chunk-S6EAEZQA.js → chunk-MLQIYKAZ.js} +106 -52
- package/dist/tsup/chunk-MLQIYKAZ.js.map +1 -0
- package/dist/tsup/{chunk-3ZMJUIL3.js → chunk-N3A5GYJU.js} +3 -3
- package/dist/tsup/{chunk-CKSA7NOS.cjs → chunk-PDFL7FBL.cjs} +717 -380
- package/dist/tsup/chunk-PDFL7FBL.cjs.map +1 -0
- package/dist/tsup/{chunk-ESD2JX3L.cjs → chunk-PPLR53PP.cjs} +3 -3
- package/dist/tsup/{chunk-ESD2JX3L.cjs.map → chunk-PPLR53PP.cjs.map} +1 -1
- package/dist/tsup/{chunk-6INXQCH7.cjs → chunk-PSCDCEXM.cjs} +17 -12
- package/dist/tsup/chunk-PSCDCEXM.cjs.map +1 -0
- package/dist/tsup/{chunk-PVKV2O2E.js → chunk-QRFXXTLG.js} +96 -43
- package/dist/tsup/chunk-QRFXXTLG.js.map +1 -0
- package/dist/tsup/{chunk-RM2V2IRK.js → chunk-R2S45MO6.js} +14 -9
- package/dist/tsup/chunk-R2S45MO6.js.map +1 -0
- package/dist/tsup/{chunk-QGUQB3NC.cjs → chunk-SIWYIRXP.cjs} +7 -6
- package/dist/tsup/chunk-SIWYIRXP.cjs.map +1 -0
- package/dist/tsup/{chunk-E77RVI3P.js → chunk-VJRXZPTT.js} +601 -264
- package/dist/tsup/chunk-VJRXZPTT.js.map +1 -0
- package/dist/tsup/{chunk-KDNB2BQX.cjs → chunk-VZMXAZKC.cjs} +229 -206
- package/dist/tsup/chunk-VZMXAZKC.cjs.map +1 -0
- package/dist/tsup/{chunk-TPJNKVFB.cjs → chunk-YKVTF7MP.cjs} +7 -7
- package/dist/tsup/{chunk-TPJNKVFB.cjs.map → chunk-YKVTF7MP.cjs.map} +1 -1
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +2 -2
- package/dist/tsup/client/mod.d.ts +2 -2
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{conn-ChAuuTr0.d.cts → conn-Cc9WHuN4.d.cts} +196 -185
- package/dist/tsup/{conn-CjUkMEcm.d.ts → conn-DfPG71FA.d.ts} +196 -185
- package/dist/tsup/driver-helpers/mod.cjs +7 -5
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
- package/dist/tsup/driver-helpers/mod.d.cts +4 -2
- package/dist/tsup/driver-helpers/mod.d.ts +4 -2
- package/dist/tsup/driver-helpers/mod.js +9 -7
- package/dist/tsup/driver-test-suite/mod.cjs +116 -102
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/driver-test-suite/mod.d.cts +3 -2
- package/dist/tsup/driver-test-suite/mod.d.ts +3 -2
- package/dist/tsup/driver-test-suite/mod.js +61 -47
- package/dist/tsup/driver-test-suite/mod.js.map +1 -1
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.d.cts +6 -6
- package/dist/tsup/inspector/mod.d.ts +6 -6
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/mod.cjs +10 -10
- package/dist/tsup/mod.d.cts +8 -39
- package/dist/tsup/mod.d.ts +8 -39
- package/dist/tsup/mod.js +9 -9
- package/dist/tsup/test/mod.cjs +11 -11
- package/dist/tsup/test/mod.d.cts +1 -1
- package/dist/tsup/test/mod.d.ts +1 -1
- package/dist/tsup/test/mod.js +10 -10
- package/dist/tsup/utils.cjs +2 -2
- package/dist/tsup/utils.d.cts +2 -1
- package/dist/tsup/utils.d.ts +2 -1
- package/dist/tsup/utils.js +1 -1
- package/package.json +4 -5
- package/src/actor/driver.ts +2 -2
- package/src/actor/instance.ts +4 -4
- package/src/actor/protocol/serde.ts +75 -3
- package/src/actor/router-endpoints.ts +6 -6
- package/src/actor/router.ts +2 -2
- package/src/client/actor-conn.ts +24 -3
- package/src/client/config.ts +18 -25
- package/src/driver-helpers/mod.ts +5 -1
- package/src/driver-test-suite/mod.ts +65 -43
- package/src/driver-test-suite/utils.ts +4 -1
- package/src/drivers/default.ts +11 -9
- package/src/drivers/engine/actor-driver.ts +40 -39
- package/src/drivers/engine/config.ts +9 -22
- package/src/drivers/engine/mod.ts +9 -8
- package/src/drivers/file-system/global-state.ts +4 -4
- package/src/engine-process/log.ts +5 -0
- package/src/engine-process/mod.ts +316 -0
- package/src/inspector/utils.ts +6 -4
- package/src/manager/driver.ts +3 -3
- package/src/manager/gateway.ts +29 -11
- package/src/manager/router-schema.ts +20 -0
- package/src/manager/router.ts +139 -58
- package/src/registry/mod.ts +146 -120
- package/src/registry/run-config.ts +116 -47
- package/src/registry/serve.ts +3 -1
- package/src/remote-manager-driver/mod.ts +3 -2
- package/src/serde.ts +18 -3
- package/src/test/config.ts +2 -2
- package/src/test/mod.ts +6 -3
- package/src/utils.ts +2 -0
- package/dist/tsup/chunk-3WRAGTDC.cjs.map +0 -1
- package/dist/tsup/chunk-6INXQCH7.cjs.map +0 -1
- package/dist/tsup/chunk-A6TV3QU6.js.map +0 -1
- package/dist/tsup/chunk-CKSA7NOS.cjs.map +0 -1
- package/dist/tsup/chunk-DQVVH5ZK.cjs.map +0 -1
- package/dist/tsup/chunk-E77RVI3P.js.map +0 -1
- package/dist/tsup/chunk-FGOZELKN.cjs.map +0 -1
- package/dist/tsup/chunk-KDNB2BQX.cjs.map +0 -1
- package/dist/tsup/chunk-N7OVEOMU.js.map +0 -1
- package/dist/tsup/chunk-QGUQB3NC.cjs.map +0 -1
- package/dist/tsup/chunk-RM2V2IRK.js.map +0 -1
- package/dist/tsup/chunk-S6EAEZQA.js.map +0 -1
- package/dist/tsup/chunk-WP7YG7S5.js.map +0 -1
- /package/dist/tsup/{chunk-2FAWAPRT.js.map → chunk-346X2XU4.js.map} +0 -0
- /package/dist/tsup/{chunk-SFRRXLRM.js.map → chunk-7E5K3375.js.map} +0 -0
- /package/dist/tsup/{chunk-DOZBWJRI.js.map → chunk-KGDZYQYE.js.map} +0 -0
- /package/dist/tsup/{chunk-3ZMJUIL3.js.map → chunk-N3A5GYJU.js.map} +0 -0
package/src/registry/mod.ts
CHANGED
|
@@ -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
|
|
22
|
-
type
|
|
23
|
-
|
|
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?:
|
|
49
|
-
const config =
|
|
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
|
-
//
|
|
110
|
+
// Set defaults based on the driver
|
|
65
111
|
if (driver.name === "engine") {
|
|
66
112
|
config.inspector.enabled = { manager: false, actor: true };
|
|
67
|
-
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
122
|
-
this.#config,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
195
|
+
driver,
|
|
196
|
+
client,
|
|
134
197
|
);
|
|
135
198
|
|
|
136
199
|
// Start server
|
|
137
|
-
if (!config.
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
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 (
|
|
173
|
-
|
|
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
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
//
|
|
186
|
-
const
|
|
249
|
+
// Make the request to configure the serverless runner
|
|
250
|
+
const configUrl = `${config.endpoint}/runner-configs/${config.runnerName}?namespace=${config.namespace}`;
|
|
187
251
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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>;
|
package/src/registry/serve.ts
CHANGED
|
@@ -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 =
|
|
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)
|
|
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)
|
|
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
|
|
81
|
+
return jsonParseCompat(buffer);
|
|
67
82
|
} else {
|
|
68
83
|
const decoder = new TextDecoder("utf-8");
|
|
69
84
|
const jsonString = decoder.decode(buffer);
|
|
70
|
-
return
|
|
85
|
+
return jsonParseCompat(jsonString);
|
|
71
86
|
}
|
|
72
87
|
} else if (encoding === "cbor") {
|
|
73
88
|
invariant(
|
package/src/test/config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { RunnerConfigSchema } from "@/registry/run-config";
|
|
3
3
|
|
|
4
|
-
export const ConfigSchema =
|
|
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 {
|
|
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 =
|
|
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
|
-
|
|
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);
|