rivetkit 2.3.0-rc.8 → 2.3.0

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 (221) hide show
  1. package/dist/browser/client.d.ts +481 -74
  2. package/dist/browser/client.js +174 -148
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +47 -18
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/actor/errors.cjs +2 -2
  7. package/dist/tsup/actor/errors.d.cts +1 -1
  8. package/dist/tsup/actor/errors.d.ts +1 -1
  9. package/dist/tsup/actor/errors.js +1 -1
  10. package/dist/tsup/agent-os/index.cjs +2160 -2086
  11. package/dist/tsup/agent-os/index.cjs.map +1 -1
  12. package/dist/tsup/agent-os/index.d.cts +479 -73
  13. package/dist/tsup/agent-os/index.d.ts +479 -73
  14. package/dist/tsup/agent-os/index.js +2160 -2086
  15. package/dist/tsup/agent-os/index.js.map +1 -1
  16. package/dist/tsup/{chunk-KY3CERZR.js → chunk-2OTRTA3J.js} +7 -21
  17. package/dist/tsup/chunk-2OTRTA3J.js.map +1 -0
  18. package/dist/tsup/{chunk-HGW6PBWR.cjs → chunk-3677IIOV.cjs} +11 -25
  19. package/dist/tsup/chunk-3677IIOV.cjs.map +1 -0
  20. package/dist/tsup/{chunk-OT7FF6GB.cjs → chunk-47HHIEXH.cjs} +24 -9
  21. package/dist/tsup/chunk-47HHIEXH.cjs.map +1 -0
  22. package/dist/tsup/{chunk-EMFKMVJR.js → chunk-4JDSFJS5.js} +69 -58
  23. package/dist/tsup/chunk-4JDSFJS5.js.map +1 -0
  24. package/dist/tsup/{chunk-7HLFSAJP.cjs → chunk-7QKCIVAY.cjs} +225 -214
  25. package/dist/tsup/chunk-7QKCIVAY.cjs.map +1 -0
  26. package/dist/tsup/{chunk-AWTPTUQ7.cjs → chunk-B6VUNZUD.cjs} +10 -10
  27. package/dist/tsup/{chunk-AWTPTUQ7.cjs.map → chunk-B6VUNZUD.cjs.map} +1 -1
  28. package/dist/tsup/{chunk-D3T3ZBSY.js → chunk-BEI24WTI.js} +2 -2
  29. package/dist/tsup/{chunk-TMLOKTRB.js → chunk-BRP62GZC.js} +1 -1
  30. package/dist/tsup/chunk-BRP62GZC.js.map +1 -0
  31. package/dist/tsup/{chunk-D5G75T7J.js → chunk-DPIMKYNB.js} +61 -2
  32. package/dist/tsup/chunk-DPIMKYNB.js.map +1 -0
  33. package/dist/tsup/{chunk-BATTOVHF.cjs → chunk-DXXJPH55.cjs} +40 -13
  34. package/dist/tsup/chunk-DXXJPH55.cjs.map +1 -0
  35. package/dist/tsup/{chunk-3YY5S6TV.js → chunk-HXUEHHJF.js} +2 -2
  36. package/dist/tsup/chunk-HXUEHHJF.js.map +1 -0
  37. package/dist/tsup/{chunk-4BPKKZJO.cjs → chunk-I4LN3FNT.cjs} +10 -10
  38. package/dist/tsup/chunk-I4LN3FNT.cjs.map +1 -0
  39. package/dist/tsup/{chunk-PCBNKI2J.js → chunk-JZ7TWV65.js} +1 -1
  40. package/dist/tsup/chunk-JZ7TWV65.js.map +1 -0
  41. package/dist/tsup/{chunk-63WNTDRC.cjs → chunk-KORQB2IR.cjs} +1 -1
  42. package/dist/tsup/{chunk-63WNTDRC.cjs.map → chunk-KORQB2IR.cjs.map} +1 -1
  43. package/dist/tsup/{chunk-6TQSSJ4F.cjs → chunk-LVTBW2RE.cjs} +3 -3
  44. package/dist/tsup/{chunk-6TQSSJ4F.cjs.map → chunk-LVTBW2RE.cjs.map} +1 -1
  45. package/dist/tsup/{chunk-4JU3IPG2.js → chunk-MEHBWPLJ.js} +6 -6
  46. package/dist/tsup/chunk-MEHBWPLJ.js.map +1 -0
  47. package/dist/tsup/{chunk-SRNOPUC6.cjs → chunk-NIY3RSPX.cjs} +62 -3
  48. package/dist/tsup/chunk-NIY3RSPX.cjs.map +1 -0
  49. package/dist/tsup/{chunk-UZXQEGVJ.js → chunk-P2GNQ4RN.js} +4 -4
  50. package/dist/tsup/{chunk-UZXQEGVJ.js.map → chunk-P2GNQ4RN.js.map} +1 -1
  51. package/dist/tsup/{chunk-VUGENVIK.js → chunk-UMZVD6DQ.js} +22 -7
  52. package/dist/tsup/chunk-UMZVD6DQ.js.map +1 -0
  53. package/dist/tsup/{chunk-LD5YASJU.cjs → chunk-VE2X4KMG.cjs} +2 -2
  54. package/dist/tsup/{chunk-LD5YASJU.cjs.map → chunk-VE2X4KMG.cjs.map} +1 -1
  55. package/dist/tsup/{chunk-GBG63SUG.js → chunk-VTTFNQQI.js} +32 -5
  56. package/dist/tsup/chunk-VTTFNQQI.js.map +1 -0
  57. package/dist/tsup/{chunk-2NDZ7JCR.cjs → chunk-ZA7FLHKH.cjs} +1 -1
  58. package/dist/tsup/chunk-ZA7FLHKH.cjs.map +1 -0
  59. package/dist/tsup/client/mod.cjs +9 -9
  60. package/dist/tsup/client/mod.d.cts +5 -5
  61. package/dist/tsup/client/mod.d.ts +5 -5
  62. package/dist/tsup/client/mod.js +8 -8
  63. package/dist/tsup/common/log.cjs +3 -3
  64. package/dist/tsup/common/log.js +2 -2
  65. package/dist/tsup/common/websocket.cjs +4 -4
  66. package/dist/tsup/common/websocket.js +3 -3
  67. package/dist/tsup/{config-Ak1lv4gF.d.ts → config-BxWAw3iH.d.ts} +512 -27
  68. package/dist/tsup/{config-DU_xj4qZ.d.cts → config-CZQQ-mso.d.cts} +512 -27
  69. package/dist/tsup/{config-CxjGYf4K.d.ts → config-D49x8NpL.d.cts} +1 -2
  70. package/dist/tsup/{config-CxjGYf4K.d.cts → config-D49x8NpL.d.ts} +1 -2
  71. package/dist/tsup/{context-DAAp4Lpg.d.ts → context-Bw7xq8w3.d.cts} +8 -8
  72. package/dist/tsup/{context-Dt_L55q8.d.cts → context-D8QA76sV.d.ts} +8 -8
  73. package/dist/tsup/db/drizzle.cjs +3 -3
  74. package/dist/tsup/db/drizzle.d.cts +1 -1
  75. package/dist/tsup/db/drizzle.d.ts +1 -1
  76. package/dist/tsup/db/drizzle.js +1 -1
  77. package/dist/tsup/db/mod.cjs +2 -2
  78. package/dist/tsup/db/mod.d.cts +2 -2
  79. package/dist/tsup/db/mod.d.ts +2 -2
  80. package/dist/tsup/db/mod.js +1 -1
  81. package/dist/tsup/dynamic/mod.cjs +24 -0
  82. package/dist/tsup/dynamic/mod.cjs.map +1 -0
  83. package/dist/tsup/dynamic/mod.d.cts +37 -0
  84. package/dist/tsup/dynamic/mod.d.ts +37 -0
  85. package/dist/tsup/dynamic/mod.js +24 -0
  86. package/dist/tsup/dynamic/mod.js.map +1 -0
  87. package/dist/tsup/inspector/mod.cjs +6 -6
  88. package/dist/tsup/inspector/mod.js +5 -5
  89. package/dist/tsup/inspector-tab/mod.cjs +173 -0
  90. package/dist/tsup/inspector-tab/mod.cjs.map +1 -0
  91. package/dist/tsup/inspector-tab/mod.d.cts +250 -0
  92. package/dist/tsup/inspector-tab/mod.d.ts +250 -0
  93. package/dist/tsup/inspector-tab/mod.js +173 -0
  94. package/dist/tsup/inspector-tab/mod.js.map +1 -0
  95. package/dist/tsup/mod.cjs +615 -348
  96. package/dist/tsup/mod.cjs.map +1 -1
  97. package/dist/tsup/mod.d.cts +5 -5
  98. package/dist/tsup/mod.d.ts +5 -5
  99. package/dist/tsup/mod.js +511 -244
  100. package/dist/tsup/mod.js.map +1 -1
  101. package/dist/tsup/test/mod.cjs +21 -18
  102. package/dist/tsup/test/mod.cjs.map +1 -1
  103. package/dist/tsup/test/mod.d.cts +4 -4
  104. package/dist/tsup/test/mod.d.ts +4 -4
  105. package/dist/tsup/test/mod.js +18 -15
  106. package/dist/tsup/test/mod.js.map +1 -1
  107. package/dist/tsup/{utils-DVekpm4I.d.cts → utils-DQosb24I.d.cts} +1 -1
  108. package/dist/tsup/{utils-DVekpm4I.d.ts → utils-DQosb24I.d.ts} +1 -1
  109. package/dist/tsup/utils.cjs +3 -3
  110. package/dist/tsup/utils.d.cts +1 -1
  111. package/dist/tsup/utils.d.ts +1 -1
  112. package/dist/tsup/utils.js +2 -2
  113. package/dist/tsup/workflow/mod.cjs +279 -279
  114. package/dist/tsup/workflow/mod.cjs.map +1 -1
  115. package/dist/tsup/workflow/mod.d.cts +6 -6
  116. package/dist/tsup/workflow/mod.d.ts +6 -6
  117. package/dist/tsup/workflow/mod.js +380 -380
  118. package/dist/tsup/workflow/mod.js.map +1 -1
  119. package/package.json +29 -9
  120. package/src/actor/config.ts +156 -51
  121. package/src/actor/contexts/index.ts +7 -2
  122. package/src/actor/definition.ts +17 -19
  123. package/src/actor/driver.ts +3 -3
  124. package/src/actor/errors.ts +8 -2
  125. package/src/actor/instance/mod.ts +26 -34
  126. package/src/actor/keys.ts +1 -1
  127. package/src/actor/mod.ts +22 -20
  128. package/src/actor/schema.ts +2 -2
  129. package/src/agent-os/actor/index.ts +38 -18
  130. package/src/agent-os/actor/preview.ts +1 -2
  131. package/src/agent-os/config.ts +1 -1
  132. package/src/agent-os/fs/database-vfs.ts +1 -1
  133. package/src/agent-os/index.ts +16 -15
  134. package/src/client/actor-common.ts +87 -54
  135. package/src/client/actor-conn.ts +11 -11
  136. package/src/client/actor-handle.ts +69 -52
  137. package/src/client/actor-query.ts +5 -5
  138. package/src/client/errors.ts +1 -1
  139. package/src/client/lifecycle-errors.ts +2 -4
  140. package/src/client/query.ts +1 -1
  141. package/src/client/queue.ts +8 -4
  142. package/src/client/raw-utils.ts +8 -6
  143. package/src/client/resolve-gateway-target.ts +1 -1
  144. package/src/client/utils.ts +2 -6
  145. package/src/common/actor-websocket.ts +3 -1
  146. package/src/common/bare/actor-persist/v1.ts +205 -163
  147. package/src/common/bare/actor-persist/v2.ts +265 -213
  148. package/src/common/bare/actor-persist/v3.ts +176 -172
  149. package/src/common/bare/actor-persist/v4.ts +254 -253
  150. package/src/common/bare/transport/v1.ts +659 -543
  151. package/src/common/client-protocol-versioned.ts +66 -64
  152. package/src/common/database/config.ts +2 -8
  153. package/src/common/database/native-database.ts +1 -1
  154. package/src/common/database/shared.ts +1 -0
  155. package/src/common/encoding.ts +13 -17
  156. package/src/common/engine.ts +28 -1
  157. package/src/common/eventsource.ts +1 -1
  158. package/src/common/inline-websocket-adapter.ts +3 -2
  159. package/src/common/router.ts +13 -17
  160. package/src/common/utils.ts +1 -2
  161. package/src/common/websocket-interface.ts +1 -1
  162. package/src/db/mod.ts +1 -1
  163. package/src/devtools-loader/index.ts +4 -7
  164. package/src/devtools-loader/serve-devtools.ts +26 -0
  165. package/src/drivers/engine/actor-driver.ts +48 -46
  166. package/src/dynamic/instance.ts +32 -0
  167. package/src/dynamic/internal.ts +50 -0
  168. package/src/dynamic/isolate-runtime.ts +66 -0
  169. package/src/dynamic/mod.ts +32 -0
  170. package/src/engine-client/actor-http-client.ts +3 -3
  171. package/src/engine-client/actor-websocket-client.ts +5 -5
  172. package/src/engine-client/api-endpoints.ts +51 -2
  173. package/src/engine-client/api-utils.ts +2 -2
  174. package/src/engine-client/driver.ts +1 -1
  175. package/src/engine-client/mod.ts +5 -3
  176. package/src/engine-client/ws-proxy.ts +9 -4
  177. package/src/inspector/client.browser.ts +5 -11
  178. package/src/inspector/mod.ts +1 -3
  179. package/src/inspector-tab/mod.ts +315 -0
  180. package/src/registry/config/envoy.ts +1 -2
  181. package/src/registry/config/index.ts +40 -16
  182. package/src/registry/index.ts +226 -83
  183. package/src/registry/napi-runtime.ts +46 -12
  184. package/src/registry/native-validation.ts +10 -12
  185. package/src/registry/native.ts +307 -164
  186. package/src/registry/process-metrics.ts +90 -23
  187. package/src/registry/runtime.ts +53 -6
  188. package/src/registry/wasm-runtime.ts +30 -3
  189. package/src/serde.ts +1 -1
  190. package/src/serverless/configure.ts +18 -7
  191. package/src/test/mod.ts +11 -8
  192. package/src/utils/endpoint-parser.ts +1 -1
  193. package/src/utils/env-vars.ts +6 -0
  194. package/src/utils/router.ts +1 -1
  195. package/src/utils/serve.ts +4 -5
  196. package/src/utils.ts +1 -2
  197. package/src/workflow/context.ts +30 -29
  198. package/src/workflow/driver.ts +4 -6
  199. package/src/workflow/inspector.ts +2 -2
  200. package/src/workflow/mod.ts +15 -17
  201. package/dist/tsup/chunk-2NDZ7JCR.cjs.map +0 -1
  202. package/dist/tsup/chunk-3YY5S6TV.js.map +0 -1
  203. package/dist/tsup/chunk-4BPKKZJO.cjs.map +0 -1
  204. package/dist/tsup/chunk-4JU3IPG2.js.map +0 -1
  205. package/dist/tsup/chunk-7HLFSAJP.cjs.map +0 -1
  206. package/dist/tsup/chunk-BATTOVHF.cjs.map +0 -1
  207. package/dist/tsup/chunk-D5G75T7J.js.map +0 -1
  208. package/dist/tsup/chunk-EMFKMVJR.js.map +0 -1
  209. package/dist/tsup/chunk-GBG63SUG.js.map +0 -1
  210. package/dist/tsup/chunk-HGW6PBWR.cjs.map +0 -1
  211. package/dist/tsup/chunk-KY3CERZR.js.map +0 -1
  212. package/dist/tsup/chunk-OT7FF6GB.cjs.map +0 -1
  213. package/dist/tsup/chunk-PCBNKI2J.js.map +0 -1
  214. package/dist/tsup/chunk-SRNOPUC6.cjs.map +0 -1
  215. package/dist/tsup/chunk-TMLOKTRB.js.map +0 -1
  216. package/dist/tsup/chunk-VUGENVIK.js.map +0 -1
  217. package/dist/tsup/process-metrics-NW754INA.js +0 -118
  218. package/dist/tsup/process-metrics-NW754INA.js.map +0 -1
  219. package/dist/tsup/process-metrics-TYAGKCEJ.cjs +0 -118
  220. package/dist/tsup/process-metrics-TYAGKCEJ.cjs.map +0 -1
  221. /package/dist/tsup/{chunk-D3T3ZBSY.js.map → chunk-BEI24WTI.js.map} +0 -0
