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.
Files changed (226) hide show
  1. package/dist/browser/client.d.ts +511 -62
  2. package/dist/browser/client.js +230 -174
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +53 -23
  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 +2163 -2087
  12. package/dist/tsup/agent-os/index.cjs.map +1 -1
  13. package/dist/tsup/agent-os/index.d.cts +509 -69
  14. package/dist/tsup/agent-os/index.d.ts +509 -69
  15. package/dist/tsup/agent-os/index.js +2163 -2087
  16. package/dist/tsup/agent-os/index.js.map +1 -1
  17. package/dist/tsup/{chunk-WQ4HNA4W.cjs → chunk-3MHDOUD7.cjs} +73 -3
  18. package/dist/tsup/chunk-3MHDOUD7.cjs.map +1 -0
  19. package/dist/tsup/{chunk-QAZLM4WT.cjs → chunk-4FC7TVS6.cjs} +8 -4
  20. package/dist/tsup/chunk-4FC7TVS6.cjs.map +1 -0
  21. package/dist/tsup/{chunk-4CGA6QJO.cjs → chunk-4UUEB43Y.cjs} +24 -9
  22. package/dist/tsup/chunk-4UUEB43Y.cjs.map +1 -0
  23. package/dist/tsup/{chunk-GVTOE34S.cjs → chunk-5IWLUJ6W.cjs} +222 -235
  24. package/dist/tsup/chunk-5IWLUJ6W.cjs.map +1 -0
  25. package/dist/tsup/{chunk-MMMEZM5J.js → chunk-H6VVZMWN.js} +4 -4
  26. package/dist/tsup/chunk-H6VVZMWN.js.map +1 -0
  27. package/dist/tsup/{chunk-3YY5S6TV.js → chunk-HXUEHHJF.js} +2 -2
  28. package/dist/tsup/chunk-HXUEHHJF.js.map +1 -0
  29. package/dist/tsup/{chunk-H7P7WR2Y.js → chunk-I35VSLEM.js} +6 -6
  30. package/dist/tsup/chunk-I35VSLEM.js.map +1 -0
  31. package/dist/tsup/{chunk-H37XQU3I.js → chunk-JBUZRPY5.js} +2 -2
  32. package/dist/tsup/{chunk-CPA4Y3RG.cjs → chunk-JLJJZYCJ.cjs} +10 -10
  33. package/dist/tsup/chunk-JLJJZYCJ.cjs.map +1 -0
  34. package/dist/tsup/{chunk-PCBNKI2J.js → chunk-JZ7TWV65.js} +1 -1
  35. package/dist/tsup/chunk-JZ7TWV65.js.map +1 -0
  36. package/dist/tsup/{chunk-VRCIXJRN.js → chunk-L2X3YFER.js} +64 -10
  37. package/dist/tsup/chunk-L2X3YFER.js.map +1 -0
  38. package/dist/tsup/{chunk-Y5NSCZA2.cjs → chunk-MNHKOS6L.cjs} +72 -18
  39. package/dist/tsup/chunk-MNHKOS6L.cjs.map +1 -0
  40. package/dist/tsup/{chunk-KJTA3ATT.js → chunk-NERUIBOT.js} +22 -7
  41. package/dist/tsup/chunk-NERUIBOT.js.map +1 -0
  42. package/dist/tsup/{chunk-4WPEZBK4.cjs → chunk-OST76LRW.cjs} +10 -10
  43. package/dist/tsup/chunk-OST76LRW.cjs.map +1 -0
  44. package/dist/tsup/{chunk-MALSPBAF.cjs → chunk-OZBCXBVP.cjs} +3 -3
  45. package/dist/tsup/{chunk-MALSPBAF.cjs.map → chunk-OZBCXBVP.cjs.map} +1 -1
  46. package/dist/tsup/{chunk-F3Q5BFQ6.js → chunk-PT6OIW5E.js} +66 -79
  47. package/dist/tsup/chunk-PT6OIW5E.js.map +1 -0
  48. package/dist/tsup/{chunk-W7EYSYVI.js → chunk-R6KPN5EW.js} +134 -20
  49. package/dist/tsup/chunk-R6KPN5EW.js.map +1 -0
  50. package/dist/tsup/{chunk-VJFRBJVQ.cjs → chunk-V5KMAMX3.cjs} +138 -24
  51. package/dist/tsup/chunk-V5KMAMX3.cjs.map +1 -0
  52. package/dist/tsup/{chunk-LD5YASJU.cjs → chunk-VE2X4KMG.cjs} +2 -2
  53. package/dist/tsup/{chunk-LD5YASJU.cjs.map → chunk-VE2X4KMG.cjs.map} +1 -1
  54. package/dist/tsup/{chunk-T6YVRM4K.js → chunk-XIX5DOZN.js} +72 -2
  55. package/dist/tsup/chunk-XIX5DOZN.js.map +1 -0
  56. package/dist/tsup/{chunk-2NDZ7JCR.cjs → chunk-ZA7FLHKH.cjs} +1 -1
  57. package/dist/tsup/chunk-ZA7FLHKH.cjs.map +1 -0
  58. package/dist/tsup/{chunk-KIWH5H3K.js → chunk-ZZ3WBRPD.js} +7 -3
  59. package/dist/tsup/chunk-ZZ3WBRPD.js.map +1 -0
  60. package/dist/tsup/client/mod.cjs +9 -9
  61. package/dist/tsup/client/mod.d.cts +5 -5
  62. package/dist/tsup/client/mod.d.ts +5 -5
  63. package/dist/tsup/client/mod.js +8 -8
  64. package/dist/tsup/common/log.cjs +3 -3
  65. package/dist/tsup/common/log.js +2 -2
  66. package/dist/tsup/common/websocket.cjs +4 -4
  67. package/dist/tsup/common/websocket.js +3 -3
  68. package/dist/tsup/{config-Ca8dN4cS.d.cts → config-CzvopP5m.d.cts} +544 -23
  69. package/dist/tsup/{config-CxjGYf4K.d.cts → config-D49x8NpL.d.cts} +1 -2
  70. package/dist/tsup/{config-CxjGYf4K.d.ts → config-D49x8NpL.d.ts} +1 -2
  71. package/dist/tsup/{config-0Ta55UV0.d.ts → config-DZuT7tcp.d.ts} +544 -23
  72. package/dist/tsup/context-CyAdY-aA.d.ts +128 -0
  73. package/dist/tsup/context-sNB28g0N.d.cts +128 -0
  74. package/dist/tsup/db/drizzle.cjs +3 -3
  75. package/dist/tsup/db/drizzle.d.cts +1 -1
  76. package/dist/tsup/db/drizzle.d.ts +1 -1
  77. package/dist/tsup/db/drizzle.js +1 -1
  78. package/dist/tsup/db/mod.cjs +2 -2
  79. package/dist/tsup/db/mod.d.cts +2 -2
  80. package/dist/tsup/db/mod.d.ts +2 -2
  81. package/dist/tsup/db/mod.js +1 -1
  82. package/dist/tsup/dynamic/mod.cjs +24 -0
  83. package/dist/tsup/dynamic/mod.cjs.map +1 -0
  84. package/dist/tsup/dynamic/mod.d.cts +37 -0
  85. package/dist/tsup/dynamic/mod.d.ts +37 -0
  86. package/dist/tsup/dynamic/mod.js +24 -0
  87. package/dist/tsup/dynamic/mod.js.map +1 -0
  88. package/dist/tsup/inspector/mod.cjs +6 -6
  89. package/dist/tsup/inspector/mod.js +5 -5
  90. package/dist/tsup/inspector-tab/mod.cjs +173 -0
  91. package/dist/tsup/inspector-tab/mod.cjs.map +1 -0
  92. package/dist/tsup/inspector-tab/mod.d.cts +250 -0
  93. package/dist/tsup/inspector-tab/mod.d.ts +250 -0
  94. package/dist/tsup/inspector-tab/mod.js +173 -0
  95. package/dist/tsup/inspector-tab/mod.js.map +1 -0
  96. package/dist/tsup/mod.cjs +758 -348
  97. package/dist/tsup/mod.cjs.map +1 -1
  98. package/dist/tsup/mod.d.cts +5 -5
  99. package/dist/tsup/mod.d.ts +5 -5
  100. package/dist/tsup/mod.js +662 -252
  101. package/dist/tsup/mod.js.map +1 -1
  102. package/dist/tsup/test/mod.cjs +21 -18
  103. package/dist/tsup/test/mod.cjs.map +1 -1
  104. package/dist/tsup/test/mod.d.cts +4 -4
  105. package/dist/tsup/test/mod.d.ts +4 -4
  106. package/dist/tsup/test/mod.js +18 -15
  107. package/dist/tsup/test/mod.js.map +1 -1
  108. package/dist/tsup/{utils-DVekpm4I.d.cts → utils-CqDnC_PS.d.cts} +2 -1
  109. package/dist/tsup/{utils-DVekpm4I.d.ts → utils-CqDnC_PS.d.ts} +2 -1
  110. package/dist/tsup/utils.cjs +3 -3
  111. package/dist/tsup/utils.d.cts +1 -1
  112. package/dist/tsup/utils.d.ts +1 -1
  113. package/dist/tsup/utils.js +2 -2
  114. package/dist/tsup/workflow/mod.cjs +383 -322
  115. package/dist/tsup/workflow/mod.cjs.map +1 -1
  116. package/dist/tsup/workflow/mod.d.cts +8 -8
  117. package/dist/tsup/workflow/mod.d.ts +8 -8
  118. package/dist/tsup/workflow/mod.js +360 -299
  119. package/dist/tsup/workflow/mod.js.map +1 -1
  120. package/package.json +35 -14
  121. package/src/actor/config.ts +173 -51
  122. package/src/actor/contexts/index.ts +7 -2
  123. package/src/actor/definition.ts +17 -19
  124. package/src/actor/driver.ts +3 -3
  125. package/src/actor/errors.ts +20 -3
  126. package/src/actor/instance/mod.ts +26 -34
  127. package/src/actor/keys.ts +1 -1
  128. package/src/actor/mod.ts +22 -20
  129. package/src/actor/schema.ts +2 -2
  130. package/src/agent-os/actor/index.ts +38 -18
  131. package/src/agent-os/actor/preview.ts +1 -2
  132. package/src/agent-os/actor/session.ts +2 -2
  133. package/src/agent-os/config.ts +1 -1
  134. package/src/agent-os/fs/database-vfs.ts +1 -1
  135. package/src/agent-os/index.ts +16 -15
  136. package/src/client/actor-common.ts +87 -54
  137. package/src/client/actor-conn.ts +8 -36
  138. package/src/client/actor-handle.ts +69 -51
  139. package/src/client/actor-query.ts +5 -5
  140. package/src/client/errors.ts +1 -1
  141. package/src/client/lifecycle-errors.ts +2 -4
  142. package/src/client/query.ts +1 -1
  143. package/src/client/queue.ts +8 -3
  144. package/src/client/raw-utils.ts +8 -6
  145. package/src/client/resolve-gateway-target.ts +1 -1
  146. package/src/client/utils.ts +2 -7
  147. package/src/common/actor-websocket.ts +3 -1
  148. package/src/common/bare/actor-persist/v1.ts +205 -163
  149. package/src/common/bare/actor-persist/v2.ts +265 -213
  150. package/src/common/bare/actor-persist/v3.ts +176 -172
  151. package/src/common/bare/actor-persist/v4.ts +254 -253
  152. package/src/common/bare/transport/v1.ts +659 -543
  153. package/src/common/client-protocol-versioned.ts +66 -64
  154. package/src/common/database/config.ts +2 -8
  155. package/src/common/database/native-database.ts +1 -1
  156. package/src/common/database/shared.ts +1 -0
  157. package/src/common/encoding.ts +250 -16
  158. package/src/common/engine.ts +28 -1
  159. package/src/common/eventsource.ts +1 -1
  160. package/src/common/inline-websocket-adapter.ts +14 -13
  161. package/src/common/log.ts +1 -0
  162. package/src/common/router.ts +13 -17
  163. package/src/common/utils.ts +1 -150
  164. package/src/common/websocket-interface.ts +1 -1
  165. package/src/db/mod.ts +1 -1
  166. package/src/devtools-loader/index.ts +4 -7
  167. package/src/devtools-loader/serve-devtools.ts +26 -0
  168. package/src/drivers/engine/actor-driver.ts +58 -56
  169. package/src/dynamic/instance.ts +32 -0
  170. package/src/dynamic/internal.ts +50 -0
  171. package/src/dynamic/isolate-runtime.ts +66 -0
  172. package/src/dynamic/mod.ts +32 -0
  173. package/src/engine-client/actor-http-client.ts +3 -3
  174. package/src/engine-client/actor-websocket-client.ts +6 -5
  175. package/src/engine-client/api-endpoints.ts +51 -2
  176. package/src/engine-client/api-utils.ts +2 -2
  177. package/src/engine-client/driver.ts +1 -1
  178. package/src/engine-client/mod.ts +6 -3
  179. package/src/engine-client/ws-proxy.ts +9 -4
  180. package/src/inspector/client.browser.ts +5 -11
  181. package/src/inspector/mod.ts +1 -3
  182. package/src/inspector-tab/mod.ts +315 -0
  183. package/src/registry/config/envoy.ts +1 -2
  184. package/src/registry/config/index.ts +40 -16
  185. package/src/registry/index.ts +209 -73
  186. package/src/registry/napi-runtime.ts +29 -2
  187. package/src/registry/native-validation.ts +10 -12
  188. package/src/registry/native.ts +433 -198
  189. package/src/registry/process-metrics.ts +250 -0
  190. package/src/registry/runtime.ts +52 -1
  191. package/src/registry/wasm-runtime.ts +29 -2
  192. package/src/registry/write-through-proxy.ts +40 -0
  193. package/src/serde.ts +2 -2
  194. package/src/serverless/configure.ts +18 -7
  195. package/src/test/mod.ts +11 -8
  196. package/src/utils/endpoint-parser.ts +1 -1
  197. package/src/utils/env-vars.ts +37 -0
  198. package/src/utils/router.ts +1 -1
  199. package/src/utils.ts +1 -2
  200. package/src/workflow/context.ts +699 -240
  201. package/src/workflow/driver.ts +23 -12
  202. package/src/workflow/inspector.ts +4 -3
  203. package/src/workflow/mod.ts +37 -23
  204. package/dist/tsup/chunk-2NDZ7JCR.cjs.map +0 -1
  205. package/dist/tsup/chunk-3YY5S6TV.js.map +0 -1
  206. package/dist/tsup/chunk-4CGA6QJO.cjs.map +0 -1
  207. package/dist/tsup/chunk-4WPEZBK4.cjs.map +0 -1
  208. package/dist/tsup/chunk-CPA4Y3RG.cjs.map +0 -1
  209. package/dist/tsup/chunk-F3Q5BFQ6.js.map +0 -1
  210. package/dist/tsup/chunk-GVTOE34S.cjs.map +0 -1
  211. package/dist/tsup/chunk-H7P7WR2Y.js.map +0 -1
  212. package/dist/tsup/chunk-KIWH5H3K.js.map +0 -1
  213. package/dist/tsup/chunk-KJTA3ATT.js.map +0 -1
  214. package/dist/tsup/chunk-MMMEZM5J.js.map +0 -1
  215. package/dist/tsup/chunk-PCBNKI2J.js.map +0 -1
  216. package/dist/tsup/chunk-QAZLM4WT.cjs.map +0 -1
  217. package/dist/tsup/chunk-T6YVRM4K.js.map +0 -1
  218. package/dist/tsup/chunk-VJFRBJVQ.cjs.map +0 -1
  219. package/dist/tsup/chunk-VRCIXJRN.js.map +0 -1
  220. package/dist/tsup/chunk-W7EYSYVI.js.map +0 -1
  221. package/dist/tsup/chunk-WQ4HNA4W.cjs.map +0 -1
  222. package/dist/tsup/chunk-Y5NSCZA2.cjs.map +0 -1
  223. package/dist/tsup/context-B_IWbWne.d.ts +0 -92
  224. package/dist/tsup/context-CUrQ9MHc.d.cts +0 -92
  225. package/src/utils/serve.ts +0 -217
  226. /package/dist/tsup/{chunk-H37XQU3I.js.map → chunk-JBUZRPY5.js.map} +0 -0
