rivetkit 0.0.0-codex-rivetkit-cli-preview.446d935 → 0.0.0-codex-docsrs-rivetkit-build.45929bf

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 (120) hide show
  1. package/dist/browser/client.d.ts +19 -6
  2. package/dist/browser/client.js +4 -4
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +4 -4
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/actor/errors.cjs +4 -2
  7. package/dist/tsup/actor/errors.cjs.map +1 -1
  8. package/dist/tsup/actor/errors.d.cts +1 -1
  9. package/dist/tsup/actor/errors.d.ts +1 -1
  10. package/dist/tsup/actor/errors.js +3 -1
  11. package/dist/tsup/agent-os/index.cjs +4 -4
  12. package/dist/tsup/agent-os/index.cjs.map +1 -1
  13. package/dist/tsup/agent-os/index.d.cts +18 -5
  14. package/dist/tsup/agent-os/index.d.ts +18 -5
  15. package/dist/tsup/agent-os/index.js +4 -4
  16. package/dist/tsup/agent-os/index.js.map +1 -1
  17. package/dist/tsup/{chunk-NIY3RSPX.cjs → chunk-3MHDOUD7.cjs} +11 -2
  18. package/dist/tsup/chunk-3MHDOUD7.cjs.map +1 -0
  19. package/dist/tsup/{chunk-KQYMWZWU.js → chunk-4CBCDH3Z.js} +5 -5
  20. package/dist/tsup/{chunk-KORQB2IR.cjs → chunk-4FC7TVS6.cjs} +6 -2
  21. package/dist/tsup/chunk-4FC7TVS6.cjs.map +1 -0
  22. package/dist/tsup/{chunk-7GDLY3M6.cjs → chunk-6BXIWI4D.cjs} +39 -14
  23. package/dist/tsup/chunk-6BXIWI4D.cjs.map +1 -0
  24. package/dist/tsup/{chunk-D3FW2226.cjs → chunk-B7RZGQNC.cjs} +5 -5
  25. package/dist/tsup/{chunk-D3FW2226.cjs.map → chunk-B7RZGQNC.cjs.map} +1 -1
  26. package/dist/tsup/{chunk-MKSZST76.cjs → chunk-BPZEWU2M.cjs} +7 -7
  27. package/dist/tsup/{chunk-MKSZST76.cjs.map → chunk-BPZEWU2M.cjs.map} +1 -1
  28. package/dist/tsup/{chunk-CW4W4YO5.js → chunk-DJ4RUPK4.js} +2 -2
  29. package/dist/tsup/{chunk-RRLIADAT.js → chunk-FK2P424N.js} +3 -3
  30. package/dist/tsup/{chunk-ENRPDJLK.js → chunk-G5HDCKP4.js} +31 -6
  31. package/dist/tsup/chunk-G5HDCKP4.js.map +1 -0
  32. package/dist/tsup/{chunk-VZFOURL6.cjs → chunk-HQ46VETO.cjs} +167 -167
  33. package/dist/tsup/{chunk-VZFOURL6.cjs.map → chunk-HQ46VETO.cjs.map} +1 -1
  34. package/dist/tsup/{chunk-YO2QBU3U.cjs → chunk-KDJO6HTM.cjs} +3 -3
  35. package/dist/tsup/{chunk-YO2QBU3U.cjs.map → chunk-KDJO6HTM.cjs.map} +1 -1
  36. package/dist/tsup/{chunk-QSNFXIGU.js → chunk-KY5BWMTK.js} +2 -2
  37. package/dist/tsup/{chunk-PO4HY4N4.cjs → chunk-RKFXYXAU.cjs} +4 -4
  38. package/dist/tsup/{chunk-PO4HY4N4.cjs.map → chunk-RKFXYXAU.cjs.map} +1 -1
  39. package/dist/tsup/{chunk-Q4H65EHF.cjs → chunk-VK5INEX2.cjs} +10 -10
  40. package/dist/tsup/{chunk-Q4H65EHF.cjs.map → chunk-VK5INEX2.cjs.map} +1 -1
  41. package/dist/tsup/{chunk-FDQCRMRV.js → chunk-WIHB6O7P.js} +4 -4
  42. package/dist/tsup/{chunk-DPIMKYNB.js → chunk-XIX5DOZN.js} +10 -1
  43. package/dist/tsup/chunk-XIX5DOZN.js.map +1 -0
  44. package/dist/tsup/{chunk-3KJ7TV3H.js → chunk-ZO4OHZGI.js} +2 -2
  45. package/dist/tsup/{chunk-BRP62GZC.js → chunk-ZZ3WBRPD.js} +5 -1
  46. package/dist/tsup/chunk-ZZ3WBRPD.js.map +1 -0
  47. package/dist/tsup/client/mod.cjs +7 -7
  48. package/dist/tsup/client/mod.d.cts +3 -3
  49. package/dist/tsup/client/mod.d.ts +3 -3
  50. package/dist/tsup/client/mod.js +6 -6
  51. package/dist/tsup/common/log.cjs +3 -3
  52. package/dist/tsup/common/log.js +2 -2
  53. package/dist/tsup/common/websocket.cjs +4 -4
  54. package/dist/tsup/common/websocket.js +3 -3
  55. package/dist/tsup/{config-CZQQ-mso.d.cts → config-CzvopP5m.d.cts} +22 -7
  56. package/dist/tsup/{config-BxWAw3iH.d.ts → config-DZuT7tcp.d.ts} +22 -7
  57. package/dist/tsup/context-CyAdY-aA.d.ts +128 -0
  58. package/dist/tsup/context-sNB28g0N.d.cts +128 -0
  59. package/dist/tsup/dynamic/mod.cjs +2 -2
  60. package/dist/tsup/dynamic/mod.d.cts +2 -2
  61. package/dist/tsup/dynamic/mod.d.ts +2 -2
  62. package/dist/tsup/dynamic/mod.js +1 -1
  63. package/dist/tsup/inspector/mod.cjs +6 -6
  64. package/dist/tsup/inspector/mod.js +5 -5
  65. package/dist/tsup/inspector-tab/mod.cjs +2 -2
  66. package/dist/tsup/inspector-tab/mod.cjs.map +1 -1
  67. package/dist/tsup/inspector-tab/mod.d.cts +3 -3
  68. package/dist/tsup/inspector-tab/mod.d.ts +3 -3
  69. package/dist/tsup/inspector-tab/mod.js +1 -1
  70. package/dist/tsup/inspector-tab/mod.js.map +1 -1
  71. package/dist/tsup/mod.cjs +299 -278
  72. package/dist/tsup/mod.cjs.map +1 -1
  73. package/dist/tsup/mod.d.cts +4 -4
  74. package/dist/tsup/mod.d.ts +4 -4
  75. package/dist/tsup/mod.js +210 -189
  76. package/dist/tsup/mod.js.map +1 -1
  77. package/dist/tsup/test/mod.cjs +10 -10
  78. package/dist/tsup/test/mod.d.cts +2 -2
  79. package/dist/tsup/test/mod.d.ts +2 -2
  80. package/dist/tsup/test/mod.js +6 -6
  81. package/dist/tsup/{utils-DQosb24I.d.cts → utils-CqDnC_PS.d.cts} +2 -1
  82. package/dist/tsup/{utils-DQosb24I.d.ts → utils-CqDnC_PS.d.ts} +2 -1
  83. package/dist/tsup/utils.cjs +3 -3
  84. package/dist/tsup/utils.d.cts +1 -1
  85. package/dist/tsup/utils.d.ts +1 -1
  86. package/dist/tsup/utils.js +2 -2
  87. package/dist/tsup/workflow/mod.cjs +184 -148
  88. package/dist/tsup/workflow/mod.cjs.map +1 -1
  89. package/dist/tsup/workflow/mod.d.cts +6 -6
  90. package/dist/tsup/workflow/mod.d.ts +6 -6
  91. package/dist/tsup/workflow/mod.js +177 -141
  92. package/dist/tsup/workflow/mod.js.map +1 -1
  93. package/package.json +11 -11
  94. package/src/actor/config.ts +14 -0
  95. package/src/actor/errors.ts +11 -0
  96. package/src/inspector-tab/mod.ts +1 -1
  97. package/src/registry/index.ts +74 -18
  98. package/src/registry/napi-runtime.ts +16 -0
  99. package/src/registry/native.ts +99 -33
  100. package/src/registry/runtime.ts +30 -3
  101. package/src/registry/wasm-runtime.ts +11 -0
  102. package/src/utils/env-vars.ts +31 -0
  103. package/src/workflow/context.ts +675 -244
  104. package/src/workflow/driver.ts +20 -7
  105. package/src/workflow/mod.ts +25 -9
  106. package/dist/tsup/chunk-7GDLY3M6.cjs.map +0 -1
  107. package/dist/tsup/chunk-BRP62GZC.js.map +0 -1
  108. package/dist/tsup/chunk-DPIMKYNB.js.map +0 -1
  109. package/dist/tsup/chunk-ENRPDJLK.js.map +0 -1
  110. package/dist/tsup/chunk-KORQB2IR.cjs.map +0 -1
  111. package/dist/tsup/chunk-NIY3RSPX.cjs.map +0 -1
  112. package/dist/tsup/context-Bw7xq8w3.d.cts +0 -92
  113. package/dist/tsup/context-D8QA76sV.d.ts +0 -92
  114. package/src/utils/serve.ts +0 -216
  115. /package/dist/tsup/{chunk-KQYMWZWU.js.map → chunk-4CBCDH3Z.js.map} +0 -0
  116. /package/dist/tsup/{chunk-CW4W4YO5.js.map → chunk-DJ4RUPK4.js.map} +0 -0
  117. /package/dist/tsup/{chunk-RRLIADAT.js.map → chunk-FK2P424N.js.map} +0 -0
  118. /package/dist/tsup/{chunk-QSNFXIGU.js.map → chunk-KY5BWMTK.js.map} +0 -0
  119. /package/dist/tsup/{chunk-FDQCRMRV.js.map → chunk-WIHB6O7P.js.map} +0 -0
  120. /package/dist/tsup/{chunk-3KJ7TV3H.js.map → chunk-ZO4OHZGI.js.map} +0 -0