package/dist/tsup/mod.js CHANGED
@@ -1,3 +1,6 @@
1
+ import {
2
+ decodeWorkflowHistoryTransport
3
+ } from "./chunk-UMZVD6DQ.js";
1
4
  import {
2
5
  ACTOR_CONTEXT_INTERNAL_SYMBOL,
3
6
  ActorConfigSchema,
@@ -6,10 +9,7 @@ import {
6
9
  getRunFunction,
7
10
  getRunInspectorConfig,
8
11
  getRunMetadata
9
- } from "./chunk-D5G75T7J.js";
10
- import {
11
- decodeWorkflowHistoryTransport
12
- } from "./chunk-VUGENVIK.js";
12
+ } from "./chunk-DPIMKYNB.js";
13
13
  import {
14
14
  ALLOWED_PUBLIC_HEADERS,
15
15
  HEADER_CONN_PARAMS,
@@ -19,7 +19,7 @@ import {
19
19
  getDatacenters,
20
20
  tryParseEndpoint,
21
21
  updateRunnerConfig
22
- } from "./chunk-EMFKMVJR.js";
22
+ } from "./chunk-4JDSFJS5.js";
23
23
  import {
24
24
  KEYS,
25
25
  makePrefixedKey,
@@ -27,15 +27,14 @@ import {
27
27
  queueMetadataKey,
28
28
  removePrefixFromKey,
29
29
  workflowStoragePrefix
30
- } from "./chunk-3YY5S6TV.js";
30
+ } from "./chunk-HXUEHHJF.js";
31
31
  import {
32
32
  assertJsonCompatValue,
33
33
  decodeCborCompat,
34
- decodeCborJsonCompat,
35
34
  encodeCborCompat
36
- } from "./chunk-KY3CERZR.js";
37
- import "./chunk-PCBNKI2J.js";
38
- import "./chunk-D3T3ZBSY.js";
35
+ } from "./chunk-2OTRTA3J.js";
36
+ import "./chunk-JZ7TWV65.js";
37
+ import "./chunk-BEI24WTI.js";
39
38
  import {
40
39
  LogLevelSchema,
41
40
  VERSION,
@@ -52,6 +51,8 @@ import {
52
51
  getRivetPublicEndpoint,
53
52
  getRivetPublicToken,
54
53
  getRivetRunEngine,
54
+ getRivetRunEngineHost,
55
+ getRivetRunEnginePort,
55
56
  getRivetRunEngineVersion,
56
57
  getRivetToken,
57
58
  getRivetTotalSlots,
@@ -60,7 +61,7 @@ import {
60
61
  noopNext,
61
62
  stringifyError,
62
63
  toUint8Array
63
- } from "./chunk-GBG63SUG.js";
64
+ } from "./chunk-VTTFNQQI.js";
64
65
  import {
65
66
  INTERNAL_ERROR_CODE,
66
67
  RivetError,
@@ -71,7 +72,7 @@ import {
71
72
  isRivetErrorLike,
72
73
  toRivetError,
73
74
  unsupportedFeature
74
- } from "./chunk-TMLOKTRB.js";
75
+ } from "./chunk-BRP62GZC.js";
75
76
 
76
77
  // src/actor/log.ts
77
78
  function loggerWithoutContext() {
@@ -143,7 +144,7 @@ function hasSchemaConfigKey(schemas, key) {
143
144
  if (!schemas) {
144
145
  return false;
145
146
  }
146
- return Object.prototype.hasOwnProperty.call(schemas, key);
147
+ return Object.hasOwn(schemas, key);
147
148
  }
148
149
  function getEventCanSubscribe(schemas, key) {
149
150
  const schema = schemas == null ? void 0 : schemas[key];
@@ -204,8 +205,8 @@ function validateSchemaSync(schemas, key, data) {
204
205
  }
205
206
 
206
207
  // src/common/inline-websocket-adapter.ts
207
- import { WSContext } from "hono/ws";
208
208
  import { VirtualWebSocket } from "@rivetkit/virtual-websocket";
209
+ import { WSContext } from "hono/ws";
209
210
  function logger() {
210
211
  return getLogger("inline-websocket-adapter");
211
212
  }
@@ -361,8 +362,23 @@ var InlineWebSocketAdapter = class {
361
362
  import { Hono } from "hono";
362
363
 
363
364
  // src/common/engine.ts
365
+ var ENGINE_HOST = "127.0.0.1";
364
366
  var ENGINE_PORT = 6420;
365
- var ENGINE_ENDPOINT = `http://127.0.0.1:${ENGINE_PORT}`;
367
+ var ENGINE_ENDPOINT = buildEngineEndpoint(ENGINE_HOST, ENGINE_PORT);
368
+ function buildEngineEndpoint(host, port) {
369
+ const urlHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
370
+ return `http://${urlHost}:${port}`;
371
+ }
372
+ function isLocalEngineEndpoint(endpoint) {
373
+ let url;
374
+ try {
375
+ url = new URL(endpoint);
376
+ } catch {
377
+ return false;
378
+ }
379
+ const hostname = url.hostname.toLowerCase();
380
+ return hostname === "localhost" || hostname === "0.0.0.0" || hostname === "::" || hostname === "[::]" || hostname === "::1" || hostname === "[::1]" || /^127(?:\.\d{1,3}){0,3}$/.test(hostname);
381
+ }
366
382
 
367
383
  // src/registry/log.ts
368
384
  function logger2() {
@@ -377,10 +393,13 @@ function sleep(ms) {
377
393
  }
378
394
  function configureTimeoutMs() {
379
395
  const value = process.env.RIVET_SERVERLESS_CONFIGURE_TIMEOUT_MS;
380
- if (value === void 0 || value === "") return DEFAULT_CONFIGURE_TIMEOUT_MS;
396
+ if (value === void 0 || value === "")
397
+ return DEFAULT_CONFIGURE_TIMEOUT_MS;
381
398
  const parsed = Number(value);
382
399
  if (!Number.isFinite(parsed) || parsed < 0) {
383
- throw new Error("RIVET_SERVERLESS_CONFIGURE_TIMEOUT_MS must be a finite non-negative number");
400
+ throw new Error(
401
+ "RIVET_SERVERLESS_CONFIGURE_TIMEOUT_MS must be a finite non-negative number"
402
+ );
384
403
  }
385
404
  return parsed;
386
405
  }
@@ -394,13 +413,19 @@ async function configureServerlessPool(config) {
394
413
  attempts += 1;
395
414
  try {
396
415
  if (!config.namespace) {
397
- throw new Error("namespace is required for serverless configuration");
416
+ throw new Error(
417
+ "namespace is required for serverless configuration"
418
+ );
398
419
  }
399
420
  if (!config.endpoint) {
400
- throw new Error("endpoint is required for serverless configuration");
421
+ throw new Error(
422
+ "endpoint is required for serverless configuration"
423
+ );
401
424
  }
402
425
  if (!config.configurePool) {
403
- throw new Error("configurePool is required for serverless configuration");
426
+ throw new Error(
427
+ "configurePool is required for serverless configuration"
428
+ );
404
429
  }
405
430
  const customConfig = config.configurePool;
406
431
  const clientConfig = convertRegistryConfigToClientConfig(config);
@@ -813,6 +838,18 @@ var RegistryConfigSchema = z3.object({
813
838
  * Starts the full Rust engine process locally.
814
839
  */
815
840
  startEngine: z3.boolean().default(() => getRivetRunEngine()),
841
+ /**
842
+ * @experimental
843
+ *
844
+ * Host to bind the spawned local engine process to.
845
+ */
846
+ engineHost: z3.string().optional().default(() => getRivetRunEngineHost() ?? ENGINE_HOST),
847
+ /**
848
+ * @experimental
849
+ *
850
+ * Port to bind the spawned local engine process to.
851
+ */
852
+ enginePort: z3.number().int().min(1).max(65535).optional().default(() => getRivetRunEnginePort() ?? ENGINE_PORT),
816
853
  /** @experimental */
817
854
  engineVersion: z3.string().optional().default(() => getRivetRunEngineVersion() ?? VERSION),
818
855
  /**
@@ -848,7 +885,7 @@ var RegistryConfigSchema = z3.object({
848
885
  * after calling `CoreRegistry::shutdown()`. Defaults to the
849
886
  * engine-provided actor stop threshold once the envoy connects.
850
887
  *
851
- * Must be >= rivetkit-core's drain timeout (20s) + margin.
888
+ * Must be long enough for rivetkit-core to drain the envoy.
852
889
  */
853
890
  gracePeriodMs: z3.number().int().min(1e3).optional(),
854
891
  /**
@@ -890,7 +927,11 @@ var RegistryConfigSchema = z3.object({
890
927
  message: "configurePool requires either endpoint or startEngine"
891
928
  });
892
929
  }
893
- const endpoint = config.startEngine ? ENGINE_ENDPOINT : (parsedEndpoint == null ? void 0 : parsedEndpoint.endpoint) ?? (isDevEnv ? ENGINE_ENDPOINT : void 0);
930
+ const localEngineEndpoint = buildEngineEndpoint(
931
+ config.engineHost,
932
+ config.enginePort
933
+ );
934
+ const endpoint = config.startEngine ? localEngineEndpoint : (parsedEndpoint == null ? void 0 : parsedEndpoint.endpoint) ?? (isDevEnv ? buildEngineEndpoint(ENGINE_HOST, ENGINE_PORT) : void 0);
894
935
  const validateServerlessEndpoint = Boolean(
895
936
  config.startEngine || parsedEndpoint
896
937
  );
@@ -907,7 +948,7 @@ var RegistryConfigSchema = z3.object({
907
948
  path: ["serverless", "publicEndpoint"]
908
949
  });
909
950
  }
910
- const publicEndpoint = (parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.endpoint) ?? (isDevEnv && config.startEngine ? ENGINE_ENDPOINT : void 0);
951
+ const publicEndpoint = (parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.endpoint) ?? (isDevEnv && config.startEngine ? endpoint : void 0);
911
952
  const publicNamespace = parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.namespace;
912
953
  const publicToken = (parsedPublicEndpoint == null ? void 0 : parsedPublicEndpoint.token) ?? config.serverless.publicToken;
913
954
  return {
@@ -1299,29 +1340,6 @@ function lastInsertRowIdColumnName(sql) {
1299
1340
  return alias;
1300
1341
  }
1301
1342
 
1302
- // src/registry/write-through-proxy.ts
1303
- import onChange from "@rivetkit/on-change";
1304
- function createWriteThroughProxy(value, commit, beforeChange) {
1305
- if (!value || typeof value !== "object") {
1306
- return value;
1307
- }
1308
- return onChange(
1309
- value,
1310
- () => {
1311
- commit(value);
1312
- },
1313
- {
1314
- // Rejection is throw-based: beforeChange throws to prevent the
1315
- // mutation. We always return true so on-change applies the change
1316
- // if beforeChange did not throw.
1317
- onValidate(_path, newValue) {
1318
- beforeChange == null ? void 0 : beforeChange(newValue);
1319
- return true;
1320
- }
1321
- }
1322
- );
1323
- }
1324
-
1325
1343
  // src/registry/runtime.ts
1326
1344
  function normalizeRuntimeSqlExecuteResult(result) {
1327
1345
  return result;
@@ -1442,15 +1460,32 @@ var NapiCoreRuntime = class {
1442
1460
  async shutdownRegistry(registry) {
1443
1461
  await asNativeRegistry(registry).shutdown();
1444
1462
  }
1445
- async registryDiagnostics(registry) {
1446
- const diagnostics = await asNativeRegistry(registry).diagnostics();
1463
+ async registryActorStopThresholdMs(registry) {
1464
+ return await asNativeRegistry(registry).actorStopThresholdMs() ?? void 0;
1465
+ }
1466
+ async registryHealth(registry) {
1467
+ const response = await asNativeRegistry(registry).health();
1447
1468
  return {
1448
- mode: diagnostics.mode,
1449
- envoyActiveActorCount: diagnostics.envoyActiveActorCount
1469
+ status: response.status,
1470
+ headers: response.headers,
1471
+ body: response.body
1450
1472
  };
1451
1473
  }
1452
- async registryActorStopThresholdMs(registry) {
1453
- return await asNativeRegistry(registry).actorStopThresholdMs() ?? void 0;
1474
+ async registryMetadata(registry) {
1475
+ const response = asNativeRegistry(registry).metadata();
1476
+ return {
1477
+ status: response.status,
1478
+ headers: response.headers,
1479
+ body: response.body
1480
+ };
1481
+ }
1482
+ async registryMetrics(registry) {
1483
+ const response = asNativeRegistry(registry).metrics();
1484
+ return {
1485
+ status: response.status,
1486
+ headers: response.headers,
1487
+ body: response.body
1488
+ };
1454
1489
  }
1455
1490
  async handleServerlessRequest(registry, req, onStreamEvent, cancelToken, config) {
1456
1491
  return await asNativeRegistry(registry).handleServerlessRequest(
@@ -1575,6 +1610,9 @@ var NapiCoreRuntime = class {
1575
1610
  async actorWaitForTrackedShutdownWork(ctx) {
1576
1611
  return await asNativeActorContext(ctx).waitForTrackedShutdownWork();
1577
1612
  }
1613
+ async actorWaitForTrackedShutdownWorkUnbounded(ctx) {
1614
+ await asNativeActorContext(ctx).waitForTrackedShutdownWorkUnbounded();
1615
+ }
1578
1616
  actorKeepAwake(ctx, promise) {
1579
1617
  asNativeActorContext(ctx).keepAwake(promise);
1580
1618
  }
@@ -1686,8 +1724,12 @@ var NapiCoreRuntime = class {
1686
1724
  )
1687
1725
  );
1688
1726
  }
1689
- async actorQueueWaitForNamesAvailable(ctx, names, options) {
1690
- await asNativeActorContext(ctx).queue().waitForNamesAvailable(names, options);
1727
+ async actorQueueWaitForNamesAvailable(ctx, names, options, signal) {
1728
+ await asNativeActorContext(ctx).queue().waitForNamesAvailable(
1729
+ names,
1730
+ options,
1731
+ signal ? asNativeCancellationToken(signal) : signal
1732
+ );
1691
1733
  }
1692
1734
  async actorQueueEnqueueAndWait(ctx, name, body, options, signal) {
1693
1735
  return await asNativeActorContext(ctx).queue().enqueueAndWait(
@@ -1821,20 +1863,18 @@ function validateQueueComplete(schemas, name, response) {
1821
1863
  response
1822
1864
  );
1823
1865
  if (!result.success) {
1824
- throw validationError(`queue \`${name}\` completion response`, result.issues);
1866
+ throw validationError(
1867
+ `queue \`${name}\` completion response`,
1868
+ result.issues
1869
+ );
1825
1870
  }
1826
1871
  return result.data;
1827
1872
  }
1828
1873
  function validationError(target, issues) {
1829
- return new RivetError(
1830
- "actor",
1831
- "validation_error",
1832
- `Invalid ${target}`,
1833
- {
1834
- public: true,
1835
- metadata: { issues }
1836
- }
1837
- );
1874
+ return new RivetError("actor", "validation_error", `Invalid ${target}`, {
1875
+ public: true,
1876
+ metadata: { issues }
1877
+ });
1838
1878
  }
1839
1879
 
1840
1880
  // src/registry/wasm-runtime.ts
@@ -1992,8 +2032,18 @@ var WasmCoreRuntime = class {
1992
2032
  async shutdownRegistry(registry) {
1993
2033
  await callWasm(() => asWasmRegistry(registry).shutdown());
1994
2034
  }
1995
- async registryDiagnostics() {
1996
- return { mode: "wasm", envoyActiveActorCount: null };
2035
+ async registryHealth() {
2036
+ return {
2037
+ status: 200,
2038
+ headers: { "content-type": "application/json" },
2039
+ body: new TextEncoder().encode(
2040
+ JSON.stringify({
2041
+ status: "ok",
2042
+ runtime: "rivetkit",
2043
+ version: "wasm"
2044
+ })
2045
+ )
2046
+ };
1997
2047
  }
1998
2048
  async handleServerlessRequest(registry, req, onStreamEvent, cancelToken, config) {
1999
2049
  return await callHandleAsync(
@@ -2148,6 +2198,12 @@ var WasmCoreRuntime = class {
2148
2198
  "waitForTrackedShutdownWork"
2149
2199
  );
2150
2200
  }
2201
+ async actorWaitForTrackedShutdownWorkUnbounded(ctx) {
2202
+ await callHandle(
2203
+ asWasmActorContext(ctx),
2204
+ "waitForTrackedShutdownWorkUnbounded"
2205
+ );
2206
+ }
2151
2207
  actorKeepAwake(ctx, promise) {
2152
2208
  const wasmCtx = asWasmActorContext(ctx);
2153
2209
  const regionId = callHandle(wasmCtx, "beginKeepAwake");
@@ -2295,9 +2351,15 @@ var WasmCoreRuntime = class {
2295
2351
  )
2296
2352
  );
2297
2353
  }
2298
- async actorQueueWaitForNamesAvailable(ctx, names, options) {
2354
+ async actorQueueWaitForNamesAvailable(ctx, names, options, signal) {
2299
2355
  const queue2 = childHandle(asWasmActorContext(ctx), "queue");
2300
- await callHandleAsync(queue2, "waitForNamesAvailable", names, options);
2356
+ await callHandleAsync(
2357
+ queue2,
2358
+ "waitForNamesAvailable",
2359
+ names,
2360
+ options,
2361
+ signal
2362
+ );
2301
2363
  }
2302
2364
  async actorQueueEnqueueAndWait(ctx, name, body, options, signal) {
2303
2365
  const queue2 = childHandle(asWasmActorContext(ctx), "queue");
@@ -2389,6 +2451,33 @@ async function loadWasmRuntime(config) {
2389
2451
  };
2390
2452
  }
2391
2453
 
2454
+ // src/registry/native.ts
2455
+ import nodeFs from "fs";
2456
+ import nodePath from "path";
2457
+
2458
+ // src/registry/write-through-proxy.ts
2459
+ import onChange from "@rivetkit/on-change";
2460
+ function createWriteThroughProxy(value, commit, beforeChange) {
2461
+ if (!value || typeof value !== "object") {
2462
+ return value;
2463
+ }
2464
+ return onChange(
2465
+ value,
2466
+ () => {
2467
+ commit(value);
2468
+ },
2469
+ {
2470
+ // Rejection is throw-based: beforeChange throws to prevent the
2471
+ // mutation. We always return true so on-change applies the change
2472
+ // if beforeChange did not throw.
2473
+ onValidate(_path, newValue) {
2474
+ beforeChange == null ? void 0 : beforeChange(newValue);
2475
+ return true;
2476
+ }
2477
+ }
2478
+ );
2479
+ }
2480
+
2392
2481
  // src/registry/native.ts
2393
2482
  var textEncoder = new TextEncoder();
2394
2483
  var textDecoder = new TextDecoder();
@@ -2601,21 +2690,23 @@ function resolveNativeDestroy(runtime, ctx) {
2601
2690
  function clearNativeRuntimeState(runtime, ctx) {
2602
2691
  callNativeSync(() => runtime.actorClearRuntimeState(ctx));
2603
2692
  }
2604
- async function cleanupNativeSleepRuntimeState(runtime, ctx) {
2605
- const waitStarted = Date.now();
2693
+ async function cleanupNativeSleepRuntimeState(runtime, ctx, afterTrackedWorkDrained) {
2606
2694
  const drained = await runtime.actorWaitForTrackedShutdownWork(ctx);
2607
- const waitMs = Date.now() - waitStarted;
2608
- if (drained) {
2609
- logger2().debug({
2610
- msg: "sleep cleanup: tracked shutdown work drained",
2611
- waitMs
2612
- });
2613
- } else {
2614
- logger2().warn({
2615
- msg: "sleep cleanup: shutdown deadline reached before tracked work drained; closing DB anyway",
2616
- waitMs
2695
+ if (!drained) {
2696
+ await closeNativeDatabaseClient(runtime, ctx);
2697
+ await closeNativeSqlDatabase(runtime, ctx);
2698
+ void runtime.actorWaitForTrackedShutdownWorkUnbounded(ctx).then(async () => {
2699
+ await (afterTrackedWorkDrained == null ? void 0 : afterTrackedWorkDrained());
2700
+ clearNativeRuntimeState(runtime, ctx);
2701
+ }).catch((error) => {
2702
+ logger2().warn({
2703
+ msg: "deferred native sleep cleanup failed",
2704
+ error: stringifyError(error)
2705
+ });
2617
2706
  });
2707
+ return;
2618
2708
  }
2709
+ await (afterTrackedWorkDrained == null ? void 0 : afterTrackedWorkDrained());
2619
2710
  await closeNativeDatabaseClient(runtime, ctx);
2620
2711
  await closeNativeSqlDatabase(runtime, ctx);
2621
2712
  clearNativeRuntimeState(runtime, ctx);
@@ -2720,11 +2811,14 @@ function decodeValue(value) {
2720
2811
  if (!value || value.length === 0) {
2721
2812
  return void 0;
2722
2813
  }
2723
- return decodeCborJsonCompat(value);
2814
+ return decodeCborCompat(value);
2724
2815
  }
2725
2816
  function encodeValue(value) {
2726
2817
  return encodeCborCompat(value);
2727
2818
  }
2819
+ function normalizeArgs(value) {
2820
+ return Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value];
2821
+ }
2728
2822
  function unwrapTsfnPayload(error, payload) {
2729
2823
  if (error !== null && error !== void 0) {
2730
2824
  throw error;
@@ -2780,12 +2874,6 @@ function callNativeSync(invoke) {
2780
2874
  throw normalizeNativeBridgeError(error);
2781
2875
  }
2782
2876
  }
2783
- function actorAbortedError() {
2784
- return Object.assign(new Error("Actor aborted"), {
2785
- group: "actor",
2786
- code: "aborted"
2787
- });
2788
- }
2789
2877
  function isClosedTaskRegistrationError(error) {
2790
2878
  const metadata = error instanceof RivetError ? error.metadata : void 0;
2791
2879
  const metadataError = metadata && typeof metadata === "object" && "error" in metadata ? metadata.error : void 0;
@@ -2918,7 +3006,7 @@ function serializeWorkflowHistoryForJson(data) {
2918
3006
  return null;
2919
3007
  }
2920
3008
  const history = decodeWorkflowHistoryTransport(data);
2921
- return {
3009
+ return jsonSafe({
2922
3010
  nameRegistry: [...history.nameRegistry],
2923
3011
  entries: history.entries.map((entry) => ({
2924
3012
  id: entry.id,
@@ -2942,7 +3030,7 @@ function serializeWorkflowHistoryForJson(data) {
2942
3030
  ]
2943
3031
  )
2944
3032
  )
2945
- };
3033
+ });
2946
3034
  }
2947
3035
  function toHttpJsonCompatible(value) {
2948
3036
  return JSON.parse(
@@ -2993,7 +3081,7 @@ function wrapNativeCallback(callback) {
2993
3081
  }
2994
3082
  function decodeArgs(value) {
2995
3083
  const decoded = decodeValue(value);
2996
- return Array.isArray(decoded) ? decoded : decoded === void 0 ? [] : [decoded];
3084
+ return normalizeArgs(decoded);
2997
3085
  }
2998
3086
  function buildRequest(init) {
2999
3087
  const url = init.uri.startsWith("http") ? init.uri : new URL(init.uri, "http://127.0.0.1").toString();
@@ -3052,11 +3140,15 @@ var NativeConnAdapter = class {
3052
3140
  }
3053
3141
  get state() {
3054
3142
  const nextState = this.#readState();
3055
- return createWriteThroughProxy(nextState, (nextValue) => {
3056
- this.#writeState(nextValue, { writeNative: true });
3057
- }, (newValue) => {
3058
- assertJsonCompatValue(newValue);
3059
- });
3143
+ return createWriteThroughProxy(
3144
+ nextState,
3145
+ (nextValue) => {
3146
+ this.#writeState(nextValue, { writeNative: true });
3147
+ },
3148
+ (newValue) => {
3149
+ assertJsonCompatValue(newValue);
3150
+ }
3151
+ );
3060
3152
  }
3061
3153
  set state(value) {
3062
3154
  assertJsonCompatValue(value);
@@ -3411,44 +3503,23 @@ var NativeQueueAdapter = class {
3411
3503
  }
3412
3504
  }
3413
3505
  async waitForNamesAvailable(names, options) {
3414
- if (!(options == null ? void 0 : options.signal)) {
3506
+ const { token, cleanup } = await createCancellationTokenHandle(
3507
+ this.#runtime,
3508
+ options == null ? void 0 : options.signal
3509
+ );
3510
+ try {
3415
3511
  await callNative(
3416
3512
  () => this.#runtime.actorQueueWaitForNamesAvailable(
3417
3513
  this.#ctx,
3418
3514
  [...names],
3419
3515
  {
3420
3516
  timeoutMs: options == null ? void 0 : options.timeout
3421
- }
3517
+ },
3518
+ token
3422
3519
  )
3423
3520
  );
3424
- return;
3425
- }
3426
- const deadline = options.timeout === void 0 ? void 0 : Date.now() + options.timeout;
3427
- for (; ; ) {
3428
- if (options.signal.aborted) {
3429
- throw actorAbortedError();
3430
- }
3431
- const remainingTimeout = deadline === void 0 ? void 0 : Math.max(0, deadline - Date.now());
3432
- const sliceTimeout = remainingTimeout === void 0 ? 100 : Math.min(remainingTimeout, 100);
3433
- try {
3434
- await callNative(
3435
- () => this.#runtime.actorQueueWaitForNamesAvailable(
3436
- this.#ctx,
3437
- [...names],
3438
- {
3439
- timeoutMs: sliceTimeout
3440
- }
3441
- )
3442
- );
3443
- return;
3444
- } catch (error) {
3445
- if (error.group === "queue" && error.code === "timed_out") {
3446
- if (remainingTimeout === void 0 || remainingTimeout > 100) {
3447
- continue;
3448
- }
3449
- }
3450
- throw error;
3451
- }
3521
+ } finally {
3522
+ cleanup == null ? void 0 : cleanup();
3452
3523
  }
3453
3524
  }
3454
3525
  async enqueueAndWait(name, body, options) {
@@ -3911,9 +3982,7 @@ var NativeConnectionMap = class {
3911
3982
  }
3912
3983
  get(key) {
3913
3984
  const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
3914
- const conn = conns.find(
3915
- (c) => this.#runtime.connId(c) === key
3916
- );
3985
+ const conn = conns.find((c) => this.#runtime.connId(c) === key);
3917
3986
  if (!conn) return void 0;
3918
3987
  return this.#connToAdapter(conn);
3919
3988
  }
@@ -4021,17 +4090,22 @@ var ActorContextHandleAdapter = class {
4021
4090
  if (!this.#stateEnabled) {
4022
4091
  throw stateNotEnabledError();
4023
4092
  }
4093
+ const actorState = getNativePersistState(this.#runtime, this.#ctx);
4024
4094
  const nextState = this.#readState();
4025
- return createWriteThroughProxy(
4026
- nextState,
4027
- (nextValue) => {
4028
- this.#writeState(nextValue, { scheduleSave: true });
4029
- },
4030
- (newValue) => {
4031
- this.#assertCanMutateState();
4032
- assertJsonCompatValue(newValue);
4033
- }
4034
- );
4095
+ if (actorState.stateProxy === void 0 || actorState.stateProxyTarget !== nextState) {
4096
+ actorState.stateProxyTarget = nextState;
4097
+ actorState.stateProxy = createWriteThroughProxy(
4098
+ nextState,
4099
+ (nextValue) => {
4100
+ this.#writeState(nextValue, { scheduleSave: true });
4101
+ },
4102
+ (newValue) => {
4103
+ this.#assertCanMutateState();
4104
+ assertJsonCompatValue(newValue);
4105
+ }
4106
+ );
4107
+ }
4108
+ return actorState.stateProxy;
4035
4109
  }
4036
4110
  set state(value) {
4037
4111
  if (!this.#stateEnabled) {
@@ -4096,7 +4170,11 @@ var ActorContextHandleAdapter = class {
4096
4170
  }
4097
4171
  get conns() {
4098
4172
  if (!this.#connMap) {
4099
- this.#connMap = new NativeConnectionMap(this.#runtime, this.#ctx, this.#schemas);
4173
+ this.#connMap = new NativeConnectionMap(
4174
+ this.#runtime,
4175
+ this.#ctx,
4176
+ this.#schemas
4177
+ );
4100
4178
  }
4101
4179
  return this.#connMap;
4102
4180
  }
@@ -4296,39 +4374,20 @@ var ActorContextHandleAdapter = class {
4296
4374
  });
4297
4375
  }
4298
4376
  keepAwake(promise) {
4299
- const startedAt = Date.now();
4300
- logger2().debug({
4301
- msg: "keepAwake registered",
4302
- at: startedAt
4303
- });
4304
- const trackedPromise = Promise.resolve(promise).then(
4305
- () => {
4306
- logger2().debug({
4307
- msg: "keepAwake promise resolved",
4308
- durationMs: Date.now() - startedAt
4309
- });
4310
- },
4311
- (error) => {
4312
- logger2().warn({
4313
- msg: "keepAwake promise rejected",
4314
- durationMs: Date.now() - startedAt,
4315
- error: stringifyError(error)
4316
- });
4317
- }
4318
- ).then(() => null);
4377
+ const trackedPromise = Promise.resolve(promise).catch((error) => {
4378
+ logger2().warn({
4379
+ msg: "keepAwake promise rejected",
4380
+ error: stringifyError(error)
4381
+ });
4382
+ }).then(() => null);
4319
4383
  try {
4320
4384
  callNativeSync(
4321
4385
  () => this.#runtime.actorKeepAwake(this.#ctx, trackedPromise)
4322
4386
  );
4323
4387
  } catch (error) {
4324
- if (isClosedTaskRegistrationError(error)) {
4325
- logger2().warn({
4326
- msg: "keepAwake registration dropped (teardown already started); promise will not delay grace",
4327
- error: stringifyError(error)
4328
- });
4329
- return promise;
4388
+ if (!isClosedTaskRegistrationError(error)) {
4389
+ throw error;
4330
4390
  }
4331
- throw error;
4332
4391
  }
4333
4392
  return promise;
4334
4393
  }
@@ -4394,6 +4453,7 @@ var ActorContextHandleAdapter = class {
4394
4453
  return false;
4395
4454
  }
4396
4455
  sleep() {
4456
+ this.#flushStateChange();
4397
4457
  callNativeSync(() => this.#runtime.actorSleep(this.#ctx));
4398
4458
  }
4399
4459
  destroy() {
@@ -4411,6 +4471,7 @@ var ActorContextHandleAdapter = class {
4411
4471
  }
4412
4472
  async dispose() {
4413
4473
  var _a;
4474
+ this.#flushStateChange();
4414
4475
  (_a = this.#abortSignalCleanup) == null ? void 0 : _a.call(this);
4415
4476
  this.#sql = void 0;
4416
4477
  }
@@ -4438,13 +4499,12 @@ var ActorContextHandleAdapter = class {
4438
4499
  return actorState.state;
4439
4500
  }
4440
4501
  #writeState(value, options) {
4441
- encodeValue(value);
4442
4502
  const actorState = getNativePersistState(this.#runtime, this.#ctx);
4443
4503
  actorState.state = value;
4444
4504
  if (!options.scheduleSave) {
4445
4505
  return;
4446
4506
  }
4447
- this.#handleStateChange();
4507
+ this.#scheduleSave();
4448
4508
  }
4449
4509
  #assertCanMutateState() {
4450
4510
  const actorState = getNativePersistState(this.#runtime, this.#ctx);
@@ -4452,9 +4512,31 @@ var ActorContextHandleAdapter = class {
4452
4512
  throw stateMutationReentrantError();
4453
4513
  }
4454
4514
  }
4455
- #handleStateChange() {
4515
+ // Coalesce the request-save and onStateChange work to once per event loop
4516
+ // tick. A synchronous burst of mutations (for example
4517
+ // `Object.assign(c.state, ...)`) would otherwise cross the NAPI boundary and
4518
+ // run onStateChange once per field, re-serializing the whole state each time
4519
+ // and pinning the event loop on large state.
4520
+ #scheduleSave() {
4456
4521
  const actorState = getNativePersistState(this.#runtime, this.#ctx);
4457
- encodeValue(actorState.state);
4522
+ if (actorState.saveScheduled) {
4523
+ return;
4524
+ }
4525
+ actorState.saveScheduled = true;
4526
+ actorState.pendingSaveHandle = setImmediate(() => {
4527
+ this.#flushStateChange();
4528
+ });
4529
+ }
4530
+ #flushStateChange() {
4531
+ const actorState = getNativePersistState(this.#runtime, this.#ctx);
4532
+ if (!actorState.saveScheduled) {
4533
+ return;
4534
+ }
4535
+ actorState.saveScheduled = false;
4536
+ if (actorState.pendingSaveHandle !== void 0) {
4537
+ clearImmediate(actorState.pendingSaveHandle);
4538
+ actorState.pendingSaveHandle = void 0;
4539
+ }
4458
4540
  callNativeSync(
4459
4541
  () => this.#runtime.actorRequestSave(this.#ctx, { immediate: false })
4460
4542
  );
@@ -4661,9 +4743,62 @@ function buildActorConfig(definition, registryConfig) {
4661
4743
  maxOutgoingMessageSize: registryConfig.maxOutgoingMessageSize,
4662
4744
  preloadMaxWorkflowBytes: options.preloadMaxWorkflowBytes,
4663
4745
  preloadMaxConnectionsBytes: options.preloadMaxConnectionsBytes,
4664
- actions: Object.keys(config.actions ?? {}).sort().map((name) => ({ name }))
4746
+ actions: Object.keys(config.actions ?? {}).sort().map((name) => ({ name })),
4747
+ inspectorTabs: buildInspectorTabs(config.inspector)
4665
4748
  };
4666
4749
  }
4750
+ function buildInspectorTabs(inspector) {
4751
+ if (!inspector || typeof inspector !== "object") return void 0;
4752
+ const tabs = inspector.tabs;
4753
+ if (!Array.isArray(tabs) || tabs.length === 0) return void 0;
4754
+ return tabs.map((raw) => {
4755
+ const entry = raw;
4756
+ if (entry.hidden === true) {
4757
+ return { id: entry.id, hidden: true };
4758
+ }
4759
+ const resolved = entry.source !== void 0 ? nodePath.resolve(entry.source) : void 0;
4760
+ if (resolved !== void 0) {
4761
+ validateInspectorTabSource(entry.id, resolved);
4762
+ }
4763
+ return {
4764
+ id: entry.id,
4765
+ label: entry.label,
4766
+ icon: entry.icon,
4767
+ source: resolved
4768
+ };
4769
+ });
4770
+ }
4771
+ function validateInspectorTabSource(tabId, resolved) {
4772
+ if (resolved === nodePath.parse(resolved).root) {
4773
+ throw new Error(
4774
+ `inspector.tabs[id="${tabId}"].source resolves to the filesystem root (${resolved}). Point it at the tab's own static-asset directory instead.`
4775
+ );
4776
+ }
4777
+ let stat;
4778
+ try {
4779
+ stat = nodeFs.statSync(resolved);
4780
+ } catch (err) {
4781
+ const code = err == null ? void 0 : err.code;
4782
+ if (code === "ENOENT") {
4783
+ throw new Error(
4784
+ `inspector.tabs[id="${tabId}"].source (${resolved}) does not exist.`
4785
+ );
4786
+ }
4787
+ if (code === "EACCES") {
4788
+ throw new Error(
4789
+ `inspector.tabs[id="${tabId}"].source (${resolved}) is not readable (EACCES).`
4790
+ );
4791
+ }
4792
+ throw new Error(
4793
+ `inspector.tabs[id="${tabId}"].source (${resolved}) could not be stat'd: ${(err == null ? void 0 : err.message) ?? err}`
4794
+ );
4795
+ }
4796
+ if (!stat.isDirectory()) {
4797
+ throw new Error(
4798
+ `inspector.tabs[id="${tabId}"].source (${resolved}) must be a directory, got ${stat.isFile() ? "file" : "non-directory"}.`
4799
+ );
4800
+ }
4801
+ }
4667
4802
  function buildNativeFactory(runtime, registryConfig, definition) {
4668
4803
  var _a;
4669
4804
  const config = definition.config;
@@ -4996,13 +5131,26 @@ function buildNativeFactory(runtime, registryConfig, definition) {
4996
5131
  );
4997
5132
  }
4998
5133
  const body = await jsRequest.json();
5134
+ if (body.args !== void 0 && body.properties !== void 0) {
5135
+ return jsonResponse(
5136
+ { error: "use either args or properties, not both" },
5137
+ { status: 400 }
5138
+ );
5139
+ }
5140
+ if (body.properties !== void 0 && (body.properties === null || typeof body.properties !== "object" || Array.isArray(body.properties))) {
5141
+ return jsonResponse(
5142
+ { error: "properties must be an object" },
5143
+ { status: 400 }
5144
+ );
5145
+ }
5146
+ const args = body.properties !== void 0 ? [body.properties] : normalizeArgs(body.args);
4999
5147
  try {
5000
5148
  const output = await action(
5001
5149
  actorCtx,
5002
5150
  ...validateActionArgs(
5003
5151
  schemaConfig.actionInputSchemas,
5004
5152
  actionName,
5005
- body.args ?? []
5153
+ args
5006
5154
  )
5007
5155
  );
5008
5156
  return jsonResponse({ output });
@@ -5150,24 +5298,30 @@ function buildNativeFactory(runtime, registryConfig, definition) {
5150
5298
  async (error, payload) => {
5151
5299
  const { ctx } = unwrapTsfnPayload(error, payload);
5152
5300
  const actorCtx = makeActorCtx(ctx);
5301
+ const saveActorState = async () => {
5302
+ if (runtime.kind === "wasm") {
5303
+ await runtime.actorSaveState(
5304
+ ctx,
5305
+ actorCtx.serializeForTick("save")
5306
+ );
5307
+ } else {
5308
+ await actorCtx.saveState({
5309
+ immediate: true
5310
+ });
5311
+ }
5312
+ };
5153
5313
  try {
5154
5314
  if (onSleep) {
5155
- try {
5156
- await onSleep(actorCtx);
5157
- } finally {
5158
- if (runtime.kind === "wasm") {
5159
- await runtime.actorSaveState(
5160
- ctx,
5161
- actorCtx.serializeForTick("save")
5162
- );
5163
- } else {
5164
- await actorCtx.saveState({ immediate: true });
5165
- }
5166
- }
5315
+ await onSleep(actorCtx);
5167
5316
  }
5317
+ await saveActorState();
5168
5318
  } finally {
5169
5319
  try {
5170
- await cleanupNativeSleepRuntimeState(runtime, ctx);
5320
+ await cleanupNativeSleepRuntimeState(
5321
+ runtime,
5322
+ ctx,
5323
+ saveActorState
5324
+ );
5171
5325
  } finally {
5172
5326
  await actorCtx.dispose();
5173
5327
  }
@@ -5612,10 +5766,17 @@ async function buildServeConfig(config) {
5612
5766
  serverlessValidateEndpoint: config.validateServerlessEndpoint,
5613
5767
  serverlessMaxStartPayloadBytes: config.serverless.maxStartPayloadBytes
5614
5768
  };
5615
- if (config.startEngine) {
5769
+ try {
5616
5770
  const { getEnginePath } = await loadEngineCli();
5617
5771
  serveConfig.engineBinaryPath = getEnginePath();
5772
+ } catch (error) {
5773
+ logger2().warn({
5774
+ 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",
5775
+ error: stringifyError(error)
5776
+ });
5618
5777
  }
5778
+ serveConfig.engineHost = config.engineHost;
5779
+ serveConfig.enginePort = config.enginePort;
5619
5780
  if ((_a = config.test) == null ? void 0 : _a.enabled) {
5620
5781
  serveConfig.inspectorTestToken = getEnvUniversal("_RIVET_TEST_INSPECTOR_TOKEN") ?? "token";
5621
5782
  }
@@ -5642,10 +5803,6 @@ async function buildRegistryWithRuntime(config, runtime) {
5642
5803
  }
5643
5804
  async function buildConfiguredRegistry(config) {
5644
5805
  const runtime = await loadConfiguredRuntime(config);
5645
- if (runtime.kind === "napi") {
5646
- const { startProcessMetrics } = await import("./process-metrics-NW754INA.js");
5647
- startProcessMetrics();
5648
- }
5649
5806
  return buildRegistryWithRuntime(
5650
5807
  normalizeRuntimeConfig(config, runtime),
5651
5808
  runtime
@@ -5669,6 +5826,8 @@ function finishShutdownSignal(signal) {
5669
5826
  }
5670
5827
  var Registry = class {
5671
5828
  #config;
5829
+ #buildConfiguredRegistry;
5830
+ routes;
5672
5831
  get config() {
5673
5832
  return this.#config;
5674
5833
  }
@@ -5683,18 +5842,24 @@ var Registry = class {
5683
5842
  #shutdownInstalled = false;
5684
5843
  #shutdownInFlight = null;
5685
5844
  #signalHandlers = {};
5686
- constructor(config) {
5845
+ constructor(config, deps) {
5687
5846
  this.#config = config;
5847
+ this.#buildConfiguredRegistry = (deps == null ? void 0 : deps.buildConfiguredRegistry) ?? buildConfiguredRegistry;
5848
+ this.routes = {
5849
+ health: () => this.#healthRoute(),
5850
+ metadata: () => this.#metadataRoute(),
5851
+ prometheusMetrics: (request) => this.#prometheusMetricsRoute(request)
5852
+ };
5688
5853
  }
5689
5854
  #ensureServerlessPoolConfigured(config) {
5690
5855
  if (!config.configurePool) return void 0;
5691
5856
  if (!this.#configureServerlessPoolPromise) {
5692
- this.#configureServerlessPoolPromise = configureServerlessPool(config).catch(
5693
- (error) => {
5694
- this.#configureServerlessPoolPromise = void 0;
5695
- throw error;
5696
- }
5697
- );
5857
+ this.#configureServerlessPoolPromise = configureServerlessPool(
5858
+ config
5859
+ ).catch((error) => {
5860
+ this.#configureServerlessPoolPromise = void 0;
5861
+ throw error;
5862
+ });
5698
5863
  this.#configureServerlessPoolPromise.catch(() => {
5699
5864
  });
5700
5865
  }
@@ -5715,7 +5880,7 @@ var Registry = class {
5715
5880
  const config = this.parseConfig();
5716
5881
  this.#printWelcome(config, "serverless");
5717
5882
  if (!this.#runtimeServerlessPromise) {
5718
- this.#runtimeServerlessPromise = buildConfiguredRegistry(config);
5883
+ this.#runtimeServerlessPromise = this.#buildConfiguredRegistry(config);
5719
5884
  }
5720
5885
  const { runtime, registry, serveConfig } = await this.#runtimeServerlessPromise;
5721
5886
  const isStartRequest = isServerlessStartRequest(
@@ -5730,7 +5895,7 @@ var Registry = class {
5730
5895
  if (isStartRequest) {
5731
5896
  try {
5732
5897
  await this.#ensureServerlessPoolConfigured(config);
5733
- } catch (error) {
5898
+ } catch (_error) {
5734
5899
  return new Response(
5735
5900
  JSON.stringify({
5736
5901
  group: "guard",
@@ -5844,7 +6009,7 @@ var Registry = class {
5844
6009
  if (isMetadataRequest && !isEngineMetadataRequest) {
5845
6010
  try {
5846
6011
  await this.#ensureServerlessPoolConfigured(config);
5847
- } catch (error) {
6012
+ } catch (_error) {
5848
6013
  return new Response(
5849
6014
  JSON.stringify({
5850
6015
  group: "guard",
@@ -5904,40 +6069,109 @@ var Registry = class {
5904
6069
  app.all("*", (c) => this.handler(c.req.raw));
5905
6070
  await crossPlatformServe(config, port, app, runtime);
5906
6071
  }
5907
- async diagnostics() {
5908
- var _a;
6072
+ /**
6073
+ * Returns a health response suitable for mounting in a user-owned router.
6074
+ */
6075
+ async #healthRoute() {
6076
+ const configured = await this.#activeConfiguredRegistry();
6077
+ if (!configured) {
6078
+ return jsonRouteResponse(503, {
6079
+ status: "not_started",
6080
+ runtime: "rivetkit",
6081
+ version: VERSION
6082
+ });
6083
+ }
6084
+ const { runtime, registry } = configured;
6085
+ if (!runtime.registryHealth) {
6086
+ return jsonRouteResponse(501, {
6087
+ status: "unsupported",
6088
+ runtime: "rivetkit",
6089
+ version: VERSION
6090
+ });
6091
+ }
6092
+ const response = await runtime.registryHealth(registry);
6093
+ return new Response(new Uint8Array(response.body), {
6094
+ status: response.status,
6095
+ headers: response.headers
6096
+ });
6097
+ }
6098
+ /**
6099
+ * Returns serverless metadata suitable for mounting in a user-owned router.
6100
+ */
6101
+ async #metadataRoute() {
6102
+ const configured = await this.#activeConfiguredRegistry();
6103
+ if (!configured) {
6104
+ return new Response("registry not started\n", {
6105
+ status: 503,
6106
+ headers: { "content-type": "text/plain; charset=utf-8" }
6107
+ });
6108
+ }
6109
+ const { runtime, registry } = configured;
6110
+ if (!runtime.registryMetadata) {
6111
+ return new Response("metadata is not supported by this runtime\n", {
6112
+ status: 501,
6113
+ headers: { "content-type": "text/plain; charset=utf-8" }
6114
+ });
6115
+ }
6116
+ const response = await runtime.registryMetadata(registry);
6117
+ return new Response(new Uint8Array(response.body), {
6118
+ status: response.status,
6119
+ headers: response.headers
6120
+ });
6121
+ }
6122
+ /**
6123
+ * Returns a Prometheus metrics response suitable for mounting in a user-owned router.
6124
+ */
6125
+ async #prometheusMetricsRoute(_request) {
6126
+ const configured = await this.#activeConfiguredRegistry();
6127
+ if (!configured) {
6128
+ return new Response("registry not started\n", {
6129
+ status: 503,
6130
+ headers: { "content-type": "text/plain; charset=utf-8" }
6131
+ });
6132
+ }
6133
+ const { runtime, registry } = configured;
6134
+ if (!runtime.registryMetrics) {
6135
+ return new Response("metrics are not supported by this runtime\n", {
6136
+ status: 501,
6137
+ headers: { "content-type": "text/plain; charset=utf-8" }
6138
+ });
6139
+ }
6140
+ const response = await runtime.registryMetrics(registry);
6141
+ return new Response(new Uint8Array(response.body), {
6142
+ status: response.status,
6143
+ headers: response.headers
6144
+ });
6145
+ }
6146
+ async #activeConfiguredRegistry() {
5909
6147
  const candidates = [
5910
6148
  this.#runtimeServerlessPromise,
5911
6149
  this.#runtimeServeConfiguredPromise
5912
6150
  ].filter(
5913
6151
  (candidate) => candidate !== void 0
5914
6152
  );
5915
- for (const candidate of candidates) {
5916
- const { runtime, registry } = await candidate;
5917
- const diagnostics = await ((_a = runtime.registryDiagnostics) == null ? void 0 : _a.call(runtime, registry));
5918
- if (diagnostics) return diagnostics;
5919
- }
5920
- return { mode: "not_started", envoyActiveActorCount: null };
6153
+ if (candidates.length === 0) return void 0;
6154
+ return await candidates[0];
5921
6155
  }
5922
6156
  /**
5923
6157
  * Starts an actor envoy for standalone server deployments.
5924
6158
  */
5925
6159
  #startEnvoy(config, printWelcome) {
5926
6160
  if (!this.#runtimeServePromise) {
5927
- const configuredRegistryPromise = buildConfiguredRegistry(config);
6161
+ const configuredRegistryPromise = this.#buildConfiguredRegistry(config);
5928
6162
  this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
5929
6163
  this.#runtimeServePromise = configuredRegistryPromise.then(async ({ runtime, registry, serveConfig }) => {
5930
6164
  await runtime.serveRegistry(registry, serveConfig);
5931
6165
  }).catch((error) => {
5932
6166
  logger2().warn({ error }, "runtime registry serve errored");
5933
6167
  });
5934
- this.#installSignalHandlers(config, configuredRegistryPromise);
6168
+ this.#installSignalHandlers(config);
5935
6169
  }
5936
6170
  if (printWelcome) {
5937
6171
  this.#printWelcome(config, "serverful");
5938
6172
  }
5939
6173
  }
5940
- #installSignalHandlers(config, configuredRegistryPromise) {
6174
+ #installSignalHandlers(config) {
5941
6175
  var _a;
5942
6176
  if (this.#shutdownInstalled) return;
5943
6177
  if ((_a = config.shutdown) == null ? void 0 : _a.disableSignalHandlers) return;
@@ -5946,54 +6180,82 @@ var Registry = class {
5946
6180
  }
5947
6181
  this.#shutdownInstalled = true;
5948
6182
  const install = (signal) => {
5949
- const handler = () => this.#onShutdownSignal(
5950
- signal,
5951
- config,
5952
- configuredRegistryPromise
5953
- );
6183
+ const handler = () => this.#onShutdownSignal(signal, config);
5954
6184
  this.#signalHandlers[signal] = handler;
5955
6185
  process.on(signal, handler);
5956
6186
  };
5957
6187
  install("SIGINT");
5958
6188
  install("SIGTERM");
5959
6189
  }
5960
- #onShutdownSignal(signal, config, configuredRegistryPromise) {
6190
+ #onShutdownSignal(signal, config) {
5961
6191
  if (this.#shutdownInFlight !== null) {
5962
6192
  this.#removeSignalHandlers();
5963
6193
  finishShutdownSignal(signal);
5964
6194
  return;
5965
6195
  }
5966
- this.#shutdownInFlight = this.#runShutdown(
5967
- signal,
5968
- config,
5969
- configuredRegistryPromise
5970
- ).catch((error) => {
5971
- logger2().warn({ error }, "shutdown error");
6196
+ this.#shutdownInFlight = this.#drain(config).catch((err) => {
6197
+ logger2().warn({ err }, "shutdown error");
6198
+ }).then(() => {
6199
+ this.#removeSignalHandlers();
6200
+ finishShutdownSignal(signal);
6201
+ });
6202
+ }
6203
+ /**
6204
+ * Gracefully drains all live registries.
6205
+ *
6206
+ * Programmatic counterpart to the SIGINT/SIGTERM handlers: tears down
6207
+ * every live `CoreRegistry` (both `start()` and `handler()` modes) and
6208
+ * waits for the serve promise to resolve, all bounded by the shutdown
6209
+ * grace period. Unlike a signal-driven shutdown, this does not re-raise a
6210
+ * signal or exit the process. The caller owns process lifetime.
6211
+ *
6212
+ * Idempotent: concurrent or repeated calls share a single drain. Safe to
6213
+ * call even if nothing has been started.
6214
+ *
6215
+ * @example
6216
+ * ```ts
6217
+ * const registry = setup({ use: { counter } });
6218
+ * registry.start();
6219
+ * // ...later, on your own shutdown trigger:
6220
+ * await registry.shutdown();
6221
+ * ```
6222
+ */
6223
+ async shutdown() {
6224
+ if (this.#shutdownInFlight !== null) return this.#shutdownInFlight;
6225
+ const config = this.parseConfig();
6226
+ this.#removeSignalHandlers();
6227
+ this.#shutdownInFlight = this.#drain(config).catch((err) => {
6228
+ logger2().warn({ err }, "shutdown error");
5972
6229
  });
