rivetkit 2.0.2 → 2.0.4

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 (246) hide show
  1. package/README.md +3 -5
  2. package/dist/schemas/actor-persist/v1.ts +225 -0
  3. package/dist/schemas/client-protocol/v1.ts +435 -0
  4. package/dist/schemas/file-system-driver/v1.ts +102 -0
  5. package/dist/tsup/actor/errors.cjs +77 -0
  6. package/dist/tsup/actor/errors.cjs.map +1 -0
  7. package/dist/tsup/actor/errors.d.cts +156 -0
  8. package/dist/tsup/actor/errors.d.ts +156 -0
  9. package/dist/tsup/actor/errors.js +77 -0
  10. package/dist/tsup/actor/errors.js.map +1 -0
  11. package/dist/tsup/chunk-3F2YSRJL.js +117 -0
  12. package/dist/tsup/chunk-3F2YSRJL.js.map +1 -0
  13. package/dist/tsup/chunk-4CXBCT26.cjs +250 -0
  14. package/dist/tsup/chunk-4CXBCT26.cjs.map +1 -0
  15. package/dist/tsup/chunk-4R73YDN3.cjs +20 -0
  16. package/dist/tsup/chunk-4R73YDN3.cjs.map +1 -0
  17. package/dist/tsup/chunk-6LJT3QRL.cjs +539 -0
  18. package/dist/tsup/chunk-6LJT3QRL.cjs.map +1 -0
  19. package/dist/tsup/chunk-GICQ3YCU.cjs +1792 -0
  20. package/dist/tsup/chunk-GICQ3YCU.cjs.map +1 -0
  21. package/dist/tsup/chunk-H26RP6GD.js +251 -0
  22. package/dist/tsup/chunk-H26RP6GD.js.map +1 -0
  23. package/dist/tsup/chunk-HI3HWJRC.js +20 -0
  24. package/dist/tsup/chunk-HI3HWJRC.js.map +1 -0
  25. package/dist/tsup/chunk-HLLF4B4Q.js +1792 -0
  26. package/dist/tsup/chunk-HLLF4B4Q.js.map +1 -0
  27. package/dist/tsup/chunk-IH6CKNDW.cjs +117 -0
  28. package/dist/tsup/chunk-IH6CKNDW.cjs.map +1 -0
  29. package/dist/tsup/chunk-LV2S3OU3.js +250 -0
  30. package/dist/tsup/chunk-LV2S3OU3.js.map +1 -0
  31. package/dist/tsup/chunk-LWNKVZG5.cjs +251 -0
  32. package/dist/tsup/chunk-LWNKVZG5.cjs.map +1 -0
  33. package/dist/tsup/chunk-NFU2BBT5.js +374 -0
  34. package/dist/tsup/chunk-NFU2BBT5.js.map +1 -0
  35. package/dist/tsup/chunk-PQY7KKTL.js +539 -0
  36. package/dist/tsup/chunk-PQY7KKTL.js.map +1 -0
  37. package/dist/tsup/chunk-QK72M5JB.js +45 -0
  38. package/dist/tsup/chunk-QK72M5JB.js.map +1 -0
  39. package/dist/tsup/chunk-QNNXFOQV.cjs +45 -0
  40. package/dist/tsup/chunk-QNNXFOQV.cjs.map +1 -0
  41. package/dist/tsup/chunk-SBHHJ6QS.cjs +374 -0
  42. package/dist/tsup/chunk-SBHHJ6QS.cjs.map +1 -0
  43. package/dist/tsup/chunk-TQ62L3X7.js +325 -0
  44. package/dist/tsup/chunk-TQ62L3X7.js.map +1 -0
  45. package/dist/tsup/chunk-VO7ZRVVD.cjs +6293 -0
  46. package/dist/tsup/chunk-VO7ZRVVD.cjs.map +1 -0
  47. package/dist/tsup/chunk-WHBPJNGW.cjs +325 -0
  48. package/dist/tsup/chunk-WHBPJNGW.cjs.map +1 -0
  49. package/dist/tsup/chunk-XJQHKJ4P.js +6293 -0
  50. package/dist/tsup/chunk-XJQHKJ4P.js.map +1 -0
  51. package/dist/tsup/client/mod.cjs +32 -0
  52. package/dist/tsup/client/mod.cjs.map +1 -0
  53. package/dist/tsup/client/mod.d.cts +20 -0
  54. package/dist/tsup/client/mod.d.ts +20 -0
  55. package/dist/tsup/client/mod.js +32 -0
  56. package/dist/tsup/client/mod.js.map +1 -0
  57. package/dist/tsup/common/log.cjs +21 -0
  58. package/dist/tsup/common/log.cjs.map +1 -0
  59. package/dist/tsup/common/log.d.cts +26 -0
  60. package/dist/tsup/common/log.d.ts +26 -0
  61. package/dist/tsup/common/log.js +21 -0
  62. package/dist/tsup/common/log.js.map +1 -0
  63. package/dist/tsup/common/websocket.cjs +10 -0
  64. package/dist/tsup/common/websocket.cjs.map +1 -0
  65. package/dist/tsup/common/websocket.d.cts +3 -0
  66. package/dist/tsup/common/websocket.d.ts +3 -0
  67. package/dist/tsup/common/websocket.js +10 -0
  68. package/dist/tsup/common/websocket.js.map +1 -0
  69. package/dist/tsup/common-CXCe7s6i.d.cts +218 -0
  70. package/dist/tsup/common-CXCe7s6i.d.ts +218 -0
  71. package/dist/tsup/connection-BI-6UIBJ.d.ts +2087 -0
  72. package/dist/tsup/connection-Dyd4NLGW.d.cts +2087 -0
  73. package/dist/tsup/driver-helpers/mod.cjs +30 -0
  74. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  75. package/dist/tsup/driver-helpers/mod.d.cts +17 -0
  76. package/dist/tsup/driver-helpers/mod.d.ts +17 -0
  77. package/dist/tsup/driver-helpers/mod.js +30 -0
  78. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  79. package/dist/tsup/driver-test-suite/mod.cjs +3411 -0
  80. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  81. package/dist/tsup/driver-test-suite/mod.d.cts +63 -0
  82. package/dist/tsup/driver-test-suite/mod.d.ts +63 -0
  83. package/dist/tsup/driver-test-suite/mod.js +3411 -0
  84. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  85. package/dist/tsup/inspector/mod.cjs +51 -0
  86. package/dist/tsup/inspector/mod.cjs.map +1 -0
  87. package/dist/tsup/inspector/mod.d.cts +408 -0
  88. package/dist/tsup/inspector/mod.d.ts +408 -0
  89. package/dist/tsup/inspector/mod.js +51 -0
  90. package/dist/tsup/inspector/mod.js.map +1 -0
  91. package/dist/tsup/mod.cjs +67 -0
  92. package/dist/tsup/mod.cjs.map +1 -0
  93. package/dist/tsup/mod.d.cts +105 -0
  94. package/dist/tsup/mod.d.ts +105 -0
  95. package/dist/tsup/mod.js +67 -0
  96. package/dist/tsup/mod.js.map +1 -0
  97. package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +65 -0
  98. package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +65 -0
  99. package/dist/tsup/test/mod.cjs +17 -0
  100. package/dist/tsup/test/mod.cjs.map +1 -0
  101. package/dist/tsup/test/mod.d.cts +26 -0
  102. package/dist/tsup/test/mod.d.ts +26 -0
  103. package/dist/tsup/test/mod.js +17 -0
  104. package/dist/tsup/test/mod.js.map +1 -0
  105. package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
  106. package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
  107. package/dist/tsup/utils.cjs +26 -0
  108. package/dist/tsup/utils.cjs.map +1 -0
  109. package/dist/tsup/utils.d.cts +36 -0
  110. package/dist/tsup/utils.d.ts +36 -0
  111. package/dist/tsup/utils.js +26 -0
  112. package/dist/tsup/utils.js.map +1 -0
  113. package/package.json +208 -5
  114. package/src/actor/action.ts +178 -0
  115. package/src/actor/config.ts +497 -0
  116. package/src/actor/connection.ts +257 -0
  117. package/src/actor/context.ts +168 -0
  118. package/src/actor/database.ts +23 -0
  119. package/src/actor/definition.ts +82 -0
  120. package/src/actor/driver.ts +84 -0
  121. package/src/actor/errors.ts +422 -0
  122. package/src/actor/generic-conn-driver.ts +246 -0
  123. package/src/actor/instance.ts +1844 -0
  124. package/src/actor/keys.test.ts +266 -0
  125. package/src/actor/keys.ts +89 -0
  126. package/src/actor/log.ts +6 -0
  127. package/src/actor/mod.ts +108 -0
  128. package/src/actor/persisted.ts +42 -0
  129. package/src/actor/protocol/old.ts +297 -0
  130. package/src/actor/protocol/serde.ts +131 -0
  131. package/src/actor/router-endpoints.ts +688 -0
  132. package/src/actor/router.ts +265 -0
  133. package/src/actor/schedule.ts +17 -0
  134. package/src/actor/unstable-react.ts +110 -0
  135. package/src/actor/utils.ts +102 -0
  136. package/src/client/actor-common.ts +30 -0
  137. package/src/client/actor-conn.ts +865 -0
  138. package/src/client/actor-handle.ts +268 -0
  139. package/src/client/actor-query.ts +65 -0
  140. package/src/client/client.ts +554 -0
  141. package/src/client/config.ts +44 -0
  142. package/src/client/errors.ts +42 -0
  143. package/src/client/log.ts +5 -0
  144. package/src/client/mod.ts +60 -0
  145. package/src/client/raw-utils.ts +149 -0
  146. package/src/client/test.ts +44 -0
  147. package/src/client/utils.ts +152 -0
  148. package/src/common/eventsource-interface.ts +47 -0
  149. package/src/common/eventsource.ts +80 -0
  150. package/src/common/fake-event-source.ts +267 -0
  151. package/src/common/inline-websocket-adapter2.ts +454 -0
  152. package/src/common/log-levels.ts +27 -0
  153. package/src/common/log.ts +214 -0
  154. package/src/common/logfmt.ts +219 -0
  155. package/src/common/network.ts +2 -0
  156. package/src/common/router.ts +80 -0
  157. package/src/common/utils.ts +336 -0
  158. package/src/common/versioned-data.ts +95 -0
  159. package/src/common/websocket-interface.ts +49 -0
  160. package/src/common/websocket.ts +42 -0
  161. package/src/driver-helpers/mod.ts +22 -0
  162. package/src/driver-helpers/utils.ts +17 -0
  163. package/src/driver-test-suite/log.ts +5 -0
  164. package/src/driver-test-suite/mod.ts +239 -0
  165. package/src/driver-test-suite/tests/action-features.ts +136 -0
  166. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  167. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  168. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  169. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  170. package/src/driver-test-suite/tests/actor-handle.ts +292 -0
  171. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  172. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  173. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  174. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  175. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  176. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  177. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  178. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  179. package/src/driver-test-suite/tests/manager-driver.ts +367 -0
  180. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
  181. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  182. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  183. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
  184. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  185. package/src/driver-test-suite/tests/request-access.ts +230 -0
  186. package/src/driver-test-suite/utils.ts +71 -0
  187. package/src/drivers/default.ts +34 -0
  188. package/src/drivers/engine/actor-driver.ts +369 -0
  189. package/src/drivers/engine/config.ts +31 -0
  190. package/src/drivers/engine/kv.ts +3 -0
  191. package/src/drivers/engine/log.ts +5 -0
  192. package/src/drivers/engine/mod.ts +35 -0
  193. package/src/drivers/file-system/actor.ts +91 -0
  194. package/src/drivers/file-system/global-state.ts +686 -0
  195. package/src/drivers/file-system/log.ts +5 -0
  196. package/src/drivers/file-system/manager.ts +329 -0
  197. package/src/drivers/file-system/mod.ts +48 -0
  198. package/src/drivers/file-system/utils.ts +109 -0
  199. package/src/globals.d.ts +6 -0
  200. package/src/inspector/actor.ts +298 -0
  201. package/src/inspector/config.ts +88 -0
  202. package/src/inspector/log.ts +5 -0
  203. package/src/inspector/manager.ts +86 -0
  204. package/src/inspector/mod.ts +2 -0
  205. package/src/inspector/protocol/actor.ts +10 -0
  206. package/src/inspector/protocol/common.ts +196 -0
  207. package/src/inspector/protocol/manager.ts +10 -0
  208. package/src/inspector/protocol/mod.ts +2 -0
  209. package/src/inspector/utils.ts +76 -0
  210. package/src/manager/driver.ts +88 -0
  211. package/src/manager/hono-websocket-adapter.ts +342 -0
  212. package/src/manager/log.ts +5 -0
  213. package/src/manager/mod.ts +2 -0
  214. package/src/manager/protocol/mod.ts +24 -0
  215. package/src/manager/protocol/query.ts +89 -0
  216. package/src/manager/router.ts +412 -0
  217. package/src/manager-api/routes/actors-create.ts +16 -0
  218. package/src/manager-api/routes/actors-delete.ts +4 -0
  219. package/src/manager-api/routes/actors-get-by-id.ts +7 -0
  220. package/src/manager-api/routes/actors-get-or-create-by-id.ts +29 -0
  221. package/src/manager-api/routes/actors-get.ts +7 -0
  222. package/src/manager-api/routes/common.ts +18 -0
  223. package/src/mod.ts +18 -0
  224. package/src/registry/config.ts +32 -0
  225. package/src/registry/log.ts +5 -0
  226. package/src/registry/mod.ts +157 -0
  227. package/src/registry/run-config.ts +52 -0
  228. package/src/registry/serve.ts +52 -0
  229. package/src/remote-manager-driver/actor-http-client.ts +72 -0
  230. package/src/remote-manager-driver/actor-websocket-client.ts +63 -0
  231. package/src/remote-manager-driver/api-endpoints.ts +79 -0
  232. package/src/remote-manager-driver/api-utils.ts +43 -0
  233. package/src/remote-manager-driver/log.ts +5 -0
  234. package/src/remote-manager-driver/mod.ts +274 -0
  235. package/src/remote-manager-driver/ws-proxy.ts +180 -0
  236. package/src/schemas/actor-persist/mod.ts +1 -0
  237. package/src/schemas/actor-persist/versioned.ts +25 -0
  238. package/src/schemas/client-protocol/mod.ts +1 -0
  239. package/src/schemas/client-protocol/versioned.ts +63 -0
  240. package/src/schemas/file-system-driver/mod.ts +1 -0
  241. package/src/schemas/file-system-driver/versioned.ts +28 -0
  242. package/src/serde.ts +90 -0
  243. package/src/test/config.ts +16 -0
  244. package/src/test/log.ts +5 -0
  245. package/src/test/mod.ts +154 -0
  246. package/src/utils.ts +172 -0
