rivetkit 2.3.0-rc.7 → 2.3.0-rc.9

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 (122) hide show
  1. package/dist/browser/client.d.ts +8 -37
  2. package/dist/browser/client.js +34 -64
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +3 -4
  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.js +1 -1
  8. package/dist/tsup/agent-os/index.cjs +5 -7
  9. package/dist/tsup/agent-os/index.cjs.map +1 -1
  10. package/dist/tsup/agent-os/index.d.cts +5 -26
  11. package/dist/tsup/agent-os/index.d.ts +5 -26
  12. package/dist/tsup/agent-os/index.js +5 -7
  13. package/dist/tsup/agent-os/index.js.map +1 -1
  14. package/dist/tsup/{chunk-55E7IR6D.cjs → chunk-4CGA6QJO.cjs} +4 -4
  15. package/dist/tsup/{chunk-55E7IR6D.cjs.map → chunk-4CGA6QJO.cjs.map} +1 -1
  16. package/dist/tsup/{chunk-G5HUSWP4.cjs → chunk-4WPEZBK4.cjs} +8 -8
  17. package/dist/tsup/{chunk-G5HUSWP4.cjs.map → chunk-4WPEZBK4.cjs.map} +1 -1
  18. package/dist/tsup/{chunk-2H4ISA4Y.cjs → chunk-CPA4Y3RG.cjs} +10 -10
  19. package/dist/tsup/chunk-CPA4Y3RG.cjs.map +1 -0
  20. package/dist/tsup/{chunk-VJ4Y4WBT.js → chunk-F3Q5BFQ6.js} +34 -10
  21. package/dist/tsup/chunk-F3Q5BFQ6.js.map +1 -0
  22. package/dist/tsup/{chunk-ZGPX6KAH.cjs → chunk-GVTOE34S.cjs} +193 -169
  23. package/dist/tsup/chunk-GVTOE34S.cjs.map +1 -0
  24. package/dist/tsup/{chunk-4DJMFOSU.js → chunk-H37XQU3I.js} +2 -2
  25. package/dist/tsup/{chunk-CMV6N5OX.js → chunk-H7P7WR2Y.js} +3 -3
  26. package/dist/tsup/{chunk-TMLOKTRB.js → chunk-KIWH5H3K.js} +3 -3
  27. package/dist/tsup/chunk-KIWH5H3K.js.map +1 -0
  28. package/dist/tsup/{chunk-52TPEKEC.js → chunk-KJTA3ATT.js} +2 -2
  29. package/dist/tsup/{chunk-SJLPZEA3.cjs → chunk-MALSPBAF.cjs} +3 -3
  30. package/dist/tsup/{chunk-SJLPZEA3.cjs.map → chunk-MALSPBAF.cjs.map} +1 -1
  31. package/dist/tsup/{chunk-VFIY6GWO.js → chunk-MMMEZM5J.js} +4 -4
  32. package/dist/tsup/chunk-MMMEZM5J.js.map +1 -0
  33. package/dist/tsup/{chunk-63WNTDRC.cjs → chunk-QAZLM4WT.cjs} +3 -3
  34. package/dist/tsup/{chunk-63WNTDRC.cjs.map → chunk-QAZLM4WT.cjs.map} +1 -1
  35. package/dist/tsup/{chunk-D5G75T7J.js → chunk-T6YVRM4K.js} +1 -3
  36. package/dist/tsup/chunk-T6YVRM4K.js.map +1 -0
  37. package/dist/tsup/{chunk-FEOG44WH.cjs → chunk-VJFRBJVQ.cjs} +9 -137
  38. package/dist/tsup/chunk-VJFRBJVQ.cjs.map +1 -0
  39. package/dist/tsup/{chunk-HERL2VQ2.js → chunk-VRCIXJRN.js} +5 -7
  40. package/dist/tsup/chunk-VRCIXJRN.js.map +1 -0
  41. package/dist/tsup/{chunk-4LTY5TOO.js → chunk-W7EYSYVI.js} +4 -132
  42. package/dist/tsup/chunk-W7EYSYVI.js.map +1 -0
  43. package/dist/tsup/{chunk-SRNOPUC6.cjs → chunk-WQ4HNA4W.cjs} +2 -4
  44. package/dist/tsup/chunk-WQ4HNA4W.cjs.map +1 -0
  45. package/dist/tsup/{chunk-X6HIFXNK.cjs → chunk-Y5NSCZA2.cjs} +12 -14
  46. package/dist/tsup/chunk-Y5NSCZA2.cjs.map +1 -0
  47. package/dist/tsup/client/mod.cjs +7 -7
  48. package/dist/tsup/client/mod.d.cts +2 -2
  49. package/dist/tsup/client/mod.d.ts +2 -2
  50. package/dist/tsup/client/mod.js +6 -6
  51. package/dist/tsup/common/log.cjs +3 -3
  52. package/dist/tsup/common/log.js +2 -2
  53. package/dist/tsup/common/websocket.cjs +4 -4
  54. package/dist/tsup/common/websocket.js +3 -3
  55. package/dist/tsup/{config-Ak1lv4gF.d.ts → config-0Ta55UV0.d.ts} +6 -27
  56. package/dist/tsup/{config-DU_xj4qZ.d.cts → config-Ca8dN4cS.d.cts} +6 -27
  57. package/dist/tsup/{context-DAAp4Lpg.d.ts → context-B_IWbWne.d.ts} +1 -1
  58. package/dist/tsup/{context-Dt_L55q8.d.cts → context-CUrQ9MHc.d.cts} +1 -1
  59. package/dist/tsup/inspector/mod.cjs +6 -6
  60. package/dist/tsup/inspector/mod.js +5 -5
  61. package/dist/tsup/mod.cjs +355 -482
  62. package/dist/tsup/mod.cjs.map +1 -1
  63. package/dist/tsup/mod.d.cts +3 -3
  64. package/dist/tsup/mod.d.ts +3 -3
  65. package/dist/tsup/mod.js +276 -403
  66. package/dist/tsup/mod.js.map +1 -1
  67. package/dist/tsup/test/mod.cjs +10 -10
  68. package/dist/tsup/test/mod.d.cts +1 -1
  69. package/dist/tsup/test/mod.d.ts +1 -1
  70. package/dist/tsup/test/mod.js +6 -6
  71. package/dist/tsup/utils.cjs +3 -3
  72. package/dist/tsup/utils.js +2 -2
  73. package/dist/tsup/workflow/mod.cjs +16 -41
  74. package/dist/tsup/workflow/mod.cjs.map +1 -1
  75. package/dist/tsup/workflow/mod.d.cts +3 -3
  76. package/dist/tsup/workflow/mod.d.ts +3 -3
  77. package/dist/tsup/workflow/mod.js +10 -35
  78. package/dist/tsup/workflow/mod.js.map +1 -1
  79. package/package.json +10 -11
  80. package/src/actor/config.ts +0 -3
  81. package/src/actor/errors.ts +2 -2
  82. package/src/agent-os/actor/session.ts +2 -2
  83. package/src/client/actor-conn.ts +34 -6
  84. package/src/client/actor-handle.ts +1 -2
  85. package/src/client/queue.ts +1 -2
  86. package/src/client/utils.ts +1 -0
  87. package/src/common/encoding.ts +5 -243
  88. package/src/common/inline-websocket-adapter.ts +12 -12
  89. package/src/common/log.ts +0 -1
  90. package/src/common/router.ts +2 -2
  91. package/src/common/utils.ts +148 -0
  92. package/src/drivers/engine/actor-driver.ts +11 -11
  93. package/src/engine-client/actor-websocket-client.ts +1 -2
  94. package/src/engine-client/mod.ts +2 -3
  95. package/src/registry/index.ts +109 -46
  96. package/src/registry/napi-runtime.ts +34 -11
  97. package/src/registry/native.ts +162 -205
  98. package/src/registry/runtime.ts +12 -5
  99. package/src/registry/wasm-runtime.ts +13 -2
  100. package/src/serde.ts +2 -2
  101. package/src/workflow/context.ts +5 -32
  102. package/src/workflow/inspector.ts +1 -2
  103. package/dist/tsup/chunk-2H4ISA4Y.cjs.map +0 -1
  104. package/dist/tsup/chunk-4LTY5TOO.js.map +0 -1
  105. package/dist/tsup/chunk-D5G75T7J.js.map +0 -1
  106. package/dist/tsup/chunk-FEOG44WH.cjs.map +0 -1
  107. package/dist/tsup/chunk-HERL2VQ2.js.map +0 -1
  108. package/dist/tsup/chunk-SRNOPUC6.cjs.map +0 -1
  109. package/dist/tsup/chunk-TMLOKTRB.js.map +0 -1
  110. package/dist/tsup/chunk-VFIY6GWO.js.map +0 -1
  111. package/dist/tsup/chunk-VJ4Y4WBT.js.map +0 -1
  112. package/dist/tsup/chunk-X6HIFXNK.cjs.map +0 -1
  113. package/dist/tsup/chunk-ZGPX6KAH.cjs.map +0 -1
  114. package/dist/tsup/process-metrics-NW754INA.js +0 -118
  115. package/dist/tsup/process-metrics-NW754INA.js.map +0 -1
  116. package/dist/tsup/process-metrics-TYAGKCEJ.cjs +0 -118
  117. package/dist/tsup/process-metrics-TYAGKCEJ.cjs.map +0 -1
  118. package/src/registry/process-metrics.ts +0 -183
  119. package/src/registry/write-through-proxy.ts +0 -40
  120. /package/dist/tsup/{chunk-4DJMFOSU.js.map → chunk-H37XQU3I.js.map} +0 -0
  121. /package/dist/tsup/{chunk-CMV6N5OX.js.map → chunk-H7P7WR2Y.js.map} +0 -0
  122. /package/dist/tsup/{chunk-52TPEKEC.js.map → chunk-KJTA3ATT.js.map} +0 -0