package/dist/tsup/mod.js CHANGED
@@ -1,14 +1,16 @@
1
+ import {
2
+ decodeWorkflowHistoryTransport
3
+ } from "./chunk-NERUIBOT.js";
1
4
  import {
2
5
  ACTOR_CONTEXT_INTERNAL_SYMBOL,
3
6
  ActorConfigSchema,
4
7
  CONN_STATE_MANAGER_SYMBOL,
8
+ RAW_STATE_SYMBOL,
9
+ disposeRunInspector,
5
10
  getRunFunction,
6
11
  getRunInspectorConfig,
7
12
  getRunMetadata
8
- } from "./chunk-T6YVRM4K.js";
9
- import {
10
- decodeWorkflowHistoryTransport
11
- } from "./chunk-KJTA3ATT.js";
13
+ } from "./chunk-XIX5DOZN.js";
12
14
  import {
13
15
  ALLOWED_PUBLIC_HEADERS,
14
16
  HEADER_CONN_PARAMS,
@@ -18,7 +20,7 @@ import {
18
20
  getDatacenters,
19
21
  tryParseEndpoint,
20
22
  updateRunnerConfig
21
- } from "./chunk-F3Q5BFQ6.js";
23
+ } from "./chunk-PT6OIW5E.js";
22
24
  import {
23
25
  KEYS,
24
26
  makePrefixedKey,
@@ -26,14 +28,14 @@ import {
26
28
  queueMetadataKey,
27
29
  removePrefixFromKey,
28
30
  workflowStoragePrefix
29
- } from "./chunk-3YY5S6TV.js";
31
+ } from "./chunk-HXUEHHJF.js";
30
32
  import {
33
+ assertJsonCompatValue,
31
34
  decodeCborCompat,
32
- decodeCborJsonCompat,
33
35
  encodeCborCompat
34
- } from "./chunk-W7EYSYVI.js";
35
- import "./chunk-PCBNKI2J.js";
36
- import "./chunk-H37XQU3I.js";
36
+ } from "./chunk-R6KPN5EW.js";
37
+ import "./chunk-JZ7TWV65.js";
38
+ import "./chunk-JBUZRPY5.js";
37
39
  import {
38
40
  LogLevelSchema,
39
41
  VERSION,
@@ -49,15 +51,20 @@ import {
49
51
  getRivetPublicEndpoint,
50
52
  getRivetPublicToken,
51
53
  getRivetRunEngine,
54
+ getRivetRunEngineHost,
55
+ getRivetRunEnginePort,
52
56
  getRivetRunEngineVersion,
53
57
  getRivetToken,
54
58
  getRivetTotalSlots,
59
+ getRivetkitPublicDir,
55
60
  getRivetkitRuntime,
61
+ getRivetkitRuntimeMode,
56
62
  isDev,
57
63
  noopNext,
64
+ parsePortEnv,
58
65
  stringifyError,
59
66
  toUint8Array
60
- } from "./chunk-VRCIXJRN.js";
67
+ } from "./chunk-L2X3YFER.js";
61
68
  import {
62
69
  INTERNAL_ERROR_CODE,
63
70
  RivetError,
@@ -65,10 +72,11 @@ import {
65
72
  decodeBridgeRivetError,
66
73
  encodeBridgeRivetError,
67
74
  forbiddenError,
75
+ isActorAbortedError,
68
76
  isRivetErrorLike,
69
77
  toRivetError,
70
78
  unsupportedFeature
71
- } from "./chunk-KIWH5H3K.js";
79
+ } from "./chunk-ZZ3WBRPD.js";
72
80
 
73
81
  // src/actor/log.ts
