rivetkit 2.3.0 → 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.
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-KORQB2IR.cjs → chunk-4FC7TVS6.cjs} +6 -2
  20. package/dist/tsup/chunk-4FC7TVS6.cjs.map +1 -0
  21. package/dist/tsup/{chunk-47HHIEXH.cjs → chunk-4UUEB43Y.cjs} +4 -4
  22. package/dist/tsup/{chunk-47HHIEXH.cjs.map → chunk-4UUEB43Y.cjs.map} +1 -1
  23. package/dist/tsup/{chunk-7QKCIVAY.cjs → chunk-5IWLUJ6W.cjs} +167 -167
  24. package/dist/tsup/{chunk-7QKCIVAY.cjs.map → chunk-5IWLUJ6W.cjs.map} +1 -1
  25. package/dist/tsup/{chunk-P2GNQ4RN.js → chunk-H6VVZMWN.js} +4 -4
  26. package/dist/tsup/{chunk-MEHBWPLJ.js → chunk-I35VSLEM.js} +3 -3
  27. package/dist/tsup/{chunk-BEI24WTI.js → chunk-JBUZRPY5.js} +2 -2
  28. package/dist/tsup/{chunk-B6VUNZUD.cjs → chunk-JLJJZYCJ.cjs} +10 -10
  29. package/dist/tsup/{chunk-B6VUNZUD.cjs.map → chunk-JLJJZYCJ.cjs.map} +1 -1
  30. package/dist/tsup/{chunk-VTTFNQQI.js → chunk-L2X3YFER.js} +31 -6
  31. package/dist/tsup/chunk-L2X3YFER.js.map +1 -0
  32. package/dist/tsup/{chunk-DXXJPH55.cjs → chunk-MNHKOS6L.cjs} +39 -14
  33. package/dist/tsup/chunk-MNHKOS6L.cjs.map +1 -0
  34. package/dist/tsup/{chunk-UMZVD6DQ.js → chunk-NERUIBOT.js} +2 -2
  35. package/dist/tsup/{chunk-I4LN3FNT.cjs → chunk-OST76LRW.cjs} +7 -7
  36. package/dist/tsup/{chunk-I4LN3FNT.cjs.map → chunk-OST76LRW.cjs.map} +1 -1
  37. package/dist/tsup/{chunk-LVTBW2RE.cjs → chunk-OZBCXBVP.cjs} +3 -3
  38. package/dist/tsup/{chunk-LVTBW2RE.cjs.map → chunk-OZBCXBVP.cjs.map} +1 -1
  39. package/dist/tsup/{chunk-4JDSFJS5.js → chunk-PT6OIW5E.js} +5 -5
  40. package/dist/tsup/{chunk-2OTRTA3J.js → chunk-R6KPN5EW.js} +2 -2
  41. package/dist/tsup/{chunk-3677IIOV.cjs → chunk-V5KMAMX3.cjs} +5 -5
  42. package/dist/tsup/{chunk-3677IIOV.cjs.map → chunk-V5KMAMX3.cjs.map} +1 -1
  43. package/dist/tsup/{chunk-DPIMKYNB.js → chunk-XIX5DOZN.js} +10 -1
  44. package/dist/tsup/chunk-XIX5DOZN.js.map +1 -0
  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 +292 -276
  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 +202 -186
  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.ts → utils-CqDnC_PS.d.cts} +2 -1
  82. package/dist/tsup/{utils-DQosb24I.d.cts → 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 +79 -30
  100. package/src/registry/runtime.ts +11 -0
  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-BRP62GZC.js.map +0 -1
  107. package/dist/tsup/chunk-DPIMKYNB.js.map +0 -1
  108. package/dist/tsup/chunk-DXXJPH55.cjs.map +0 -1
  109. package/dist/tsup/chunk-KORQB2IR.cjs.map +0 -1
  110. package/dist/tsup/chunk-NIY3RSPX.cjs.map +0 -1
  111. package/dist/tsup/chunk-VTTFNQQI.js.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-P2GNQ4RN.js.map → chunk-H6VVZMWN.js.map} +0 -0
  116. /package/dist/tsup/{chunk-MEHBWPLJ.js.map → chunk-I35VSLEM.js.map} +0 -0
  117. /package/dist/tsup/{chunk-BEI24WTI.js.map → chunk-JBUZRPY5.js.map} +0 -0
  118. /package/dist/tsup/{chunk-UMZVD6DQ.js.map → chunk-NERUIBOT.js.map} +0 -0
  119. /package/dist/tsup/{chunk-4JDSFJS5.js.map → chunk-PT6OIW5E.js.map} +0 -0
  120. /package/dist/tsup/{chunk-2OTRTA3J.js.map → chunk-R6KPN5EW.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
 
@@ -4802,6 +4844,13 @@ export async function buildRegistryWithRuntime(
4802
4844
  trySetProcessEnv("_RIVET_TEST_INSPECTOR_TOKEN", "token");
4803
4845
  }
4804
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
+
4805
4854
  const registry = runtime.createRegistry();
4806
4855
 
4807
4856
  for (const [name, definition] of Object.entries(config.use)) {
@@ -265,6 +265,12 @@ export interface RuntimeServeConfig {
265
265
  serverlessMaxStartPayloadBytes: number;
266
266
  }
267
267
 
268
+ export interface RuntimeListenerConfig {
269
+ port: number;
270
+ host?: string;
271
+ publicDir?: string;
272
+ }
273
+
268
274
  export interface RuntimeServerlessRequest {
269
275
  method: string;
270
276
  url: string;
@@ -340,6 +346,11 @@ export interface CoreRuntime {
340
346
  cancelToken: CancellationTokenHandle,
341
347
  config: RuntimeServeConfig,
342
348
  ): Promise<RuntimeServerlessResponseHead>;
349
+ serveListener(
350
+ registry: RegistryHandle,
351
+ listener: RuntimeListenerConfig,
352
+ config: RuntimeServeConfig,
353
+ ): Promise<void>;
343
354
  registryHealth?(
344
355
  registry: RegistryHandle,
345
356
  ): Promise<RuntimeRegistryRouteResponse>;
@@ -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