rivetkit 0.0.0-skip-ready-wait-flatten-client-options.1cae221 → 0.0.0-sqlite-uds.4e59a38

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 (253) hide show
  1. package/dist/browser/client.d.ts +561 -89
  2. package/dist/browser/client.js +1063 -430
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.d.ts +22 -2
  5. package/dist/browser/inspector/client.js +1036 -232
  6. package/dist/browser/inspector/client.js.map +1 -1
  7. package/dist/tsup/actor/errors.cjs +6 -2
  8. package/dist/tsup/actor/errors.cjs.map +1 -1
  9. package/dist/tsup/actor/errors.d.cts +1 -74
  10. package/dist/tsup/actor/errors.d.ts +1 -74
  11. package/dist/tsup/actor/errors.js +5 -1
  12. package/dist/tsup/agent-os/index.cjs +2218 -2082
  13. package/dist/tsup/agent-os/index.cjs.map +1 -1
  14. package/dist/tsup/agent-os/index.d.cts +556 -85
  15. package/dist/tsup/agent-os/index.d.ts +556 -85
  16. package/dist/tsup/agent-os/index.js +2220 -2084
  17. package/dist/tsup/agent-os/index.js.map +1 -1
  18. package/dist/tsup/{chunk-NFC5VU36.cjs → chunk-3GC3EP6D.cjs} +18 -10
  19. package/dist/tsup/chunk-3GC3EP6D.cjs.map +1 -0
  20. package/dist/tsup/{chunk-7MRGNVSR.js → chunk-3GLNEWGY.js} +78 -6
  21. package/dist/tsup/chunk-3GLNEWGY.js.map +1 -0
  22. package/dist/tsup/{chunk-V3QNBJ7N.cjs → chunk-4FC7TVS6.cjs} +35 -10
  23. package/dist/tsup/chunk-4FC7TVS6.cjs.map +1 -0
  24. package/dist/tsup/{chunk-POTPHU3P.cjs → chunk-62LSMTP2.cjs} +3 -3
  25. package/dist/tsup/{chunk-POTPHU3P.cjs.map → chunk-62LSMTP2.cjs.map} +1 -1
  26. package/dist/tsup/{chunk-OIKOPSXQ.js → chunk-7IVUT2JT.js} +12 -4
  27. package/dist/tsup/chunk-7IVUT2JT.js.map +1 -0
  28. package/dist/tsup/{chunk-22XU3BVY.cjs → chunk-GEYQLGXC.cjs} +925 -328
  29. package/dist/tsup/chunk-GEYQLGXC.cjs.map +1 -0
  30. package/dist/tsup/{chunk-D2TLG75Y.cjs → chunk-GMN45CQ6.cjs} +10 -10
  31. package/dist/tsup/chunk-GMN45CQ6.cjs.map +1 -0
  32. package/dist/tsup/{chunk-3BFYSYRU.js → chunk-HXUEHHJF.js} +3 -2
  33. package/dist/tsup/chunk-HXUEHHJF.js.map +1 -0
  34. package/dist/tsup/{chunk-IOYKCB6Y.cjs → chunk-I336PMWT.cjs} +44 -9
  35. package/dist/tsup/chunk-I336PMWT.cjs.map +1 -0
  36. package/dist/tsup/{chunk-RZEJJJKU.js → chunk-IB73AMGJ.js} +42 -7
  37. package/dist/tsup/chunk-IB73AMGJ.js.map +1 -0
  38. package/dist/tsup/{chunk-4ZIWB4CQ.js → chunk-ITWJ6Y7G.js} +2 -2
  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-W54QCENI.js → chunk-KTNBYGRU.js} +134 -20
  42. package/dist/tsup/chunk-KTNBYGRU.js.map +1 -0
  43. package/dist/tsup/{chunk-AK57AL7S.cjs → chunk-OAPVVVTX.cjs} +79 -7
  44. package/dist/tsup/chunk-OAPVVVTX.cjs.map +1 -0
  45. package/dist/tsup/{chunk-TPBHXFB2.cjs → chunk-OUDV3ITX.cjs} +138 -24
  46. package/dist/tsup/chunk-OUDV3ITX.cjs.map +1 -0
  47. package/dist/tsup/{chunk-XNZR7UD2.cjs → chunk-PRXTIERO.cjs} +90 -65
  48. package/dist/tsup/chunk-PRXTIERO.cjs.map +1 -0
  49. package/dist/tsup/{chunk-LLD2D5LO.cjs → chunk-VE2X4KMG.cjs} +3 -2
  50. package/dist/tsup/chunk-VE2X4KMG.cjs.map +1 -0
  51. package/dist/tsup/{chunk-KSG2COSQ.js → chunk-WRZEVVLL.js} +6 -6
  52. package/dist/tsup/chunk-WRZEVVLL.js.map +1 -0
  53. package/dist/tsup/{chunk-LNMB25HW.js → chunk-XAIMHUPG.js} +780 -183
  54. package/dist/tsup/chunk-XAIMHUPG.js.map +1 -0
  55. package/dist/tsup/{chunk-D4TSTM6C.js → chunk-XZ62SWSC.js} +83 -58
  56. package/dist/tsup/chunk-XZ62SWSC.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/{chunk-K34B3OVG.js → chunk-ZZ3WBRPD.js} +34 -9
  60. package/dist/tsup/chunk-ZZ3WBRPD.js.map +1 -0
  61. package/dist/tsup/client/mod.cjs +9 -9
  62. package/dist/tsup/client/mod.cjs.map +1 -1
  63. package/dist/tsup/client/mod.d.cts +8 -9
  64. package/dist/tsup/client/mod.d.ts +8 -9
  65. package/dist/tsup/client/mod.js +8 -8
  66. package/dist/tsup/common/log.cjs +5 -3
  67. package/dist/tsup/common/log.cjs.map +1 -1
  68. package/dist/tsup/common/log.d.cts +5 -1
  69. package/dist/tsup/common/log.d.ts +5 -1
  70. package/dist/tsup/common/log.js +6 -4
  71. package/dist/tsup/common/websocket.cjs +4 -4
  72. package/dist/tsup/common/websocket.js +3 -3
  73. package/dist/tsup/{config-CRdGwwbr.d.cts → config-CxG53eQo.d.cts} +577 -36
  74. package/dist/tsup/{config-kxXbtrJU.d.ts → config-DLOxy81E.d.cts} +5 -5
  75. package/dist/tsup/{config-kxXbtrJU.d.cts → config-DLOxy81E.d.ts} +5 -5
  76. package/dist/tsup/{config-DIpBWm5C.d.ts → config-Ds6DCRhV.d.ts} +577 -36
  77. package/dist/tsup/context-8KlcOYIs.d.cts +129 -0
  78. package/dist/tsup/context-Cfbm4QLr.d.ts +129 -0
  79. package/dist/tsup/db/drizzle.cjs +151 -79
  80. package/dist/tsup/db/drizzle.cjs.map +1 -1
  81. package/dist/tsup/db/drizzle.d.cts +2 -2
  82. package/dist/tsup/db/drizzle.d.ts +2 -2
  83. package/dist/tsup/db/drizzle.js +151 -79
  84. package/dist/tsup/db/drizzle.js.map +1 -1
  85. package/dist/tsup/db/mod.cjs +79 -24
  86. package/dist/tsup/db/mod.cjs.map +1 -1
  87. package/dist/tsup/db/mod.d.cts +2 -2
  88. package/dist/tsup/db/mod.d.ts +2 -2
  89. package/dist/tsup/db/mod.js +78 -23
  90. package/dist/tsup/db/mod.js.map +1 -1
  91. package/dist/tsup/dynamic/mod.cjs +24 -0
  92. package/dist/tsup/dynamic/mod.cjs.map +1 -0
  93. package/dist/tsup/dynamic/mod.d.cts +37 -0
  94. package/dist/tsup/dynamic/mod.d.ts +37 -0
  95. package/dist/tsup/dynamic/mod.js +24 -0
  96. package/dist/tsup/dynamic/mod.js.map +1 -0
  97. package/dist/tsup/inspector/mod.cjs +47 -12
  98. package/dist/tsup/inspector/mod.cjs.map +1 -1
  99. package/dist/tsup/inspector/mod.d.cts +37 -15
  100. package/dist/tsup/inspector/mod.d.ts +37 -15
  101. package/dist/tsup/inspector/mod.js +46 -11
  102. package/dist/tsup/inspector/mod.js.map +1 -1
  103. package/dist/tsup/inspector-tab/mod.cjs +162 -0
  104. package/dist/tsup/inspector-tab/mod.cjs.map +1 -0
  105. package/dist/tsup/inspector-tab/mod.d.cts +240 -0
  106. package/dist/tsup/inspector-tab/mod.d.ts +240 -0
  107. package/dist/tsup/inspector-tab/mod.js +162 -0
  108. package/dist/tsup/inspector-tab/mod.js.map +1 -0
  109. package/dist/tsup/mod.cjs +1078 -479
  110. package/dist/tsup/mod.cjs.map +1 -1
  111. package/dist/tsup/mod.d.cts +5 -6
  112. package/dist/tsup/mod.d.ts +5 -6
  113. package/dist/tsup/mod.js +996 -397
  114. package/dist/tsup/mod.js.map +1 -1
  115. package/dist/tsup/test/mod.cjs +21 -18
  116. package/dist/tsup/test/mod.cjs.map +1 -1
  117. package/dist/tsup/test/mod.d.cts +4 -5
  118. package/dist/tsup/test/mod.d.ts +4 -5
  119. package/dist/tsup/test/mod.js +18 -15
  120. package/dist/tsup/test/mod.js.map +1 -1
  121. package/dist/tsup/utils-CqDnC_PS.d.cts +104 -0
  122. package/dist/tsup/utils-CqDnC_PS.d.ts +104 -0
  123. package/dist/tsup/utils.cjs +3 -3
  124. package/dist/tsup/utils.d.cts +1 -1
  125. package/dist/tsup/utils.d.ts +1 -1
  126. package/dist/tsup/utils.js +2 -2
  127. package/dist/tsup/workflow/mod.cjs +386 -322
  128. package/dist/tsup/workflow/mod.cjs.map +1 -1
  129. package/dist/tsup/workflow/mod.d.cts +8 -9
  130. package/dist/tsup/workflow/mod.d.ts +8 -9
  131. package/dist/tsup/workflow/mod.js +363 -299
  132. package/dist/tsup/workflow/mod.js.map +1 -1
  133. package/package.json +35 -14
  134. package/src/actor/config.ts +188 -59
  135. package/src/actor/contexts/index.ts +7 -2
  136. package/src/actor/definition.ts +17 -19
  137. package/src/actor/driver.ts +3 -3
  138. package/src/actor/errors.ts +70 -7
  139. package/src/actor/instance/mod.ts +39 -56
  140. package/src/actor/keys.ts +2 -1
  141. package/src/actor/mod.ts +22 -20
  142. package/src/actor/schema.ts +2 -2
  143. package/src/agent-os/actor/index.ts +38 -18
  144. package/src/agent-os/actor/preview.ts +1 -2
  145. package/src/agent-os/actor/session.ts +2 -2
  146. package/src/agent-os/config.ts +1 -1
  147. package/src/agent-os/fs/database-vfs.ts +1 -1
  148. package/src/agent-os/index.ts +16 -15
  149. package/src/client/actor-common.ts +88 -62
  150. package/src/client/actor-conn.ts +58 -63
  151. package/src/client/actor-handle.ts +125 -71
  152. package/src/client/actor-query.ts +5 -5
  153. package/src/client/config.ts +3 -3
  154. package/src/client/errors.ts +2 -1
  155. package/src/client/lifecycle-errors.ts +2 -4
  156. package/src/client/query.ts +1 -1
  157. package/src/client/queue.ts +8 -3
  158. package/src/client/raw-utils.ts +10 -10
  159. package/src/client/resolve-gateway-target.ts +1 -1
  160. package/src/client/utils.ts +34 -10
  161. package/src/common/actor-router-consts.ts +7 -4
  162. package/src/common/actor-websocket.ts +3 -1
  163. package/src/common/bare/actor-persist/v1.ts +205 -163
  164. package/src/common/bare/actor-persist/v2.ts +265 -213
  165. package/src/common/bare/actor-persist/v3.ts +176 -172
  166. package/src/common/bare/actor-persist/v4.ts +254 -253
  167. package/src/common/bare/generated/client-protocol/v4.ts +599 -0
  168. package/src/common/bare/generated/inspector/v5.ts +1016 -0
  169. package/src/common/bare/transport/v1.ts +694 -542
  170. package/src/common/client-protocol-versioned.ts +176 -67
  171. package/src/common/client-protocol-zod.ts +7 -0
  172. package/src/common/client-protocol.ts +1 -1
  173. package/src/common/database/config.ts +16 -5
  174. package/src/common/database/mod.test.ts +83 -16
  175. package/src/common/database/mod.ts +86 -30
  176. package/src/common/database/native-database.test.ts +35 -22
  177. package/src/common/database/native-database.ts +26 -10
  178. package/src/common/database/shared.ts +1 -0
  179. package/src/common/encoding.ts +250 -16
  180. package/src/common/engine.ts +28 -1
  181. package/src/common/eventsource.ts +1 -1
  182. package/src/common/inline-websocket-adapter.ts +14 -13
  183. package/src/common/log.ts +15 -8
  184. package/src/common/router.ts +49 -23
  185. package/src/common/utils.ts +10 -202
  186. package/src/common/websocket-interface.ts +1 -1
  187. package/src/db/drizzle.ts +173 -96
  188. package/src/db/mod.ts +1 -1
  189. package/src/devtools-loader/index.ts +4 -7
  190. package/src/devtools-loader/serve-devtools.ts +26 -0
  191. package/src/drivers/engine/actor-driver.ts +76 -73
  192. package/src/dynamic/instance.ts +32 -0
  193. package/src/dynamic/internal.ts +50 -0
  194. package/src/dynamic/isolate-runtime.ts +66 -0
  195. package/src/dynamic/mod.ts +32 -0
  196. package/src/engine-client/actor-http-client.ts +6 -9
  197. package/src/engine-client/actor-websocket-client.ts +14 -13
  198. package/src/engine-client/api-endpoints.ts +51 -2
  199. package/src/engine-client/api-utils.ts +2 -2
  200. package/src/engine-client/driver.ts +3 -4
  201. package/src/engine-client/mod.ts +17 -10
  202. package/src/engine-client/ws-proxy.ts +9 -4
  203. package/src/inspector/client.browser.ts +66 -15
  204. package/src/inspector/mod.ts +2 -4
  205. package/src/inspector-tab/mod.ts +300 -0
  206. package/src/registry/config/envoy.ts +1 -2
  207. package/src/registry/config/index.ts +46 -20
  208. package/src/registry/index.ts +364 -87
  209. package/src/registry/napi-runtime.ts +97 -8
  210. package/src/registry/native-validation.ts +10 -12
  211. package/src/registry/native.ts +592 -343
  212. package/src/registry/process-metrics.ts +250 -0
  213. package/src/registry/runtime.ts +85 -6
  214. package/src/registry/wasm-runtime.ts +72 -3
  215. package/src/registry/write-through-proxy.ts +40 -0
  216. package/src/serde.ts +2 -2
  217. package/src/serverless/configure.ts +19 -8
  218. package/src/test/mod.ts +11 -8
  219. package/src/utils/crypto.ts +14 -0
  220. package/src/utils/endpoint-parser.ts +1 -1
  221. package/src/utils/env-vars.ts +37 -0
  222. package/src/utils/router.ts +1 -1
  223. package/src/utils.ts +1 -2
  224. package/src/workflow/context.ts +703 -240
  225. package/src/workflow/driver.ts +23 -12
  226. package/src/workflow/inspector.ts +12 -3
  227. package/src/workflow/mod.ts +37 -23
  228. package/dist/tsup/chunk-22XU3BVY.cjs.map +0 -1
  229. package/dist/tsup/chunk-2NDZ7JCR.cjs.map +0 -1
  230. package/dist/tsup/chunk-3BFYSYRU.js.map +0 -1
  231. package/dist/tsup/chunk-7MRGNVSR.js.map +0 -1
  232. package/dist/tsup/chunk-AK57AL7S.cjs.map +0 -1
  233. package/dist/tsup/chunk-D2TLG75Y.cjs.map +0 -1
  234. package/dist/tsup/chunk-D4TSTM6C.js.map +0 -1
  235. package/dist/tsup/chunk-IOYKCB6Y.cjs.map +0 -1
  236. package/dist/tsup/chunk-K34B3OVG.js.map +0 -1
  237. package/dist/tsup/chunk-KSG2COSQ.js.map +0 -1
  238. package/dist/tsup/chunk-LLD2D5LO.cjs.map +0 -1
  239. package/dist/tsup/chunk-LNMB25HW.js.map +0 -1
  240. package/dist/tsup/chunk-NFC5VU36.cjs.map +0 -1
  241. package/dist/tsup/chunk-OIKOPSXQ.js.map +0 -1
  242. package/dist/tsup/chunk-PCBNKI2J.js.map +0 -1
  243. package/dist/tsup/chunk-RZEJJJKU.js.map +0 -1
  244. package/dist/tsup/chunk-TPBHXFB2.cjs.map +0 -1
  245. package/dist/tsup/chunk-V3QNBJ7N.cjs.map +0 -1
  246. package/dist/tsup/chunk-W54QCENI.js.map +0 -1
  247. package/dist/tsup/chunk-XNZR7UD2.cjs.map +0 -1
  248. package/dist/tsup/context-B7G6sk7x.d.ts +0 -92
  249. package/dist/tsup/context-DzMRHkjC.d.cts +0 -92
  250. package/dist/tsup/utils-fwx3o3K9.d.cts +0 -18
  251. package/dist/tsup/utils-fwx3o3K9.d.ts +0 -18
  252. package/src/utils/serve.ts +0 -217
  253. /package/dist/tsup/{chunk-4ZIWB4CQ.js.map → chunk-ITWJ6Y7G.js.map} +0 -0