@@ -1,118 +0,0 @@
1
- // src/registry/process-metrics.ts
2
- import { monitorEventLoopDelay, performance, PerformanceObserver } from "perf_hooks";
3
- import { getHeapStatistics } from "v8";
4
- import * as napi from "@rivetkit/rivetkit-napi";
5
- function callIfFn(fn, ...args) {
6
- if (typeof fn === "function") {
7
- fn(...args);
8
- }
9
- }
10
- var SCRAPE_INTERVAL_MS = 5e3;
11
- var HEARTBEAT_INTERVAL_MS = 100;
12
- var EVENTLOOP_DELAY_RESOLUTION_MS = 20;
13
- var NS_PER_SECOND = 1e9;
14
- var US_PER_SECOND = 1e6;
15
- var GC_KIND_NAMES = {
16
- 1: "minor",
17
- 2: "major",
18
- 4: "incremental",
19
- 8: "weakcb"
20
- };
21
- var state;
22
- function startProcessMetrics() {
23
- if (state) {
24
- return;
25
- }
26
- const eventLoopHistogram = monitorEventLoopDelay({
27
- resolution: EVENTLOOP_DELAY_RESOLUTION_MS
28
- });
29
- eventLoopHistogram.enable();
30
- const gcObserver = new PerformanceObserver((list) => {
31
- var _a;
32
- for (const entry of list.getEntries()) {
33
- const kind = ((_a = entry.detail) == null ? void 0 : _a.kind) ?? entry.kind;
34
- if (typeof kind !== "number") continue;
35
- const kindName = GC_KIND_NAMES[kind];
36
- if (!kindName) continue;
37
- callIfFn(napi.jsObserveGcDuration, kindName, entry.duration / 1e3);
38
- }
39
- });
40
- gcObserver.observe({ entryTypes: ["gc"], buffered: false });
41
- const lastCpuUsage = process.cpuUsage();
42
- const lastEventLoopUtilization = performance.eventLoopUtilization();
43
- const heartbeatInterval = setInterval(() => {
44
- callIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());
45
- }, HEARTBEAT_INTERVAL_MS);
46
- heartbeatInterval.unref();
47
- const scrapeInterval = setInterval(() => {
48
- try {
49
- collectAndPush();
50
- } catch {
51
- }
52
- }, SCRAPE_INTERVAL_MS);
53
- scrapeInterval.unref();
54
- state = {
55
- scrapeInterval,
56
- heartbeatInterval,
57
- gcObserver,
58
- eventLoopHistogram,
59
- lastCpuUsage,
60
- lastEventLoopUtilization
61
- };
62
- callIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());
63
- try {
64
- collectAndPush();
65
- } catch {
66
- }
67
- }
68
- function stopProcessMetrics() {
69
- if (!state) {
70
- return;
71
- }
72
- clearInterval(state.scrapeInterval);
73
- clearInterval(state.heartbeatInterval);
74
- state.gcObserver.disconnect();
75
- state.eventLoopHistogram.disable();
76
- state = void 0;
77
- }
78
- function collectAndPush() {
79
- if (!state) return;
80
- const hist = state.eventLoopHistogram;
81
- callIfFn(napi.jsSetEventloopLagQuantile, "p50", hist.percentile(50) / NS_PER_SECOND);
82
- callIfFn(napi.jsSetEventloopLagQuantile, "p90", hist.percentile(90) / NS_PER_SECOND);
83
- callIfFn(napi.jsSetEventloopLagQuantile, "p99", hist.percentile(99) / NS_PER_SECOND);
84
- callIfFn(napi.jsSetEventloopLagQuantile, "max", hist.max / NS_PER_SECOND);
85
- hist.reset();
86
- const nextElu = performance.eventLoopUtilization();
87
- const eluDelta = performance.eventLoopUtilization(nextElu, state.lastEventLoopUtilization);
88
- state.lastEventLoopUtilization = nextElu;
89
- callIfFn(napi.jsSetEventloopUtilization, eluDelta.utilization);
90
- const nextCpu = process.cpuUsage();
91
- const userDeltaUs = nextCpu.user - state.lastCpuUsage.user;
92
- const systemDeltaUs = nextCpu.system - state.lastCpuUsage.system;
93
- state.lastCpuUsage = nextCpu;
94
- if (userDeltaUs > 0) {
95
- callIfFn(napi.jsAddProcessCpuSeconds, "user", userDeltaUs / US_PER_SECOND);
96
- }
97
- if (systemDeltaUs > 0) {
98
- callIfFn(napi.jsAddProcessCpuSeconds, "system", systemDeltaUs / US_PER_SECOND);
99
- }
100
- const mem = process.memoryUsage();
101
- callIfFn(napi.jsSetProcessResidentMemoryBytes, mem.rss);
102
- callIfFn(napi.jsSetHeapBytes, "used", mem.heapUsed);
103
- callIfFn(napi.jsSetHeapBytes, "total", mem.heapTotal);
104
- const heapLimit = getHeapStatistics().heap_size_limit;
105
- callIfFn(napi.jsSetHeapBytes, "limit", heapLimit);
106
- const proc = process;
107
- if (typeof proc._getActiveHandles === "function") {
108
- callIfFn(napi.jsSetActiveHandles, proc._getActiveHandles().length);
109
- }
110
- if (typeof proc._getActiveRequests === "function") {
111
- callIfFn(napi.jsSetActiveRequests, proc._getActiveRequests().length);
112
- }
113
- }
114
- export {
115
- startProcessMetrics,
116
- stopProcessMetrics
117
- };
118
- //# sourceMappingURL=process-metrics-NW754INA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/registry/process-metrics.ts"],"sourcesContent":["/**\n * Node.js runtime health metrics.\n *\n * Collects JS-internal data (event loop lag, GC, heap, libuv handles,\n * event loop utilization, CPU) using Node built-ins (`node:perf_hooks`,\n * `process`, `node:v8`, `PerformanceObserver`) and pushes them across NAPI\n * into Rust-side prometheus collectors registered with\n * `rivet_metrics::REGISTRY` so they appear on the existing `/metrics`\n * endpoint.\n *\n * All data collection happens here in TypeScript. The NAPI bridge is pure\n * type marshalling and the Rust side only registers + stores the metrics.\n */\nimport { monitorEventLoopDelay, performance, PerformanceObserver } from \"node:perf_hooks\";\nimport { getHeapStatistics } from \"node:v8\";\nimport * as napi from \"@rivetkit/rivetkit-napi\";\n\n// Some napi process-metrics symbols may be missing on older native binaries\n// (the auto-generated index.js destructures them as `undefined` if the\n// underlying `.node` was built before they were added). Guard each call so\n// the metrics collection runs as a no-op instead of throwing\n// `TypeError: napi.jsXxx is not a function` on every interval tick.\nfunction callIfFn<T extends unknown[]>(\n\tfn: ((...args: T) => void) | undefined,\n\t...args: T\n): void {\n\tif (typeof fn === \"function\") {\n\t\tfn(...args);\n\t}\n}\n\nconst SCRAPE_INTERVAL_MS = 5_000;\nconst HEARTBEAT_INTERVAL_MS = 100;\nconst EVENTLOOP_DELAY_RESOLUTION_MS = 20;\nconst NS_PER_SECOND = 1e9;\nconst US_PER_SECOND = 1e6;\n\n// V8 GC kind bitfield from Node's perf_hooks documentation. A `gc` performance\n// entry's `kind` field is one of these values.\nconst GC_KIND_NAMES: Record<number, string> = {\n\t1: \"minor\",\n\t2: \"major\",\n\t4: \"incremental\",\n\t8: \"weakcb\",\n};\n\ninterface ProcessMetricsState {\n\tscrapeInterval: NodeJS.Timeout;\n\theartbeatInterval: NodeJS.Timeout;\n\tgcObserver: PerformanceObserver;\n\teventLoopHistogram: ReturnType<typeof monitorEventLoopDelay>;\n\tlastCpuUsage: NodeJS.CpuUsage;\n\tlastEventLoopUtilization: ReturnType<typeof performance.eventLoopUtilization>;\n}\n\nlet state: ProcessMetricsState | undefined;\n\nexport function startProcessMetrics(): void {\n\tif (state) {\n\t\treturn;\n\t}\n\n\tconst eventLoopHistogram = monitorEventLoopDelay({\n\t\tresolution: EVENTLOOP_DELAY_RESOLUTION_MS,\n\t});\n\teventLoopHistogram.enable();\n\n\tconst gcObserver = new PerformanceObserver((list) => {\n\t\tfor (const entry of list.getEntries()) {\n\t\t\tconst kind =\n\t\t\t\t(entry as PerformanceEntry & { detail?: { kind?: number }; kind?: number }).detail\n\t\t\t\t\t?.kind ??\n\t\t\t\t(entry as PerformanceEntry & { kind?: number }).kind;\n\t\t\tif (typeof kind !== \"number\") continue;\n\t\t\tconst kindName = GC_KIND_NAMES[kind];\n\t\t\tif (!kindName) continue;\n\t\t\t// `entry.duration` is in milliseconds; convert to seconds.\n\t\t\tcallIfFn(napi.jsObserveGcDuration, kindName, entry.duration / 1000);\n\t\t}\n\t});\n\tgcObserver.observe({ entryTypes: [\"gc\"], buffered: false });\n\n\tconst lastCpuUsage = process.cpuUsage();\n\tconst lastEventLoopUtilization = performance.eventLoopUtilization();\n\n\tconst heartbeatInterval = setInterval(() => {\n\t\tcallIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());\n\t}, HEARTBEAT_INTERVAL_MS);\n\theartbeatInterval.unref();\n\n\tconst scrapeInterval = setInterval(() => {\n\t\ttry {\n\t\t\tcollectAndPush();\n\t\t} catch {\n\t\t\t// Collection errors must never bring down the process; metrics\n\t\t\t// are best-effort.\n\t\t}\n\t}, SCRAPE_INTERVAL_MS);\n\tscrapeInterval.unref();\n\n\tstate = {\n\t\tscrapeInterval,\n\t\theartbeatInterval,\n\t\tgcObserver,\n\t\teventLoopHistogram,\n\t\tlastCpuUsage,\n\t\tlastEventLoopUtilization,\n\t};\n\n\t// Emit one snapshot immediately so freshly-scraped instances have data.\n\tcallIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());\n\ttry {\n\t\tcollectAndPush();\n\t} catch {\n\t\t// As above; best-effort.\n\t}\n}\n\nexport function stopProcessMetrics(): void {\n\tif (!state) {\n\t\treturn;\n\t}\n\tclearInterval(state.scrapeInterval);\n\tclearInterval(state.heartbeatInterval);\n\tstate.gcObserver.disconnect();\n\tstate.eventLoopHistogram.disable();\n\tstate = undefined;\n}\n\nfunction collectAndPush(): void {\n\tif (!state) return;\n\n\t// Event loop delay quantiles. `monitorEventLoopDelay()` reports values in\n\t// nanoseconds; convert to seconds. Reset after reading so the next window\n\t// reflects only the new interval.\n\tconst hist = state.eventLoopHistogram;\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"p50\", hist.percentile(50) / NS_PER_SECOND);\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"p90\", hist.percentile(90) / NS_PER_SECOND);\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"p99\", hist.percentile(99) / NS_PER_SECOND);\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"max\", hist.max / NS_PER_SECOND);\n\thist.reset();\n\n\t// Event loop utilization delta over the scrape window.\n\tconst nextElu = performance.eventLoopUtilization();\n\tconst eluDelta = performance.eventLoopUtilization(nextElu, state.lastEventLoopUtilization);\n\tstate.lastEventLoopUtilization = nextElu;\n\tcallIfFn(napi.jsSetEventloopUtilization, eluDelta.utilization);\n\n\t// CPU usage delta. `process.cpuUsage()` returns microseconds.\n\tconst nextCpu = process.cpuUsage();\n\tconst userDeltaUs = nextCpu.user - state.lastCpuUsage.user;\n\tconst systemDeltaUs = nextCpu.system - state.lastCpuUsage.system;\n\tstate.lastCpuUsage = nextCpu;\n\tif (userDeltaUs > 0) {\n\t\tcallIfFn(napi.jsAddProcessCpuSeconds, \"user\", userDeltaUs / US_PER_SECOND);\n\t}\n\tif (systemDeltaUs > 0) {\n\t\tcallIfFn(napi.jsAddProcessCpuSeconds, \"system\", systemDeltaUs / US_PER_SECOND);\n\t}\n\n\t// Memory + heap.\n\tconst mem = process.memoryUsage();\n\tcallIfFn(napi.jsSetProcessResidentMemoryBytes, mem.rss);\n\tcallIfFn(napi.jsSetHeapBytes, \"used\", mem.heapUsed);\n\tcallIfFn(napi.jsSetHeapBytes, \"total\", mem.heapTotal);\n\tconst heapLimit = getHeapStatistics().heap_size_limit;\n\tcallIfFn(napi.jsSetHeapBytes, \"limit\", heapLimit);\n\n\t// libuv active handles + requests. These are unstable Node internals\n\t// guarded behind underscore-prefixed names; if a future Node release\n\t// removes them the try/catch above keeps the rest of the collection\n\t// alive.\n\tconst proc = process as unknown as {\n\t\t_getActiveHandles?: () => unknown[];\n\t\t_getActiveRequests?: () => unknown[];\n\t};\n\tif (typeof proc._getActiveHandles === \"function\") {\n\t\tcallIfFn(napi.jsSetActiveHandles, proc._getActiveHandles().length);\n\t}\n\tif (typeof proc._getActiveRequests === \"function\") {\n\t\tcallIfFn(napi.jsSetActiveRequests, proc._getActiveRequests().length);\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -1,118 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/registry/process-metrics.ts
2
- var _perf_hooks = require('perf_hooks');
3
- var _v8 = require('v8');
4
- var _rivetkitnapi = require('@rivetkit/rivetkit-napi'); var napi = _interopRequireWildcard(_rivetkitnapi);
5
- function callIfFn(fn, ...args) {
6
- if (typeof fn === "function") {
7
- fn(...args);
8
- }
9
- }
10
- var SCRAPE_INTERVAL_MS = 5e3;
11
- var HEARTBEAT_INTERVAL_MS = 100;
12
- var EVENTLOOP_DELAY_RESOLUTION_MS = 20;
13
- var NS_PER_SECOND = 1e9;
14
- var US_PER_SECOND = 1e6;
15
- var GC_KIND_NAMES = {
16
- 1: "minor",
17
- 2: "major",
18
- 4: "incremental",
19
- 8: "weakcb"
20
- };
21
- var state;
22
- function startProcessMetrics() {
23
- if (state) {
24
- return;
25
- }
26
- const eventLoopHistogram = _perf_hooks.monitorEventLoopDelay.call(void 0, {
27
- resolution: EVENTLOOP_DELAY_RESOLUTION_MS
28
- });
29
- eventLoopHistogram.enable();
30
- const gcObserver = new (0, _perf_hooks.PerformanceObserver)((list) => {
31
- var _a;
32
- for (const entry of list.getEntries()) {
33
- const kind = _nullishCoalesce(((_a = entry.detail) == null ? void 0 : _a.kind), () => ( entry.kind));
34
- if (typeof kind !== "number") continue;
35
- const kindName = GC_KIND_NAMES[kind];
36
- if (!kindName) continue;
37
- callIfFn(napi.jsObserveGcDuration, kindName, entry.duration / 1e3);
38
- }
39
- });
40
- gcObserver.observe({ entryTypes: ["gc"], buffered: false });
41
- const lastCpuUsage = process.cpuUsage();
42
- const lastEventLoopUtilization = _perf_hooks.performance.eventLoopUtilization();
43
- const heartbeatInterval = setInterval(() => {
44
- callIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());
45
- }, HEARTBEAT_INTERVAL_MS);
46
- heartbeatInterval.unref();
47
- const scrapeInterval = setInterval(() => {
48
- try {
49
- collectAndPush();
50
- } catch (e) {
51
- }
52
- }, SCRAPE_INTERVAL_MS);
53
- scrapeInterval.unref();
54
- state = {
55
- scrapeInterval,
56
- heartbeatInterval,
57
- gcObserver,
58
- eventLoopHistogram,
59
- lastCpuUsage,
60
- lastEventLoopUtilization
61
- };
62
- callIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());
63
- try {
64
- collectAndPush();
65
- } catch (e2) {
66
- }
67
- }
68
- function stopProcessMetrics() {
69
- if (!state) {
70
- return;
71
- }
72
- clearInterval(state.scrapeInterval);
73
- clearInterval(state.heartbeatInterval);
74
- state.gcObserver.disconnect();
75
- state.eventLoopHistogram.disable();
76
- state = void 0;
77
- }
78
- function collectAndPush() {
79
- if (!state) return;
80
- const hist = state.eventLoopHistogram;
81
- callIfFn(napi.jsSetEventloopLagQuantile, "p50", hist.percentile(50) / NS_PER_SECOND);
82
- callIfFn(napi.jsSetEventloopLagQuantile, "p90", hist.percentile(90) / NS_PER_SECOND);
83
- callIfFn(napi.jsSetEventloopLagQuantile, "p99", hist.percentile(99) / NS_PER_SECOND);
84
- callIfFn(napi.jsSetEventloopLagQuantile, "max", hist.max / NS_PER_SECOND);
85
- hist.reset();
86
- const nextElu = _perf_hooks.performance.eventLoopUtilization();
87
- const eluDelta = _perf_hooks.performance.eventLoopUtilization(nextElu, state.lastEventLoopUtilization);
88
- state.lastEventLoopUtilization = nextElu;
89
- callIfFn(napi.jsSetEventloopUtilization, eluDelta.utilization);
90
- const nextCpu = process.cpuUsage();
91
- const userDeltaUs = nextCpu.user - state.lastCpuUsage.user;
92
- const systemDeltaUs = nextCpu.system - state.lastCpuUsage.system;
93
- state.lastCpuUsage = nextCpu;
94
- if (userDeltaUs > 0) {
95
- callIfFn(napi.jsAddProcessCpuSeconds, "user", userDeltaUs / US_PER_SECOND);
96
- }
97
- if (systemDeltaUs > 0) {
98
- callIfFn(napi.jsAddProcessCpuSeconds, "system", systemDeltaUs / US_PER_SECOND);
99
- }
100
- const mem = process.memoryUsage();
101
- callIfFn(napi.jsSetProcessResidentMemoryBytes, mem.rss);
102
- callIfFn(napi.jsSetHeapBytes, "used", mem.heapUsed);
103
- callIfFn(napi.jsSetHeapBytes, "total", mem.heapTotal);
104
- const heapLimit = _v8.getHeapStatistics.call(void 0, ).heap_size_limit;
105
- callIfFn(napi.jsSetHeapBytes, "limit", heapLimit);
106
- const proc = process;
107
- if (typeof proc._getActiveHandles === "function") {
108
- callIfFn(napi.jsSetActiveHandles, proc._getActiveHandles().length);
109
- }
110
- if (typeof proc._getActiveRequests === "function") {
111
- callIfFn(napi.jsSetActiveRequests, proc._getActiveRequests().length);
112
- }
113
- }
114
-
115
-
116
-
117
- exports.startProcessMetrics = startProcessMetrics; exports.stopProcessMetrics = stopProcessMetrics;
118
- //# sourceMappingURL=process-metrics-TYAGKCEJ.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/rivetkit/dist/tsup/process-metrics-TYAGKCEJ.cjs","../../src/registry/process-metrics.ts"],"names":[],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/rivetkit/dist/tsup/process-metrics-TYAGKCEJ.cjs","sourcesContent":[null,"/**\n * Node.js runtime health metrics.\n *\n * Collects JS-internal data (event loop lag, GC, heap, libuv handles,\n * event loop utilization, CPU) using Node built-ins (`node:perf_hooks`,\n * `process`, `node:v8`, `PerformanceObserver`) and pushes them across NAPI\n * into Rust-side prometheus collectors registered with\n * `rivet_metrics::REGISTRY` so they appear on the existing `/metrics`\n * endpoint.\n *\n * All data collection happens here in TypeScript. The NAPI bridge is pure\n * type marshalling and the Rust side only registers + stores the metrics.\n */\nimport { monitorEventLoopDelay, performance, PerformanceObserver } from \"node:perf_hooks\";\nimport { getHeapStatistics } from \"node:v8\";\nimport * as napi from \"@rivetkit/rivetkit-napi\";\n\n// Some napi process-metrics symbols may be missing on older native binaries\n// (the auto-generated index.js destructures them as `undefined` if the\n// underlying `.node` was built before they were added). Guard each call so\n// the metrics collection runs as a no-op instead of throwing\n// `TypeError: napi.jsXxx is not a function` on every interval tick.\nfunction callIfFn<T extends unknown[]>(\n\tfn: ((...args: T) => void) | undefined,\n\t...args: T\n): void {\n\tif (typeof fn === \"function\") {\n\t\tfn(...args);\n\t}\n}\n\nconst SCRAPE_INTERVAL_MS = 5_000;\nconst HEARTBEAT_INTERVAL_MS = 100;\nconst EVENTLOOP_DELAY_RESOLUTION_MS = 20;\nconst NS_PER_SECOND = 1e9;\nconst US_PER_SECOND = 1e6;\n\n// V8 GC kind bitfield from Node's perf_hooks documentation. A `gc` performance\n// entry's `kind` field is one of these values.\nconst GC_KIND_NAMES: Record<number, string> = {\n\t1: \"minor\",\n\t2: \"major\",\n\t4: \"incremental\",\n\t8: \"weakcb\",\n};\n\ninterface ProcessMetricsState {\n\tscrapeInterval: NodeJS.Timeout;\n\theartbeatInterval: NodeJS.Timeout;\n\tgcObserver: PerformanceObserver;\n\teventLoopHistogram: ReturnType<typeof monitorEventLoopDelay>;\n\tlastCpuUsage: NodeJS.CpuUsage;\n\tlastEventLoopUtilization: ReturnType<typeof performance.eventLoopUtilization>;\n}\n\nlet state: ProcessMetricsState | undefined;\n\nexport function startProcessMetrics(): void {\n\tif (state) {\n\t\treturn;\n\t}\n\n\tconst eventLoopHistogram = monitorEventLoopDelay({\n\t\tresolution: EVENTLOOP_DELAY_RESOLUTION_MS,\n\t});\n\teventLoopHistogram.enable();\n\n\tconst gcObserver = new PerformanceObserver((list) => {\n\t\tfor (const entry of list.getEntries()) {\n\t\t\tconst kind =\n\t\t\t\t(entry as PerformanceEntry & { detail?: { kind?: number }; kind?: number }).detail\n\t\t\t\t\t?.kind ??\n\t\t\t\t(entry as PerformanceEntry & { kind?: number }).kind;\n\t\t\tif (typeof kind !== \"number\") continue;\n\t\t\tconst kindName = GC_KIND_NAMES[kind];\n\t\t\tif (!kindName) continue;\n\t\t\t// `entry.duration` is in milliseconds; convert to seconds.\n\t\t\tcallIfFn(napi.jsObserveGcDuration, kindName, entry.duration / 1000);\n\t\t}\n\t});\n\tgcObserver.observe({ entryTypes: [\"gc\"], buffered: false });\n\n\tconst lastCpuUsage = process.cpuUsage();\n\tconst lastEventLoopUtilization = performance.eventLoopUtilization();\n\n\tconst heartbeatInterval = setInterval(() => {\n\t\tcallIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());\n\t}, HEARTBEAT_INTERVAL_MS);\n\theartbeatInterval.unref();\n\n\tconst scrapeInterval = setInterval(() => {\n\t\ttry {\n\t\t\tcollectAndPush();\n\t\t} catch {\n\t\t\t// Collection errors must never bring down the process; metrics\n\t\t\t// are best-effort.\n\t\t}\n\t}, SCRAPE_INTERVAL_MS);\n\tscrapeInterval.unref();\n\n\tstate = {\n\t\tscrapeInterval,\n\t\theartbeatInterval,\n\t\tgcObserver,\n\t\teventLoopHistogram,\n\t\tlastCpuUsage,\n\t\tlastEventLoopUtilization,\n\t};\n\n\t// Emit one snapshot immediately so freshly-scraped instances have data.\n\tcallIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());\n\ttry {\n\t\tcollectAndPush();\n\t} catch {\n\t\t// As above; best-effort.\n\t}\n}\n\nexport function stopProcessMetrics(): void {\n\tif (!state) {\n\t\treturn;\n\t}\n\tclearInterval(state.scrapeInterval);\n\tclearInterval(state.heartbeatInterval);\n\tstate.gcObserver.disconnect();\n\tstate.eventLoopHistogram.disable();\n\tstate = undefined;\n}\n\nfunction collectAndPush(): void {\n\tif (!state) return;\n\n\t// Event loop delay quantiles. `monitorEventLoopDelay()` reports values in\n\t// nanoseconds; convert to seconds. Reset after reading so the next window\n\t// reflects only the new interval.\n\tconst hist = state.eventLoopHistogram;\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"p50\", hist.percentile(50) / NS_PER_SECOND);\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"p90\", hist.percentile(90) / NS_PER_SECOND);\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"p99\", hist.percentile(99) / NS_PER_SECOND);\n\tcallIfFn(napi.jsSetEventloopLagQuantile, \"max\", hist.max / NS_PER_SECOND);\n\thist.reset();\n\n\t// Event loop utilization delta over the scrape window.\n\tconst nextElu = performance.eventLoopUtilization();\n\tconst eluDelta = performance.eventLoopUtilization(nextElu, state.lastEventLoopUtilization);\n\tstate.lastEventLoopUtilization = nextElu;\n\tcallIfFn(napi.jsSetEventloopUtilization, eluDelta.utilization);\n\n\t// CPU usage delta. `process.cpuUsage()` returns microseconds.\n\tconst nextCpu = process.cpuUsage();\n\tconst userDeltaUs = nextCpu.user - state.lastCpuUsage.user;\n\tconst systemDeltaUs = nextCpu.system - state.lastCpuUsage.system;\n\tstate.lastCpuUsage = nextCpu;\n\tif (userDeltaUs > 0) {\n\t\tcallIfFn(napi.jsAddProcessCpuSeconds, \"user\", userDeltaUs / US_PER_SECOND);\n\t}\n\tif (systemDeltaUs > 0) {\n\t\tcallIfFn(napi.jsAddProcessCpuSeconds, \"system\", systemDeltaUs / US_PER_SECOND);\n\t}\n\n\t// Memory + heap.\n\tconst mem = process.memoryUsage();\n\tcallIfFn(napi.jsSetProcessResidentMemoryBytes, mem.rss);\n\tcallIfFn(napi.jsSetHeapBytes, \"used\", mem.heapUsed);\n\tcallIfFn(napi.jsSetHeapBytes, \"total\", mem.heapTotal);\n\tconst heapLimit = getHeapStatistics().heap_size_limit;\n\tcallIfFn(napi.jsSetHeapBytes, \"limit\", heapLimit);\n\n\t// libuv active handles + requests. These are unstable Node internals\n\t// guarded behind underscore-prefixed names; if a future Node release\n\t// removes them the try/catch above keeps the rest of the collection\n\t// alive.\n\tconst proc = process as unknown as {\n\t\t_getActiveHandles?: () => unknown[];\n\t\t_getActiveRequests?: () => unknown[];\n\t};\n\tif (typeof proc._getActiveHandles === \"function\") {\n\t\tcallIfFn(napi.jsSetActiveHandles, proc._getActiveHandles().length);\n\t}\n\tif (typeof proc._getActiveRequests === \"function\") {\n\t\tcallIfFn(napi.jsSetActiveRequests, proc._getActiveRequests().length);\n\t}\n}\n"]}
@@ -1,183 +0,0 @@
1
- /**
2
- * Node.js runtime health metrics.
3
- *
4
- * Collects JS-internal data (event loop lag, GC, heap, libuv handles,
5
- * event loop utilization, CPU) using Node built-ins (`node:perf_hooks`,
6
- * `process`, `node:v8`, `PerformanceObserver`) and pushes them across NAPI
7
- * into Rust-side prometheus collectors registered with
8
- * `rivet_metrics::REGISTRY` so they appear on the existing `/metrics`
9
- * endpoint.
10
- *
11
- * All data collection happens here in TypeScript. The NAPI bridge is pure
12
- * type marshalling and the Rust side only registers + stores the metrics.
13
- */
14
- import { monitorEventLoopDelay, performance, PerformanceObserver } from "node:perf_hooks";
15
- import { getHeapStatistics } from "node:v8";
16
- import * as napi from "@rivetkit/rivetkit-napi";
17
-
18
- // Some napi process-metrics symbols may be missing on older native binaries
19
- // (the auto-generated index.js destructures them as `undefined` if the
20
- // underlying `.node` was built before they were added). Guard each call so
21
- // the metrics collection runs as a no-op instead of throwing
22
- // `TypeError: napi.jsXxx is not a function` on every interval tick.
23
- function callIfFn<T extends unknown[]>(
24
- fn: ((...args: T) => void) | undefined,
25
- ...args: T
26
- ): void {
27
- if (typeof fn === "function") {
28
- fn(...args);
29
- }
30
- }
31
-
32
- const SCRAPE_INTERVAL_MS = 5_000;
33
- const HEARTBEAT_INTERVAL_MS = 100;
34
- const EVENTLOOP_DELAY_RESOLUTION_MS = 20;
35
- const NS_PER_SECOND = 1e9;
36
- const US_PER_SECOND = 1e6;
37
-
38
- // V8 GC kind bitfield from Node's perf_hooks documentation. A `gc` performance
39
- // entry's `kind` field is one of these values.
40
- const GC_KIND_NAMES: Record<number, string> = {
41
- 1: "minor",
42
- 2: "major",
43
- 4: "incremental",
44
- 8: "weakcb",
45
- };
46
-
47
- interface ProcessMetricsState {
48
- scrapeInterval: NodeJS.Timeout;
49
- heartbeatInterval: NodeJS.Timeout;
50
- gcObserver: PerformanceObserver;
51
- eventLoopHistogram: ReturnType<typeof monitorEventLoopDelay>;
52
- lastCpuUsage: NodeJS.CpuUsage;
53
- lastEventLoopUtilization: ReturnType<typeof performance.eventLoopUtilization>;
54
- }
55
-
56
- let state: ProcessMetricsState | undefined;
57
-
58
- export function startProcessMetrics(): void {
59
- if (state) {
60
- return;
61
- }
62
-
63
- const eventLoopHistogram = monitorEventLoopDelay({
64
- resolution: EVENTLOOP_DELAY_RESOLUTION_MS,
65
- });
66
- eventLoopHistogram.enable();
67
-
68
- const gcObserver = new PerformanceObserver((list) => {
69
- for (const entry of list.getEntries()) {
70
- const kind =
71
- (entry as PerformanceEntry & { detail?: { kind?: number }; kind?: number }).detail
72
- ?.kind ??
73
- (entry as PerformanceEntry & { kind?: number }).kind;
74
- if (typeof kind !== "number") continue;
75
- const kindName = GC_KIND_NAMES[kind];
76
- if (!kindName) continue;
77
- // `entry.duration` is in milliseconds; convert to seconds.
78
- callIfFn(napi.jsObserveGcDuration, kindName, entry.duration / 1000);
79
- }
80
- });
81
- gcObserver.observe({ entryTypes: ["gc"], buffered: false });
82
-
83
- const lastCpuUsage = process.cpuUsage();
84
- const lastEventLoopUtilization = performance.eventLoopUtilization();
85
-
86
- const heartbeatInterval = setInterval(() => {
87
- callIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());
88
- }, HEARTBEAT_INTERVAL_MS);
89
- heartbeatInterval.unref();
90
-
91
- const scrapeInterval = setInterval(() => {
92
- try {
93
- collectAndPush();
94
- } catch {
95
- // Collection errors must never bring down the process; metrics
96
- // are best-effort.
97
- }
98
- }, SCRAPE_INTERVAL_MS);
99
- scrapeInterval.unref();
100
-
101
- state = {
102
- scrapeInterval,
103
- heartbeatInterval,
104
- gcObserver,
105
- eventLoopHistogram,
106
- lastCpuUsage,
107
- lastEventLoopUtilization,
108
- };
109
-
110
- // Emit one snapshot immediately so freshly-scraped instances have data.
111
- callIfFn(napi.jsSetEventloopHeartbeatTsMs, Date.now());
112
- try {
113
- collectAndPush();
114
- } catch {
115
- // As above; best-effort.
116
- }
117
- }
118
-
119
- export function stopProcessMetrics(): void {
120
- if (!state) {
121
- return;
122
- }
123
- clearInterval(state.scrapeInterval);
124
- clearInterval(state.heartbeatInterval);
125
- state.gcObserver.disconnect();
126
- state.eventLoopHistogram.disable();
127
- state = undefined;
128
- }
129
-
130
- function collectAndPush(): void {
131
- if (!state) return;
132
-
133
- // Event loop delay quantiles. `monitorEventLoopDelay()` reports values in
134
- // nanoseconds; convert to seconds. Reset after reading so the next window
135
- // reflects only the new interval.
136
- const hist = state.eventLoopHistogram;
137
- callIfFn(napi.jsSetEventloopLagQuantile, "p50", hist.percentile(50) / NS_PER_SECOND);
138
- callIfFn(napi.jsSetEventloopLagQuantile, "p90", hist.percentile(90) / NS_PER_SECOND);
139
- callIfFn(napi.jsSetEventloopLagQuantile, "p99", hist.percentile(99) / NS_PER_SECOND);
140
- callIfFn(napi.jsSetEventloopLagQuantile, "max", hist.max / NS_PER_SECOND);
141
- hist.reset();
142
-
143
- // Event loop utilization delta over the scrape window.
144
- const nextElu = performance.eventLoopUtilization();
145
- const eluDelta = performance.eventLoopUtilization(nextElu, state.lastEventLoopUtilization);
146
- state.lastEventLoopUtilization = nextElu;
147
- callIfFn(napi.jsSetEventloopUtilization, eluDelta.utilization);
148
-
149
- // CPU usage delta. `process.cpuUsage()` returns microseconds.
150
- const nextCpu = process.cpuUsage();
151
- const userDeltaUs = nextCpu.user - state.lastCpuUsage.user;
152
- const systemDeltaUs = nextCpu.system - state.lastCpuUsage.system;
153
- state.lastCpuUsage = nextCpu;
154
- if (userDeltaUs > 0) {
155
- callIfFn(napi.jsAddProcessCpuSeconds, "user", userDeltaUs / US_PER_SECOND);
156
- }
157
- if (systemDeltaUs > 0) {
158
- callIfFn(napi.jsAddProcessCpuSeconds, "system", systemDeltaUs / US_PER_SECOND);
159
- }
160
-
161
- // Memory + heap.
162
- const mem = process.memoryUsage();
163
- callIfFn(napi.jsSetProcessResidentMemoryBytes, mem.rss);
164
- callIfFn(napi.jsSetHeapBytes, "used", mem.heapUsed);
165
- callIfFn(napi.jsSetHeapBytes, "total", mem.heapTotal);
166
- const heapLimit = getHeapStatistics().heap_size_limit;
167
- callIfFn(napi.jsSetHeapBytes, "limit", heapLimit);
168
-
169
- // libuv active handles + requests. These are unstable Node internals
170
- // guarded behind underscore-prefixed names; if a future Node release
171
- // removes them the try/catch above keeps the rest of the collection
172
- // alive.
173
- const proc = process as unknown as {
174
- _getActiveHandles?: () => unknown[];
175
- _getActiveRequests?: () => unknown[];
176
- };
177
- if (typeof proc._getActiveHandles === "function") {
178
- callIfFn(napi.jsSetActiveHandles, proc._getActiveHandles().length);
179
- }
180
- if (typeof proc._getActiveRequests === "function") {
181
- callIfFn(napi.jsSetActiveRequests, proc._getActiveRequests().length);
182
- }
183
- }
@@ -1,40 +0,0 @@
1
- import onChange from "@rivetkit/on-change";
2
-
3
- /**
4
- * Creates a proxy that tracks deep mutations on an object and calls `commit`
5
- * after every change. Uses `@rivetkit/on-change` internally, which correctly
6
- * detects mutations via methods on Map, Set, Date, TypedArrays, and arrays.
7
- *
8
- * If the value is not an object (primitive, null, undefined), it is returned
9
- * as-is since primitives cannot be proxied or mutated.
10
- *
11
- * @param value - The root value to watch.
12
- * @param commit - Called after every detected mutation with the root object.
13
- * @param beforeChange - Called before every mutation with the new value being
14
- * assigned. Throw to reject the change.
15
- */
16
- export function createWriteThroughProxy<T>(
17
- value: T,
18
- commit: (next: T) => void,
19
- beforeChange?: (newValue: unknown) => void,
20
- ): T {
21
- if (!value || typeof value !== "object") {
22
- return value;
23
- }
24
-
25
- return onChange(
26
- value as T & Record<string, any>,
27
- () => {
28
- commit(value);
29
- },
30
- {
31
- // Rejection is throw-based: beforeChange throws to prevent the
32
- // mutation. We always return true so on-change applies the change
33
- // if beforeChange did not throw.
34
- onValidate(_path: string, newValue: unknown) {
35
- beforeChange?.(newValue);
36
- return true;
37
- },
38
- },
39
- ) as T;
40
- }