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.
- package/README.md +3 -5
- package/dist/schemas/actor-persist/v1.ts +225 -0
- package/dist/schemas/client-protocol/v1.ts +435 -0
- package/dist/schemas/file-system-driver/v1.ts +102 -0
- package/dist/tsup/actor/errors.cjs +77 -0
- package/dist/tsup/actor/errors.cjs.map +1 -0
- package/dist/tsup/actor/errors.d.cts +156 -0
- package/dist/tsup/actor/errors.d.ts +156 -0
- package/dist/tsup/actor/errors.js +77 -0
- package/dist/tsup/actor/errors.js.map +1 -0
- package/dist/tsup/chunk-3F2YSRJL.js +117 -0
- package/dist/tsup/chunk-3F2YSRJL.js.map +1 -0
- package/dist/tsup/chunk-4CXBCT26.cjs +250 -0
- package/dist/tsup/chunk-4CXBCT26.cjs.map +1 -0
- package/dist/tsup/chunk-4R73YDN3.cjs +20 -0
- package/dist/tsup/chunk-4R73YDN3.cjs.map +1 -0
- package/dist/tsup/chunk-6LJT3QRL.cjs +539 -0
- package/dist/tsup/chunk-6LJT3QRL.cjs.map +1 -0
- package/dist/tsup/chunk-GICQ3YCU.cjs +1792 -0
- package/dist/tsup/chunk-GICQ3YCU.cjs.map +1 -0
- package/dist/tsup/chunk-H26RP6GD.js +251 -0
- package/dist/tsup/chunk-H26RP6GD.js.map +1 -0
- package/dist/tsup/chunk-HI3HWJRC.js +20 -0
- package/dist/tsup/chunk-HI3HWJRC.js.map +1 -0
- package/dist/tsup/chunk-HLLF4B4Q.js +1792 -0
- package/dist/tsup/chunk-HLLF4B4Q.js.map +1 -0
- package/dist/tsup/chunk-IH6CKNDW.cjs +117 -0
- package/dist/tsup/chunk-IH6CKNDW.cjs.map +1 -0
- package/dist/tsup/chunk-LV2S3OU3.js +250 -0
- package/dist/tsup/chunk-LV2S3OU3.js.map +1 -0
- package/dist/tsup/chunk-LWNKVZG5.cjs +251 -0
- package/dist/tsup/chunk-LWNKVZG5.cjs.map +1 -0
- package/dist/tsup/chunk-NFU2BBT5.js +374 -0
- package/dist/tsup/chunk-NFU2BBT5.js.map +1 -0
- package/dist/tsup/chunk-PQY7KKTL.js +539 -0
- package/dist/tsup/chunk-PQY7KKTL.js.map +1 -0
- package/dist/tsup/chunk-QK72M5JB.js +45 -0
- package/dist/tsup/chunk-QK72M5JB.js.map +1 -0
- package/dist/tsup/chunk-QNNXFOQV.cjs +45 -0
- package/dist/tsup/chunk-QNNXFOQV.cjs.map +1 -0
- package/dist/tsup/chunk-SBHHJ6QS.cjs +374 -0
- package/dist/tsup/chunk-SBHHJ6QS.cjs.map +1 -0
- package/dist/tsup/chunk-TQ62L3X7.js +325 -0
- package/dist/tsup/chunk-TQ62L3X7.js.map +1 -0
- package/dist/tsup/chunk-VO7ZRVVD.cjs +6293 -0
- package/dist/tsup/chunk-VO7ZRVVD.cjs.map +1 -0
- package/dist/tsup/chunk-WHBPJNGW.cjs +325 -0
- package/dist/tsup/chunk-WHBPJNGW.cjs.map +1 -0
- package/dist/tsup/chunk-XJQHKJ4P.js +6293 -0
- package/dist/tsup/chunk-XJQHKJ4P.js.map +1 -0
- package/dist/tsup/client/mod.cjs +32 -0
- package/dist/tsup/client/mod.cjs.map +1 -0
- package/dist/tsup/client/mod.d.cts +20 -0
- package/dist/tsup/client/mod.d.ts +20 -0
- package/dist/tsup/client/mod.js +32 -0
- package/dist/tsup/client/mod.js.map +1 -0
- package/dist/tsup/common/log.cjs +21 -0
- package/dist/tsup/common/log.cjs.map +1 -0
- package/dist/tsup/common/log.d.cts +26 -0
- package/dist/tsup/common/log.d.ts +26 -0
- package/dist/tsup/common/log.js +21 -0
- package/dist/tsup/common/log.js.map +1 -0
- package/dist/tsup/common/websocket.cjs +10 -0
- package/dist/tsup/common/websocket.cjs.map +1 -0
- package/dist/tsup/common/websocket.d.cts +3 -0
- package/dist/tsup/common/websocket.d.ts +3 -0
- package/dist/tsup/common/websocket.js +10 -0
- package/dist/tsup/common/websocket.js.map +1 -0
- package/dist/tsup/common-CXCe7s6i.d.cts +218 -0
- package/dist/tsup/common-CXCe7s6i.d.ts +218 -0
- package/dist/tsup/connection-BI-6UIBJ.d.ts +2087 -0
- package/dist/tsup/connection-Dyd4NLGW.d.cts +2087 -0
- package/dist/tsup/driver-helpers/mod.cjs +30 -0
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
- package/dist/tsup/driver-helpers/mod.d.cts +17 -0
- package/dist/tsup/driver-helpers/mod.d.ts +17 -0
- package/dist/tsup/driver-helpers/mod.js +30 -0
- package/dist/tsup/driver-helpers/mod.js.map +1 -0
- package/dist/tsup/driver-test-suite/mod.cjs +3411 -0
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
- package/dist/tsup/driver-test-suite/mod.d.cts +63 -0
- package/dist/tsup/driver-test-suite/mod.d.ts +63 -0
- package/dist/tsup/driver-test-suite/mod.js +3411 -0
- package/dist/tsup/driver-test-suite/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +51 -0
- package/dist/tsup/inspector/mod.cjs.map +1 -0
- package/dist/tsup/inspector/mod.d.cts +408 -0
- package/dist/tsup/inspector/mod.d.ts +408 -0
- package/dist/tsup/inspector/mod.js +51 -0
- package/dist/tsup/inspector/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +67 -0
- package/dist/tsup/mod.cjs.map +1 -0
- package/dist/tsup/mod.d.cts +105 -0
- package/dist/tsup/mod.d.ts +105 -0
- package/dist/tsup/mod.js +67 -0
- package/dist/tsup/mod.js.map +1 -0
- package/dist/tsup/router-endpoints-BTe_Rsdn.d.cts +65 -0
- package/dist/tsup/router-endpoints-CBSrKHmo.d.ts +65 -0
- package/dist/tsup/test/mod.cjs +17 -0
- package/dist/tsup/test/mod.cjs.map +1 -0
- package/dist/tsup/test/mod.d.cts +26 -0
- package/dist/tsup/test/mod.d.ts +26 -0
- package/dist/tsup/test/mod.js +17 -0
- package/dist/tsup/test/mod.js.map +1 -0
- package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
- package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
- package/dist/tsup/utils.cjs +26 -0
- package/dist/tsup/utils.cjs.map +1 -0
- package/dist/tsup/utils.d.cts +36 -0
- package/dist/tsup/utils.d.ts +36 -0
- package/dist/tsup/utils.js +26 -0
- package/dist/tsup/utils.js.map +1 -0
- package/package.json +208 -5
- package/src/actor/action.ts +178 -0
- package/src/actor/config.ts +497 -0
- package/src/actor/connection.ts +257 -0
- package/src/actor/context.ts +168 -0
- package/src/actor/database.ts +23 -0
- package/src/actor/definition.ts +82 -0
- package/src/actor/driver.ts +84 -0
- package/src/actor/errors.ts +422 -0
- package/src/actor/generic-conn-driver.ts +246 -0
- package/src/actor/instance.ts +1844 -0
- package/src/actor/keys.test.ts +266 -0
- package/src/actor/keys.ts +89 -0
- package/src/actor/log.ts +6 -0
- package/src/actor/mod.ts +108 -0
- package/src/actor/persisted.ts +42 -0
- package/src/actor/protocol/old.ts +297 -0
- package/src/actor/protocol/serde.ts +131 -0
- package/src/actor/router-endpoints.ts +688 -0
- package/src/actor/router.ts +265 -0
- package/src/actor/schedule.ts +17 -0
- package/src/actor/unstable-react.ts +110 -0
- package/src/actor/utils.ts +102 -0
- package/src/client/actor-common.ts +30 -0
- package/src/client/actor-conn.ts +865 -0
- package/src/client/actor-handle.ts +268 -0
- package/src/client/actor-query.ts +65 -0
- package/src/client/client.ts +554 -0
- package/src/client/config.ts +44 -0
- package/src/client/errors.ts +42 -0
- package/src/client/log.ts +5 -0
- package/src/client/mod.ts +60 -0
- package/src/client/raw-utils.ts +149 -0
- package/src/client/test.ts +44 -0
- package/src/client/utils.ts +152 -0
- package/src/common/eventsource-interface.ts +47 -0
- package/src/common/eventsource.ts +80 -0
- package/src/common/fake-event-source.ts +267 -0
- package/src/common/inline-websocket-adapter2.ts +454 -0
- package/src/common/log-levels.ts +27 -0
- package/src/common/log.ts +214 -0
- package/src/common/logfmt.ts +219 -0
- package/src/common/network.ts +2 -0
- package/src/common/router.ts +80 -0
- package/src/common/utils.ts +336 -0
- package/src/common/versioned-data.ts +95 -0
- package/src/common/websocket-interface.ts +49 -0
- package/src/common/websocket.ts +42 -0
- package/src/driver-helpers/mod.ts +22 -0
- package/src/driver-helpers/utils.ts +17 -0
- package/src/driver-test-suite/log.ts +5 -0
- package/src/driver-test-suite/mod.ts +239 -0
- package/src/driver-test-suite/tests/action-features.ts +136 -0
- package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
- package/src/driver-test-suite/tests/actor-conn.ts +349 -0
- package/src/driver-test-suite/tests/actor-driver.ts +25 -0
- package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
- package/src/driver-test-suite/tests/actor-handle.ts +292 -0
- package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
- package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
- package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
- package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
- package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
- package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
- package/src/driver-test-suite/tests/actor-state.ts +54 -0
- package/src/driver-test-suite/tests/actor-vars.ts +93 -0
- package/src/driver-test-suite/tests/manager-driver.ts +367 -0
- package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
- package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
- package/src/driver-test-suite/tests/raw-http.ts +347 -0
- package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
- package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
- package/src/driver-test-suite/tests/request-access.ts +230 -0
- package/src/driver-test-suite/utils.ts +71 -0
- package/src/drivers/default.ts +34 -0
- package/src/drivers/engine/actor-driver.ts +369 -0
- package/src/drivers/engine/config.ts +31 -0
- package/src/drivers/engine/kv.ts +3 -0
- package/src/drivers/engine/log.ts +5 -0
- package/src/drivers/engine/mod.ts +35 -0
- package/src/drivers/file-system/actor.ts +91 -0
- package/src/drivers/file-system/global-state.ts +686 -0
- package/src/drivers/file-system/log.ts +5 -0
- package/src/drivers/file-system/manager.ts +329 -0
- package/src/drivers/file-system/mod.ts +48 -0
- package/src/drivers/file-system/utils.ts +109 -0
- package/src/globals.d.ts +6 -0
- package/src/inspector/actor.ts +298 -0
- package/src/inspector/config.ts +88 -0
- package/src/inspector/log.ts +5 -0
- package/src/inspector/manager.ts +86 -0
- package/src/inspector/mod.ts +2 -0
- package/src/inspector/protocol/actor.ts +10 -0
- package/src/inspector/protocol/common.ts +196 -0
- package/src/inspector/protocol/manager.ts +10 -0
- package/src/inspector/protocol/mod.ts +2 -0
- package/src/inspector/utils.ts +76 -0
- package/src/manager/driver.ts +88 -0
- package/src/manager/hono-websocket-adapter.ts +342 -0
- package/src/manager/log.ts +5 -0
- package/src/manager/mod.ts +2 -0
- package/src/manager/protocol/mod.ts +24 -0
- package/src/manager/protocol/query.ts +89 -0
- package/src/manager/router.ts +412 -0
- package/src/manager-api/routes/actors-create.ts +16 -0
- package/src/manager-api/routes/actors-delete.ts +4 -0
- package/src/manager-api/routes/actors-get-by-id.ts +7 -0
- package/src/manager-api/routes/actors-get-or-create-by-id.ts +29 -0
- package/src/manager-api/routes/actors-get.ts +7 -0
- package/src/manager-api/routes/common.ts +18 -0
- package/src/mod.ts +18 -0
- package/src/registry/config.ts +32 -0
- package/src/registry/log.ts +5 -0
- package/src/registry/mod.ts +157 -0
- package/src/registry/run-config.ts +52 -0
- package/src/registry/serve.ts +52 -0
- package/src/remote-manager-driver/actor-http-client.ts +72 -0
- package/src/remote-manager-driver/actor-websocket-client.ts +63 -0
- package/src/remote-manager-driver/api-endpoints.ts +79 -0
- package/src/remote-manager-driver/api-utils.ts +43 -0
- package/src/remote-manager-driver/log.ts +5 -0
- package/src/remote-manager-driver/mod.ts +274 -0
- package/src/remote-manager-driver/ws-proxy.ts +180 -0
- package/src/schemas/actor-persist/mod.ts +1 -0
- package/src/schemas/actor-persist/versioned.ts +25 -0
- package/src/schemas/client-protocol/mod.ts +1 -0
- package/src/schemas/client-protocol/versioned.ts +63 -0
- package/src/schemas/file-system-driver/mod.ts +1 -0
- package/src/schemas/file-system-driver/versioned.ts +28 -0
- package/src/serde.ts +90 -0
- package/src/test/config.ts +16 -0
- package/src/test/log.ts +5 -0
- package/src/test/mod.ts +154 -0
- 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,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,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);
|