74
82
  function loggerWithoutContext() {
@@ -140,7 +148,7 @@ function hasSchemaConfigKey(schemas, key) {
140
148
  if (!schemas) {
141
149
  return false;
142
150
  }
143
- return Object.prototype.hasOwnProperty.call(schemas, key);
151
+ return Object.hasOwn(schemas, key);
144
152
  }
145
153
  function getEventCanSubscribe(schemas, key) {
146
154
  const schema = schemas == null ? void 0 : schemas[key];
@@ -201,8 +209,8 @@ function validateSchemaSync(schemas, key, data) {
201
209
  }
202
210
 
203
211
  // src/common/inline-websocket-adapter.ts
204
- import { WSContext } from "hono/ws";
205
212
  import { VirtualWebSocket } from "@rivetkit/virtual-websocket";
213
+ import { WSContext } from "hono/ws";
206
214
  function logger() {
207
215
  return getLogger("inline-websocket-adapter");
208
216
  }
@@ -314,24 +322,24 @@ var InlineWebSocketAdapter = class {
314
322
  this.#close(1011, "Internal error during initialization");
315
323
  }
316
324
  }
317
- #handleError(err) {
318
- console.error("INLINE_WEBSOCKET_ADAPTER_ERROR", err);
325
+ #handleError(error) {
326
+ console.error("INLINE_WEBSOCKET_ADAPTER_ERROR", error);
319
327
  logger().error({
320
328
  msg: "error in websocket",
321
- error: err,
322
- errorMessage: err instanceof Error ? err.message : String(err),
323
- stack: err instanceof Error ? err.stack : void 0
329
+ error,
330
+ errorMessage: error instanceof Error ? error.message : String(error),
331
+ stack: error instanceof Error ? error.stack : void 0
324
332
  });
325
333
  try {
326
- this.#handler.onError(err, this.#wsContext);
327
- } catch (handlerErr) {
334
+ this.#handler.onError(error, this.#wsContext);
335
+ } catch (error2) {
328
336
  logger().error({
329
337
  msg: "error in onError handler",
330
- error: handlerErr
338
+ error: error2
331
339
  });
332
340
  }
333
- this.#clientWs.triggerError(err);
334
- this.#actorWs.triggerError(err);
341
+ this.#clientWs.triggerError(error);
342
+ this.#actorWs.triggerError(error);
335
343
  }
336
344
  #close(code, reason) {