@@ -2,6 +2,7 @@ import { VirtualWebSocket } from "@rivetkit/virtual-websocket";
2
2
  import {
3
3
  ACTOR_CONTEXT_INTERNAL_SYMBOL,
4
4
  CONN_STATE_MANAGER_SYMBOL,
5
+ disposeRunInspector,
5
6
  getRunFunction,
6
7
  getRunInspectorConfig,
7
8
  RAW_STATE_SYMBOL,
@@ -13,6 +14,7 @@ import {
13
14
  encodeBridgeRivetError,
14
15
  forbiddenError,
15
16
  INTERNAL_ERROR_CODE,
17
+ isActorAbortedError,
16
18
  isRivetErrorLike,
17
19
  RivetError,
18
20
  type RivetErrorLike,
@@ -51,6 +53,11 @@ import type {
51
53
  } from "@/registry/config";
52
54
  import { decodeCborCompat, encodeCborCompat } from "@/serde";
53
55
  import { getEnvUniversal, VERSION } from "@/utils";
56
+ import {
57
+ getNodeFsSync,
58
+ getNodePath,
59
+ importNodeDependencies,
60
+ } from "@/utils/node";
54
61
  import { logger } from "./log";
55
62
  import { loadNapiRuntime } from "./napi-runtime";
56
63
  import {
@@ -78,12 +85,11 @@ import type {
78
85
  WebSocketHandle,
79
86
  } from "./runtime";
80
87
  import { loadWasmRuntime } from "./wasm-runtime";
81
- import nodeFs from "node:fs";
82
- import nodePath from "node:path";
83
88
  import { createWriteThroughProxy } from "./write-through-proxy";
84
89
 
85
90
  const textEncoder = new TextEncoder();
86
91
  const textDecoder = new TextDecoder();
92
+
87
93
  type ResolvedRuntimeKind = Exclude<RuntimeKind, "auto">;
88
94
  type RuntimeHostKind = "node-like" | "edge-like";
89
95
  export type RuntimeLoaders = {
@@ -93,6 +99,7 @@ export type RuntimeLoaders = {
93
99
  ) => ReturnType<typeof loadWasmRuntime>;
94
100
  detectHost: () => RuntimeHostKind;
95
101
  };
102
+
96
103
  type SerializeStateReason = "save" | "inspector";
97
104
  type NativeOnStateChangeHandler = (
98
105
  ctx: ActorContextHandleAdapter,
@@ -1806,11 +1813,7 @@ class NativeQueueAdapter {
1806
1813
  }
1807
1814
  yield message;
1808
1815
  } catch (error) {
1809
- if (
1810
- isRivetErrorLike(error) &&
1811
- error.group === "actor" &&
1812
- error.code === "aborted"
1813
- ) {
1816
+ if (isActorAbortedError(error)) {
1814
1817
  return;
1815
1818
  }
1816
1819
  throw error;
@@ -2843,7 +2846,15 @@ export class ActorContextHandleAdapter {
2843
2846
 
2844
2847
  internalKeepAwake<T>(run: Promise<T> | (() => Promise<T>)): Promise<T> {
2845
2848
  const promise = typeof run === "function" ? run() : run;
2846
- const trackedPromise = promise.then(() => null);
2849
+ // Track only completion, swallowing the outcome. The real result/error
2850
+ // is delivered through the returned `promise`; without a rejection
2851
+ // handler here every workflow yield (which rejects with SleepError)
2852
+ // would be funneled into the registered task and logged as a spurious
2853
+ // "keep_awake promise rejected" warning.
2854
+ const trackedPromise = promise.then(
2855
+ () => null,
2856
+ () => null,
2857
+ );
2847
2858
  try {
2848
2859
  callNativeSync(() =>
2849
2860
  this.#runtime.actorRegisterTask(this.#ctx, trackedPromise),
@@ -3276,6 +3287,7 @@ function withConnContext(
3276
3287
  function buildActorConfig(
3277
3288
  definition: AnyActorDefinition,
3278
3289
  registryConfig: RegistryConfig,
3290
+ runtimeKind: "napi" | "wasm",
3279
3291
  ): RuntimeActorConfig {
3280
3292
  const config = definition.config as unknown as Record<string, unknown>;
3281
3293
  const options = (config.options ?? {}) as Record<string, unknown>;
@@ -3330,12 +3342,13 @@ function buildActorConfig(
3330
3342
  actions: Object.keys((config.actions ?? {}) as Record<string, unknown>)
3331
3343
  .sort()
3332
3344
  .map((name) => ({ name })),
3333
- inspectorTabs: buildInspectorTabs(config.inspector),
3345
+ inspectorTabs: buildInspectorTabs(config.inspector, runtimeKind),
3334
3346
  };
3335
3347
  }
3336
3348
 
3337
3349
  function buildInspectorTabs(
3338
3350
  inspector: unknown,
3351
+ runtimeKind: "napi" | "wasm",
3339
3352
  ): Array<RuntimeInspectorTabEntry> | undefined {
3340
3353
  if (!inspector || typeof inspector !== "object") return undefined;
3341
3354
  const tabs = (inspector as { tabs?: unknown }).tabs;
@@ -3351,12 +3364,28 @@ function buildInspectorTabs(
3351
3364
  if (entry.hidden === true) {
3352
3365
  return { id: entry.id, hidden: true };
3353
3366
  }
3354
- // Resolve the author's source path against the current working
3355
- // directory so the Rust runtime gets an absolute path. The author
3356
- // runs the actor process from their project root by convention.
3367
+
3368
+ if (runtimeKind === "wasm") {
3369
+ if (entry.source !== undefined) {
3370
+ logger().warn(
3371
+ {
3372
+ tabId: entry.id,
3373
+ runtimeKind,
3374
+ },
3375
+ "inspector.tabs[].source is not supported on wasm runners (current host: wasm). Tab descriptors will still appear in the dashboard strip but the tab body will render a not-available placeholder.",
3376
+ );
3377
+ }
3378
+ return {
3379
+ id: entry.id,
3380
+ label: entry.label,
3381
+ icon: entry.icon,
3382
+ source: undefined,
3383
+ };
3384
+ }
3385
+
3357
3386
  const resolved =
3358
3387
  entry.source !== undefined
3359
- ? nodePath.resolve(entry.source)
3388
+ ? getNodePath().resolve(entry.source)
3360
3389
  : undefined;
3361
3390
  if (resolved !== undefined) {
3362
3391
  validateInspectorTabSource(entry.id, resolved);
@@ -3371,11 +3400,7 @@ function buildInspectorTabs(
3371
3400
  }
3372
3401
 
3373
3402
  function validateInspectorTabSource(tabId: string, resolved: string): void {
3374
- // Catch obviously dangerous misconfigurations at registry construction
3375
- // rather than silently exposing the wrong subtree over the unauthenticated
3376
- // `/inspector/custom-tabs/<id>/*` route. Fail loudly so misconfigured
3377
- // actors never start.
3378
- if (resolved === nodePath.parse(resolved).root) {
3403
+ if (resolved === getNodePath().parse(resolved).root) {
3379
3404
  throw new Error(
3380
3405
  `inspector.tabs[id="${tabId}"].source resolves to the filesystem root (${resolved}). ` +
3381
3406
  "Point it at the tab's own static-asset directory instead.",
@@ -3383,7 +3408,7 @@ function validateInspectorTabSource(tabId: string, resolved: string): void {
3383
3408
  }
3384
3409
  let stat: import("node:fs").Stats;
3385
3410
  try {
3386
- stat = nodeFs.statSync(resolved);
3411
+ stat = getNodeFsSync().statSync(resolved);
3387
3412
  } catch (err) {
3388
3413
  const code = (err as NodeJS.ErrnoException)?.code;
3389
3414
  if (code === "ENOENT") {
@@ -3542,15 +3567,23 @@ export function buildNativeFactory(
3542
3567
  },
3543
3568
  );
3544
3569
  };
3545
- try {
3546
- await runtime.actorVerifyInspectorAuth(
3547
- ctx,
3548
- jsRequest.headers
3549
- .get("authorization")
3550
- ?.replace(/^Bearer\s+/i, "") ?? null,
3551
- );
3552
- } catch (error) {
3553
- return errorResponse(error, 401);
3570
+
3571
+ const isPublicPerActorPath =
3572
+ jsRequest.method === "GET" &&
3573
+ (url.pathname === "/inspector/tab-config" ||
3574
+ url.pathname.startsWith("/inspector/custom-tabs/"));
3575
+
3576
+ if (!isPublicPerActorPath) {
3577
+ try {
3578
+ await runtime.actorVerifyInspectorAuth(
3579
+ ctx,
3580
+ jsRequest.headers
3581
+ .get("authorization")
3582
+ ?.replace(/^Bearer\s+/i, "") ?? null,
3583
+ );
3584
+ } catch (error) {
3585
+ return errorResponse(error, 401);
3586
+ }
3554
3587
  }
3555
3588
 
3556
3589
  const workflowHistory = () =>
@@ -4115,6 +4148,11 @@ export function buildNativeFactory(
4115
4148
  await config.onDestroy(actorCtx);
4116
4149
  }
4117
4150
  } finally {
4151
+ const actorId = callNativeSync(() => runtime.actorId(ctx));
4152
+ // Release actorId-keyed state so it does not accumulate per
4153
+ // destroyed actor.
4154
+ nativeRunHandlerActiveByActorId.delete(actorId);
4155
+ disposeRunInspector(config.run, actorId);
4118
4156
  resolveNativeDestroy(runtime, ctx);
4119
4157
  await actorCtx.closeDatabase();
4120
4158
  clearNativeRuntimeState(runtime, ctx);
@@ -4518,7 +4556,11 @@ export function buildNativeFactory(
4518
4556
  try {
4519
4557
  await run(actorCtx);
4520
4558
  } finally {
4521
- nativeRunHandlerActiveByActorId.set(actorId, false);
4559
+ // Delete rather than set(false): an absent entry already
4560
+ // reads as inactive, and deleting keeps this map bounded
4561
+ // to currently-running handlers instead of accumulating an
4562
+ // entry per actor id forever.
4563
+ nativeRunHandlerActiveByActorId.delete(actorId);
4522
4564
  await actorCtx.dispose();
4523
4565
  }
4524
4566
  },
@@ -4729,7 +4771,7 @@ export function buildNativeFactory(
4729
4771
 
4730
4772
  return runtime.createActorFactory(
4731
4773
  callbacks,
4732
- buildActorConfig(definition, registryConfig),
4774
+ buildActorConfig(definition, registryConfig, runtime.kind),
4733
4775
  );
4734
4776
  }
4735
4777
 
@@ -4756,12 +4798,29 @@ export async function buildServeConfig(
4756
4798
  serverlessMaxStartPayloadBytes: config.serverless.maxStartPayloadBytes,
4757
4799
  };
4758
4800
 
4759
- if (config.startEngine) {
4801
+ // Always best-effort resolve the npm-installed engine binary and hand its
4802
+ // path to the core. The core alone decides whether to actually spawn a local
4803
+ // engine (its `should_manage_engine`, based on the endpoint + spawn mode), so
4804
+ // JS must not duplicate that decision here. Only JS knows the npm
4805
+ // `node_modules` layout, so it resolves the path; if no binary is available
4806
+ // (remote-only install, unsupported platform, optional deps skipped), leave
4807
+ // it unset and let the core report `engine.binary_unavailable` if it actually
4808
+ // needs one.
4809
+ try {
4760
4810
  const { getEnginePath } = await loadEngineCli();
4761
4811
  serveConfig.engineBinaryPath = getEnginePath();
4762
- serveConfig.engineHost = config.engineHost;
4763
- serveConfig.enginePort = config.enginePort;
4812
+ } catch (error) {
4813
+ // The npm-installed engine binary could not be resolved. The core still
4814
+ // decides whether it needs to spawn a local engine; if it does, it will
4815
+ // fail with engine.binary_unavailable (auto-download is off in the napi
4816
+ // runtime). Warn so the cause is actionable.
4817
+ logger().warn({
4818
+ msg: "could not resolve a local engine binary; if a local engine must be spawned it will fail with engine.binary_unavailable — set RIVET_ENGINE_BINARY_PATH or install the @rivetkit/engine-cli platform package",
4819
+ error: stringifyError(error),
4820
+ });
4764
4821
  }
4822
+ serveConfig.engineHost = config.engineHost;
4823
+ serveConfig.enginePort = config.enginePort;
4765
4824
  if (config.test?.enabled) {
4766
4825
  serveConfig.inspectorTestToken =
4767
4826
  getEnvUniversal("_RIVET_TEST_INSPECTOR_TOKEN") ?? "token";
@@ -4785,6 +4844,13 @@ export async function buildRegistryWithRuntime(
4785
4844
  trySetProcessEnv("_RIVET_TEST_INSPECTOR_TOKEN", "token");
4786
4845
  }
4787
4846
 
4847
+ // Custom inspector tab `source` paths are resolved with node:path while
4848
+ // building actor configs below, so the Node modules must be loaded first.
4849
+ // Native (napi) runtime only; wasm has no filesystem.
4850
+ if (runtime.kind === "napi") {
4851
+ importNodeDependencies();
4852
+ }
4853
+
4788
4854
  const registry = runtime.createRegistry();
4789
4855
 
4790
4856
  for (const [name, definition] of Object.entries(config.use)) {
@@ -1,5 +1,7 @@
1
+ import { stringifyError } from "@/common/utils";
1
2
  import type { SqliteNativeMetrics } from "@/common/database/config";
2
3
  import type { RegistryConfig } from "./config";
4
+ import { logger } from "./log";
3
5
 
4
6
  declare const handleBrand: unique symbol;
5
7
 
@@ -263,6 +265,12 @@ export interface RuntimeServeConfig {
263
265
  serverlessMaxStartPayloadBytes: number;
264
266
  }
265
267
 
268
+ export interface RuntimeListenerConfig {
269
+ port: number;
270
+ host?: string;
271
+ publicDir?: string;
272
+ }
273
+
266
274
  export interface RuntimeServerlessRequest {
267
275
  method: string;
268
276
  url: string;
@@ -338,6 +346,11 @@ export interface CoreRuntime {
338
346
  cancelToken: CancellationTokenHandle,
339
347
  config: RuntimeServeConfig,
340
348
  ): Promise<RuntimeServerlessResponseHead>;
349
+ serveListener(
350
+ registry: RegistryHandle,
351
+ listener: RuntimeListenerConfig,
352
+ config: RuntimeServeConfig,
353
+ ): Promise<void>;
341
354
  registryHealth?(
342
355
  registry: RegistryHandle,
343
356
  ): Promise<RuntimeRegistryRouteResponse>;
@@ -599,11 +612,25 @@ export async function buildServeConfig(
599
612
  serverlessMaxStartPayloadBytes: config.serverless.maxStartPayloadBytes,
600
613
  };
601
614
 
602
- if (config.startEngine) {
615
+ // Always best-effort resolve the engine binary path and hand it to the core.
616
+ // The core alone decides whether to actually spawn a local engine, so JS must
617
+ // not duplicate that decision here. `loadEnginePath` throws when no binary is
618
+ // available (remote-only install, unsupported platform, optional deps
619
+ // skipped); in that case leave it unset and let the core report
620
+ // `engine.binary_unavailable` only if it actually needs one.
621
+ try {
603
622
  serveConfig.engineBinaryPath = await loadEnginePath();
604
- serveConfig.engineHost = config.engineHost;
605
- serveConfig.enginePort = config.enginePort;
623
+ } catch (error) {
624
+ // The engine binary could not be resolved. The core still decides whether
625
+ // it needs to spawn a local engine; if it does, it will fail with
626
+ // engine.binary_unavailable (auto-download is off in the napi runtime).
627
+ logger().warn({
628
+ msg: "could not resolve a local engine binary; if a local engine must be spawned it will fail with engine.binary_unavailable — set RIVET_ENGINE_BINARY_PATH or install the @rivetkit/engine-cli platform package",
629
+ error: stringifyError(error),
630
+ });
606
631
  }
632
+ serveConfig.engineHost = config.engineHost;
633
+ serveConfig.enginePort = config.enginePort;
607
634
  if (config.test?.enabled) {
608
635
  serveConfig.inspectorTestToken =
609
636
  process.env._RIVET_TEST_INSPECTOR_TOKEN ?? "token";
@@ -26,6 +26,7 @@ import type {
26
26
  RuntimeInspectorSnapshot,
27
27
  RuntimeKvEntry,
28
28
  RuntimeKvListOptions,
29
+ RuntimeListenerConfig,
29
30
  RuntimeQueueEnqueueAndWaitOptions,
30
31
  RuntimeQueueInspectMessage,
31
32
  RuntimeQueueMessage,
@@ -302,6 +303,16 @@ export class WasmCoreRuntime implements CoreRuntime {
302
303
  );
303
304
  }
304
305
 
306
+ async serveListener(
307
+ _registry: RegistryHandle,
308
+ _listener: RuntimeListenerConfig,
309
+ _config: RuntimeServeConfig,
310
+ ): Promise<void> {
311
+ throw new Error(
312
+ "registry.listen() is not supported on the wasm runtime; use registry.serve() and mount the handler in your platform's HTTP server instead",
313
+ );
314
+ }
315
+
305
316
  createActorFactory(
306
317
  callbacks: object,
307
318
  config?: RuntimeActorConfig | undefined | null,
@@ -50,6 +50,37 @@ export const getRivetkitStoragePath = (): string | undefined =>
50
50
  getEnvUniversal("RIVETKIT_STORAGE_PATH");
51
51
  export const getRivetkitRuntime = (): string | undefined =>
52
52
  getEnvUniversal("RIVETKIT_RUNTIME");
53
+ export type RuntimeMode = "envoy" | "serverless";
54
+
55
+ export const getRivetkitRuntimeMode = (): RuntimeMode => {
56
+ const value = getEnvUniversal("RIVETKIT_RUNTIME_MODE");
57
+ if (value === undefined) return "envoy";
58
+ if (value === "envoy" || value === "serverless") return value;
59
+ throw new Error(
60
+ `RIVETKIT_RUNTIME_MODE env var must be "envoy" or "serverless"; got "${value}"`,
61
+ );
62
+ };
63
+
64
+ export const getRivetkitPublicDir = (): string | undefined => {
65
+ const value = getEnvUniversal("RIVETKIT_PUBLIC_DIR");
66
+ return value === undefined || value === "" ? undefined : value;
67
+ };
68
+
69
+ export function parsePortEnv(raw: string | undefined): number | undefined {
70
+ if (raw === undefined || raw === "") return undefined;
71
+ const parsed = Number.parseInt(raw, 10);
72
+ if (
73
+ !Number.isFinite(parsed) ||
74
+ parsed < 1 ||
75
+ parsed > 65535 ||
76
+ String(parsed) !== raw.trim()
77
+ ) {
78
+ throw new Error(
79
+ `RIVET_PORT env var must be an integer between 1 and 65535; got "${raw}"`,
80
+ );
81
+ }
82
+ return parsed;
83
+ }
53
84
 
54
85
  // Logging configuration
55
86
  // DEPRECATED: LOG_LEVEL will be removed in a future version