6230
+ return this.#shutdownInFlight;
5973
6231
  }
5974
- async #runShutdown(signal, config, configuredRegistryPromise) {
6232
+ async #drain(config) {
5975
6233
  var _a;
5976
- const gracePeriodMs = ((_a = config.shutdown) == null ? void 0 : _a.gracePeriodMs) ?? await this.#actorStopThresholdMs(configuredRegistryPromise) ?? 30 * 60 * 1e3;
6234
+ const modeAPromise = this.#runtimeServeConfiguredPromise;
6235
+ const modeBPromise = this.#runtimeServerlessPromise;
6236
+ const gracePeriodMs = ((_a = config.shutdown) == null ? void 0 : _a.gracePeriodMs) ?? await this.#actorStopThresholdMs(modeAPromise ?? modeBPromise) ?? 30 * 60 * 1e3;
5977
6237
  const drain = async () => {
5978
- const registries = [
5979
- (async () => {
5980
- try {
5981
- const { runtime, registry } = await configuredRegistryPromise;
5982
- await runtime.shutdownRegistry(registry);
5983
- } catch (error) {
5984
- logger2().warn(
5985
- { error },
5986
- "runtime registry shutdown errored (mode A)"
5987
- );
5988
- }
5989
- })()
5990
- ];
5991
- const runtimeServerlessPromise = this.#runtimeServerlessPromise;
5992
- if (runtimeServerlessPromise !== void 0) {
6238
+ const registries = [];
6239
+ if (modeAPromise !== void 0) {
5993
6240
  registries.push(
5994
6241
  (async () => {
5995
6242
  try {
5996
- const { runtime, registry } = await runtimeServerlessPromise;
6243
+ const { runtime, registry } = await modeAPromise;
6244
+ await runtime.shutdownRegistry(registry);
6245
+ } catch (err) {
6246
+ logger2().warn(
6247
+ { err },
6248
+ "runtime registry shutdown errored (mode A)"
6249
+ );
6250
+ }
6251
+ })()
6252
+ );
6253
+ }
6254
+ if (modeBPromise !== void 0) {
6255
+ registries.push(
6256
+ (async () => {
6257
+ try {
6258
+ const { runtime, registry } = await modeBPromise;
5997
6259
  await runtime.shutdownRegistry(registry);
5998
6260
  } catch (err) {
5999
6261
  logger2().warn(
@@ -6019,11 +6281,10 @@ var Registry = class {
6019
6281
  }
6020
6282
  )
6021
6283
  ]);
6022
- this.#removeSignalHandlers();
6023
- finishShutdownSignal(signal);
6024
6284
  }
6025
6285
  async #actorStopThresholdMs(configuredRegistryPromise) {
6026
6286
  var _a;
6287
+ if (configuredRegistryPromise === void 0) return void 0;
6027
6288
  try {
6028
6289
  const { runtime, registry } = await configuredRegistryPromise;
6029
6290
  const thresholdMs = await ((_a = runtime.registryActorStopThresholdMs) == null ? void 0 : _a.call(runtime, registry));
@@ -6077,7 +6338,7 @@ var Registry = class {
6077
6338
  logLine("Namespace", config.namespace);
6078
6339
  }
6079
6340
  if (config.endpoint) {
6080
- const endpointType = config.endpoint === ENGINE_ENDPOINT ? "local native" : "remote";
6341
+ const endpointType = config.startEngine || isLocalEngineEndpoint(config.endpoint) ? "local native" : "remote";
6081
6342
  logLine("Endpoint", `${config.endpoint} (${endpointType})`);
6082
6343
  }
6083
6344
  if (kind === "serverless" && config.publicEndpoint) {
@@ -6099,6 +6360,12 @@ function isServerlessMetadataRequest(request, basePath) {
6099
6360
  const normalizedBase = basePath === "/" ? "" : `/${basePath.replace(/^\/+|\/+$/g, "")}`;
6100
6361
  return parsed.pathname === `${normalizedBase}/metadata`;
6101
6362
  }
6363
+ function jsonRouteResponse(status, body) {
6364
+ return new Response(JSON.stringify(body), {
6365
+ status,
6366
+ headers: { "content-type": "application/json" }
6367
+ });
6368
+ }
6102
6369
  function setup(input) {
6103
6370
  return new Registry(input);
6104
6371
  }