@@ -1,6 +1,12 @@
1
- import { ENGINE_ENDPOINT } from "@/common/engine";
1
+ import { isLocalEngineEndpoint } from "@/common/engine";
2
+ import { configureBaseLogger } from "@/common/log";
2
3
  import { configureServerlessPool } from "@/serverless/configure";
3
4
  import { VERSION } from "@/utils";
5
+ import {
6
+ getRivetkitPublicDir,
7
+ getRivetkitRuntimeMode,
8
+ parsePortEnv,
9
+ } from "@/utils/env-vars";
4
10
  import {
5
11
  type RegistryActors,
6
12
  type RegistryConfig,
@@ -13,6 +19,22 @@ import type { RuntimeServerlessResponseHead } from "./runtime";
13
19
 
14
20
  type ShutdownSignal = "SIGINT" | "SIGTERM";
15
21
 
22
+ function signalExitCode(signal: ShutdownSignal): number {
23
+ switch (signal) {
24
+ case "SIGINT":
25
+ return 130;
26
+ case "SIGTERM":
27
+ return 143;
28
+ }
29
+ }
30
+
31
+ function finishShutdownSignal(signal: ShutdownSignal): void {
32
+ if (process.pid === 1) {
33
+ process.exit(signalExitCode(signal));
34
+ }
35
+ process.kill(process.pid, signal);
36
+ }
37
+
16
38
  export type FetchHandler = (
17
39
  request: Request,
18
40
  ...args: any
@@ -22,13 +44,25 @@ export interface ServerlessHandler {
22
44
  fetch: FetchHandler;
23
45
  }
24
46
 
25
- export interface RegistryDiagnostics {
26
- mode: string;
27
- envoyActiveActorCount?: number | null;
47
+ export interface RegistryRoutes {
48
+ health(): Promise<Response>;
49
+ metadata(): Promise<Response>;
50
+ prometheusMetrics(request?: Request): Promise<Response>;
51
+ }
52
+
53
+ /**
54
+ * Injectable dependencies for {@link Registry}. Production code uses the
55
+ * defaults. Tests override `buildConfiguredRegistry` to drive lifecycle
56
+ * orchestration against a fake `CoreRuntime` without an engine.
57
+ */
58
+ export interface RegistryDeps {
59
+ buildConfiguredRegistry: typeof buildConfiguredRegistry;
28
60
  }
29
61
 
30
62
  export class Registry<A extends RegistryActors> {
31
63
  #config: RegistryConfigInput<A>;
64
+ #buildConfiguredRegistry: typeof buildConfiguredRegistry;
65
+ public readonly routes: RegistryRoutes;
32
66
 
33
67
  get config(): RegistryConfigInput<A> {
34
68
  return this.#config;
@@ -47,20 +81,39 @@ export class Registry<A extends RegistryActors> {
47
81
  #shutdownInFlight: Promise<void> | null = null;
48
82
  #signalHandlers: Partial<Record<ShutdownSignal, () => void>> = {};
49
83
 
50
- constructor(config: RegistryConfigInput<A>) {
84
+ constructor(config: RegistryConfigInput<A>, deps?: Partial<RegistryDeps>) {
51
85
  this.#config = config;
86
+ if (config.logging?.baseLogger) {
87
+ configureBaseLogger(config.logging.baseLogger);
88
+ }
89
+ this.#buildConfiguredRegistry =
90
+ deps?.buildConfiguredRegistry ?? buildConfiguredRegistry;
91
+ this.routes = {
92
+ health: () => this.#healthRoute(),
93
+ metadata: () => this.#metadataRoute(),
94
+ prometheusMetrics: (request?: Request) =>
95
+ this.#prometheusMetricsRoute(request),
96
+ };
52
97
  }
53
98
 
54
- #ensureServerlessPoolConfigured(config: RegistryConfig): Promise<void> | undefined {
99
+ /**
100
+ * Fires `configureServerlessPool` once per process when the registry
101
+ * config opts into it. Cached on the instance so repeated calls (from
102
+ * `handler()` and `listen()`) only run the upsert once. The retry loop
103
+ * inside `configureServerlessPool` tolerates the engine still warming up.
104
+ */
105
+ #ensureServerlessPoolConfigured(
106
+ config: RegistryConfig,
107
+ ): Promise<void> | undefined {
55
108
  if (!config.configurePool) return undefined;
56
109
 
57
110
  if (!this.#configureServerlessPoolPromise) {
58
- this.#configureServerlessPoolPromise = configureServerlessPool(config).catch(
59
- (error) => {
60
- this.#configureServerlessPoolPromise = undefined;
61
- throw error;
62
- },
63
- );
111
+ this.#configureServerlessPoolPromise = configureServerlessPool(
112
+ config,
113
+ ).catch((error) => {
114
+ this.#configureServerlessPoolPromise = undefined;
115
+ throw error;
116
+ });
64
117
  this.#configureServerlessPoolPromise.catch(() => {});
65
118
  }
66
119
 
@@ -82,7 +135,8 @@ export class Registry<A extends RegistryActors> {
82
135
  this.#printWelcome(config, "serverless");
83
136
 
84
137
  if (!this.#runtimeServerlessPromise) {
85
- this.#runtimeServerlessPromise = buildConfiguredRegistry(config);
138
+ this.#runtimeServerlessPromise =
139
+ this.#buildConfiguredRegistry(config);
86
140
  }
87
141
 
88
142
  const { runtime, registry, serveConfig } =
@@ -96,12 +150,13 @@ export class Registry<A extends RegistryActors> {
96
150
  serveConfig.serverlessBasePath ?? "/api/rivet",
97
151
  );
98
152
  const isEngineMetadataRequest =
99
- request.headers.get("user-agent")?.startsWith("RivetEngine/") ?? false;
153
+ request.headers.get("user-agent")?.startsWith("RivetEngine/") ??
154
+ false;
100
155
 
101
156
  if (isStartRequest) {
102
157
  try {
103
158
  await this.#ensureServerlessPoolConfigured(config);
104
- } catch (error) {
159
+ } catch (_error) {
105
160
  return new Response(
106
161
  JSON.stringify({
107
162
  group: "guard",
@@ -243,7 +298,7 @@ export class Registry<A extends RegistryActors> {
243
298
  if (isMetadataRequest && !isEngineMetadataRequest) {
244
299
  try {
245
300
  await this.#ensureServerlessPoolConfigured(config);
246
- } catch (error) {
301
+ } catch (_error) {
247
302
  return new Response(
248
303
  JSON.stringify({
249
304
  group: "guard",
@@ -279,21 +334,152 @@ export class Registry<A extends RegistryActors> {
279
334
  };
280
335
  }
281
336
 
282
- public async diagnostics(): Promise<RegistryDiagnostics> {
337
+ /**
338
+ * Bind an HTTP listener provided by the native (Rust) runtime and serve
339
+ * the registry's serverless endpoints over it. Resolves only after the
340
+ * registry is shut down (SIGINT/SIGTERM or `nativeRegistry.shutdown()`).
341
+ *
342
+ * @param opts.port Port to listen on. Defaults to `process.env.RIVET_PORT`
343
+ * if set, otherwise 3000.
344
+ * @param opts.host Address to bind. Defaults to `0.0.0.0`.
345
+ * @param opts.publicDir If set, serves static files from this directory
346
+ * as a fallback below the framework routes.
347
+ *
348
+ * @example
349
+ * ```ts
350
+ * await registry.listen();
351
+ * await registry.listen({ port: 8080, publicDir: "./public" });
352
+ * ```
353
+ */
354
+ public async listen(
355
+ opts: { port?: number; host?: string; publicDir?: string } = {},
356
+ ): Promise<void> {
357
+ const port = opts.port ?? parsePortEnv(process.env.RIVET_PORT) ?? 3000;
358
+ const publicDir = opts.publicDir ?? getRivetkitPublicDir();
359
+ const config = this.parseConfig();
360
+
361
+ // Cache on both promise fields so the shutdown drain sees Mode A and B.
362
+ const configuredRegistryPromise = buildConfiguredRegistry(config);
363
+ this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
364
+ this.#runtimeServerlessPromise = configuredRegistryPromise;
365
+ this.#installSignalHandlers(config);
366
+
367
+ this.#printWelcome(config, "serverless", {
368
+ port,
369
+ host: opts.host,
370
+ publicDir,
371
+ });
372
+
373
+ // Background fire; the retry loop tolerates engine warm-up.
374
+ this.#ensureServerlessPoolConfigured(config);
375
+
376
+ const { runtime, registry, serveConfig } =
377
+ await configuredRegistryPromise;
378
+ await runtime.serveListener(
379
+ registry,
380
+ { port, host: opts.host, publicDir },
381
+ serveConfig,
382
+ );
383
+ }
384
+
385
+ /**
386
+ * Returns a health response suitable for mounting in a user-owned router.
387
+ */
388
+ async #healthRoute(): Promise<Response> {
389
+ const configured = await this.#activeConfiguredRegistry();
390
+ if (!configured) {
391
+ return jsonRouteResponse(503, {
392
+ status: "not_started",
393
+ runtime: "rivetkit",
394
+ version: VERSION,
395
+ });
396
+ }
397
+
398
+ const { runtime, registry } = configured;
399
+ if (!runtime.registryHealth) {
400
+ return jsonRouteResponse(501, {
401
+ status: "unsupported",
402
+ runtime: "rivetkit",
403
+ version: VERSION,
404
+ });
405
+ }
406
+
407
+ const response = await runtime.registryHealth(registry);
408
+ return new Response(new Uint8Array(response.body), {
409
+ status: response.status,
410
+ headers: response.headers,
411
+ });
412
+ }
413
+
414
+ /**
415
+ * Returns serverless metadata suitable for mounting in a user-owned router.
416
+ */
417
+ async #metadataRoute(): Promise<Response> {
418
+ const configured = await this.#activeConfiguredRegistry();
419
+ if (!configured) {
420
+ return new Response("registry not started\n", {
421
+ status: 503,
422
+ headers: { "content-type": "text/plain; charset=utf-8" },
423
+ });
424
+ }
425
+
426
+ const { runtime, registry } = configured;
427
+ if (!runtime.registryMetadata) {
428
+ return new Response("metadata is not supported by this runtime\n", {
429
+ status: 501,
430
+ headers: { "content-type": "text/plain; charset=utf-8" },
431
+ });
432
+ }
433
+
434
+ const response = await runtime.registryMetadata(registry);
435
+ return new Response(new Uint8Array(response.body), {
436
+ status: response.status,
437
+ headers: response.headers,
438
+ });
439
+ }
440
+
441
+ /**
442
+ * Returns a Prometheus metrics response suitable for mounting in a user-owned router.
443
+ */
444
+ async #prometheusMetricsRoute(_request?: Request): Promise<Response> {
445
+ const configured = await this.#activeConfiguredRegistry();
446
+ if (!configured) {
447
+ return new Response("registry not started\n", {
448
+ status: 503,
449
+ headers: { "content-type": "text/plain; charset=utf-8" },
450
+ });
451
+ }
452
+
453
+ const { runtime, registry } = configured;
454
+ if (!runtime.registryMetrics) {
455
+ return new Response("metrics are not supported by this runtime\n", {
456
+ status: 501,
457
+ headers: { "content-type": "text/plain; charset=utf-8" },
458
+ });
459
+ }
460
+
461
+ const response = await runtime.registryMetrics(registry);
462
+ return new Response(new Uint8Array(response.body), {
463
+ status: response.status,
464
+ headers: response.headers,
465
+ });
466
+ }
467
+
468
+ async #activeConfiguredRegistry(): Promise<
469
+ Awaited<ReturnType<typeof buildConfiguredRegistry>> | undefined
470
+ > {
283
471
  const candidates = [
284
472
  this.#runtimeServerlessPromise,
285
473
  this.#runtimeServeConfiguredPromise,
286
- ].filter((candidate): candidate is ReturnType<typeof buildConfiguredRegistry> =>
287
- candidate !== undefined
474
+ ].filter(
475
+ (
476
+ candidate,
477
+ ): candidate is ReturnType<typeof buildConfiguredRegistry> =>
478
+ candidate !== undefined,
288
479
  );
289
480
 
290
- for (const candidate of candidates) {
291
- const { runtime, registry } = await candidate;
292
- const diagnostics = await runtime.registryDiagnostics?.(registry);
293
- if (diagnostics) return diagnostics;
294
- }
295
-
296
- return { mode: "not_started", envoyActiveActorCount: null };
481
+ if (candidates.length === 0) return undefined;
482
+ return await candidates[0]!;
297
483
  }
298
484
 
299
485
  /**
@@ -301,35 +487,33 @@ export class Registry<A extends RegistryActors> {
301
487
  */
302
488
  #startEnvoy(config: RegistryConfig, printWelcome: boolean) {
303
489
  if (!this.#runtimeServePromise) {
304
- const configuredRegistryPromise = buildConfiguredRegistry(config);
490
+ const configuredRegistryPromise =
491
+ this.#buildConfiguredRegistry(config);
305
492
  this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
306
493
  this.#runtimeServePromise = configuredRegistryPromise
307
494
  .then(async ({ runtime, registry, serveConfig }) => {
308
495
  await runtime.serveRegistry(registry, serveConfig);
309
496
  })
310
- .catch((err) => {
497
+ .catch((error) => {
311
498
  // Always-attached catch so the stored promise never leaves a
312
499
  // rejection unhandled. Downstream awaits (e.g. #runShutdown's
313
500
  // Promise.race) attach their own catches and still observe
314
501
  // resolution via the race.
315
- logger().warn({ err }, "runtime registry serve errored");
502
+ logger().warn({ error }, "runtime registry serve errored");
316
503
  });
317
504
  // Install signal handlers once an envoy lifecycle has begun. Only
318
505
  // Mode A ever reaches here. Mode B (handler(request)) intentionally
319
506
  // does not install handlers because it runs on Workers/Vercel/Deno
320
507
  // Deploy where `process.on` is absent or forbidden; those platforms
321
508
  // own their own signal policy.
322
- this.#installSignalHandlers(config, configuredRegistryPromise);
509
+ this.#installSignalHandlers(config);
323
510
  }
324
511
  if (printWelcome) {
325
512
  this.#printWelcome(config, "serverful");
326
513
  }
327
514
  }
328
515
 
329
- #installSignalHandlers(
330
- config: RegistryConfig,
331
- configuredRegistryPromise: ReturnType<typeof buildConfiguredRegistry>,
332
- ): void {
516
+ #installSignalHandlers(config: RegistryConfig): void {
333
517
  if (this.#shutdownInstalled) return;
334
518
  if (config.shutdown?.disableSignalHandlers) return;
335
519
  // Guard against non-Node runtimes (Workers/Edge) where `process` may
@@ -344,12 +528,7 @@ export class Registry<A extends RegistryActors> {
344
528
  this.#shutdownInstalled = true;
345
529
 
346
530
  const install = (signal: ShutdownSignal) => {
347
- const handler = () =>
348
- this.#onShutdownSignal(
349
- signal,
350
- config,
351
- configuredRegistryPromise,
352
- );
531
+ const handler = () => this.#onShutdownSignal(signal, config);
353
532
  this.#signalHandlers[signal] = handler;
354
533
  process.on(signal, handler);
355
534
  };
@@ -357,68 +536,101 @@ export class Registry<A extends RegistryActors> {
357
536
  install("SIGTERM");
358
537
  }
359
538
 
360
- #onShutdownSignal(
361
- signal: ShutdownSignal,
362
- config: RegistryConfig,
363
- configuredRegistryPromise: ReturnType<typeof buildConfiguredRegistry>,
364
- ): void {
539
+ #onShutdownSignal(signal: ShutdownSignal, config: RegistryConfig): void {
365
540
  if (this.#shutdownInFlight !== null) {
366
- // Second delivery of the same (or another) shutdown signal.
367
- // Remove our handler only (preserving any user-installed listeners)
368
- // and re-raise so Node proceeds with its default exit path.
541
+ // Second delivery of the same (or another) shutdown signal, or a
542
+ // drain already started by an explicit `shutdown()` call. Remove
543
+ // our handler only, preserving any user-installed listeners. PID 1
544
+ // must exit directly because re-raised default signals can be
545
+ // swallowed by the container signal path.
369
546
  this.#removeSignalHandlers();
370
- process.kill(process.pid, signal);
547
+ finishShutdownSignal(signal);
371
548
  return;
372
549
  }
373
- this.#shutdownInFlight = this.#runShutdown(
374
- signal,
375
- config,
376
- configuredRegistryPromise,
377
- ).catch((err) => {
550
+ this.#shutdownInFlight = this.#drain(config)
551
+ .catch((err) => {
552
+ logger().warn({ err }, "shutdown error");
553
+ })
554
+ .then(() => {
555
+ this.#removeSignalHandlers();
556
+ finishShutdownSignal(signal);
557
+ });
558
+ }
559
+
560
+ /**
561
+ * Gracefully drains all live registries.
562
+ *
563
+ * Programmatic counterpart to the SIGINT/SIGTERM handlers: tears down
564
+ * every live `CoreRegistry` (both `start()` and `handler()` modes) and
565
+ * waits for the serve promise to resolve, all bounded by the shutdown
566
+ * grace period. Unlike a signal-driven shutdown, this does not re-raise a
567
+ * signal or exit the process. The caller owns process lifetime.
568
+ *
569
+ * Idempotent: concurrent or repeated calls share a single drain. Safe to
570
+ * call even if nothing has been started.
571
+ *
572
+ * @example
573
+ * ```ts
574
+ * const registry = setup({ use: { counter } });
575
+ * registry.start();
576
+ * // ...later, on your own shutdown trigger:
577
+ * await registry.shutdown();
578
+ * ```
579
+ */
580
+ public async shutdown(): Promise<void> {
581
+ if (this.#shutdownInFlight !== null) return this.#shutdownInFlight;
582
+ const config = this.parseConfig();
583
+ // Uninstall our signal handlers so a later SIGINT/SIGTERM does not
584
+ // re-trigger a drain on already-torn-down registries. Subsequent
585
+ // signals fall back to Node's default termination behavior.
586
+ this.#removeSignalHandlers();
587
+ this.#shutdownInFlight = this.#drain(config).catch((err) => {
378
588
  logger().warn({ err }, "shutdown error");
379
589
  });
590
+ return this.#shutdownInFlight;
380
591
  }
381
592
 
382
- async #runShutdown(
383
- signal: ShutdownSignal,
384
- config: RegistryConfig,
385
- configuredRegistryPromise: ReturnType<typeof buildConfiguredRegistry>,
386
- ): Promise<void> {
387
- const gracePeriodMs = config.shutdown?.gracePeriodMs ?? 30_000;
593
+ async #drain(config: RegistryConfig): Promise<void> {
594
+ const modeAPromise = this.#runtimeServeConfiguredPromise;
595
+ const modeBPromise = this.#runtimeServerlessPromise;
596
+
597
+ const gracePeriodMs =
598
+ config.shutdown?.gracePeriodMs ??
599
+ (await this.#actorStopThresholdMs(modeAPromise ?? modeBPromise)) ??
600
+ 30 * 60 * 1000;
388
601
  // Race the entire drain sequence (both modes + serve promise) against
389
- // a single grace ceiling. Without this, each mode's Rust-side drain
390
- // (20s) could stack sequentially and blow past gracePeriodMs before
391
- // we re-raise the signal.
602
+ // a single grace ceiling. By default, this uses the engine-provided
603
+ // actor stop threshold, matching Pegboard's hard cutoff for actors.
392
604
  const drain = async () => {
393
605
  // Shut down every live `CoreRegistry` we know about. Mode A
394
606
  // (`start()`) and Mode B (`handler()`) each build a separate
395
- // runtime registry, so one signal handler fans out to both to
396
- // honor the spec invariant "single shutdown tears down both modes".
397
- const registries: Promise<void>[] = [
398
- (async () => {
399
- try {
400
- const { runtime, registry } =
401
- await configuredRegistryPromise;
402
- await runtime.shutdownRegistry(registry);
403
- } catch (err) {
404
- logger().warn(
405
- { err },
406
- "runtime registry shutdown errored (mode A)",
407
- );
408
- }
409
- })(),
410
- ];
411
- const runtimeServerlessPromise = this.#runtimeServerlessPromise;
412
- if (runtimeServerlessPromise !== undefined) {
607
+ // runtime registry, so one drain fans out to both to honor the
608
+ // spec invariant "single shutdown tears down both modes".
609
+ const registries: Promise<void>[] = [];
610
+ if (modeAPromise !== undefined) {
413
611
  registries.push(
414
612
  (async () => {
415
613
  try {
416
- const { runtime, registry } =
417
- await runtimeServerlessPromise;
614
+ const { runtime, registry } = await modeAPromise;
418
615
  await runtime.shutdownRegistry(registry);
419
616
  } catch (err) {
420
617
  logger().warn(
421
618
  { err },
619
+ "runtime registry shutdown errored (mode A)",
620
+ );
621
+ }
622
+ })(),
623
+ );
624
+ }
625
+ if (modeBPromise !== undefined) {
626
+ registries.push(
627
+ (async () => {
628
+ try {
629
+ const { runtime, registry } = await modeBPromise;
630
+ await runtime.shutdownRegistry(registry);
631
+ } catch (err) {
632
+ logger().warn(
633
+ { error: err },
422
634
  "runtime registry shutdown errored (mode B)",
423
635
  );
424
636
  }
@@ -441,8 +653,32 @@ export class Registry<A extends RegistryActors> {
441
653
  setTimeout(resolve, gracePeriodMs).unref?.(),
442
654
  ),
443
655
  ]);
444
- this.#removeSignalHandlers();
445
- process.kill(process.pid, signal);
656
+ }
657
+
658
+ async #actorStopThresholdMs(
659
+ configuredRegistryPromise:
660
+ | ReturnType<typeof buildConfiguredRegistry>
661
+ | undefined,
662
+ ): Promise<number | undefined> {
663
+ if (configuredRegistryPromise === undefined) return undefined;
664
+ try {
665
+ const { runtime, registry } = await configuredRegistryPromise;
666
+ const thresholdMs =
667
+ await runtime.registryActorStopThresholdMs?.(registry);
668
+ if (
669
+ thresholdMs !== undefined &&
670
+ Number.isFinite(thresholdMs) &&
671
+ thresholdMs > 0
672
+ ) {
673
+ return thresholdMs;
674
+ }
675
+ } catch (err) {
676
+ logger().warn(
677
+ { err },
678
+ "failed to read actor stop threshold for shutdown grace",
679
+ );
680
+ }
681
+ return undefined;
446
682
  }
447
683
 
448
684
  #removeSignalHandlers(): void {
@@ -461,6 +697,10 @@ export class Registry<A extends RegistryActors> {
461
697
  /**
462
698
  * Starts the actor envoy for standalone server deployments.
463
699
  *
700
+ * Set `RIVETKIT_RUNTIME_MODE=serverless` to instead bind an HTTP listener
701
+ * via `listen()` (Mode B). Mode A (envoy) and Mode B (listener) are
702
+ * mutually exclusive per registry instance.
703
+ *
464
704
  * @example
465
705
  * ```ts
466
706
  * const registry = setup({ use: { counter } });
@@ -468,6 +708,21 @@ export class Registry<A extends RegistryActors> {
468
708
  * ```
469
709
  */
470
710
  public start() {
711
+ if (getRivetkitRuntimeMode() === "serverless") {
712
+ // start() defaults publicDir to "/public" unless overridden by env.
713
+ const publicDir = getRivetkitPublicDir() ?? "/public";
714
+ // Detached listener; bind failures are fatal so exit hard.
715
+ this.listen({ publicDir }).catch((error) => {
716
+ logger().error({ error }, "auto-listen failed; exiting");
717
+ if (
718
+ typeof process !== "undefined" &&
719
+ typeof process.exit === "function"
720
+ ) {
721
+ process.exit(1);
722
+ }
723
+ });
724
+ return;
725
+ }
471
726
  const config = this.parseConfig();
472
727
  this.#startEnvoy(config, true);
473
728
  }
@@ -475,6 +730,7 @@ export class Registry<A extends RegistryActors> {
475
730
  #printWelcome(
476
731
  config: RegistryConfig,
477
732
  kind: "serverless" | "serverful",
733
+ listener?: { port: number; host?: string; publicDir?: string },
478
734
  ): void {
479
735
  if (config.noWelcome || this.#welcomePrinted) return;
480
736
  this.#welcomePrinted = true;
@@ -495,7 +751,9 @@ export class Registry<A extends RegistryActors> {
495
751
 
496
752
  if (config.endpoint) {
497
753
  const endpointType =
498
- config.endpoint === ENGINE_ENDPOINT ? "local native" : "remote";
754
+ config.startEngine || isLocalEngineEndpoint(config.endpoint)
755
+ ? "local native"
756
+ : "remote";
499
757
  logLine("Endpoint", `${config.endpoint} (${endpointType})`);
500
758
  }
501
759
 
@@ -504,6 +762,15 @@ export class Registry<A extends RegistryActors> {
504
762
  }
505
763
 
506
764
  logLine("Actors", Object.keys(config.use).length.toString());
765
+
766
+ if (listener) {
767
+ const host = listener.host ?? "0.0.0.0";
768
+ logLine("Listening", `http://${host}:${listener.port}`);
769
+ if (listener.publicDir) {
770
+ logLine("Public Dir", listener.publicDir);
771
+ }
772
+ }
773
+
507
774
  console.log();
508
775
  }
509
776
  }
@@ -516,7 +783,10 @@ function isServerlessStartRequest(request: Request, basePath: string): boolean {
516
783
  return parsed.pathname === `${normalizedBase}/start`;
517
784
  }
518
785
 
519
- function isServerlessMetadataRequest(request: Request, basePath: string): boolean {
786
+ function isServerlessMetadataRequest(
787
+ request: Request,
788
+ basePath: string,
789
+ ): boolean {
520
790
  if (request.method !== "GET") return false;
521
791
  const parsed = new URL(request.url);
522
792
  const normalizedBase =
@@ -524,6 +794,13 @@ function isServerlessMetadataRequest(request: Request, basePath: string): boolea
524
794
  return parsed.pathname === `${normalizedBase}/metadata`;
525
795
  }
526
796
 
797
+ function jsonRouteResponse(status: number, body: unknown): Response {
798
+ return new Response(JSON.stringify(body), {
799
+ status,
800
+ headers: { "content-type": "application/json" },
801
+ });
802
+ }
803
+
527
804
  export function setup<A extends RegistryActors>(
528
805
  input: RegistryConfigInput<A>,
529
806
  ): Registry<A> {