@@ -0,0 +1,298 @@
1
+ import { sValidator } from "@hono/standard-validator";
2
+ import jsonPatch from "@rivetkit/fast-json-patch";
3
+ import { Hono } from "hono";
4
+ import { streamSSE } from "hono/streaming";
5
+ import { createNanoEvents, type Unsubscribe } from "nanoevents";
6
+ import z from "zod/v4";
7
+ import type {
8
+ AnyDatabaseProvider,
9
+ InferDatabaseClient,
10
+ } from "@/actor/database";
11
+ import {
12
+ ColumnsSchema,
13
+ type Connection,
14
+ ForeignKeysSchema,
15
+ PatchSchema,
16
+ type RealtimeEvent,
17
+ type RecordedRealtimeEvent,
18
+ TablesSchema,
19
+ } from "./protocol/common";
20
+
21
+ export type ActorInspectorRouterEnv = {
22
+ Variables: {
23
+ inspector: ActorInspector;
24
+ };
25
+ };
26
+
27
+ /**
28
+ * Create a router for the Actor Inspector.
29
+ * @internal
30
+ */
31
+ export function createActorInspectorRouter() {
32
+ return new Hono<ActorInspectorRouterEnv>()
33
+ .get("/ping", (c) => {
34
+ return c.json({ message: "pong" }, 200);
35
+ })
36
+ .get("/state", async (c) => {
37
+ if (await c.var.inspector.accessors.isStateEnabled()) {
38
+ return c.json(
39
+ {
40
+ enabled: true,
41
+ state: await c.var.inspector.accessors.getState(),
42
+ },
43
+ 200,
44
+ );
45
+ }
46
+ return c.json({ enabled: false, state: null }, 200);
47
+ })
48
+ .patch(
49
+ "/state",
50
+ sValidator(
51
+ "json",
52
+ z.object({ patch: PatchSchema }).or(z.object({ replace: z.any() })),
53
+ ),
54
+ async (c) => {
55
+ if (!(await c.var.inspector.accessors.isStateEnabled())) {
56
+ return c.json({ enabled: false }, 200);
57
+ }
58
+
59
+ const body = c.req.valid("json");
60
+ if ("replace" in body) {
61
+ await c.var.inspector.accessors.setState(body.replace);
62
+ return c.json(
63
+ {
64
+ enabled: true,
65
+ state: await c.var.inspector.accessors.getState(),
66
+ },
67
+ 200,
68
+ );
69
+ }
70
+ const state = await c.var.inspector.accessors.getState();
71
+
72
+ const { newDocument: newState } = jsonPatch.applyPatch(
73
+ state,
74
+ body.patch,
75
+ );
76
+ await c.var.inspector.accessors.setState(newState);
77
+
78
+ return c.json(
79
+ { enabled: true, state: await c.var.inspector.accessors.getState() },
80
+ 200,
81
+ );
82
+ },
83
+ )
84
+ .get("/state/stream", async (c) => {
85
+ if (!(await c.var.inspector.accessors.isStateEnabled())) {
86
+ return c.json({ enabled: false }, 200);
87
+ }
88
+
89
+ let id = 0;
90
+ let unsub: Unsubscribe;
91
+ return streamSSE(
92
+ c,
93
+ async (stream) => {
94
+ unsub = c.var.inspector.emitter.on("stateUpdated", async (state) => {
95
+ stream.writeSSE({
96
+ data: JSON.stringify(state) || "",
97
+ event: "state-update",
98
+ id: String(id++),
99
+ });
100
+ });
101
+
102
+ const { promise } = Promise.withResolvers<void>();
103
+
104
+ return promise;
105
+ },
106
+ async () => {
107
+ unsub?.();
108
+ },
109
+ );
110
+ })
111
+ .get("/connections", async (c) => {
112
+ const connections = await c.var.inspector.accessors.getConnections();
113
+ return c.json({ connections }, 200);
114
+ })
115
+ .get("/connections/stream", async (c) => {
116
+ let id = 0;
117
+ let unsub: Unsubscribe;
118
+ return streamSSE(
119
+ c,
120
+ async (stream) => {
121
+ unsub = c.var.inspector.emitter.on("connectionUpdated", async () => {
122
+ stream.writeSSE({
123
+ data: JSON.stringify(
124
+ await c.var.inspector.accessors.getConnections(),
125
+ ),
126
+ event: "connection-update",
127
+ id: String(id++),
128
+ });
129
+ });
130
+
131
+ const { promise } = Promise.withResolvers<void>();
132
+
133
+ return promise;
134
+ },
135
+ async () => {
136
+ unsub?.();
137
+ },
138
+ );
139
+ })
140
+ .get("/events", async (c) => {
141
+ const events = c.var.inspector.lastRealtimeEvents;
142
+ return c.json({ events }, 200);
143
+ })
144
+ .post("/events/clear", async (c) => {
145
+ c.var.inspector.lastRealtimeEvents.length = 0; // Clear the events
146
+ return c.json({ message: "Events cleared" }, 200);
147
+ })
148
+ .get("/events/stream", async (c) => {
149
+ let id = 0;
150
+ let unsub: Unsubscribe;
151
+ return streamSSE(
152
+ c,
153
+ async (stream) => {
154
+ unsub = c.var.inspector.emitter.on("eventFired", () => {
155
+ stream.writeSSE({
156
+ data: JSON.stringify(c.var.inspector.lastRealtimeEvents),
157
+ event: "realtime-event",
158
+ id: String(id++),
159
+ });
160
+ });
161
+
162
+ const { promise } = Promise.withResolvers<void>();
163
+
164
+ return promise;
165
+ },
166
+ async () => {
167
+ unsub?.();
168
+ },
169
+ );
170
+ })
171
+ .get("/rpcs", async (c) => {
172
+ const rpcs = await c.var.inspector.accessors.getRpcs();
173
+ return c.json({ rpcs }, 200);
174
+ })
175
+ .get("/db", async (c) => {
176
+ if (!(await c.var.inspector.accessors.isDbEnabled())) {
177
+ return c.json({ enabled: false, db: null }, 200);
178
+ }
179
+
180
+ // Access the SQLite database
181
+ const db = await c.var.inspector.accessors.getDb();
182
+
183
+ // Get list of tables
184
+ const rows = await db.execute(`PRAGMA table_list`);
185
+ const tables = TablesSchema.parse(rows).filter(
186
+ (table) => table.schema !== "temp" && !table.name.startsWith("sqlite_"),
187
+ );
188
+ // Get columns for each table
189
+ const tablesInfo = await Promise.all(
190
+ tables.map((table) => db.execute(`PRAGMA table_info(${table.name})`)),
191
+ );
192
+ const columns = tablesInfo.map((def) => ColumnsSchema.parse(def));
193
+
194
+ // Get foreign keys for each table
195
+ const foreignKeysList = await Promise.all(
196
+ tables.map((table) =>
197
+ db.execute(`PRAGMA foreign_key_list(${table.name})`),
198
+ ),
199
+ );
200
+ const foreignKeys = foreignKeysList.map((def) =>
201
+ ForeignKeysSchema.parse(def),
202
+ );
203
+
204
+ // Get record counts for each table
205
+ const countInfo = await Promise.all(
206
+ tables.map((table) =>
207
+ db.execute(`SELECT COUNT(*) as count FROM ${table.name}`),
208
+ ),
209
+ );
210
+ const counts = countInfo.map((def) => {
211
+ return def[0].count || 0;
212
+ });
213
+
214
+ return c.json(
215
+ {
216
+ enabled: true,
217
+ db: tablesInfo.map((_, index) => {
218
+ return {
219
+ table: tables[index],
220
+ columns: columns[index],
221
+ foreignKeys: foreignKeys[index],
222
+ records: counts[index],
223
+ };
224
+ }),
225
+ },
226
+ 200,
227
+ );
228
+ })
229
+ .post(
230
+ "/db",
231
+ sValidator(
232
+ "json",
233
+ z.object({ query: z.string(), params: z.array(z.any()).optional() }),
234
+ ),
235
+ async (c) => {
236
+ if (!(await c.var.inspector.accessors.isDbEnabled())) {
237
+ return c.json({ enabled: false }, 200);
238
+ }
239
+ const db = await c.var.inspector.accessors.getDb();
240
+
241
+ try {
242
+ const result = (await db.execute(
243
+ c.req.valid("json").query,
244
+ ...(c.req.valid("json").params || []),
245
+ )) as unknown;
246
+ return c.json({ result }, 200);
247
+ } catch (error) {
248
+ c;
249
+ return c.json({ error: (error as Error).message }, 500);
250
+ }
251
+ },
252
+ );
253
+ }
254
+
255
+ interface ActorInspectorAccessors {
256
+ isStateEnabled: () => Promise<boolean>;
257
+ getState: () => Promise<unknown>;
258
+ setState: (state: unknown) => Promise<void>;
259
+ isDbEnabled: () => Promise<boolean>;
260
+ getDb: () => Promise<InferDatabaseClient<AnyDatabaseProvider>>;
261
+ getRpcs: () => Promise<string[]>;
262
+ getConnections: () => Promise<Connection[]>;
263
+ }
264
+
265
+ interface ActorInspectorEmitterEvents {
266
+ stateUpdated: (state: unknown) => void;
267
+ connectionUpdated: () => void;
268
+ eventFired: (event: RealtimeEvent) => void;
269
+ }
270
+
271
+ /**
272
+ * Provides a unified interface for inspecting actor external and internal state.
273
+ */
274
+ export class ActorInspector {
275
+ public readonly accessors: ActorInspectorAccessors;
276
+ public readonly emitter = createNanoEvents<ActorInspectorEmitterEvents>();
277
+
278
+ #lastRealtimeEvents: RecordedRealtimeEvent[] = [];
279
+
280
+ get lastRealtimeEvents() {
281
+ return this.#lastRealtimeEvents;
282
+ }
283
+
284
+ constructor(accessors: () => ActorInspectorAccessors) {
285
+ this.accessors = accessors();
286
+ this.emitter.on("eventFired", (event) => {
287
+ this.#lastRealtimeEvents.push({
288
+ id: crypto.randomUUID(),
289
+ timestamp: Date.now(),
290
+ ...event,
291
+ });
292
+ // keep the last 100 events
293
+ if (this.#lastRealtimeEvents.length > 100) {
294
+ this.#lastRealtimeEvents = this.#lastRealtimeEvents.slice(-100);
295
+ }
296
+ });
297
+ }
298
+ }
@@ -0,0 +1,88 @@
1
+ import type { cors } from "hono/cors";
2
+ import { z } from "zod";
3
+ import { HEADER_ACTOR_QUERY } from "@/driver-helpers/mod";
4
+ import { getEnvUniversal } from "@/utils";
5
+
6
+ type CorsOptions = NonNullable<Parameters<typeof cors>[0]>;
7
+
8
+ const defaultTokenFn = () => {
9
+ const envToken = getEnvUniversal("RIVETKIT_INSPECTOR_TOKEN");
10
+
11
+ if (envToken) {
12
+ return envToken;
13
+ }
14
+
15
+ return "";
16
+ };
17
+
18
+ const defaultEnabled = () => {
19
+ return (
20
+ getEnvUniversal("NODE_ENV") !== "production" ||
21
+ !getEnvUniversal("RIVETKIT_INSPECTOR_DISABLE")
22
+ );
23
+ };
24
+
25
+ const defaultInspectorOrigins = [
26
+ "http://localhost:43708",
27
+ "http://localhost:43709",
28
+ "https://studio.rivet.gg",
29
+ "https://inspect.rivet.dev",
30
+ ];
31
+
32
+ const defaultCors: CorsOptions = {
33
+ origin: (origin) => {
34
+ if (
35
+ defaultInspectorOrigins.includes(origin) ||
36
+ (origin.startsWith("https://") && origin.endsWith("rivet-dev.vercel.app"))
37
+ ) {
38
+ return origin;
39
+ } else {
40
+ return null;
41
+ }
42
+ },
43
+ allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
44
+ allowHeaders: [
45
+ "Authorization",
46
+ "Content-Type",
47
+ "User-Agent",
48
+ "baggage",
49
+ "sentry-trace",
50
+ "x-rivet-actor",
51
+ "x-rivet-target",
52
+ ],
53
+ maxAge: 3600,
54
+ credentials: true,
55
+ };
56
+
57
+ export const InspectorConfigSchema = z
58
+ .object({
59
+ enabled: z.boolean().optional().default(defaultEnabled),
60
+ /** CORS configuration for the router. Uses Hono's CORS middleware options. */
61
+ cors: z
62
+ .custom<CorsOptions>()
63
+ .optional()
64
+ .default(() => defaultCors),
65
+
66
+ /**
67
+ * Token used to access the Inspector.
68
+ */
69
+ token: z
70
+ .function()
71
+ .returns(z.string())
72
+ .optional()
73
+ .default(() => defaultTokenFn),
74
+
75
+ /**
76
+ * Default RivetKit server endpoint for Rivet Inspector to connect to. This should be the same endpoint as what you use for your Rivet client to connect to RivetKit.
77
+ *
78
+ * This is a convenience property just for printing out the inspector URL.
79
+ */
80
+ defaultEndpoint: z.string().optional(),
81
+ })
82
+ .optional()
83
+ .default(() => ({
84
+ enabled: defaultEnabled(),
85
+ token: defaultTokenFn,
86
+ cors: defaultCors,
87
+ }));
88
+ export type InspectorConfig = z.infer<typeof InspectorConfigSchema>;
@@ -0,0 +1,5 @@
1
+ import { getLogger } from "@/common/log";
2
+
3
+ export function inspectorLogger() {
4
+ return getLogger("inspector");
5
+ }
@@ -0,0 +1,86 @@
1
+ import { sValidator } from "@hono/standard-validator";
2
+ import { Hono } from "hono";
3
+ import invariant from "invariant";
4
+ import type { CreateInput } from "@/manager/driver";
5
+ import { inspectorLogger } from "./log";
6
+ import { type Actor, type Builds, CreateActorSchema } from "./protocol/common";
7
+
8
+ export type ManagerInspectorRouterEnv = {
9
+ Variables: {
10
+ inspector: ManagerInspector;
11
+ };
12
+ };
13
+
14
+ /**
15
+ * Create a router for the Manager Inspector.
16
+ * @internal
17
+ */
18
+ export function createManagerInspectorRouter() {
19
+ return new Hono<ManagerInspectorRouterEnv>()
20
+ .get("/ping", (c) => {
21
+ return c.json({ message: "pong" }, 200);
22
+ })
23
+ .get("/actors", async (c) => {
24
+ const limit = Number.parseInt(c.req.query("limit") ?? "") || undefined;
25
+ const cursor = c.req.query("cursor") || undefined;
26
+
27
+ if (!limit || (limit && limit <= 0)) {
28
+ return c.json("Invalid limit", 400);
29
+ }
30
+
31
+ try {
32
+ const actors = await c.var.inspector.accessors.getAllActors({
33
+ limit,
34
+ cursor,
35
+ });
36
+ return c.json(actors, 200);
37
+ } catch (error) {
38
+ inspectorLogger().error({ msg: "Failed to fetch actors", error });
39
+ return c.json("Failed to fetch actors", 500);
40
+ }
41
+ })
42
+
43
+ .post("/actors", sValidator("json", CreateActorSchema), async (c) => {
44
+ const actor = await c.var.inspector.accessors.createActor(
45
+ c.req.valid("json"),
46
+ );
47
+ return c.json(actor, 201);
48
+ })
49
+ .get("/builds", async (c) => {
50
+ const builds = await c.var.inspector.accessors.getBuilds();
51
+ return c.json(builds, 200);
52
+ })
53
+ .get("/actor/:id", async (c) => {
54
+ const id = c.req.param("id");
55
+ const actor = await c.var.inspector.accessors.getActorById(id);
56
+ if (!actor) {
57
+ return c.json({ error: "Actor not found" }, 404);
58
+ }
59
+ return c.json(actor, 200);
60
+ })
61
+ .get("/bootstrap", async (c) => {
62
+ const actors = await c.var.inspector.accessors.getAllActors({
63
+ limit: 10,
64
+ });
65
+ return c.json({ actors }, 200);
66
+ });
67
+ }
68
+
69
+ interface ManagerInspectorAccessors {
70
+ getAllActors: (param: { cursor?: string; limit: number }) => Promise<Actor[]>;
71
+ getActorById: (id: string) => Promise<Actor | null>;
72
+ getBuilds: () => Promise<Builds>;
73
+ createActor: (input: CreateInput) => Promise<Actor | null>;
74
+ }
75
+
76
+ /**
77
+ * Provides a unified interface for inspecting actor external and internal state.
78
+ */
79
+ export class ManagerInspector {
80
+ public readonly accessors: ManagerInspectorAccessors;
81
+
82
+ constructor(accessors: () => ManagerInspectorAccessors) {
83
+ this.accessors = accessors();
84
+ inspectorLogger().debug({ msg: "Manager Inspector enabled and ready" });
85
+ }
86
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./protocol/common";
2
+ export * from "./protocol/mod";
@@ -0,0 +1,10 @@
1
+ import { hc } from "hono/client";
2
+ import type { createActorInspectorRouter } from "../actor";
3
+
4
+ type ActorInspectorRouter = ReturnType<typeof createActorInspectorRouter>;
5
+ const client = hc<ActorInspectorRouter>("");
6
+ export type ActorInspectorClient = typeof client;
7
+
8
+ export const createActorInspectorClient = (
9
+ ...args: Parameters<typeof hc>
10
+ ): ActorInspectorClient => hc<ActorInspectorRouter>(...args);
@@ -0,0 +1,196 @@
1
+ import z from "zod/v4";
2
+ import { ActorKeySchema, MAX_ACTOR_KEY_SIZE } from "@/manager/protocol/query";
3
+
4
+ export const ActorId = z.string().brand("ActorId");
5
+ export type ActorId = z.infer<typeof ActorId>;
6
+
7
+ export enum ActorFeature {
8
+ Logs = "logs",
9
+ Config = "config",
10
+ Connections = "connections",
11
+ State = "state",
12
+ Console = "console",
13
+ Runtime = "runtime",
14
+ Metrics = "metrics",
15
+ EventsMonitoring = "events-monitoring",
16
+ Database = "database",
17
+ }
18
+
19
+ export const ActorLogEntry = z.object({
20
+ level: z.string(),
21
+ message: z.string(),
22
+ timestamp: z.string(),
23
+ metadata: z.record(z.string(), z.any()).optional(),
24
+ });
25
+
26
+ export const ActorSchema = z.object({
27
+ id: ActorId,
28
+ name: z.string(),
29
+ key: z.array(z.string()),
30
+ tags: z.record(z.string(), z.string()).optional(),
31
+ region: z.string().optional(),
32
+ createdAt: z.string().optional(),
33
+ startedAt: z.string().optional(),
34
+ destroyedAt: z.string().optional(),
35
+ features: z.array(z.enum(ActorFeature)).optional(),
36
+ });
37
+
38
+ export type Actor = z.infer<typeof ActorSchema>;
39
+ export type ActorLogEntry = z.infer<typeof ActorLogEntry>;
40
+
41
+ // MARK: State
42
+
43
+ export const OperationSchema = z.discriminatedUnion("op", [
44
+ z.object({
45
+ op: z.literal("remove"),
46
+ path: z.string(),
47
+ }),
48
+ z.object({
49
+ op: z.literal("add"),
50
+ path: z.string(),
51
+ value: z.unknown(),
52
+ }),
53
+ z.object({
54
+ op: z.literal("replace"),
55
+ path: z.string(),
56
+ value: z.unknown(),
57
+ }),
58
+ z.object({
59
+ op: z.literal("move"),
60
+ path: z.string(),
61
+ from: z.string(),
62
+ }),
63
+ z.object({
64
+ op: z.literal("copy"),
65
+ path: z.string(),
66
+ from: z.string(),
67
+ }),
68
+ z.object({
69
+ op: z.literal("test"),
70
+ path: z.string(),
71
+ value: z.unknown(),
72
+ }),
73
+ ]);
74
+ export type Operation = z.infer<typeof OperationSchema>;
75
+
76
+ export const PatchSchema = z.array(OperationSchema);
77
+ export type Patch = z.infer<typeof PatchSchema>;
78
+
79
+ // MARK: Connections
80
+
81
+ export const ConnectionSchema = z.object({
82
+ params: z.record(z.string(), z.any()).optional(),
83
+ id: z.string(),
84
+ stateEnabled: z.boolean().optional(),
85
+ state: z.any().optional(),
86
+ auth: z.record(z.string(), z.any()).optional(),
87
+ });
88
+ export type Connection = z.infer<typeof ConnectionSchema>;
89
+
90
+ // MARK: Realtime Events
91
+
92
+ export const RealtimeEventSchema = z.discriminatedUnion("type", [
93
+ z.object({
94
+ type: z.literal("action"),
95
+ name: z.string(),
96
+ args: z.array(z.any()),
97
+ connId: z.string(),
98
+ }),
99
+ z.object({
100
+ type: z.literal("broadcast"),
101
+ eventName: z.string(),
102
+ args: z.array(z.any()),
103
+ }),
104
+ z.object({
105
+ type: z.literal("subscribe"),
106
+ eventName: z.string(),
107
+ connId: z.string(),
108
+ }),
109
+ z.object({
110
+ type: z.literal("unsubscribe"),
111
+ eventName: z.string(),
112
+ connId: z.string(),
113
+ }),
114
+ z.object({
115
+ type: z.literal("event"),
116
+ eventName: z.string(),
117
+ args: z.array(z.any()),
118
+ connId: z.string(),
119
+ }),
120
+ ]);
121
+ export type RealtimeEvent = z.infer<typeof RealtimeEventSchema>;
122
+ export const RecordedRealtimeEventSchema = RealtimeEventSchema.and(
123
+ z.object({
124
+ id: z.string(),
125
+ timestamp: z.number(),
126
+ }),
127
+ );
128
+ export type RecordedRealtimeEvent = z.infer<typeof RecordedRealtimeEventSchema>;
129
+
130
+ // MARK: Database
131
+
132
+ export const DatabaseQuerySchema = z.object({
133
+ sql: z.string(),
134
+ args: z.array(z.string().or(z.number())),
135
+ });
136
+ export type DatabaseQuery = z.infer<typeof DatabaseQuerySchema>;
137
+
138
+ export const TableSchema = z.object({
139
+ schema: z.string(),
140
+ name: z.string(),
141
+ type: z.enum(["table", "view"]),
142
+ });
143
+ export type Table = z.infer<typeof TableSchema>;
144
+
145
+ export const TablesSchema = z.array(TableSchema);
146
+ export type Tables = z.infer<typeof TablesSchema>;
147
+
148
+ export const ColumnSchema = z.object({
149
+ cid: z.number(),
150
+ name: z.string(),
151
+ type: z
152
+ .string()
153
+ .toLowerCase()
154
+ .transform((val) => {
155
+ return z
156
+ .enum(["integer", "text", "real", "blob", "numeric", "serial"])
157
+ .parse(val);
158
+ }),
159
+ notnull: z.coerce.boolean(),
160
+ dflt_value: z.string().nullable(),
161
+ pk: z.coerce.boolean().nullable(),
162
+ });
163
+ export type Column = z.infer<typeof ColumnSchema>;
164
+
165
+ export const ColumnsSchema = z.array(ColumnSchema);
166
+ export type Columns = z.infer<typeof ColumnsSchema>;
167
+
168
+ export const ForeignKeySchema = z.object({
169
+ id: z.number(),
170
+ table: z.string(),
171
+ from: z.string(),
172
+ to: z.string(),
173
+ });
174
+ export type ForeignKey = z.infer<typeof ForeignKeySchema>;
175
+
176
+ export const ForeignKeysSchema = z.array(ForeignKeySchema);
177
+ export type ForeignKeys = z.infer<typeof ForeignKeysSchema>;
178
+
179
+ // MARK: Builds
180
+
181
+ export const BuildSchema = z.object({
182
+ name: z.string(),
183
+ createdAt: z.string().optional(),
184
+ tags: z.record(z.string(), z.string()).optional(),
185
+ });
186
+ export type Build = z.infer<typeof BuildSchema>;
187
+ export const BuildsSchema = z.array(BuildSchema);
188
+ export type Builds = z.infer<typeof BuildsSchema>;
189
+
190
+ export const CreateActorSchema = z.object({
191
+ name: z.string(),
192
+ // FIXME: Replace with ActorKeySchema when ready
193
+ key: z.array(z.string().max(MAX_ACTOR_KEY_SIZE)),
194
+ input: z.any(),
195
+ });
196
+ export type CreateActor = z.infer<typeof CreateActorSchema>;
@@ -0,0 +1,10 @@
1
+ import { hc } from "hono/client";
2
+ import type { createManagerInspectorRouter } from "../manager";
3
+
4
+ type ManagerInspectorRouter = ReturnType<typeof createManagerInspectorRouter>;
5
+ const client = hc<ManagerInspectorRouter>("");
6
+ export type ManagerInspectorClient = typeof client;
7
+
8
+ export const createManagerInspectorClient = (
9
+ ...args: Parameters<typeof hc>
10
+ ): ManagerInspectorClient => hc<ManagerInspectorRouter>(...args);
@@ -0,0 +1,2 @@
1
+ export * from "./actor";
2
+ export * from "./manager";