337
345
  if (this.#readyState === 3 || this.#readyState === 2) {
@@ -344,8 +352,8 @@ var InlineWebSocketAdapter = class {
344
352
  { code, reason, wasClean: true },
345
353
  this.#wsContext
346
354
  );
347
- } catch (err) {
348
- logger().error({ msg: "error closing websocket", error: err });
355
+ } catch (error) {
356
+ logger().error({ msg: "error closing websocket", error });
349
357
  } finally {
350
358
  this.#readyState = 3;
351
359
  this.#clientWs.triggerClose(code, reason);
@@ -355,8 +363,23 @@ var InlineWebSocketAdapter = class {
355
363
  };
356
364
 
357
365
  // src/common/engine.ts
366
+ var ENGINE_HOST = "127.0.0.1";
358
367
  var ENGINE_PORT = 6420;
359
- var ENGINE_ENDPOINT = `http://127.0.0.1:${ENGINE_PORT}`;
368
+ var ENGINE_ENDPOINT = buildEngineEndpoint(ENGINE_HOST, ENGINE_PORT);
369
+ function buildEngineEndpoint(host, port) {
370
+ const urlHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
371
+ return `http://${urlHost}:${port}`;
372
+ }
373
+ function isLocalEngineEndpoint(endpoint) {
374
+ let url;
375
+ try {
376
+ url = new URL(endpoint);
377
+ } catch {
378
+ return false;
379
+ }
380
+ const hostname = url.hostname.toLowerCase();
381
+ return hostname === "localhost" || hostname === "0.0.0.0" || hostname === "::" || hostname === "[::]" || hostname === "::1" || hostname === "[::1]" || /^127(?:\.\d{1,3}){0,3}$/.test(hostname);
382
+ }
360
383
 
361
384
  // src/registry/log.ts
362
385
  function logger2() {
@@ -371,10 +394,13 @@ function sleep(ms) {
371
394
  }
372
395
  function configureTimeoutMs() {
373
396
  const value = process.env.RIVET_SERVERLESS_CONFIGURE_TIMEOUT_MS;
374
- if (value === void 0 || value === "") return DEFAULT_CONFIGURE_TIMEOUT_MS;
397
+ if (value === void 0 || value === "")
398
+ return DEFAULT_CONFIGURE_TIMEOUT_MS;
375
399
  const parsed = Number(value);
376
400
  if (!Number.isFinite(parsed) || parsed < 0) {
377
- throw new Error("RIVET_SERVERLESS_CONFIGURE_TIMEOUT_MS must be a finite non-negative number");
401
+ throw new Error(
402
+ "RIVET_SERVERLESS_CONFIGURE_TIMEOUT_MS must be a finite non-negative number"
403
+ );
378
404
  }
379
405
  return parsed;
380
406
  }
@@ -388,13 +414,19 @@ async function configureServerlessPool(config) {
388
414
  attempts += 1;
389
415
  try {
390
416
  if (!config.namespace) {
391
- throw new Error("namespace is required for serverless configuration");
417
+ throw new Error(
418
+ "namespace is required for serverless configuration"
419
+ );
392
420
  }
393
421
  if (!config.endpoint) {
394
- throw new Error("endpoint is required for serverless configuration");
422
+ throw new Error(
423
+ "endpoint is required for serverless configuration"
424
+ );
395
425
  }
396
426
  if (!config.configurePool) {
397
- throw new Error("configurePool is required for serverless configuration");
427
+ throw new Error(
428
+ "configurePool is required for serverless configuration"
429
+ );
398
430
  }
399
431
  const customConfig = config.configurePool;
400
432
  const clientConfig = convertRegistryConfigToClientConfig(config);
@@ -668,6 +700,18 @@ var RegistryConfigSchema = z3.object({
668
700
  * Starts the full Rust engine process locally.
669
701
  */
670
702
  startEngine: z3.boolean().default(() => getRivetRunEngine()),
703
+ /**
704
+ * @experimental
705
+ *
706
+ * Host to bind the spawned local engine process to.
707
+ */
708
+ engineHost: z3.string().optional().default(() => getRivetRunEngineHost() ?? ENGINE_HOST),
709
+ /**
710
+ * @experimental
711
+ *
712
+ * Port to bind the spawned local engine process to.
713
+ */
714
+ enginePort: z3.number().int().min(1).max(65535).optional().default(() => getRivetRunEnginePort() ?? ENGINE_PORT),
671
715
  /** @experimental */
672
716
  engineVersion: z3.string().optional().default(() => getRivetRunEngineVersion() ?? VERSION),
673
717
  /**
@@ -703,7 +747,7 @@ var RegistryConfigSchema = z3.object({
703
747
  * after calling `CoreRegistry::shutdown()`. Defaults to the
704
748
  * engine-provided actor stop threshold once the envoy connects.
705
749
  *
706
- * Must be >= rivetkit-core's drain timeout (20s) + margin.
750
+ * Must be long enough for rivetkit-core to drain the envoy.
707
751
  */
708
752
  gracePeriodMs: z3.number().int().min(1e3).optional(),
709
753
  /**
@@ -745,7 +789,11 @@ var RegistryConfigSchema = z3.object({
745
789
  message: "configurePool requires either endpoint or startEngine"
746
790
  });
747
791
  }
748
- const endpoint = config.startEngine ? ENGINE_ENDPOINT : (parsedEndpoint == null ? void 0 : parsedEndpoint.endpoint) ?? (isDevEnv ? ENGINE_ENDPOINT : void 0);
792
+ const localEngineEndpoint = buildEngineEndpoint(
793
+ config.engineHost,
794
+ config.enginePort
795
+ );
796
+ const endpoint = config.startEngine ? localEngineEndpoint : (parsedEndpoint == null ? void 0 : parsedEndpoint.endpoint) ?? (isDevEnv ? buildEngineEndpoint(ENGINE_HOST, ENGINE_PORT) : void 0);
749
797
  const validateServerlessEndpoint = Boolean(
750
798
  config.startEngine || parsedEndpoint
751
799
  );
@@ -762,7 +810,7 @@ var RegistryConfigSchema = z3.object({
762
810
  path: ["serverless", "publicEndpoint"]
763
811
  });
764
812
  }
765
- const publicEndpoint = (parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.endpoint) ?? (isDevEnv && config.startEngine ? ENGINE_ENDPOINT : void 0);
813
+ const publicEndpoint = (parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.endpoint) ?? (isDevEnv && config.startEngine ? endpoint : void 0);
766
814
  const publicNamespace = parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.namespace;
767
815
  const publicToken = (parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.token) ?? config.serverless.publicToken;
768
816
  return {
@@ -1154,6 +1202,82 @@ function lastInsertRowIdColumnName(sql) {
1154
1202
  return alias;
1155
1203
  }
1156
1204
 
1205
+ // src/utils/node.ts
1206
+ import { createRequire } from "module";
1207
+ var nodeCrypto;
1208
+ var nodeFsSync;
1209
+ var nodeFs;
1210
+ var nodePath;
1211
+ var nodeOs;
1212
+ var nodeChildProcess;
1213
+ var nodeStream;
1214
+ var nodeUrl;
1215
+ var hasImportedDependencies = false;
1216
+ function getRequireFn() {
1217
+ return createRequire(import.meta.url);
1218
+ }
1219
+ function importNodeDependencies() {
1220
+ if (hasImportedDependencies) return;
1221
+ try {
1222
+ const requireFn = getRequireFn();
1223
+ nodeCrypto = requireFn(
1224
+ /* webpackIgnore: true */
1225
+ "node:crypto"
1226
+ );
1227
+ nodeFsSync = requireFn(
1228
+ /* webpackIgnore: true */
1229
+ "node:fs"
1230
+ );
1231
+ nodeFs = requireFn(
1232
+ /* webpackIgnore: true */
1233
+ "node:fs/promises"
1234
+ );
1235
+ nodePath = requireFn(
1236
+ /* webpackIgnore: true */
1237
+ "node:path"
1238
+ );
1239
+ nodeOs = requireFn(
1240
+ /* webpackIgnore: true */
1241
+ "node:os"
1242
+ );
1243
+ nodeChildProcess = requireFn(
1244
+ /* webpackIgnore: true */
1245
+ "node:child_process"
1246
+ );
1247
+ nodeStream = requireFn(
1248
+ /* webpackIgnore: true */
1249
+ "node:stream/promises"
1250
+ );
1251
+ nodeUrl = requireFn(
1252
+ /* webpackIgnore: true */
1253
+ "node:url"
1254
+ );
1255
+ hasImportedDependencies = true;
1256
+ } catch (err) {
1257
+ console.warn(
1258
+ "Node.js modules not available, file system driver will not work",
1259
+ err
1260
+ );
1261
+ throw err;
1262
+ }
1263
+ }
1264
+ function getNodeFsSync() {
1265
+ if (!nodeFsSync) {
1266
+ throw new Error(
1267
+ "Node fs module not loaded. Ensure importNodeDependencies() has been called."
1268
+ );
1269
+ }
1270
+ return nodeFsSync;
1271
+ }
1272
+ function getNodePath() {
1273
+ if (!nodePath) {
1274
+ throw new Error(
1275
+ "Node path module not loaded. Ensure importNodeDependencies() has been called."
1276
+ );
1277
+ }
1278
+ return nodePath;
1279
+ }
1280
+
1157
1281
  // src/registry/runtime.ts
1158
1282
  function normalizeRuntimeSqlExecuteResult(result) {
1159
1283
  return result;
@@ -1309,6 +1433,16 @@ var NapiCoreRuntime = class {
1309
1433
  config
1310
1434
  );
1311
1435
  }
1436
+ async serveListener(registry, listener, config) {
1437
+ await asNativeRegistry(registry).serveListener(
1438
+ {
1439
+ port: listener.port,
1440
+ host: listener.host,
1441
+ publicDir: listener.publicDir
1442
+ },
1443
+ config
1444
+ );
1445
+ }
1312
1446
  createActorFactory(callbacks, config) {
1313
1447
  return asActorFactoryHandle(
1314
1448
  new this.#bindings.NapiActorFactory(callbacks, config)
@@ -1424,6 +1558,9 @@ var NapiCoreRuntime = class {
1424
1558
  async actorWaitForTrackedShutdownWork(ctx) {
1425
1559
  return await asNativeActorContext(ctx).waitForTrackedShutdownWork();
1426
1560
  }
1561
+ async actorWaitForTrackedShutdownWorkUnbounded(ctx) {
1562
+ await asNativeActorContext(ctx).waitForTrackedShutdownWorkUnbounded();
1563
+ }
1427
1564
  actorKeepAwake(ctx, promise) {
1428
1565
  asNativeActorContext(ctx).keepAwake(promise);
1429
1566
  }
@@ -1535,8 +1672,12 @@ var NapiCoreRuntime = class {
1535
1672
  )
1536
1673
  );
1537
1674
  }
1538
- async actorQueueWaitForNamesAvailable(ctx, names, options) {
1539
- await asNativeActorContext(ctx).queue().waitForNamesAvailable(names, options);
1675
+ async actorQueueWaitForNamesAvailable(ctx, names, options, signal) {
1676
+ await asNativeActorContext(ctx).queue().waitForNamesAvailable(
1677
+ names,
1678
+ options,
1679
+ signal ? asNativeCancellationToken(signal) : signal
1680
+ );
1540
1681
  }
1541
1682
  async actorQueueEnqueueAndWait(ctx, name, body, options, signal) {
1542
1683
  return await asNativeActorContext(ctx).queue().enqueueAndWait(
@@ -1670,20 +1811,18 @@ function validateQueueComplete(schemas, name, response) {
1670
1811
  response
1671
1812
  );
1672
1813
  if (!result.success) {
1673
- throw validationError(`queue \`${name}\` completion response`, result.issues);
1814
+ throw validationError(
1815
+ `queue \`${name}\` completion response`,
1816
+ result.issues
1817
+ );
1674
1818
  }
1675
1819
  return result.data;
1676
1820
  }
1677
1821
  function validationError(target, issues) {
1678
- return new RivetError(
1679
- "actor",
1680
- "validation_error",
1681
- `Invalid ${target}`,
1682
- {
1683
- public: true,
1684
- metadata: { issues }
1685
- }
1686
- );
1822
+ return new RivetError("actor", "validation_error", `Invalid ${target}`, {
1823
+ public: true,
1824
+ metadata: { issues }
1825
+ });
1687
1826
  }
1688
1827
 
1689
1828
  // src/registry/wasm-runtime.ts
@@ -1864,6 +2003,11 @@ var WasmCoreRuntime = class {
1864
2003
  config
1865
2004
  );
1866
2005
  }
2006
+ async serveListener(_registry, _listener, _config) {
2007
+ throw new Error(
2008
+ "registry.listen() is not supported on the wasm runtime; use registry.serve() and mount the handler in your platform's HTTP server instead"
2009
+ );
2010
+ }
1867
2011
  createActorFactory(callbacks, config) {
1868
2012
  return callWasmSync(
1869
2013
  () => asActorFactoryHandle2(
@@ -2007,6 +2151,12 @@ var WasmCoreRuntime = class {
2007
2151
  "waitForTrackedShutdownWork"
2008
2152
  );
2009
2153
  }
2154
+ async actorWaitForTrackedShutdownWorkUnbounded(ctx) {
2155
+ await callHandle(
2156
+ asWasmActorContext(ctx),
2157
+ "waitForTrackedShutdownWorkUnbounded"
2158
+ );
2159
+ }
2010
2160
  actorKeepAwake(ctx, promise) {
2011
2161
  const wasmCtx = asWasmActorContext(ctx);
2012
2162
  const regionId = callHandle(wasmCtx, "beginKeepAwake");
@@ -2154,9 +2304,15 @@ var WasmCoreRuntime = class {
2154
2304
  )
2155
2305
  );
2156
2306
  }
2157
- async actorQueueWaitForNamesAvailable(ctx, names, options) {
2307
+ async actorQueueWaitForNamesAvailable(ctx, names, options, signal) {
2158
2308
  const queue2 = childHandle(asWasmActorContext(ctx), "queue");
2159
- await callHandleAsync(queue2, "waitForNamesAvailable", names, options);
2309
+ await callHandleAsync(
2310
+ queue2,
2311
+ "waitForNamesAvailable",
2312
+ names,
2313
+ options,
2314
+ signal
2315
+ );
2160
2316
  }
2161
2317
  async actorQueueEnqueueAndWait(ctx, name, body, options, signal) {
2162
2318
  const queue2 = childHandle(asWasmActorContext(ctx), "queue");
@@ -2248,6 +2404,29 @@ async function loadWasmRuntime(config) {
2248
2404
  };
2249
2405
  }
2250
2406
 
2407
+ // src/registry/write-through-proxy.ts
2408
+ import onChange from "@rivetkit/on-change";
2409
+ function createWriteThroughProxy(value, commit, beforeChange) {
2410
+ if (!value || typeof value !== "object") {
2411
+ return value;
2412
+ }
2413
+ return onChange(
2414
+ value,
2415
+ () => {
2416
+ commit(value);
2417
+ },
2418
+ {
2419
+ // Rejection is throw-based: beforeChange throws to prevent the
2420
+ // mutation. We always return true so on-change applies the change
2421
+ // if beforeChange did not throw.
2422
+ onValidate(_path, newValue) {
2423
+ beforeChange == null ? void 0 : beforeChange(newValue);
2424
+ return true;
2425
+ }
2426
+ }
2427
+ );
2428
+ }
2429
+
2251
2430
  // src/registry/native.ts
2252
2431
  var textEncoder = new TextEncoder();
2253
2432
  var textDecoder = new TextDecoder();
@@ -2401,6 +2580,14 @@ function databaseNotConfiguredError() {
2401
2580
  { public: true }
2402
2581
  );
2403
2582
  }
2583
+ function databaseClientNotReadyError() {
2584
+ return new RivetError(
2585
+ "actor",
2586
+ "database_client_not_ready",
2587
+ "actor database client was not initialized before user code ran. this is an internal lifecycle error; the migration callback should have pre-warmed the client. file an issue if you can reproduce.",
2588
+ { public: true }
2589
+ );
2590
+ }
2404
2591
  function stateNotEnabledError() {
2405
2592
  return new RivetError(
2406
2593
  "actor",
@@ -2452,8 +2639,23 @@ function resolveNativeDestroy(runtime, ctx) {
2452
2639
  function clearNativeRuntimeState(runtime, ctx) {
2453
2640
  callNativeSync(() => runtime.actorClearRuntimeState(ctx));
2454
2641
  }
2455
- async function cleanupNativeSleepRuntimeState(runtime, ctx) {
2456
- await runtime.actorWaitForTrackedShutdownWork(ctx);
2642
+ async function cleanupNativeSleepRuntimeState(runtime, ctx, afterTrackedWorkDrained) {
2643
+ const drained = await runtime.actorWaitForTrackedShutdownWork(ctx);
2644
+ if (!drained) {
2645
+ await closeNativeDatabaseClient(runtime, ctx);
2646
+ await closeNativeSqlDatabase(runtime, ctx);
2647
+ void runtime.actorWaitForTrackedShutdownWorkUnbounded(ctx).then(async () => {
2648
+ await (afterTrackedWorkDrained == null ? void 0 : afterTrackedWorkDrained());
2649
+ clearNativeRuntimeState(runtime, ctx);
2650
+ }).catch((error) => {
2651
+ logger2().warn({
2652
+ msg: "deferred native sleep cleanup failed",
2653
+ error: stringifyError(error)
2654
+ });
2655
+ });
2656
+ return;
2657
+ }
2658
+ await (afterTrackedWorkDrained == null ? void 0 : afterTrackedWorkDrained());
2457
2659
  await closeNativeDatabaseClient(runtime, ctx);
2458
2660
  await closeNativeSqlDatabase(runtime, ctx);
2459
2661
  clearNativeRuntimeState(runtime, ctx);
@@ -2558,11 +2760,14 @@ function decodeValue(value) {
2558
2760
  if (!value || value.length === 0) {
2559
2761
  return void 0;
2560
2762
  }
2561
- return decodeCborJsonCompat(value);
2763
+ return decodeCborCompat(value);
2562
2764
  }
2563
2765
  function encodeValue(value) {
2564
2766
  return encodeCborCompat(value);
2565
2767
  }
2768
+ function normalizeArgs(value) {
2769
+ return Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value];
2770
+ }
2566
2771
  function unwrapTsfnPayload(error, payload) {
2567
2772
  if (error !== null && error !== void 0) {
2568
2773
  throw error;
@@ -2618,12 +2823,6 @@ function callNativeSync(invoke) {
2618
2823
  throw normalizeNativeBridgeError(error);
2619
2824
  }
2620
2825
  }
2621
- function actorAbortedError() {
2622
- return Object.assign(new Error("Actor aborted"), {
2623
- group: "actor",
2624
- code: "aborted"
2625
- });
2626
- }
2627
2826
  function isClosedTaskRegistrationError(error) {
2628
2827
  const metadata = error instanceof RivetError ? error.metadata : void 0;
2629
2828
  const metadataError = metadata && typeof metadata === "object" && "error" in metadata ? metadata.error : void 0;
@@ -2756,7 +2955,7 @@ function serializeWorkflowHistoryForJson(data) {
2756
2955
  return null;
2757
2956
  }
2758
2957
  const history = decodeWorkflowHistoryTransport(data);
2759
- return {
2958
+ return jsonSafe({
2760
2959
  nameRegistry: [...history.nameRegistry],
2761
2960
  entries: history.entries.map((entry) => ({
2762
2961
  id: entry.id,
@@ -2780,7 +2979,7 @@ function serializeWorkflowHistoryForJson(data) {
2780
2979
  ]
2781
2980
  )
2782
2981
  )
2783
- };
2982
+ });
2784
2983
  }
2785
2984
  function toHttpJsonCompatible(value) {
2786
2985
  return JSON.parse(
@@ -2831,45 +3030,7 @@ function wrapNativeCallback(callback) {
2831
3030
  }
2832
3031
  function decodeArgs(value) {
2833
3032
  const decoded = decodeValue(value);
2834
- return Array.isArray(decoded) ? decoded : decoded === void 0 ? [] : [decoded];
2835
- }
2836
- function createWriteThroughProxy(value, commit, beforeChange) {
2837
- if (!value || typeof value !== "object") {
2838
- return value;
2839
- }
2840
- const proxies = /* @__PURE__ */ new WeakMap();
2841
- const wrap = (target) => {
2842
- const cached = proxies.get(target);
2843
- if (cached) {
2844
- return cached;
2845
- }
2846
- const proxy = new Proxy(target, {
2847
- get(innerTarget, property, receiver) {
2848
- const result = Reflect.get(innerTarget, property, receiver);
2849
- return result && typeof result === "object" ? wrap(result) : result;
2850
- },
2851
- set(innerTarget, property, nextValue, receiver) {
2852
- beforeChange == null ? void 0 : beforeChange();
2853
- const updated = Reflect.set(
2854
- innerTarget,
2855
- property,
2856
- nextValue,
2857
- receiver
2858
- );
2859
- commit(value);
2860
- return updated;
2861
- },
2862
- deleteProperty(innerTarget, property) {
2863
- beforeChange == null ? void 0 : beforeChange();
2864
- const updated = Reflect.deleteProperty(innerTarget, property);
2865
- commit(value);
2866
- return updated;
2867
- }
2868
- });
2869
- proxies.set(target, proxy);
2870
- return proxy;
2871
- };
2872
- return wrap(value);
3033
+ return normalizeArgs(decoded);
2873
3034
  }
2874
3035
  function buildRequest(init) {
2875
3036
  const url = init.uri.startsWith("http") ? init.uri : new URL(init.uri, "http://127.0.0.1").toString();
@@ -2923,13 +3084,23 @@ var NativeConnAdapter = class {
2923
3084
  decodeValue(this.#runtime.connParams(this.#conn))
2924
3085
  );
2925
3086
  }
3087
+ [RAW_STATE_SYMBOL]() {
3088
+ return this.#readState();
3089
+ }
2926
3090
  get state() {
2927
3091
  const nextState = this.#readState();
2928
- return createWriteThroughProxy(nextState, (nextValue) => {
2929
- this.#writeState(nextValue, { writeNative: true });
2930
- });
3092
+ return createWriteThroughProxy(
3093
+ nextState,
3094
+ (nextValue) => {
3095
+ this.#writeState(nextValue, { writeNative: true });
3096
+ },
3097
+ (newValue) => {
3098
+ assertJsonCompatValue(newValue);
3099
+ }
3100
+ );
2931
3101
  }
2932
3102
  set state(value) {
3103
+ assertJsonCompatValue(value);
2933
3104
  this.#writeState(value, { writeNative: true });
2934
3105
  }
2935
3106
  initializeState(value) {
@@ -3281,44 +3452,23 @@ var NativeQueueAdapter = class {
3281
3452
  }
3282
3453
  }
3283
3454
  async waitForNamesAvailable(names, options) {
3284
- if (!(options == null ? void 0 : options.signal)) {
3455
+ const { token, cleanup } = await createCancellationTokenHandle(
3456
+ this.#runtime,
3457
+ options == null ? void 0 : options.signal
3458
+ );
3459
+ try {
3285
3460
  await callNative(
3286
3461
  () => this.#runtime.actorQueueWaitForNamesAvailable(
3287
3462
  this.#ctx,
3288
3463
  [...names],
3289
3464
  {
3290
3465
  timeoutMs: options == null ? void 0 : options.timeout
3291
- }
3466
+ },
3467
+ token
3292
3468
  )
3293
3469
  );
3294
- return;
3295
- }
3296
- const deadline = options.timeout === void 0 ? void 0 : Date.now() + options.timeout;
3297
- for (; ; ) {
3298
- if (options.signal.aborted) {
3299
- throw actorAbortedError();
3300
- }
3301
- const remainingTimeout = deadline === void 0 ? void 0 : Math.max(0, deadline - Date.now());
3302
- const sliceTimeout = remainingTimeout === void 0 ? 100 : Math.min(remainingTimeout, 100);
3303
- try {
3304
- await callNative(
3305
- () => this.#runtime.actorQueueWaitForNamesAvailable(
3306
- this.#ctx,
3307
- [...names],
3308
- {
3309
- timeoutMs: sliceTimeout
3310
- }
3311
- )
3312
- );
3313
- return;
3314
- } catch (error) {
3315
- if (error.group === "queue" && error.code === "timed_out") {
3316
- if (remainingTimeout === void 0 || remainingTimeout > 100) {
3317
- continue;
3318
- }
3319
- }
3320
- throw error;
3321
- }
3470
+ } finally {
3471
+ cleanup == null ? void 0 : cleanup();
3322
3472
  }
3323
3473
  }
3324
3474
  async enqueueAndWait(name, body, options) {
@@ -3388,7 +3538,7 @@ var NativeQueueAdapter = class {
3388
3538
  }
3389
3539
  yield message;
3390
3540
  } catch (error) {
3391
- if (isRivetErrorLike(error) && error.group === "actor" && error.code === "aborted") {
3541
+ if (isActorAbortedError(error)) {
3392
3542
  return;
3393
3543
  }
3394
3544
  throw error;
@@ -3753,6 +3903,68 @@ var TrackedWebSocketHandleAdapter = class {
3753
3903
  return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
3754
3904
  }
3755
3905
  };
3906
+ var NativeConnectionMap = class {
3907
+ #runtime;
3908
+ #ctx;
3909
+ #schemas;
3910
+ constructor(runtime, ctx, schemas) {
3911
+ this.#runtime = runtime;
3912
+ this.#ctx = ctx;
3913
+ this.#schemas = schemas;
3914
+ }
3915
+ #connToAdapter(conn) {
3916
+ return new NativeConnAdapter(
3917
+ this.#runtime,
3918
+ conn,
3919
+ this.#schemas,
3920
+ this.#ctx,
3921
+ (connId) => callNativeSync(
3922
+ () => this.#runtime.actorQueueHibernationRemoval(
3923
+ this.#ctx,
3924
+ connId
3925
+ )
3926
+ )
3927
+ );
3928
+ }
3929
+ get size() {
3930
+ return callNativeSync(() => this.#runtime.actorConns(this.#ctx)).length;
3931
+ }
3932
+ get(key) {
3933
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3934
+ const conn = conns.find((c) => this.#runtime.connId(c) === key);
3935
+ if (!conn) return void 0;
3936
+ return this.#connToAdapter(conn);
3937
+ }
3938
+ has(key) {
3939
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3940
+ return conns.some((c) => this.#runtime.connId(c) === key);
3941
+ }
3942
+ keys() {
3943
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3944
+ return conns.map((c) => this.#runtime.connId(c))[Symbol.iterator]();
3945
+ }
3946
+ values() {
3947
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3948
+ return conns.map((c) => this.#connToAdapter(c))[Symbol.iterator]();
3949
+ }
3950
+ entries() {
3951
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3952
+ return conns.map(
3953
+ (c) => [this.#runtime.connId(c), this.#connToAdapter(c)]
3954
+ )[Symbol.iterator]();
3955
+ }
3956
+ forEach(callback, thisArg) {
3957
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3958
+ for (const conn of conns) {
3959
+ const id = this.#runtime.connId(conn);
3960
+ callback.call(thisArg, this.#connToAdapter(conn), id, this);
3961
+ }
3962
+ }
3963
+ [Symbol.iterator]() {
3964
+ return this.entries();
3965
+ }
3966
+ [Symbol.toStringTag] = "NativeConnectionMap";
3967
+ };
3756
3968
  var ActorContextHandleAdapter = class {
3757
3969
  #runtime;
3758
3970
  #ctx;
@@ -3761,9 +3973,9 @@ var ActorContextHandleAdapter = class {
3761
3973
  #abortSignalCleanup;
3762
3974
  #client;
3763
3975
  #clientFactory;
3976
+ #connMap;
3764
3977
  #databaseProvider;
3765
3978
  #db;
3766
- #dbProxy;
3767
3979
  #dispatchCancelToken;
3768
3980
  #kv;
3769
3981
  #queue;
@@ -3806,30 +4018,22 @@ var ActorContextHandleAdapter = class {
3806
4018
  if (!this.#databaseProvider) {
3807
4019
  throw databaseNotConfiguredError();
3808
4020
  }
3809
- if (!this.#dbProxy) {
3810
- this.#dbProxy = new Proxy(
3811
- {},
3812
- {
3813
- get: (_target, property) => {
3814
- if (property === "then") {
3815
- return void 0;
3816
- }
3817
- return async (...args) => {
3818
- const client = await this.ensureDatabaseClient();
3819
- const value = Reflect.get(
3820
- client,
3821
- property
3822
- );
3823
- if (typeof value !== "function") {
3824
- return value;
3825
- }
3826
- return await value.apply(client, args);
3827
- };
3828
- }
3829
- }
3830
- );
4021
+ if (this.#db) {
4022
+ return this.#db;
3831
4023
  }
3832
- return this.#dbProxy;
4024
+ const runtimeState = getNativeRuntimeState(this.#runtime, this.#ctx);
4025
+ const cachedClient = runtimeState.databaseClient;
4026
+ if (cachedClient) {
4027
+ this.#db = cachedClient.client;
4028
+ return this.#db;
4029
+ }
4030
+ throw databaseClientNotReadyError();
4031
+ }
4032
+ [RAW_STATE_SYMBOL]() {
4033
+ if (!this.#stateEnabled) {
4034
+ throw stateNotEnabledError();
4035
+ }
4036
+ return this.#readState();
3833
4037
  }
3834
4038
  get state() {
3835
4039
  if (!this.#stateEnabled) {
@@ -3844,8 +4048,9 @@ var ActorContextHandleAdapter = class {
3844
4048
  (nextValue) => {
3845
4049
  this.#writeState(nextValue, { scheduleSave: true });
3846
4050
  },
3847
- () => {
4051
+ (newValue) => {
3848
4052
  this.#assertCanMutateState();
4053
+ assertJsonCompatValue(newValue);
3849
4054
  }
3850
4055
  );
3851
4056
  }
@@ -3856,6 +4061,7 @@ var ActorContextHandleAdapter = class {
3856
4061
  throw stateNotEnabledError();
3857
4062
  }
3858
4063
  this.#assertCanMutateState();
4064
+ assertJsonCompatValue(value);
3859
4065
  this.#writeState(value, { scheduleSave: true });
3860
4066
  }
3861
4067
  initializeState(value) {
@@ -3912,25 +4118,14 @@ var ActorContextHandleAdapter = class {
3912
4118
  return callNativeSync(() => this.#runtime.actorRegion(this.#ctx));
3913
4119
  }
3914
4120
  get conns() {
3915
- return new Map(
3916
- callNativeSync(() => this.#runtime.actorConns(this.#ctx)).map(
3917
- (conn) => [
3918
- this.#runtime.connId(conn),
3919
- new NativeConnAdapter(
3920
- this.#runtime,
3921
- conn,
3922
- this.#schemas,
3923
- this.#ctx,
3924
- (connId) => callNativeSync(
3925
- () => this.#runtime.actorQueueHibernationRemoval(
3926
- this.#ctx,
3927
- connId
3928
- )
3929
- )
3930
- )
3931
- ]
3932
- )
3933
- );
4121
+ if (!this.#connMap) {
4122
+ this.#connMap = new NativeConnectionMap(
4123
+ this.#runtime,
4124
+ this.#ctx,
4125
+ this.#schemas
4126
+ );
4127
+ }
4128
+ return this.#connMap;
3934
4129
  }
3935
4130
  get log() {
3936
4131
  return logger2();
@@ -4151,7 +4346,10 @@ var ActorContextHandleAdapter = class {
4151
4346
  }
4152
4347
  internalKeepAwake(run) {
4153
4348
  const promise = typeof run === "function" ? run() : run;
4154
- const trackedPromise = promise.then(() => null);
4349
+ const trackedPromise = promise.then(
4350
+ () => null,
4351
+ () => null
4352
+ );
4155
4353
  try {
4156
4354
  callNativeSync(
4157
4355
  () => this.#runtime.actorRegisterTask(this.#ctx, trackedPromise)
@@ -4207,6 +4405,7 @@ var ActorContextHandleAdapter = class {
4207
4405
  return false;
4208
4406
  }
4209
4407
  sleep() {
4408
+ this.#flushStateChange();
4210
4409
  callNativeSync(() => this.#runtime.actorSleep(this.#ctx));
4211
4410
  }
4212
4411
  destroy() {
@@ -4467,7 +4666,7 @@ function withConnContext(runtime, ctx, conn, clientFactory, schemas = {}, databa
4467
4666
  }
4468
4667
  );
4469
4668
  }
4470
- function buildActorConfig(definition, registryConfig) {
4669
+ function buildActorConfig(definition, registryConfig, runtimeKind) {
4471
4670
  const config = definition.config;
4472
4671
  const options = config.options ?? {};
4473
4672
  const canHibernate = options.canHibernateWebSocket;
@@ -4496,9 +4695,79 @@ function buildActorConfig(definition, registryConfig) {
4496
4695
  maxOutgoingMessageSize: registryConfig.maxOutgoingMessageSize,
4497
4696
  preloadMaxWorkflowBytes: options.preloadMaxWorkflowBytes,
4498
4697
  preloadMaxConnectionsBytes: options.preloadMaxConnectionsBytes,
4499
- actions: Object.keys(config.actions ?? {}).sort().map((name) => ({ name }))
4698
+ actions: Object.keys(config.actions ?? {}).sort().map((name) => ({ name })),
4699
+ inspectorTabs: buildInspectorTabs(config.inspector, runtimeKind)
4500
4700
  };
4501
4701
  }
4702
+ function buildInspectorTabs(inspector, runtimeKind) {
4703
+ if (!inspector || typeof inspector !== "object") return void 0;
4704
+ const tabs = inspector.tabs;
4705
+ if (!Array.isArray(tabs) || tabs.length === 0) return void 0;
4706
+ return tabs.map((raw) => {
4707
+ const entry = raw;
4708
+ if (entry.hidden === true) {
4709
+ return { id: entry.id, hidden: true };
4710
+ }
4711
+ if (runtimeKind === "wasm") {
4712
+ if (entry.source !== void 0) {
4713
+ logger2().warn(
4714
+ {
4715
+ tabId: entry.id,
4716
+ runtimeKind
4717
+ },
4718
+ "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."
4719
+ );
4720
+ }
4721
+ return {
4722
+ id: entry.id,
4723
+ label: entry.label,
4724
+ icon: entry.icon,
4725
+ source: void 0
4726
+ };
4727
+ }
4728
+ const resolved = entry.source !== void 0 ? getNodePath().resolve(entry.source) : void 0;
4729
+ if (resolved !== void 0) {
4730
+ validateInspectorTabSource(entry.id, resolved);
4731
+ }
4732
+ return {
4733
+ id: entry.id,
4734
+ label: entry.label,
4735
+ icon: entry.icon,
4736
+ source: resolved
4737
+ };
4738
+ });
4739
+ }
4740
+ function validateInspectorTabSource(tabId, resolved) {
4741
+ if (resolved === getNodePath().parse(resolved).root) {
4742
+ throw new Error(
4743
+ `inspector.tabs[id="${tabId}"].source resolves to the filesystem root (${resolved}). Point it at the tab's own static-asset directory instead.`
4744
+ );
4745
+ }
4746
+ let stat;
4747
+ try {
4748
+ stat = getNodeFsSync().statSync(resolved);
4749
+ } catch (err) {
4750
+ const code = err == null ? void 0 : err.code;
4751
+ if (code === "ENOENT") {
4752
+ throw new Error(
4753
+ `inspector.tabs[id="${tabId}"].source (${resolved}) does not exist.`
4754
+ );
4755
+ }
4756
+ if (code === "EACCES") {
4757
+ throw new Error(
4758
+ `inspector.tabs[id="${tabId}"].source (${resolved}) is not readable (EACCES).`
4759
+ );
4760
+ }
4761
+ throw new Error(
4762
+ `inspector.tabs[id="${tabId}"].source (${resolved}) could not be stat'd: ${(err == null ? void 0 : err.message) ?? err}`
4763
+ );
4764
+ }
4765
+ if (!stat.isDirectory()) {
4766
+ throw new Error(
4767
+ `inspector.tabs[id="${tabId}"].source (${resolved}) must be a directory, got ${stat.isFile() ? "file" : "non-directory"}.`
4768
+ );
4769
+ }
4770
+ }
4502
4771
  function buildNativeFactory(runtime, registryConfig, definition) {
4503
4772
  var _a;
4504
4773
  const config = definition.config;
@@ -4590,13 +4859,16 @@ function buildNativeFactory(runtime, registryConfig, definition) {
4590
4859
  }
4591
4860
  );
4592
4861
  };
4593
- try {
4594
- await runtime.actorVerifyInspectorAuth(
4595
- ctx,
4596
- ((_a2 = jsRequest.headers.get("authorization")) == null ? void 0 : _a2.replace(/^Bearer\s+/i, "")) ?? null
4597
- );
4598
- } catch (error) {
4599
- return errorResponse(error, 401);
4862
+ const isPublicPerActorPath = jsRequest.method === "GET" && (url.pathname === "/inspector/tab-config" || url.pathname.startsWith("/inspector/custom-tabs/"));
4863
+ if (!isPublicPerActorPath) {
4864
+ try {
4865
+ await runtime.actorVerifyInspectorAuth(
4866
+ ctx,
4867
+ ((_a2 = jsRequest.headers.get("authorization")) == null ? void 0 : _a2.replace(/^Bearer\s+/i, "")) ?? null
4868
+ );
4869
+ } catch (error) {
4870
+ return errorResponse(error, 401);
4871
+ }
4600
4872
  }
4601
4873
  const workflowHistory = () => {
4602
4874
  var _a3;
@@ -4687,6 +4959,10 @@ function buildNativeFactory(runtime, registryConfig, definition) {
4687
4959
  isWorkflowEnabled: getNativeWorkflowInspector(ctx) !== void 0
4688
4960
  });
4689
4961
  } catch (error) {
4962
+ logger2().error({
4963
+ msg: "error replaying workflow history",
4964
+ error
4965
+ });
4690
4966
  return errorResponse(error);
4691
4967
  }
4692
4968
  }
@@ -4827,17 +5103,34 @@ function buildNativeFactory(runtime, registryConfig, definition) {
4827
5103
  );
4828
5104
  }
4829
5105
  const body = await jsRequest.json();
5106
+ if (body.args !== void 0 && body.properties !== void 0) {
5107
+ return jsonResponse(
5108
+ { error: "use either args or properties, not both" },
5109
+ { status: 400 }
5110
+ );
5111
+ }
5112
+ if (body.properties !== void 0 && (body.properties === null || typeof body.properties !== "object" || Array.isArray(body.properties))) {
5113
+ return jsonResponse(
5114
+ { error: "properties must be an object" },
5115
+ { status: 400 }
5116
+ );
5117
+ }
5118
+ const args = body.properties !== void 0 ? [body.properties] : normalizeArgs(body.args);
4830
5119
  try {
4831
5120
  const output = await action(
4832
5121
  actorCtx,
4833
5122
  ...validateActionArgs(
4834
5123
  schemaConfig.actionInputSchemas,
4835
5124
  actionName,
4836
- body.args ?? []
5125
+ args
4837
5126
  )
4838
5127
  );
4839
5128
  return jsonResponse({ output });
4840
5129
  } catch (error) {
5130
+ logger2().error({
5131
+ msg: "Error handling inspector action request",
5132
+ error
5133
+ });
4841
5134
  return errorResponse(error);
4842
5135
  }
4843
5136
  }
@@ -4851,6 +5144,10 @@ function buildNativeFactory(runtime, registryConfig, definition) {
4851
5144
  { status: 404 }
4852
5145
  );
4853
5146
  } catch (error) {
5147
+ logger2().error({
5148
+ msg: "Error handling inspector request",
5149
+ error
5150
+ });
4854
5151
  return errorResponse(error);
4855
5152
  } finally {
4856
5153
  await actorCtx.dispose();
@@ -4973,24 +5270,30 @@ function buildNativeFactory(runtime, registryConfig, definition) {
4973
5270
  async (error, payload) => {
4974
5271
  const { ctx } = unwrapTsfnPayload(error, payload);
4975
5272
  const actorCtx = makeActorCtx(ctx);
5273
+ const saveActorState = async () => {
5274
+ if (runtime.kind === "wasm") {
5275
+ await runtime.actorSaveState(
5276
+ ctx,
5277
+ actorCtx.serializeForTick("save")
5278
+ );
5279
+ } else {
5280
+ await actorCtx.saveState({
5281
+ immediate: true
5282
+ });
5283
+ }
5284
+ };
4976
5285
  try {
4977
5286
  if (onSleep) {
4978
- try {
4979
- await onSleep(actorCtx);
4980
- } finally {
4981
- if (runtime.kind === "wasm") {
4982
- await runtime.actorSaveState(
4983
- ctx,
4984
- actorCtx.serializeForTick("save")
4985
- );
4986
- } else {
4987
- await actorCtx.saveState({ immediate: true });
4988
- }
4989
- }
5287
+ await onSleep(actorCtx);
4990
5288
  }
5289
+ await saveActorState();
4991
5290
  } finally {
4992
5291
  try {
4993
- await cleanupNativeSleepRuntimeState(runtime, ctx);
5292
+ await cleanupNativeSleepRuntimeState(
5293
+ runtime,
5294
+ ctx,
5295
+ saveActorState
5296
+ );
4994
5297
  } finally {
4995
5298
  await actorCtx.dispose();
4996
5299
  }
@@ -5006,6 +5309,9 @@ function buildNativeFactory(runtime, registryConfig, definition) {
5006
5309
  await config.onDestroy(actorCtx);
5007
5310
  }
5008
5311
  } finally {
5312
+ const actorId = callNativeSync(() => runtime.actorId(ctx));
5313
+ nativeRunHandlerActiveByActorId.delete(actorId);
5314
+ disposeRunInspector(config.run, actorId);
5009
5315
  resolveNativeDestroy(runtime, ctx);
5010
5316
  await actorCtx.closeDatabase();
5011
5317
  clearNativeRuntimeState(runtime, ctx);
@@ -5279,7 +5585,7 @@ function buildNativeFactory(runtime, registryConfig, definition) {
5279
5585
  try {
5280
5586
  await run(actorCtx);
5281
5587
  } finally {
5282
- nativeRunHandlerActiveByActorId.set(actorId, false);
5588
+ nativeRunHandlerActiveByActorId.delete(actorId);
5283
5589
  await actorCtx.dispose();
5284
5590
  }
5285
5591
  }
@@ -5412,7 +5718,7 @@ function buildNativeFactory(runtime, registryConfig, definition) {
5412
5718
  };
5413
5719
  return runtime.createActorFactory(
5414
5720
  callbacks,
5415
- buildActorConfig(definition, registryConfig)
5721
+ buildActorConfig(definition, registryConfig, runtime.kind)
5416
5722
  );
5417
5723
  }
5418
5724
  async function buildServeConfig(config) {
@@ -5435,10 +5741,17 @@ async function buildServeConfig(config) {
5435
5741
  serverlessValidateEndpoint: config.validateServerlessEndpoint,
5436
5742
  serverlessMaxStartPayloadBytes: config.serverless.maxStartPayloadBytes
5437
5743
  };
5438
- if (config.startEngine) {
5744
+ try {
5439
5745
  const { getEnginePath } = await loadEngineCli();
5440
5746
  serveConfig.engineBinaryPath = getEnginePath();
5747
+ } catch (error) {
5748
+ logger2().warn({
5749
+ msg: "could not resolve a local engine binary; if a local engine must be spawned it will fail with engine.binary_unavailable \u2014 set RIVET_ENGINE_BINARY_PATH or install the @rivetkit/engine-cli platform package",
5750
+ error: stringifyError(error)
5751
+ });
5441
5752
  }
5753
+ serveConfig.engineHost = config.engineHost;
5754
+ serveConfig.enginePort = config.enginePort;
5442
5755
  if ((_a = config.test) == null ? void 0 : _a.enabled) {
5443
5756
  serveConfig.inspectorTestToken = getEnvUniversal("_RIVET_TEST_INSPECTOR_TOKEN") ?? "token";
5444
5757
  }
@@ -5449,6 +5762,9 @@ async function buildRegistryWithRuntime(config, runtime) {
5449
5762
  if (((_a = config.test) == null ? void 0 : _a.enabled) && getEnvUniversal("_RIVET_TEST_INSPECTOR_TOKEN") === void 0) {
5450
5763
  trySetProcessEnv("_RIVET_TEST_INSPECTOR_TOKEN", "token");
5451
5764
  }
5765
+ if (runtime.kind === "napi") {
5766
+ importNodeDependencies();
5767
+ }
5452
5768
  const registry = runtime.createRegistry();
5453
5769
  for (const [name, definition] of Object.entries(config.use)) {
5454
5770
  runtime.registerActor(
@@ -5488,6 +5804,7 @@ function finishShutdownSignal(signal) {
5488
5804
  }
5489
5805
  var Registry = class {
5490
5806
  #config;
5807
+ #buildConfiguredRegistry;
5491
5808
  routes;
5492
5809
  get config() {
5493
5810
  return this.#config;
@@ -5503,23 +5820,30 @@ var Registry = class {
5503
5820
  #shutdownInstalled = false;
5504
5821
  #shutdownInFlight = null;
5505
5822
  #signalHandlers = {};
5506
- constructor(config) {
5823
+ constructor(config, deps) {
5507
5824
  this.#config = config;
5825
+ this.#buildConfiguredRegistry = (deps == null ? void 0 : deps.buildConfiguredRegistry) ?? buildConfiguredRegistry;
5508
5826
  this.routes = {
5509
5827
  health: () => this.#healthRoute(),
5510
5828
  metadata: () => this.#metadataRoute(),
5511
5829
  prometheusMetrics: (request) => this.#prometheusMetricsRoute(request)
5512
5830
  };
5513
5831
  }
5832
+ /**
5833
+ * Fires `configureServerlessPool` once per process when the registry
5834
+ * config opts into it. Cached on the instance so repeated calls (from
5835
+ * `handler()` and `listen()`) only run the upsert once. The retry loop
5836
+ * inside `configureServerlessPool` tolerates the engine still warming up.
5837
+ */
5514
5838
  #ensureServerlessPoolConfigured(config) {
5515
5839
  if (!config.configurePool) return void 0;
5516
5840
  if (!this.#configureServerlessPoolPromise) {
5517
- this.#configureServerlessPoolPromise = configureServerlessPool(config).catch(
5518
- (error) => {
5519
- this.#configureServerlessPoolPromise = void 0;
5520
- throw error;
5521
- }
5522
- );
5841
+ this.#configureServerlessPoolPromise = configureServerlessPool(
5842
+ config
5843
+ ).catch((error) => {
5844
+ this.#configureServerlessPoolPromise = void 0;
5845
+ throw error;
5846
+ });
5523
5847
  this.#configureServerlessPoolPromise.catch(() => {
5524
5848
  });
5525
5849
  }
@@ -5540,7 +5864,7 @@ var Registry = class {
5540
5864
  const config = this.parseConfig();
5541
5865
  this.#printWelcome(config, "serverless");
5542
5866
  if (!this.#runtimeServerlessPromise) {
5543
- this.#runtimeServerlessPromise = buildConfiguredRegistry(config);
5867
+ this.#runtimeServerlessPromise = this.#buildConfiguredRegistry(config);
5544
5868
  }
5545
5869
  const { runtime, registry, serveConfig } = await this.#runtimeServerlessPromise;
5546
5870
  const isStartRequest = isServerlessStartRequest(
@@ -5555,7 +5879,7 @@ var Registry = class {
5555
5879
  if (isStartRequest) {
5556
5880
  try {
5557
5881
  await this.#ensureServerlessPoolConfigured(config);
5558
- } catch (error) {
5882
+ } catch (_error) {
5559
5883
  return new Response(
5560
5884
  JSON.stringify({
5561
5885
  group: "guard",
@@ -5669,7 +5993,7 @@ var Registry = class {
5669
5993
  if (isMetadataRequest && !isEngineMetadataRequest) {
5670
5994
  try {
5671
5995
  await this.#ensureServerlessPoolConfigured(config);
5672
- } catch (error) {
5996
+ } catch (_error) {
5673
5997
  return new Response(
5674
5998
  JSON.stringify({
5675
5999
  group: "guard",
@@ -5702,6 +6026,44 @@ var Registry = class {
5702
6026
  fetch: (request) => this.handler(request)
5703
6027
  };
5704
6028
  }
6029
+ /**
6030
+ * Bind an HTTP listener provided by the native (Rust) runtime and serve
6031
+ * the registry's serverless endpoints over it. Resolves only after the
6032
+ * registry is shut down (SIGINT/SIGTERM or `nativeRegistry.shutdown()`).
6033
+ *
6034
+ * @param opts.port Port to listen on. Defaults to `process.env.RIVET_PORT`
6035
+ * if set, otherwise 3000.
6036
+ * @param opts.host Address to bind. Defaults to `0.0.0.0`.
6037
+ * @param opts.publicDir If set, serves static files from this directory
6038
+ * as a fallback below the framework routes.
6039
+ *
6040
+ * @example
6041
+ * ```ts
6042
+ * await registry.listen();
6043
+ * await registry.listen({ port: 8080, publicDir: "./public" });
6044
+ * ```
6045
+ */
6046
+ async listen(opts = {}) {
6047
+ const port = opts.port ?? parsePortEnv(process.env.RIVET_PORT) ?? 3e3;
6048
+ const publicDir = opts.publicDir ?? getRivetkitPublicDir();
6049
+ const config = this.parseConfig();
6050
+ const configuredRegistryPromise = buildConfiguredRegistry(config);
6051
+ this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
6052
+ this.#runtimeServerlessPromise = configuredRegistryPromise;
6053
+ this.#installSignalHandlers(config);
6054
+ this.#printWelcome(config, "serverless", {
6055
+ port,
6056
+ host: opts.host,
6057
+ publicDir
6058
+ });
6059
+ this.#ensureServerlessPoolConfigured(config);
6060
+ const { runtime, registry, serveConfig } = await configuredRegistryPromise;
6061
+ await runtime.serveListener(
6062
+ registry,
6063
+ { port, host: opts.host, publicDir },
6064
+ serveConfig
6065
+ );
6066
+ }
5705
6067
  /**
5706
6068
  * Returns a health response suitable for mounting in a user-owned router.
5707
6069
  */
@@ -5791,20 +6153,20 @@ var Registry = class {
5791
6153
  */
5792
6154
  #startEnvoy(config, printWelcome) {
5793
6155
  if (!this.#runtimeServePromise) {
5794
- const configuredRegistryPromise = buildConfiguredRegistry(config);
6156
+ const configuredRegistryPromise = this.#buildConfiguredRegistry(config);
5795
6157
  this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
5796
6158
  this.#runtimeServePromise = configuredRegistryPromise.then(async ({ runtime, registry, serveConfig }) => {
5797
6159
  await runtime.serveRegistry(registry, serveConfig);
5798
- }).catch((err) => {
5799
- logger2().warn({ err }, "runtime registry serve errored");
6160
+ }).catch((error) => {
6161
+ logger2().warn({ error }, "runtime registry serve errored");
5800
6162
  });
5801
- this.#installSignalHandlers(config, configuredRegistryPromise);
6163
+ this.#installSignalHandlers(config);
5802
6164
  }
5803
6165
  if (printWelcome) {
5804
6166
  this.#printWelcome(config, "serverful");
5805
6167
  }
5806
6168
  }
5807
- #installSignalHandlers(config, configuredRegistryPromise) {
6169
+ #installSignalHandlers(config) {
5808
6170
  var _a;
5809
6171
  if (this.#shutdownInstalled) return;
5810
6172
  if ((_a = config.shutdown) == null ? void 0 : _a.disableSignalHandlers) return;
@@ -5813,58 +6175,86 @@ var Registry = class {
5813
6175
  }
5814
6176
  this.#shutdownInstalled = true;
5815
6177
  const install = (signal) => {
5816
- const handler = () => this.#onShutdownSignal(
5817
- signal,
5818
- config,
5819
- configuredRegistryPromise
5820
- );
6178
+ const handler = () => this.#onShutdownSignal(signal, config);
5821
6179
  this.#signalHandlers[signal] = handler;
5822
6180
  process.on(signal, handler);
5823
6181
  };
5824
6182
  install("SIGINT");
5825
6183
  install("SIGTERM");
5826
6184
  }
5827
- #onShutdownSignal(signal, config, configuredRegistryPromise) {
6185
+ #onShutdownSignal(signal, config) {
5828
6186
  if (this.#shutdownInFlight !== null) {
5829
6187
  this.#removeSignalHandlers();
5830
6188
  finishShutdownSignal(signal);
5831
6189
  return;
5832
6190
  }
5833
- this.#shutdownInFlight = this.#runShutdown(
5834
- signal,
5835
- config,
5836
- configuredRegistryPromise
5837
- ).catch((err) => {
6191
+ this.#shutdownInFlight = this.#drain(config).catch((err) => {
5838
6192
  logger2().warn({ err }, "shutdown error");
6193
+ }).then(() => {
6194
+ this.#removeSignalHandlers();
6195
+ finishShutdownSignal(signal);
5839
6196
  });
5840
6197
  }
5841
- async #runShutdown(signal, config, configuredRegistryPromise) {
6198
+ /**
6199
+ * Gracefully drains all live registries.
6200
+ *
6201
+ * Programmatic counterpart to the SIGINT/SIGTERM handlers: tears down
6202
+ * every live `CoreRegistry` (both `start()` and `handler()` modes) and
6203
+ * waits for the serve promise to resolve, all bounded by the shutdown
6204
+ * grace period. Unlike a signal-driven shutdown, this does not re-raise a
6205
+ * signal or exit the process. The caller owns process lifetime.
6206
+ *
6207
+ * Idempotent: concurrent or repeated calls share a single drain. Safe to
6208
+ * call even if nothing has been started.
6209
+ *
6210
+ * @example
6211
+ * ```ts
6212
+ * const registry = setup({ use: { counter } });
6213
+ * registry.start();
6214
+ * // ...later, on your own shutdown trigger:
6215
+ * await registry.shutdown();
6216
+ * ```
6217
+ */
6218
+ async shutdown() {
6219
+ if (this.#shutdownInFlight !== null) return this.#shutdownInFlight;
6220
+ const config = this.parseConfig();
6221
+ this.#removeSignalHandlers();
6222
+ this.#shutdownInFlight = this.#drain(config).catch((err) => {
6223
+ logger2().warn({ err }, "shutdown error");
6224
+ });
6225
+ return this.#shutdownInFlight;
6226
+ }
6227
+ async #drain(config) {
5842
6228
  var _a;
5843
- const gracePeriodMs = ((_a = config.shutdown) == null ? void 0 : _a.gracePeriodMs) ?? await this.#actorStopThresholdMs(configuredRegistryPromise) ?? 30 * 60 * 1e3;
6229
+ const modeAPromise = this.#runtimeServeConfiguredPromise;
6230
+ const modeBPromise = this.#runtimeServerlessPromise;
6231
+ const gracePeriodMs = ((_a = config.shutdown) == null ? void 0 : _a.gracePeriodMs) ?? await this.#actorStopThresholdMs(modeAPromise ?? modeBPromise) ?? 30 * 60 * 1e3;
5844
6232
  const drain = async () => {
5845
- const registries = [
5846
- (async () => {
5847
- try {
5848
- const { runtime, registry } = await configuredRegistryPromise;
5849
- await runtime.shutdownRegistry(registry);
5850
- } catch (err) {
5851
- logger2().warn(
5852
- { err },
5853
- "runtime registry shutdown errored (mode A)"
5854
- );
5855
- }
5856
- })()
5857
- ];
5858
- const runtimeServerlessPromise = this.#runtimeServerlessPromise;
5859
- if (runtimeServerlessPromise !== void 0) {
6233
+ const registries = [];
6234
+ if (modeAPromise !== void 0) {
5860
6235
  registries.push(
5861
6236
  (async () => {
5862
6237
  try {
5863
- const { runtime, registry } = await runtimeServerlessPromise;
6238
+ const { runtime, registry } = await modeAPromise;
5864
6239
  await runtime.shutdownRegistry(registry);
5865
6240
  } catch (err) {
5866
6241
  logger2().warn(
5867
6242
  { err },
6243
+ "runtime registry shutdown errored (mode A)"
6244
+ );
6245
+ }
6246
+ })()
6247
+ );
6248
+ }
6249
+ if (modeBPromise !== void 0) {
6250
+ registries.push(
6251
+ (async () => {
6252
+ try {
6253
+ const { runtime, registry } = await modeBPromise;
6254
+ await runtime.shutdownRegistry(registry);
6255
+ } catch (err) {
6256
+ logger2().warn(
6257
+ { error: err },
5868
6258
  "runtime registry shutdown errored (mode B)"
5869
6259
  );
5870
6260
  }
@@ -5886,11 +6276,10 @@ var Registry = class {
5886
6276
  }
5887
6277
  )
5888
6278
  ]);
5889
- this.#removeSignalHandlers();
5890
- finishShutdownSignal(signal);
5891
6279
  }
5892
6280
  async #actorStopThresholdMs(configuredRegistryPromise) {
5893
6281
  var _a;
6282
+ if (configuredRegistryPromise === void 0) return void 0;
5894
6283
  try {
5895
6284
  const { runtime, registry } = await configuredRegistryPromise;
5896
6285
  const thresholdMs = await ((_a = runtime.registryActorStopThresholdMs) == null ? void 0 : _a.call(runtime, registry));
@@ -5919,6 +6308,10 @@ var Registry = class {
5919
6308
  /**
5920
6309
  * Starts the actor envoy for standalone server deployments.
5921
6310
  *
6311
+ * Set `RIVETKIT_RUNTIME_MODE=serverless` to instead bind an HTTP listener
6312
+ * via `listen()` (Mode B). Mode A (envoy) and Mode B (listener) are
6313
+ * mutually exclusive per registry instance.
6314
+ *
5922
6315
  * @example
5923
6316
  * ```ts
5924
6317
  * const registry = setup({ use: { counter } });
@@ -5926,10 +6319,20 @@ var Registry = class {
5926
6319
  * ```
5927
6320
  */
5928
6321
  start() {
6322
+ if (getRivetkitRuntimeMode() === "serverless") {
6323
+ const publicDir = getRivetkitPublicDir() ?? "/public";
6324
+ this.listen({ publicDir }).catch((error) => {
6325
+ logger2().error({ error }, "auto-listen failed; exiting");
6326
+ if (typeof process !== "undefined" && typeof process.exit === "function") {
6327
+ process.exit(1);
6328
+ }
6329
+ });
6330
+ return;
6331
+ }
5929
6332
  const config = this.parseConfig();
5930
6333
  this.#startEnvoy(config, true);
5931
6334
  }
5932
- #printWelcome(config, kind) {
6335
+ #printWelcome(config, kind, listener) {
5933
6336
  if (config.noWelcome || this.#welcomePrinted) return;
5934
6337
  this.#welcomePrinted = true;
5935
6338
  const logLine = (label, value) => {
@@ -5944,13 +6347,20 @@ var Registry = class {
5944
6347
  logLine("Namespace", config.namespace);
5945
6348
  }
5946
6349
  if (config.endpoint) {
5947
- const endpointType = config.endpoint === ENGINE_ENDPOINT ? "local native" : "remote";
6350
+ const endpointType = config.startEngine || isLocalEngineEndpoint(config.endpoint) ? "local native" : "remote";
5948
6351
  logLine("Endpoint", `${config.endpoint} (${endpointType})`);
5949
6352
  }
5950
6353
  if (kind === "serverless" && config.publicEndpoint) {
5951
6354
  logLine("Client", config.publicEndpoint);
5952
6355
  }
5953
6356
  logLine("Actors", Object.keys(config.use).length.toString());
6357
+ if (listener) {
6358
+ const host = listener.host ?? "0.0.0.0";
6359
+ logLine("Listening", `http://${host}:${listener.port}`);
6360
+ if (listener.publicDir) {
6361
+ logLine("Public Dir", listener.publicDir);
6362
+ }
6363
+ }
5954
6364
  console.log();
5955
6365
  }
5956
6366
  };