rivetkit 2.3.0-rc.9 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/client.d.ts +511 -62
- package/dist/browser/client.js +230 -174
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.js +53 -23
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/actor/errors.cjs +4 -2
- package/dist/tsup/actor/errors.cjs.map +1 -1
- package/dist/tsup/actor/errors.d.cts +1 -1
- package/dist/tsup/actor/errors.d.ts +1 -1
- package/dist/tsup/actor/errors.js +3 -1
- package/dist/tsup/agent-os/index.cjs +2163 -2087
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +509 -69
- package/dist/tsup/agent-os/index.d.ts +509 -69
- package/dist/tsup/agent-os/index.js +2163 -2087
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-WQ4HNA4W.cjs → chunk-3MHDOUD7.cjs} +73 -3
- package/dist/tsup/chunk-3MHDOUD7.cjs.map +1 -0
- package/dist/tsup/{chunk-QAZLM4WT.cjs → chunk-4FC7TVS6.cjs} +8 -4
- package/dist/tsup/chunk-4FC7TVS6.cjs.map +1 -0
- package/dist/tsup/{chunk-4CGA6QJO.cjs → chunk-4UUEB43Y.cjs} +24 -9
- package/dist/tsup/chunk-4UUEB43Y.cjs.map +1 -0
- package/dist/tsup/{chunk-GVTOE34S.cjs → chunk-5IWLUJ6W.cjs} +222 -235
- package/dist/tsup/chunk-5IWLUJ6W.cjs.map +1 -0
- package/dist/tsup/{chunk-MMMEZM5J.js → chunk-H6VVZMWN.js} +4 -4
- package/dist/tsup/chunk-H6VVZMWN.js.map +1 -0
- package/dist/tsup/{chunk-3YY5S6TV.js → chunk-HXUEHHJF.js} +2 -2
- package/dist/tsup/chunk-HXUEHHJF.js.map +1 -0
- package/dist/tsup/{chunk-H7P7WR2Y.js → chunk-I35VSLEM.js} +6 -6
- package/dist/tsup/chunk-I35VSLEM.js.map +1 -0
- package/dist/tsup/{chunk-H37XQU3I.js → chunk-JBUZRPY5.js} +2 -2
- package/dist/tsup/{chunk-CPA4Y3RG.cjs → chunk-JLJJZYCJ.cjs} +10 -10
- package/dist/tsup/chunk-JLJJZYCJ.cjs.map +1 -0
- package/dist/tsup/{chunk-PCBNKI2J.js → chunk-JZ7TWV65.js} +1 -1
- package/dist/tsup/chunk-JZ7TWV65.js.map +1 -0
- package/dist/tsup/{chunk-VRCIXJRN.js → chunk-L2X3YFER.js} +64 -10
- package/dist/tsup/chunk-L2X3YFER.js.map +1 -0
- package/dist/tsup/{chunk-Y5NSCZA2.cjs → chunk-MNHKOS6L.cjs} +72 -18
- package/dist/tsup/chunk-MNHKOS6L.cjs.map +1 -0
- package/dist/tsup/{chunk-KJTA3ATT.js → chunk-NERUIBOT.js} +22 -7
- package/dist/tsup/chunk-NERUIBOT.js.map +1 -0
- package/dist/tsup/{chunk-4WPEZBK4.cjs → chunk-OST76LRW.cjs} +10 -10
- package/dist/tsup/chunk-OST76LRW.cjs.map +1 -0
- package/dist/tsup/{chunk-MALSPBAF.cjs → chunk-OZBCXBVP.cjs} +3 -3
- package/dist/tsup/{chunk-MALSPBAF.cjs.map → chunk-OZBCXBVP.cjs.map} +1 -1
- package/dist/tsup/{chunk-F3Q5BFQ6.js → chunk-PT6OIW5E.js} +66 -79
- package/dist/tsup/chunk-PT6OIW5E.js.map +1 -0
- package/dist/tsup/{chunk-W7EYSYVI.js → chunk-R6KPN5EW.js} +134 -20
- package/dist/tsup/chunk-R6KPN5EW.js.map +1 -0
- package/dist/tsup/{chunk-VJFRBJVQ.cjs → chunk-V5KMAMX3.cjs} +138 -24
- package/dist/tsup/chunk-V5KMAMX3.cjs.map +1 -0
- package/dist/tsup/{chunk-LD5YASJU.cjs → chunk-VE2X4KMG.cjs} +2 -2
- package/dist/tsup/{chunk-LD5YASJU.cjs.map → chunk-VE2X4KMG.cjs.map} +1 -1
- package/dist/tsup/{chunk-T6YVRM4K.js → chunk-XIX5DOZN.js} +72 -2
- package/dist/tsup/chunk-XIX5DOZN.js.map +1 -0
- package/dist/tsup/{chunk-2NDZ7JCR.cjs → chunk-ZA7FLHKH.cjs} +1 -1
- package/dist/tsup/chunk-ZA7FLHKH.cjs.map +1 -0
- package/dist/tsup/{chunk-KIWH5H3K.js → chunk-ZZ3WBRPD.js} +7 -3
- package/dist/tsup/chunk-ZZ3WBRPD.js.map +1 -0
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +5 -5
- package/dist/tsup/client/mod.d.ts +5 -5
- 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/{config-Ca8dN4cS.d.cts → config-CzvopP5m.d.cts} +544 -23
- package/dist/tsup/{config-CxjGYf4K.d.cts → config-D49x8NpL.d.cts} +1 -2
- package/dist/tsup/{config-CxjGYf4K.d.ts → config-D49x8NpL.d.ts} +1 -2
- package/dist/tsup/{config-0Ta55UV0.d.ts → config-DZuT7tcp.d.ts} +544 -23
- package/dist/tsup/context-CyAdY-aA.d.ts +128 -0
- package/dist/tsup/context-sNB28g0N.d.cts +128 -0
- package/dist/tsup/db/drizzle.cjs +3 -3
- package/dist/tsup/db/drizzle.d.cts +1 -1
- package/dist/tsup/db/drizzle.d.ts +1 -1
- package/dist/tsup/db/drizzle.js +1 -1
- package/dist/tsup/db/mod.cjs +2 -2
- package/dist/tsup/db/mod.d.cts +2 -2
- package/dist/tsup/db/mod.d.ts +2 -2
- package/dist/tsup/db/mod.js +1 -1
- package/dist/tsup/dynamic/mod.cjs +24 -0
- package/dist/tsup/dynamic/mod.cjs.map +1 -0
- package/dist/tsup/dynamic/mod.d.cts +37 -0
- package/dist/tsup/dynamic/mod.d.ts +37 -0
- package/dist/tsup/dynamic/mod.js +24 -0
- package/dist/tsup/dynamic/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/inspector-tab/mod.cjs +173 -0
- package/dist/tsup/inspector-tab/mod.cjs.map +1 -0
- package/dist/tsup/inspector-tab/mod.d.cts +250 -0
- package/dist/tsup/inspector-tab/mod.d.ts +250 -0
- package/dist/tsup/inspector-tab/mod.js +173 -0
- package/dist/tsup/inspector-tab/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +758 -348
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +5 -5
- package/dist/tsup/mod.d.ts +5 -5
- package/dist/tsup/mod.js +662 -252
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +21 -18
- package/dist/tsup/test/mod.cjs.map +1 -1
- package/dist/tsup/test/mod.d.cts +4 -4
- package/dist/tsup/test/mod.d.ts +4 -4
- package/dist/tsup/test/mod.js +18 -15
- package/dist/tsup/test/mod.js.map +1 -1
- package/dist/tsup/{utils-DVekpm4I.d.cts → utils-CqDnC_PS.d.cts} +2 -1
- package/dist/tsup/{utils-DVekpm4I.d.ts → utils-CqDnC_PS.d.ts} +2 -1
- package/dist/tsup/utils.cjs +3 -3
- package/dist/tsup/utils.d.cts +1 -1
- package/dist/tsup/utils.d.ts +1 -1
- package/dist/tsup/utils.js +2 -2
- package/dist/tsup/workflow/mod.cjs +383 -322
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +8 -8
- package/dist/tsup/workflow/mod.d.ts +8 -8
- package/dist/tsup/workflow/mod.js +360 -299
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +35 -14
- package/src/actor/config.ts +173 -51
- package/src/actor/contexts/index.ts +7 -2
- package/src/actor/definition.ts +17 -19
- package/src/actor/driver.ts +3 -3
- package/src/actor/errors.ts +20 -3
- package/src/actor/instance/mod.ts +26 -34
- package/src/actor/keys.ts +1 -1
- package/src/actor/mod.ts +22 -20
- package/src/actor/schema.ts +2 -2
- package/src/agent-os/actor/index.ts +38 -18
- package/src/agent-os/actor/preview.ts +1 -2
- package/src/agent-os/actor/session.ts +2 -2
- package/src/agent-os/config.ts +1 -1
- package/src/agent-os/fs/database-vfs.ts +1 -1
- package/src/agent-os/index.ts +16 -15
- package/src/client/actor-common.ts +87 -54
- package/src/client/actor-conn.ts +8 -36
- package/src/client/actor-handle.ts +69 -51
- package/src/client/actor-query.ts +5 -5
- package/src/client/errors.ts +1 -1
- package/src/client/lifecycle-errors.ts +2 -4
- package/src/client/query.ts +1 -1
- package/src/client/queue.ts +8 -3
- package/src/client/raw-utils.ts +8 -6
- package/src/client/resolve-gateway-target.ts +1 -1
- package/src/client/utils.ts +2 -7
- package/src/common/actor-websocket.ts +3 -1
- package/src/common/bare/actor-persist/v1.ts +205 -163
- package/src/common/bare/actor-persist/v2.ts +265 -213
- package/src/common/bare/actor-persist/v3.ts +176 -172
- package/src/common/bare/actor-persist/v4.ts +254 -253
- package/src/common/bare/transport/v1.ts +659 -543
- package/src/common/client-protocol-versioned.ts +66 -64
- package/src/common/database/config.ts +2 -8
- package/src/common/database/native-database.ts +1 -1
- package/src/common/database/shared.ts +1 -0
- package/src/common/encoding.ts +250 -16
- package/src/common/engine.ts +28 -1
- package/src/common/eventsource.ts +1 -1
- package/src/common/inline-websocket-adapter.ts +14 -13
- package/src/common/log.ts +1 -0
- package/src/common/router.ts +13 -17
- package/src/common/utils.ts +1 -150
- package/src/common/websocket-interface.ts +1 -1
- package/src/db/mod.ts +1 -1
- package/src/devtools-loader/index.ts +4 -7
- package/src/devtools-loader/serve-devtools.ts +26 -0
- package/src/drivers/engine/actor-driver.ts +58 -56
- package/src/dynamic/instance.ts +32 -0
- package/src/dynamic/internal.ts +50 -0
- package/src/dynamic/isolate-runtime.ts +66 -0
- package/src/dynamic/mod.ts +32 -0
- package/src/engine-client/actor-http-client.ts +3 -3
- package/src/engine-client/actor-websocket-client.ts +6 -5
- package/src/engine-client/api-endpoints.ts +51 -2
- package/src/engine-client/api-utils.ts +2 -2
- package/src/engine-client/driver.ts +1 -1
- package/src/engine-client/mod.ts +6 -3
- package/src/engine-client/ws-proxy.ts +9 -4
- package/src/inspector/client.browser.ts +5 -11
- package/src/inspector/mod.ts +1 -3
- package/src/inspector-tab/mod.ts +315 -0
- package/src/registry/config/envoy.ts +1 -2
- package/src/registry/config/index.ts +40 -16
- package/src/registry/index.ts +209 -73
- package/src/registry/napi-runtime.ts +29 -2
- package/src/registry/native-validation.ts +10 -12
- package/src/registry/native.ts +433 -198
- package/src/registry/process-metrics.ts +250 -0
- package/src/registry/runtime.ts +52 -1
- package/src/registry/wasm-runtime.ts +29 -2
- package/src/registry/write-through-proxy.ts +40 -0
- package/src/serde.ts +2 -2
- package/src/serverless/configure.ts +18 -7
- package/src/test/mod.ts +11 -8
- package/src/utils/endpoint-parser.ts +1 -1
- package/src/utils/env-vars.ts +37 -0
- package/src/utils/router.ts +1 -1
- package/src/utils.ts +1 -2
- package/src/workflow/context.ts +699 -240
- package/src/workflow/driver.ts +23 -12
- package/src/workflow/inspector.ts +4 -3
- package/src/workflow/mod.ts +37 -23
- package/dist/tsup/chunk-2NDZ7JCR.cjs.map +0 -1
- package/dist/tsup/chunk-3YY5S6TV.js.map +0 -1
- package/dist/tsup/chunk-4CGA6QJO.cjs.map +0 -1
- package/dist/tsup/chunk-4WPEZBK4.cjs.map +0 -1
- package/dist/tsup/chunk-CPA4Y3RG.cjs.map +0 -1
- package/dist/tsup/chunk-F3Q5BFQ6.js.map +0 -1
- package/dist/tsup/chunk-GVTOE34S.cjs.map +0 -1
- package/dist/tsup/chunk-H7P7WR2Y.js.map +0 -1
- package/dist/tsup/chunk-KIWH5H3K.js.map +0 -1
- package/dist/tsup/chunk-KJTA3ATT.js.map +0 -1
- package/dist/tsup/chunk-MMMEZM5J.js.map +0 -1
- package/dist/tsup/chunk-PCBNKI2J.js.map +0 -1
- package/dist/tsup/chunk-QAZLM4WT.cjs.map +0 -1
- package/dist/tsup/chunk-T6YVRM4K.js.map +0 -1
- package/dist/tsup/chunk-VJFRBJVQ.cjs.map +0 -1
- package/dist/tsup/chunk-VRCIXJRN.js.map +0 -1
- package/dist/tsup/chunk-W7EYSYVI.js.map +0 -1
- package/dist/tsup/chunk-WQ4HNA4W.cjs.map +0 -1
- package/dist/tsup/chunk-Y5NSCZA2.cjs.map +0 -1
- package/dist/tsup/context-B_IWbWne.d.ts +0 -92
- package/dist/tsup/context-CUrQ9MHc.d.cts +0 -92
- package/src/utils/serve.ts +0 -217
- /package/dist/tsup/{chunk-H37XQU3I.js.map → chunk-JBUZRPY5.js.map} +0 -0
package/src/registry/index.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isLocalEngineEndpoint } from "@/common/engine";
|
|
2
2
|
import { configureServerlessPool } from "@/serverless/configure";
|
|
3
3
|
import { VERSION } from "@/utils";
|
|
4
|
+
import {
|
|
5
|
+
getRivetkitPublicDir,
|
|
6
|
+
getRivetkitRuntimeMode,
|
|
7
|
+
parsePortEnv,
|
|
8
|
+
} from "@/utils/env-vars";
|
|
4
9
|
import {
|
|
5
10
|
type RegistryActors,
|
|
6
11
|
type RegistryConfig,
|
|
@@ -44,8 +49,18 @@ export interface RegistryRoutes {
|
|
|
44
49
|
prometheusMetrics(request?: Request): Promise<Response>;
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Injectable dependencies for {@link Registry}. Production code uses the
|
|
54
|
+
* defaults. Tests override `buildConfiguredRegistry` to drive lifecycle
|
|
55
|
+
* orchestration against a fake `CoreRuntime` without an engine.
|
|
56
|
+
*/
|
|
57
|
+
export interface RegistryDeps {
|
|
58
|
+
buildConfiguredRegistry: typeof buildConfiguredRegistry;
|
|
59
|
+
}
|
|
60
|
+
|
|
47
61
|
export class Registry<A extends RegistryActors> {
|
|
48
62
|
#config: RegistryConfigInput<A>;
|
|
63
|
+
#buildConfiguredRegistry: typeof buildConfiguredRegistry;
|
|
49
64
|
public readonly routes: RegistryRoutes;
|
|
50
65
|
|
|
51
66
|
get config(): RegistryConfigInput<A> {
|
|
@@ -65,8 +80,10 @@ export class Registry<A extends RegistryActors> {
|
|
|
65
80
|
#shutdownInFlight: Promise<void> | null = null;
|
|
66
81
|
#signalHandlers: Partial<Record<ShutdownSignal, () => void>> = {};
|
|
67
82
|
|
|
68
|
-
constructor(config: RegistryConfigInput<A>) {
|
|
83
|
+
constructor(config: RegistryConfigInput<A>, deps?: Partial<RegistryDeps>) {
|
|
69
84
|
this.#config = config;
|
|
85
|
+
this.#buildConfiguredRegistry =
|
|
86
|
+
deps?.buildConfiguredRegistry ?? buildConfiguredRegistry;
|
|
70
87
|
this.routes = {
|
|
71
88
|
health: () => this.#healthRoute(),
|
|
72
89
|
metadata: () => this.#metadataRoute(),
|
|
@@ -75,16 +92,24 @@ export class Registry<A extends RegistryActors> {
|
|
|
75
92
|
};
|
|
76
93
|
}
|
|
77
94
|
|
|
78
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Fires `configureServerlessPool` once per process when the registry
|
|
97
|
+
* config opts into it. Cached on the instance so repeated calls (from
|
|
98
|
+
* `handler()` and `listen()`) only run the upsert once. The retry loop
|
|
99
|
+
* inside `configureServerlessPool` tolerates the engine still warming up.
|
|
100
|
+
*/
|
|
101
|
+
#ensureServerlessPoolConfigured(
|
|
102
|
+
config: RegistryConfig,
|
|
103
|
+
): Promise<void> | undefined {
|
|
79
104
|
if (!config.configurePool) return undefined;
|
|
80
105
|
|
|
81
106
|
if (!this.#configureServerlessPoolPromise) {
|
|
82
|
-
this.#configureServerlessPoolPromise = configureServerlessPool(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
);
|
|
107
|
+
this.#configureServerlessPoolPromise = configureServerlessPool(
|
|
108
|
+
config,
|
|
109
|
+
).catch((error) => {
|
|
110
|
+
this.#configureServerlessPoolPromise = undefined;
|
|
111
|
+
throw error;
|
|
112
|
+
});
|
|
88
113
|
this.#configureServerlessPoolPromise.catch(() => {});
|
|
89
114
|
}
|
|
90
115
|
|
|
@@ -106,7 +131,8 @@ export class Registry<A extends RegistryActors> {
|
|
|
106
131
|
this.#printWelcome(config, "serverless");
|
|
107
132
|
|
|
108
133
|
if (!this.#runtimeServerlessPromise) {
|
|
109
|
-
this.#runtimeServerlessPromise =
|
|
134
|
+
this.#runtimeServerlessPromise =
|
|
135
|
+
this.#buildConfiguredRegistry(config);
|
|
110
136
|
}
|
|
111
137
|
|
|
112
138
|
const { runtime, registry, serveConfig } =
|
|
@@ -120,12 +146,13 @@ export class Registry<A extends RegistryActors> {
|
|
|
120
146
|
serveConfig.serverlessBasePath ?? "/api/rivet",
|
|
121
147
|
);
|
|
122
148
|
const isEngineMetadataRequest =
|
|
123
|
-
request.headers.get("user-agent")?.startsWith("RivetEngine/") ??
|
|
149
|
+
request.headers.get("user-agent")?.startsWith("RivetEngine/") ??
|
|
150
|
+
false;
|
|
124
151
|
|
|
125
152
|
if (isStartRequest) {
|
|
126
153
|
try {
|
|
127
154
|
await this.#ensureServerlessPoolConfigured(config);
|
|
128
|
-
} catch (
|
|
155
|
+
} catch (_error) {
|
|
129
156
|
return new Response(
|
|
130
157
|
JSON.stringify({
|
|
131
158
|
group: "guard",
|
|
@@ -267,7 +294,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
267
294
|
if (isMetadataRequest && !isEngineMetadataRequest) {
|
|
268
295
|
try {
|
|
269
296
|
await this.#ensureServerlessPoolConfigured(config);
|
|
270
|
-
} catch (
|
|
297
|
+
} catch (_error) {
|
|
271
298
|
return new Response(
|
|
272
299
|
JSON.stringify({
|
|
273
300
|
group: "guard",
|
|
@@ -303,6 +330,54 @@ export class Registry<A extends RegistryActors> {
|
|
|
303
330
|
};
|
|
304
331
|
}
|
|
305
332
|
|
|
333
|
+
/**
|
|
334
|
+
* Bind an HTTP listener provided by the native (Rust) runtime and serve
|
|
335
|
+
* the registry's serverless endpoints over it. Resolves only after the
|
|
336
|
+
* registry is shut down (SIGINT/SIGTERM or `nativeRegistry.shutdown()`).
|
|
337
|
+
*
|
|
338
|
+
* @param opts.port Port to listen on. Defaults to `process.env.RIVET_PORT`
|
|
339
|
+
* if set, otherwise 3000.
|
|
340
|
+
* @param opts.host Address to bind. Defaults to `0.0.0.0`.
|
|
341
|
+
* @param opts.publicDir If set, serves static files from this directory
|
|
342
|
+
* as a fallback below the framework routes.
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* await registry.listen();
|
|
347
|
+
* await registry.listen({ port: 8080, publicDir: "./public" });
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
public async listen(
|
|
351
|
+
opts: { port?: number; host?: string; publicDir?: string } = {},
|
|
352
|
+
): Promise<void> {
|
|
353
|
+
const port = opts.port ?? parsePortEnv(process.env.RIVET_PORT) ?? 3000;
|
|
354
|
+
const publicDir = opts.publicDir ?? getRivetkitPublicDir();
|
|
355
|
+
const config = this.parseConfig();
|
|
356
|
+
|
|
357
|
+
// Cache on both promise fields so the shutdown drain sees Mode A and B.
|
|
358
|
+
const configuredRegistryPromise = buildConfiguredRegistry(config);
|
|
359
|
+
this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
|
|
360
|
+
this.#runtimeServerlessPromise = configuredRegistryPromise;
|
|
361
|
+
this.#installSignalHandlers(config);
|
|
362
|
+
|
|
363
|
+
this.#printWelcome(config, "serverless", {
|
|
364
|
+
port,
|
|
365
|
+
host: opts.host,
|
|
366
|
+
publicDir,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// Background fire; the retry loop tolerates engine warm-up.
|
|
370
|
+
this.#ensureServerlessPoolConfigured(config);
|
|
371
|
+
|
|
372
|
+
const { runtime, registry, serveConfig } =
|
|
373
|
+
await configuredRegistryPromise;
|
|
374
|
+
await runtime.serveListener(
|
|
375
|
+
registry,
|
|
376
|
+
{ port, host: opts.host, publicDir },
|
|
377
|
+
serveConfig,
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
306
381
|
/**
|
|
307
382
|
* Returns a health response suitable for mounting in a user-owned router.
|
|
308
383
|
*/
|
|
@@ -392,8 +467,11 @@ export class Registry<A extends RegistryActors> {
|
|
|
392
467
|
const candidates = [
|
|
393
468
|
this.#runtimeServerlessPromise,
|
|
394
469
|
this.#runtimeServeConfiguredPromise,
|
|
395
|
-
].filter(
|
|
396
|
-
|
|
470
|
+
].filter(
|
|
471
|
+
(
|
|
472
|
+
candidate,
|
|
473
|
+
): candidate is ReturnType<typeof buildConfiguredRegistry> =>
|
|
474
|
+
candidate !== undefined,
|
|
397
475
|
);
|
|
398
476
|
|
|
399
477
|
if (candidates.length === 0) return undefined;
|
|
@@ -405,35 +483,33 @@ export class Registry<A extends RegistryActors> {
|
|
|
405
483
|
*/
|
|
406
484
|
#startEnvoy(config: RegistryConfig, printWelcome: boolean) {
|
|
407
485
|
if (!this.#runtimeServePromise) {
|
|
408
|
-
const configuredRegistryPromise =
|
|
486
|
+
const configuredRegistryPromise =
|
|
487
|
+
this.#buildConfiguredRegistry(config);
|
|
409
488
|
this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
|
|
410
489
|
this.#runtimeServePromise = configuredRegistryPromise
|
|
411
490
|
.then(async ({ runtime, registry, serveConfig }) => {
|
|
412
491
|
await runtime.serveRegistry(registry, serveConfig);
|
|
413
492
|
})
|
|
414
|
-
.catch((
|
|
493
|
+
.catch((error) => {
|
|
415
494
|
// Always-attached catch so the stored promise never leaves a
|
|
416
495
|
// rejection unhandled. Downstream awaits (e.g. #runShutdown's
|
|
417
496
|
// Promise.race) attach their own catches and still observe
|
|
418
497
|
// resolution via the race.
|
|
419
|
-
logger().warn({
|
|
498
|
+
logger().warn({ error }, "runtime registry serve errored");
|
|
420
499
|
});
|
|
421
500
|
// Install signal handlers once an envoy lifecycle has begun. Only
|
|
422
501
|
// Mode A ever reaches here. Mode B (handler(request)) intentionally
|
|
423
502
|
// does not install handlers because it runs on Workers/Vercel/Deno
|
|
424
503
|
// Deploy where `process.on` is absent or forbidden; those platforms
|
|
425
504
|
// own their own signal policy.
|
|
426
|
-
this.#installSignalHandlers(config
|
|
505
|
+
this.#installSignalHandlers(config);
|
|
427
506
|
}
|
|
428
507
|
if (printWelcome) {
|
|
429
508
|
this.#printWelcome(config, "serverful");
|
|
430
509
|
}
|
|
431
510
|
}
|
|
432
511
|
|
|
433
|
-
#installSignalHandlers(
|
|
434
|
-
config: RegistryConfig,
|
|
435
|
-
configuredRegistryPromise: ReturnType<typeof buildConfiguredRegistry>,
|
|
436
|
-
): void {
|
|
512
|
+
#installSignalHandlers(config: RegistryConfig): void {
|
|
437
513
|
if (this.#shutdownInstalled) return;
|
|
438
514
|
if (config.shutdown?.disableSignalHandlers) return;
|
|
439
515
|
// Guard against non-Node runtimes (Workers/Edge) where `process` may
|
|
@@ -448,12 +524,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
448
524
|
this.#shutdownInstalled = true;
|
|
449
525
|
|
|
450
526
|
const install = (signal: ShutdownSignal) => {
|
|
451
|
-
const handler = () =>
|
|
452
|
-
this.#onShutdownSignal(
|
|
453
|
-
signal,
|
|
454
|
-
config,
|
|
455
|
-
configuredRegistryPromise,
|
|
456
|
-
);
|
|
527
|
+
const handler = () => this.#onShutdownSignal(signal, config);
|
|
457
528
|
this.#signalHandlers[signal] = handler;
|
|
458
529
|
process.on(signal, handler);
|
|
459
530
|
};
|
|
@@ -461,37 +532,67 @@ export class Registry<A extends RegistryActors> {
|
|
|
461
532
|
install("SIGTERM");
|
|
462
533
|
}
|
|
463
534
|
|
|
464
|
-
#onShutdownSignal(
|
|
465
|
-
signal: ShutdownSignal,
|
|
466
|
-
config: RegistryConfig,
|
|
467
|
-
configuredRegistryPromise: ReturnType<typeof buildConfiguredRegistry>,
|
|
468
|
-
): void {
|
|
535
|
+
#onShutdownSignal(signal: ShutdownSignal, config: RegistryConfig): void {
|
|
469
536
|
if (this.#shutdownInFlight !== null) {
|
|
470
|
-
// Second delivery of the same (or another) shutdown signal
|
|
471
|
-
//
|
|
472
|
-
//
|
|
537
|
+
// Second delivery of the same (or another) shutdown signal, or a
|
|
538
|
+
// drain already started by an explicit `shutdown()` call. Remove
|
|
539
|
+
// our handler only, preserving any user-installed listeners. PID 1
|
|
540
|
+
// must exit directly because re-raised default signals can be
|
|
473
541
|
// swallowed by the container signal path.
|
|
474
542
|
this.#removeSignalHandlers();
|
|
475
543
|
finishShutdownSignal(signal);
|
|
476
544
|
return;
|
|
477
545
|
}
|
|
478
|
-
this.#shutdownInFlight = this.#
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
546
|
+
this.#shutdownInFlight = this.#drain(config)
|
|
547
|
+
.catch((err) => {
|
|
548
|
+
logger().warn({ err }, "shutdown error");
|
|
549
|
+
})
|
|
550
|
+
.then(() => {
|
|
551
|
+
this.#removeSignalHandlers();
|
|
552
|
+
finishShutdownSignal(signal);
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Gracefully drains all live registries.
|
|
558
|
+
*
|
|
559
|
+
* Programmatic counterpart to the SIGINT/SIGTERM handlers: tears down
|
|
560
|
+
* every live `CoreRegistry` (both `start()` and `handler()` modes) and
|
|
561
|
+
* waits for the serve promise to resolve, all bounded by the shutdown
|
|
562
|
+
* grace period. Unlike a signal-driven shutdown, this does not re-raise a
|
|
563
|
+
* signal or exit the process. The caller owns process lifetime.
|
|
564
|
+
*
|
|
565
|
+
* Idempotent: concurrent or repeated calls share a single drain. Safe to
|
|
566
|
+
* call even if nothing has been started.
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* ```ts
|
|
570
|
+
* const registry = setup({ use: { counter } });
|
|
571
|
+
* registry.start();
|
|
572
|
+
* // ...later, on your own shutdown trigger:
|
|
573
|
+
* await registry.shutdown();
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
576
|
+
public async shutdown(): Promise<void> {
|
|
577
|
+
if (this.#shutdownInFlight !== null) return this.#shutdownInFlight;
|
|
578
|
+
const config = this.parseConfig();
|
|
579
|
+
// Uninstall our signal handlers so a later SIGINT/SIGTERM does not
|
|
580
|
+
// re-trigger a drain on already-torn-down registries. Subsequent
|
|
581
|
+
// signals fall back to Node's default termination behavior.
|
|
582
|
+
this.#removeSignalHandlers();
|
|
583
|
+
this.#shutdownInFlight = this.#drain(config).catch((err) => {
|
|
483
584
|
logger().warn({ err }, "shutdown error");
|
|
484
585
|
});
|
|
586
|
+
return this.#shutdownInFlight;
|
|
485
587
|
}
|
|
486
588
|
|
|
487
|
-
async #
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
): Promise<void> {
|
|
589
|
+
async #drain(config: RegistryConfig): Promise<void> {
|
|
590
|
+
const modeAPromise = this.#runtimeServeConfiguredPromise;
|
|
591
|
+
const modeBPromise = this.#runtimeServerlessPromise;
|
|
592
|
+
|
|
492
593
|
const gracePeriodMs =
|
|
493
594
|
config.shutdown?.gracePeriodMs ??
|
|
494
|
-
(await this.#actorStopThresholdMs(
|
|
595
|
+
(await this.#actorStopThresholdMs(modeAPromise ?? modeBPromise)) ??
|
|
495
596
|
30 * 60 * 1000;
|
|
496
597
|
// Race the entire drain sequence (both modes + serve promise) against
|
|
497
598
|
// a single grace ceiling. By default, this uses the engine-provided
|
|
@@ -499,33 +600,33 @@ export class Registry<A extends RegistryActors> {
|
|
|
499
600
|
const drain = async () => {
|
|
500
601
|
// Shut down every live `CoreRegistry` we know about. Mode A
|
|
501
602
|
// (`start()`) and Mode B (`handler()`) each build a separate
|
|
502
|
-
// runtime registry, so one
|
|
503
|
-
//
|
|
504
|
-
const registries: Promise<void>[] = [
|
|
505
|
-
|
|
506
|
-
try {
|
|
507
|
-
const { runtime, registry } =
|
|
508
|
-
await configuredRegistryPromise;
|
|
509
|
-
await runtime.shutdownRegistry(registry);
|
|
510
|
-
} catch (err) {
|
|
511
|
-
logger().warn(
|
|
512
|
-
{ err },
|
|
513
|
-
"runtime registry shutdown errored (mode A)",
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
})(),
|
|
517
|
-
];
|
|
518
|
-
const runtimeServerlessPromise = this.#runtimeServerlessPromise;
|
|
519
|
-
if (runtimeServerlessPromise !== undefined) {
|
|
603
|
+
// runtime registry, so one drain fans out to both to honor the
|
|
604
|
+
// spec invariant "single shutdown tears down both modes".
|
|
605
|
+
const registries: Promise<void>[] = [];
|
|
606
|
+
if (modeAPromise !== undefined) {
|
|
520
607
|
registries.push(
|
|
521
608
|
(async () => {
|
|
522
609
|
try {
|
|
523
|
-
const { runtime, registry } =
|
|
524
|
-
await runtimeServerlessPromise;
|
|
610
|
+
const { runtime, registry } = await modeAPromise;
|
|
525
611
|
await runtime.shutdownRegistry(registry);
|
|
526
612
|
} catch (err) {
|
|
527
613
|
logger().warn(
|
|
528
614
|
{ err },
|
|
615
|
+
"runtime registry shutdown errored (mode A)",
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
})(),
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
if (modeBPromise !== undefined) {
|
|
622
|
+
registries.push(
|
|
623
|
+
(async () => {
|
|
624
|
+
try {
|
|
625
|
+
const { runtime, registry } = await modeBPromise;
|
|
626
|
+
await runtime.shutdownRegistry(registry);
|
|
627
|
+
} catch (err) {
|
|
628
|
+
logger().warn(
|
|
629
|
+
{ error: err },
|
|
529
630
|
"runtime registry shutdown errored (mode B)",
|
|
530
631
|
);
|
|
531
632
|
}
|
|
@@ -548,13 +649,14 @@ export class Registry<A extends RegistryActors> {
|
|
|
548
649
|
setTimeout(resolve, gracePeriodMs).unref?.(),
|
|
549
650
|
),
|
|
550
651
|
]);
|
|
551
|
-
this.#removeSignalHandlers();
|
|
552
|
-
finishShutdownSignal(signal);
|
|
553
652
|
}
|
|
554
653
|
|
|
555
654
|
async #actorStopThresholdMs(
|
|
556
|
-
configuredRegistryPromise:
|
|
655
|
+
configuredRegistryPromise:
|
|
656
|
+
| ReturnType<typeof buildConfiguredRegistry>
|
|
657
|
+
| undefined,
|
|
557
658
|
): Promise<number | undefined> {
|
|
659
|
+
if (configuredRegistryPromise === undefined) return undefined;
|
|
558
660
|
try {
|
|
559
661
|
const { runtime, registry } = await configuredRegistryPromise;
|
|
560
662
|
const thresholdMs =
|
|
@@ -591,6 +693,10 @@ export class Registry<A extends RegistryActors> {
|
|
|
591
693
|
/**
|
|
592
694
|
* Starts the actor envoy for standalone server deployments.
|
|
593
695
|
*
|
|
696
|
+
* Set `RIVETKIT_RUNTIME_MODE=serverless` to instead bind an HTTP listener
|
|
697
|
+
* via `listen()` (Mode B). Mode A (envoy) and Mode B (listener) are
|
|
698
|
+
* mutually exclusive per registry instance.
|
|
699
|
+
*
|
|
594
700
|
* @example
|
|
595
701
|
* ```ts
|
|
596
702
|
* const registry = setup({ use: { counter } });
|
|
@@ -598,6 +704,21 @@ export class Registry<A extends RegistryActors> {
|
|
|
598
704
|
* ```
|
|
599
705
|
*/
|
|
600
706
|
public start() {
|
|
707
|
+
if (getRivetkitRuntimeMode() === "serverless") {
|
|
708
|
+
// start() defaults publicDir to "/public" unless overridden by env.
|
|
709
|
+
const publicDir = getRivetkitPublicDir() ?? "/public";
|
|
710
|
+
// Detached listener; bind failures are fatal so exit hard.
|
|
711
|
+
this.listen({ publicDir }).catch((error) => {
|
|
712
|
+
logger().error({ error }, "auto-listen failed; exiting");
|
|
713
|
+
if (
|
|
714
|
+
typeof process !== "undefined" &&
|
|
715
|
+
typeof process.exit === "function"
|
|
716
|
+
) {
|
|
717
|
+
process.exit(1);
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
601
722
|
const config = this.parseConfig();
|
|
602
723
|
this.#startEnvoy(config, true);
|
|
603
724
|
}
|
|
@@ -605,6 +726,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
605
726
|
#printWelcome(
|
|
606
727
|
config: RegistryConfig,
|
|
607
728
|
kind: "serverless" | "serverful",
|
|
729
|
+
listener?: { port: number; host?: string; publicDir?: string },
|
|
608
730
|
): void {
|
|
609
731
|
if (config.noWelcome || this.#welcomePrinted) return;
|
|
610
732
|
this.#welcomePrinted = true;
|
|
@@ -625,7 +747,9 @@ export class Registry<A extends RegistryActors> {
|
|
|
625
747
|
|
|
626
748
|
if (config.endpoint) {
|
|
627
749
|
const endpointType =
|
|
628
|
-
config.
|
|
750
|
+
config.startEngine || isLocalEngineEndpoint(config.endpoint)
|
|
751
|
+
? "local native"
|
|
752
|
+
: "remote";
|
|
629
753
|
logLine("Endpoint", `${config.endpoint} (${endpointType})`);
|
|
630
754
|
}
|
|
631
755
|
|
|
@@ -634,6 +758,15 @@ export class Registry<A extends RegistryActors> {
|
|
|
634
758
|
}
|
|
635
759
|
|
|
636
760
|
logLine("Actors", Object.keys(config.use).length.toString());
|
|
761
|
+
|
|
762
|
+
if (listener) {
|
|
763
|
+
const host = listener.host ?? "0.0.0.0";
|
|
764
|
+
logLine("Listening", `http://${host}:${listener.port}`);
|
|
765
|
+
if (listener.publicDir) {
|
|
766
|
+
logLine("Public Dir", listener.publicDir);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
637
770
|
console.log();
|
|
638
771
|
}
|
|
639
772
|
}
|
|
@@ -646,7 +779,10 @@ function isServerlessStartRequest(request: Request, basePath: string): boolean {
|
|
|
646
779
|
return parsed.pathname === `${normalizedBase}/start`;
|
|
647
780
|
}
|
|
648
781
|
|
|
649
|
-
function isServerlessMetadataRequest(
|
|
782
|
+
function isServerlessMetadataRequest(
|
|
783
|
+
request: Request,
|
|
784
|
+
basePath: string,
|
|
785
|
+
): boolean {
|
|
650
786
|
if (request.method !== "GET") return false;
|
|
651
787
|
const parsed = new URL(request.url);
|
|
652
788
|
const normalizedBase =
|
|
@@ -18,13 +18,14 @@ import type {
|
|
|
18
18
|
RuntimeHttpRequest,
|
|
19
19
|
RuntimeKvEntry,
|
|
20
20
|
RuntimeKvListOptions,
|
|
21
|
+
RuntimeListenerConfig,
|
|
21
22
|
RuntimeQueueEnqueueAndWaitOptions,
|
|
22
23
|
RuntimeQueueMessage,
|
|
23
24
|
RuntimeQueueNextBatchOptions,
|
|
24
25
|
RuntimeQueueTryNextBatchOptions,
|
|
25
26
|
RuntimeQueueWaitOptions,
|
|
26
|
-
RuntimeRequestSaveOpts,
|
|
27
27
|
RuntimeRegistryRouteResponse,
|
|
28
|
+
RuntimeRequestSaveOpts,
|
|
28
29
|
RuntimeServeConfig,
|
|
29
30
|
RuntimeServerlessRequest,
|
|
30
31
|
RuntimeServerlessResponseHead,
|
|
@@ -259,6 +260,21 @@ export class NapiCoreRuntime implements CoreRuntime {
|
|
|
259
260
|
);
|
|
260
261
|
}
|
|
261
262
|
|
|
263
|
+
async serveListener(
|
|
264
|
+
registry: RegistryHandle,
|
|
265
|
+
listener: RuntimeListenerConfig,
|
|
266
|
+
config: RuntimeServeConfig,
|
|
267
|
+
): Promise<void> {
|
|
268
|
+
await asNativeRegistry(registry).serveListener(
|
|
269
|
+
{
|
|
270
|
+
port: listener.port,
|
|
271
|
+
host: listener.host,
|
|
272
|
+
publicDir: listener.publicDir,
|
|
273
|
+
},
|
|
274
|
+
config,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
262
278
|
createActorFactory(
|
|
263
279
|
callbacks: object,
|
|
264
280
|
config?: RuntimeActorConfig | undefined | null,
|
|
@@ -452,6 +468,12 @@ export class NapiCoreRuntime implements CoreRuntime {
|
|
|
452
468
|
return await asNativeActorContext(ctx).waitForTrackedShutdownWork();
|
|
453
469
|
}
|
|
454
470
|
|
|
471
|
+
async actorWaitForTrackedShutdownWorkUnbounded(
|
|
472
|
+
ctx: ActorContextHandle,
|
|
473
|
+
): Promise<void> {
|
|
474
|
+
await asNativeActorContext(ctx).waitForTrackedShutdownWorkUnbounded();
|
|
475
|
+
}
|
|
476
|
+
|
|
455
477
|
actorKeepAwake(ctx: ActorContextHandle, promise: Promise<unknown>): void {
|
|
456
478
|
asNativeActorContext(ctx).keepAwake(promise);
|
|
457
479
|
}
|
|
@@ -677,10 +699,15 @@ export class NapiCoreRuntime implements CoreRuntime {
|
|
|
677
699
|
ctx: ActorContextHandle,
|
|
678
700
|
names: string[],
|
|
679
701
|
options?: RuntimeQueueWaitOptions | undefined | null,
|
|
702
|
+
signal?: CancellationTokenHandle | undefined | null,
|
|
680
703
|
): Promise<void> {
|
|
681
704
|
await asNativeActorContext(ctx)
|
|
682
705
|
.queue()
|
|
683
|
-
.waitForNamesAvailable(
|
|
706
|
+
.waitForNamesAvailable(
|
|
707
|
+
names,
|
|
708
|
+
options,
|
|
709
|
+
signal ? asNativeCancellationToken(signal) : signal,
|
|
710
|
+
);
|
|
684
711
|
}
|
|
685
712
|
|
|
686
713
|
async actorQueueEnqueueAndWait(
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { RivetError } from "@/actor/errors";
|
|
2
2
|
import {
|
|
3
|
+
type EventSchemaConfig,
|
|
3
4
|
isEventSchemaDefinition,
|
|
4
5
|
isQueueSchemaDefinition,
|
|
5
6
|
isStandardSchema,
|
|
6
|
-
validateSchemaSync,
|
|
7
|
-
type EventSchemaConfig,
|
|
8
7
|
type PrimitiveSchema,
|
|
9
8
|
type QueueSchemaConfig,
|
|
9
|
+
validateSchemaSync,
|
|
10
10
|
} from "@/actor/schema";
|
|
11
11
|
|
|
12
12
|
const CONN_PARAMS_KEY = "__conn_params__";
|
|
@@ -126,19 +126,17 @@ export function validateQueueComplete(
|
|
|
126
126
|
response,
|
|
127
127
|
);
|
|
128
128
|
if (!result.success) {
|
|
129
|
-
throw validationError(
|
|
129
|
+
throw validationError(
|
|
130
|
+
`queue \`${name}\` completion response`,
|
|
131
|
+
result.issues,
|
|
132
|
+
);
|
|
130
133
|
}
|
|
131
134
|
return result.data;
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
function validationError(target: string, issues: unknown[]): RivetError {
|
|
135
|
-
return new RivetError(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{
|
|
140
|
-
public: true,
|
|
141
|
-
metadata: { issues },
|
|
142
|
-
},
|
|
143
|
-
);
|
|
138
|
+
return new RivetError("actor", "validation_error", `Invalid ${target}`, {
|
|
139
|
+
public: true,
|
|
140
|
+
metadata: { issues },
|
|
141
|
+
});
|
|
144
142
|
}
|