@opendatalabs/personal-server-ts-server 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts +12 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +54 -2
- package/dist/app.js.map +1 -1
- package/dist/bootstrap.d.ts +6 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +65 -21
- package/dist/bootstrap.js.map +1 -1
- package/dist/enclave-main.d.ts +11 -0
- package/dist/enclave-main.d.ts.map +1 -0
- package/dist/enclave-main.js +188 -0
- package/dist/enclave-main.js.map +1 -0
- package/dist/index.js +11 -23
- package/dist/index.js.map +1 -1
- package/dist/jobs/access-reporter.d.ts +36 -0
- package/dist/jobs/access-reporter.d.ts.map +1 -0
- package/dist/jobs/access-reporter.js +272 -0
- package/dist/jobs/access-reporter.js.map +1 -0
- package/dist/jobs/raw-envelope-stream.d.ts +3 -0
- package/dist/jobs/raw-envelope-stream.d.ts.map +1 -0
- package/dist/jobs/raw-envelope-stream.js +371 -0
- package/dist/jobs/raw-envelope-stream.js.map +1 -0
- package/dist/jobs/types.d.ts +17 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +3 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/jobs/worker.d.ts +43 -0
- package/dist/jobs/worker.d.ts.map +1 -0
- package/dist/jobs/worker.js +491 -0
- package/dist/jobs/worker.js.map +1 -0
- package/dist/listen.d.ts +11 -0
- package/dist/listen.d.ts.map +1 -0
- package/dist/listen.js +23 -0
- package/dist/listen.js.map +1 -0
- package/dist/mcp/durable-state.d.ts +75 -0
- package/dist/mcp/durable-state.d.ts.map +1 -0
- package/dist/mcp/durable-state.js +418 -0
- package/dist/mcp/durable-state.js.map +1 -0
- package/dist/mcp/grants.d.ts +12 -0
- package/dist/mcp/grants.d.ts.map +1 -0
- package/dist/mcp/grants.js +33 -0
- package/dist/mcp/grants.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/tee-ingress.d.ts +29 -0
- package/dist/mcp/tee-ingress.d.ts.map +1 -0
- package/dist/mcp/tee-ingress.js +203 -0
- package/dist/mcp/tee-ingress.js.map +1 -0
- package/dist/middleware/local-listener.d.ts +33 -0
- package/dist/middleware/local-listener.d.ts.map +1 -0
- package/dist/middleware/local-listener.js +103 -0
- package/dist/middleware/local-listener.js.map +1 -0
- package/dist/package.json +67 -0
- package/dist/routes/enclave-fleet.d.ts +14 -0
- package/dist/routes/enclave-fleet.d.ts.map +1 -0
- package/dist/routes/enclave-fleet.js +43 -0
- package/dist/routes/enclave-fleet.js.map +1 -0
- package/dist/routes/enclave-jobs.d.ts +9 -0
- package/dist/routes/enclave-jobs.d.ts.map +1 -0
- package/dist/routes/enclave-jobs.js +106 -0
- package/dist/routes/enclave-jobs.js.map +1 -0
- package/dist/routes/enclave-mcp.d.ts +9 -0
- package/dist/routes/enclave-mcp.d.ts.map +1 -0
- package/dist/routes/enclave-mcp.js +46 -0
- package/dist/routes/enclave-mcp.js.map +1 -0
- package/dist/routes/mcp.d.ts +5 -2
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +49 -17
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/ui.d.ts +7 -0
- package/dist/routes/ui.d.ts.map +1 -1
- package/dist/routes/ui.js +32 -3
- package/dist/routes/ui.js.map +1 -1
- package/dist/scripts/bundle-verification.d.ts +2 -0
- package/dist/scripts/bundle-verification.d.ts.map +1 -0
- package/dist/scripts/bundle-verification.js +32 -0
- package/dist/scripts/bundle-verification.js.map +1 -0
- package/dist/scripts/verify-bundle.d.ts +2 -0
- package/dist/scripts/verify-bundle.d.ts.map +1 -0
- package/dist/scripts/verify-bundle.js +44 -0
- package/dist/scripts/verify-bundle.js.map +1 -0
- package/dist/storage/hierarchy.d.ts +4 -0
- package/dist/storage/hierarchy.d.ts.map +1 -1
- package/dist/storage/hierarchy.js +10 -0
- package/dist/storage/hierarchy.js.map +1 -1
- package/dist/storage/node-data-storage.d.ts.map +1 -1
- package/dist/storage/node-data-storage.js +7 -1
- package/dist/storage/node-data-storage.js.map +1 -1
- package/dist/ui/index.html +13 -0
- package/dist/ui/ps-lite-debug.js +3205 -5575
- package/package.json +15 -7
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { cors } from "hono/cors";
|
|
3
|
+
import { isAddress } from "viem";
|
|
4
|
+
import { approveMcpOAuthAuthorization, handleMcpHandshake, hashConnectionToken, isMcpHandshake, toMcpOAuthAuthorizationView, } from "@opendatalabs/personal-server-ts-core/mcp";
|
|
5
|
+
import { mcpOAuthRoutes } from "../routes/mcp.js";
|
|
6
|
+
import { createBodyLimit } from "../middleware/body-limit.js";
|
|
7
|
+
/** Stable, non-retryable code for a caller whose owner withdrew enclave access
|
|
8
|
+
* (server deregistered, identity epoch bumped, delegation revoked). Retrying
|
|
9
|
+
* cannot help; the owner has to approve this enclave again. */
|
|
10
|
+
export const OWNER_ACCESS_REVOKED_CODE = "OWNER_ACCESS_REVOKED";
|
|
11
|
+
const OWNER_ACCESS_REVOKED_MESSAGE = "Owner access to this enclave was revoked; ask the owner to approve it again";
|
|
12
|
+
/** Thrown by `dispatch`/`ownerReady` providers when the live protocol identity
|
|
13
|
+
* shows the owner no longer authorizes this enclave. */
|
|
14
|
+
export class McpOwnerAccessRevokedError extends Error {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(OWNER_ACCESS_REVOKED_MESSAGE);
|
|
17
|
+
this.name = "McpOwnerAccessRevokedError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Public ingress: HTTPS terminates in the same CVM as this process. */
|
|
21
|
+
export function createTeeMcpIngress(deps) {
|
|
22
|
+
const app = new Hono();
|
|
23
|
+
const { state } = deps;
|
|
24
|
+
const redirectUris = new Set(deps.allowedRedirectUris);
|
|
25
|
+
app.use("*", createBodyLimit(256 * 1024));
|
|
26
|
+
app.use("*", cors({
|
|
27
|
+
origin: new URL(deps.approvalUrl).origin,
|
|
28
|
+
allowMethods: ["GET", "POST", "OPTIONS"],
|
|
29
|
+
allowHeaders: ["Content-Type", "Authorization", "MCP-Protocol-Version"],
|
|
30
|
+
exposeHeaders: ["WWW-Authenticate"],
|
|
31
|
+
}));
|
|
32
|
+
app.use("*", async (c, next) => {
|
|
33
|
+
c.header("Cache-Control", "no-store");
|
|
34
|
+
c.header("X-Content-Type-Options", "nosniff");
|
|
35
|
+
await next();
|
|
36
|
+
});
|
|
37
|
+
// One ingress writer serializes the core engine's multi-step OAuth updates.
|
|
38
|
+
app.use("/mcp/oauth/*", (c, next) => state.exclusive(async () => {
|
|
39
|
+
if (c.req.path === "/mcp/oauth/authorize" &&
|
|
40
|
+
!redirectUris.has(c.req.query("redirect_uri") ?? "")) {
|
|
41
|
+
return c.json({
|
|
42
|
+
error: "invalid_request",
|
|
43
|
+
error_description: "Unregistered demo redirect URI",
|
|
44
|
+
}, 400);
|
|
45
|
+
}
|
|
46
|
+
if (c.req.path === "/mcp/oauth/register") {
|
|
47
|
+
let body;
|
|
48
|
+
try {
|
|
49
|
+
body = await c.req.raw.clone().json();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return c.json({ error: "invalid_client_metadata" }, 400);
|
|
53
|
+
}
|
|
54
|
+
if (!Array.isArray(body.redirect_uris) ||
|
|
55
|
+
body.redirect_uris.length === 0 ||
|
|
56
|
+
body.redirect_uris.some((uri) => typeof uri !== "string" || !redirectUris.has(uri))) {
|
|
57
|
+
return c.json({ error: "invalid_redirect_uri" }, 400);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
await next();
|
|
61
|
+
}));
|
|
62
|
+
// The random pending authorization ID reveals only the new grantee's public
|
|
63
|
+
// consent metadata. It does not authorize approval or return a private key.
|
|
64
|
+
app.get("/v1/mcp/readiness", async (c) => {
|
|
65
|
+
const owner = c.req.query("owner");
|
|
66
|
+
const chainId = Number(c.req.query("chainId"));
|
|
67
|
+
if (!owner || !isAddress(owner) || !Number.isSafeInteger(chainId))
|
|
68
|
+
return c.json({ error: "Owner and chain required" }, 400);
|
|
69
|
+
return c.json({
|
|
70
|
+
ready: (await deps.ownerReady?.({ owner, chainId })) ?? false,
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
app.get("/v1/mcp/oauth/authorizations/:id", async (c) => {
|
|
74
|
+
const record = await state.authorizations.getById(c.req.param("id"));
|
|
75
|
+
if (!record ||
|
|
76
|
+
record.status !== "pending" ||
|
|
77
|
+
Date.parse(record.expiresAt) <= Date.now())
|
|
78
|
+
return c.json({ error: "Authorization not found" }, 404);
|
|
79
|
+
const connection = await state.connections.getById(record.connectionId);
|
|
80
|
+
if (!connection)
|
|
81
|
+
return c.json({ error: "Connection not found" }, 404);
|
|
82
|
+
await deps.registerGrantee(connection, record.redirectUri);
|
|
83
|
+
return c.json(toMcpOAuthAuthorizationView(record));
|
|
84
|
+
});
|
|
85
|
+
app.post("/v1/mcp/oauth/authorizations/:id/approve", (c) => state.exclusive(async () => {
|
|
86
|
+
let body;
|
|
87
|
+
try {
|
|
88
|
+
body = await c.req.json();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return c.json({ error: "Invalid JSON" }, 400);
|
|
92
|
+
}
|
|
93
|
+
if (!body.owner ||
|
|
94
|
+
!isAddress(body.owner) ||
|
|
95
|
+
!Number.isSafeInteger(body.chainId) ||
|
|
96
|
+
!Array.isArray(body.grants) ||
|
|
97
|
+
body.grants.length === 0 ||
|
|
98
|
+
body.grants.some((grant) => !grant ||
|
|
99
|
+
typeof grant.grantId !== "string" ||
|
|
100
|
+
!Array.isArray(grant.scopes) ||
|
|
101
|
+
grant.scopes.length === 0 ||
|
|
102
|
+
grant.scopes.some((scope) => typeof scope !== "string"))) {
|
|
103
|
+
return c.json({ error: "Owner, chain and grants required" }, 400);
|
|
104
|
+
}
|
|
105
|
+
const authorization = await state.authorizations.getById(c.req.param("id"));
|
|
106
|
+
if (!authorization ||
|
|
107
|
+
authorization.status !== "pending" ||
|
|
108
|
+
Date.parse(authorization.expiresAt) <= Date.now())
|
|
109
|
+
return c.json({ error: "Authorization unavailable" }, 409);
|
|
110
|
+
const connection = await state.connections.getById(authorization.connectionId);
|
|
111
|
+
if (!connection)
|
|
112
|
+
return c.json({ error: "Connection unavailable" }, 404);
|
|
113
|
+
const binding = {
|
|
114
|
+
owner: body.owner,
|
|
115
|
+
chainId: body.chainId,
|
|
116
|
+
};
|
|
117
|
+
try {
|
|
118
|
+
await deps.verifyGrants(connection, binding, body.grants);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return c.json({ error: "Owner grant verification failed" }, 403);
|
|
122
|
+
}
|
|
123
|
+
if (deps.ownerReady && !(await deps.ownerReady(binding)))
|
|
124
|
+
return c.json({
|
|
125
|
+
error: "OWNER_PREWARM_REQUIRED",
|
|
126
|
+
message: "Finish owner prewarm before approving MCP",
|
|
127
|
+
}, 503);
|
|
128
|
+
try {
|
|
129
|
+
await deps.beforeOwnerApproval?.(binding);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return c.json({ error: "Owner scheduling unavailable" }, 503);
|
|
133
|
+
}
|
|
134
|
+
await state.bindOwner(connection.id, binding);
|
|
135
|
+
const approved = await approveMcpOAuthAuthorization({ authorizationId: authorization.id, grants: body.grants }, {
|
|
136
|
+
connectionStore: state.connections,
|
|
137
|
+
authorizationStore: state.authorizations,
|
|
138
|
+
});
|
|
139
|
+
return c.json({ redirectTo: approved.redirectTo });
|
|
140
|
+
}));
|
|
141
|
+
app.all("/mcp", async (c) => {
|
|
142
|
+
const header = c.req.header("authorization");
|
|
143
|
+
const token = header?.startsWith("Bearer ") ? header.slice(7).trim() : "";
|
|
144
|
+
const connection = token
|
|
145
|
+
? await state.connections.getByTokenHash(await hashConnectionToken(token))
|
|
146
|
+
: null;
|
|
147
|
+
const binding = connection ? await state.getOwner(connection.id) : null;
|
|
148
|
+
if (!connection || !binding) {
|
|
149
|
+
c.header("WWW-Authenticate", `Bearer resource_metadata="${deps.origin}/.well-known/oauth-protected-resource/mcp", scope="vana:read"`);
|
|
150
|
+
return c.json({ error: "MCP authorization required" }, 401);
|
|
151
|
+
}
|
|
152
|
+
if (c.req.method !== "POST")
|
|
153
|
+
return c.body(null, 405, { Allow: "POST" });
|
|
154
|
+
// The handshake reads the static tool table, nothing of the owner's, so it
|
|
155
|
+
// is answered here rather than through grant verification, placement and
|
|
156
|
+
// two attested peer hops per message — the three messages a fresh client
|
|
157
|
+
// sends cost ~18 s each on that path.
|
|
158
|
+
let body;
|
|
159
|
+
try {
|
|
160
|
+
body = await c.req.raw.clone().json();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
body = undefined;
|
|
164
|
+
}
|
|
165
|
+
if (isMcpHandshake(body))
|
|
166
|
+
return handleMcpHandshake(c.req.raw.clone());
|
|
167
|
+
try {
|
|
168
|
+
await deps.verifyGrants(connection, binding, connection.grants);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return c.json({ error: "MCP grants are no longer valid" }, 403);
|
|
172
|
+
}
|
|
173
|
+
return deps.dispatch(c.req.raw, connection, binding);
|
|
174
|
+
});
|
|
175
|
+
app.route("/", mcpOAuthRoutes({
|
|
176
|
+
gateway: deps.gateway,
|
|
177
|
+
serverOrigin: deps.origin,
|
|
178
|
+
oauthApprovalUrl: deps.approvalUrl,
|
|
179
|
+
connectionStore: state.connections,
|
|
180
|
+
oauthAuthorizationStore: state.authorizations,
|
|
181
|
+
}));
|
|
182
|
+
app.onError((error) => {
|
|
183
|
+
// A revoked owner is a terminal answer, not the transient 503 every other
|
|
184
|
+
// ingress failure gets: the MCP client must stop retrying this connection.
|
|
185
|
+
if (error instanceof McpOwnerAccessRevokedError)
|
|
186
|
+
return jsonError(403, {
|
|
187
|
+
error: OWNER_ACCESS_REVOKED_CODE,
|
|
188
|
+
message: OWNER_ACCESS_REVOKED_MESSAGE,
|
|
189
|
+
});
|
|
190
|
+
return jsonError(503, { error: "MCP request unavailable" });
|
|
191
|
+
});
|
|
192
|
+
return app;
|
|
193
|
+
}
|
|
194
|
+
function jsonError(status, body) {
|
|
195
|
+
return new Response(JSON.stringify(body), {
|
|
196
|
+
status,
|
|
197
|
+
headers: {
|
|
198
|
+
"content-type": "application/json",
|
|
199
|
+
"cache-control": "no-store",
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=tee-ingress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tee-ingress.js","sourceRoot":"","sources":["../../src/mcp/tee-ingress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
export interface LoopbackListenerDeps {
|
|
3
|
+
/**
|
|
4
|
+
* Port of the loopback-only auth listener (see `index.ts`). The dev UI is
|
|
5
|
+
* served ONLY to connections that arrived on this listener. `undefined`
|
|
6
|
+
* (cloud mode, or not yet bound) means the UI is never served.
|
|
7
|
+
*/
|
|
8
|
+
localApprovalPort: number | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* The main (tunneled) server port. If the loopback port collides with it
|
|
11
|
+
* the loopback bind fails but the port value survives, and every tunneled
|
|
12
|
+
* request would match — so a collision disables the UI outright.
|
|
13
|
+
*/
|
|
14
|
+
serverPort?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Restrict a route subtree to requests that physically arrived on the
|
|
18
|
+
* loopback auth listener, addressed it by a loopback name, and did not come
|
|
19
|
+
* from another browser origin.
|
|
20
|
+
*
|
|
21
|
+
* Why the listener port and not the peer address: the tunnel client (frpc)
|
|
22
|
+
* runs on the same host and connects to the MAIN server port from
|
|
23
|
+
* 127.0.0.1, so every tunneled request already looks local by
|
|
24
|
+
* `remoteAddress`. The one thing a remote caller can never influence is
|
|
25
|
+
* which listening socket accepted the connection — the tunnel forwards to
|
|
26
|
+
* `config.server.port` only, never to the loopback auth port.
|
|
27
|
+
*
|
|
28
|
+
* Fails closed: no socket information (tests, non-Node runtimes), no
|
|
29
|
+
* loopback listener configured, a port collision, or an unparseable URL →
|
|
30
|
+
* 404, so the subtree is invisible.
|
|
31
|
+
*/
|
|
32
|
+
export declare function requireLoopbackListener(deps: LoopbackListenerDeps): MiddlewareHandler;
|
|
33
|
+
//# sourceMappingURL=local-listener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-listener.d.ts","sourceRoot":"","sources":["../../src/middleware/local-listener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAkED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,oBAAoB,GACzB,iBAAiB,CAgCnB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const LOOPBACK_V4 = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
2
|
+
/** Socket-level check: is this IP address (not a hostname) loopback? */
|
|
3
|
+
function isLoopbackIp(address) {
|
|
4
|
+
if (!address)
|
|
5
|
+
return false;
|
|
6
|
+
return (address === "::1" ||
|
|
7
|
+
address === "::ffff:127.0.0.1" ||
|
|
8
|
+
LOOPBACK_V4.test(address));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Host-header check (DNS-rebinding defense). A hostile page can point a
|
|
12
|
+
* name it controls at 127.0.0.1 and then fetch
|
|
13
|
+
* `http://attacker.example:<port>/ui`; the browser sends that name as both
|
|
14
|
+
* `Host` and `Origin`, so origin equality alone would pass and the browser
|
|
15
|
+
* would treat the response as same-origin. Only loopback literals and the
|
|
16
|
+
* exact name `localhost` may address this listener. (`URL.hostname` keeps
|
|
17
|
+
* IPv6 brackets.)
|
|
18
|
+
*/
|
|
19
|
+
function isLoopbackRequestHost(hostname) {
|
|
20
|
+
return (hostname === "localhost" ||
|
|
21
|
+
hostname === "127.0.0.1" ||
|
|
22
|
+
hostname === "[::1]" ||
|
|
23
|
+
hostname === "::1" ||
|
|
24
|
+
LOOPBACK_V4.test(hostname));
|
|
25
|
+
}
|
|
26
|
+
function getSocket(c) {
|
|
27
|
+
// Access the Node.js socket via Hono's env bindings when running on the
|
|
28
|
+
// real server (@hono/node-server sets `c.env.incoming`).
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
return c.env?.incoming?.socket;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Browser check. A cross-origin fetch always carries an `Origin` header
|
|
34
|
+
* naming the requesting site; same-origin navigations carry none, and the
|
|
35
|
+
* page's own fetches (if the browser adds one) carry the page's origin,
|
|
36
|
+
* which is this listener's origin. Anything else is another page in the
|
|
37
|
+
* user's browser probing the loopback listener — the app's global CORS is
|
|
38
|
+
* `*`, and not every browser enforces Private Network Access.
|
|
39
|
+
*
|
|
40
|
+
* Exact equality against the request's own origin, deliberately: hostname
|
|
41
|
+
* heuristics are bypassable (`127.attacker.example` is a public name), and
|
|
42
|
+
* another *local* origin such as `http://localhost:12345` must not read
|
|
43
|
+
* this page either. Combined with the Host allowlist above, the request
|
|
44
|
+
* origin itself is guaranteed to be a loopback origin.
|
|
45
|
+
*/
|
|
46
|
+
function hasForeignOrigin(c, requestOrigin) {
|
|
47
|
+
const origin = c.req.header("origin");
|
|
48
|
+
if (!origin)
|
|
49
|
+
return false;
|
|
50
|
+
try {
|
|
51
|
+
return new URL(origin).origin !== requestOrigin;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Restrict a route subtree to requests that physically arrived on the
|
|
59
|
+
* loopback auth listener, addressed it by a loopback name, and did not come
|
|
60
|
+
* from another browser origin.
|
|
61
|
+
*
|
|
62
|
+
* Why the listener port and not the peer address: the tunnel client (frpc)
|
|
63
|
+
* runs on the same host and connects to the MAIN server port from
|
|
64
|
+
* 127.0.0.1, so every tunneled request already looks local by
|
|
65
|
+
* `remoteAddress`. The one thing a remote caller can never influence is
|
|
66
|
+
* which listening socket accepted the connection — the tunnel forwards to
|
|
67
|
+
* `config.server.port` only, never to the loopback auth port.
|
|
68
|
+
*
|
|
69
|
+
* Fails closed: no socket information (tests, non-Node runtimes), no
|
|
70
|
+
* loopback listener configured, a port collision, or an unparseable URL →
|
|
71
|
+
* 404, so the subtree is invisible.
|
|
72
|
+
*/
|
|
73
|
+
export function requireLoopbackListener(deps) {
|
|
74
|
+
return async (c, next) => {
|
|
75
|
+
const port = deps.localApprovalPort;
|
|
76
|
+
if (port === undefined || port === deps.serverPort) {
|
|
77
|
+
return c.notFound();
|
|
78
|
+
}
|
|
79
|
+
const socket = getSocket(c);
|
|
80
|
+
if (!socket ||
|
|
81
|
+
socket.localPort !== port ||
|
|
82
|
+
!isLoopbackIp(typeof socket.localAddress === "string"
|
|
83
|
+
? socket.localAddress
|
|
84
|
+
: undefined)) {
|
|
85
|
+
return c.notFound();
|
|
86
|
+
}
|
|
87
|
+
let requestUrl;
|
|
88
|
+
try {
|
|
89
|
+
requestUrl = new URL(c.req.url);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return c.notFound();
|
|
93
|
+
}
|
|
94
|
+
if (!isLoopbackRequestHost(requestUrl.hostname)) {
|
|
95
|
+
return c.notFound();
|
|
96
|
+
}
|
|
97
|
+
if (hasForeignOrigin(c, requestUrl.origin)) {
|
|
98
|
+
return c.notFound();
|
|
99
|
+
}
|
|
100
|
+
await next();
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=local-listener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-listener.js","sourceRoot":"","sources":["../../src/middleware/local-listener.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,GAAG,kCAAkC,CAAC;AAEvD,wEAAwE;AACxE,SAAS,YAAY,CAAC,OAA2B;IAC/C,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,CACL,OAAO,KAAK,KAAK;QACjB,OAAO,KAAK,kBAAkB;QAC9B,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAC1B,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,OAAO,CACL,QAAQ,KAAK,WAAW;QACxB,QAAQ,KAAK,WAAW;QACxB,QAAQ,KAAK,OAAO;QACpB,QAAQ,KAAK,KAAK;QAClB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAC3B,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAChB,CAAU;IAEV,wEAAwE;IACxE,yDAAyD;IACzD,8DAA8D;IAC9D,OAAQ,CAAC,CAAC,GAAW,EAAE,QAAQ,EAAE,MAAM,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,gBAAgB,CAAC,CAAU,EAAE,aAAqB;IACzD,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAA0B;IAE1B,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACpC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACnD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5B,IACE,CAAC,MAAM;YACP,MAAM,CAAC,SAAS,KAAK,IAAI;YACzB,CAAC,YAAY,CACX,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ;gBACrC,CAAC,CAAC,MAAM,CAAC,YAAY;gBACrB,CAAC,CAAC,SAAS,CACd,EACD,CAAC;YACD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,UAAe,CAAC;QACpB,IAAI,CAAC;YACH,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,gBAAgB,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opendatalabs/personal-server-ts-server",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Hono HTTP server for the Vana Personal Server — routes, middleware, composition root",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/vana-com/personal-server-ts.git",
|
|
9
|
+
"directory": "packages/server"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/vana-com/personal-server-ts#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/vana-com/personal-server-ts/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/api.js",
|
|
17
|
+
"types": "./dist/api.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
"./mcp/tee": {
|
|
20
|
+
"types": "./dist/mcp/index.d.ts",
|
|
21
|
+
"import": "./dist/mcp/index.js"
|
|
22
|
+
},
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/api.d.ts",
|
|
25
|
+
"import": "./dist/api.js"
|
|
26
|
+
},
|
|
27
|
+
"./config": {
|
|
28
|
+
"types": "./dist/config/index.d.ts",
|
|
29
|
+
"import": "./dist/config/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./runtime": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"!dist/bundle"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"copy-ui": "mkdir -p dist/ui && cp src/ui/index.html dist/ui/index.html && cp ../lite/src/browser-tls-rustls/browser_tls_rustls_bg.wasm dist/ui/browser_tls_rustls_bg.wasm",
|
|
45
|
+
"bundle-ui": "esbuild src/ui/ps-lite-debug.ts --bundle --format=esm --platform=browser --target=es2022 --outfile=dist/ui/ps-lite-debug.js",
|
|
46
|
+
"build:bundle": "mkdir -p dist/bundle && esbuild dist/index.js --bundle --platform=node --format=esm --target=node22 --outfile=dist/bundle/enclave-main.mjs --external:better-sqlite3 --external:pino --external:pino-pretty --external:secp256k1 --external:thread-stream --packages=bundle --banner:js=\"import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __filename = __bundleFileURLToPath(import.meta.url); const __dirname = __bundleDirname(__filename);\" && cp package.json dist/package.json && npm run verify:bundle",
|
|
47
|
+
"verify:bundle": "node dist/scripts/verify-bundle.js",
|
|
48
|
+
"build": "tsc --build && npm run copy-ui && npm run bundle-ui && npm run build:bundle",
|
|
49
|
+
"start": "node dist/index.js",
|
|
50
|
+
"dev": "node --watch dist/index.js"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@hono/node-server": "^1.19.13",
|
|
54
|
+
"@opendatalabs/personal-server-ts-core": "*",
|
|
55
|
+
"@opendatalabs/personal-server-ts-lite": "*",
|
|
56
|
+
"@opendatalabs/vana-sdk": "3.23.0-pr.211.36da1d8",
|
|
57
|
+
"better-sqlite3": "^12.11.1",
|
|
58
|
+
"hono": "^4.12.27",
|
|
59
|
+
"pino": "^10.3.1",
|
|
60
|
+
"pino-pretty": "^13.0.0",
|
|
61
|
+
"viem": "^2.54.2"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
65
|
+
"esbuild": "0.28.1"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
/** Sandbox-local endpoint. Never mounted on a full PS or a public router. */
|
|
3
|
+
export declare function enclaveFleetRoutes(deps: {
|
|
4
|
+
accessToken: string;
|
|
5
|
+
hydrate(scopes: string[]): Promise<void>;
|
|
6
|
+
observe(scope: string): {
|
|
7
|
+
dataVersion: number | null;
|
|
8
|
+
ready: boolean;
|
|
9
|
+
} | Promise<{
|
|
10
|
+
dataVersion: number | null;
|
|
11
|
+
ready: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
}): Hono;
|
|
14
|
+
//# sourceMappingURL=enclave-fleet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclave-fleet.d.ts","sourceRoot":"","sources":["../../src/routes/enclave-fleet.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,CACL,KAAK,EAAE,MAAM,GAEX;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAC9C,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC7D,GAAG,IAAI,CAkDP"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { ScopeSchema } from "@opendatalabs/vana-sdk/protocol/scopes";
|
|
4
|
+
import { createBodyLimit } from "../middleware/body-limit.js";
|
|
5
|
+
/** Sandbox-local endpoint. Never mounted on a full PS or a public router. */
|
|
6
|
+
export function enclaveFleetRoutes(deps) {
|
|
7
|
+
const app = new Hono();
|
|
8
|
+
app.use("*", createBodyLimit(16 * 1024));
|
|
9
|
+
app.post("/readiness", async (c) => {
|
|
10
|
+
const received = Buffer.from(c.req.header("authorization") ?? "");
|
|
11
|
+
const expected = Buffer.from(`Bearer ${deps.accessToken}`);
|
|
12
|
+
if (received.length !== expected.length ||
|
|
13
|
+
!timingSafeEqual(received, expected))
|
|
14
|
+
return c.json({ error: "authorization required" }, 401);
|
|
15
|
+
const body = (await c.req.json().catch(() => null));
|
|
16
|
+
if (!body ||
|
|
17
|
+
!Array.isArray(body.scopes) ||
|
|
18
|
+
body.scopes.length > 32 ||
|
|
19
|
+
body.scopes.some((s) => !s ||
|
|
20
|
+
!ScopeSchema.safeParse(s.scope).success ||
|
|
21
|
+
(s.minimumVersion !== undefined &&
|
|
22
|
+
(!Number.isSafeInteger(s.minimumVersion) || s.minimumVersion < 1)))) {
|
|
23
|
+
return c.json({ error: "invalid scopes" }, 400);
|
|
24
|
+
}
|
|
25
|
+
if (body.hydrate)
|
|
26
|
+
await deps.hydrate(body.scopes.map((s) => s.scope));
|
|
27
|
+
return c.json(await Promise.all(body.scopes.map(async (s) => {
|
|
28
|
+
const observed = await deps.observe(s.scope);
|
|
29
|
+
return {
|
|
30
|
+
scope: s.scope,
|
|
31
|
+
dataVersion: observed.dataVersion,
|
|
32
|
+
state: observed.ready &&
|
|
33
|
+
observed.dataVersion !== null &&
|
|
34
|
+
observed.dataVersion >= (s.minimumVersion ?? 1)
|
|
35
|
+
? "ready"
|
|
36
|
+
: "pending",
|
|
37
|
+
observedAt: new Date().toISOString(),
|
|
38
|
+
};
|
|
39
|
+
})));
|
|
40
|
+
});
|
|
41
|
+
return app;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=enclave-fleet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclave-fleet.js","sourceRoot":"","sources":["../../src/routes/enclave-fleet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { type JobRequestEnvelope } from "@opendatalabs/vana-sdk/protocol/jobs";
|
|
3
|
+
import type { JobExecuteResponse } from "../jobs/types.js";
|
|
4
|
+
export interface EnclaveJobRouteDeps {
|
|
5
|
+
accessToken: string;
|
|
6
|
+
executeJob(envelope: JobRequestEnvelope): Promise<JobExecuteResponse>;
|
|
7
|
+
}
|
|
8
|
+
export declare function enclaveJobRoutes(deps: EnclaveJobRouteDeps): Hono;
|
|
9
|
+
//# sourceMappingURL=enclave-jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclave-jobs.d.ts","sourceRoot":"","sources":["../../src/routes/enclave-jobs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACvE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CA0ChE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { isAddress, isHex } from "viem";
|
|
4
|
+
import { JOB_OPERATIONS, JOB_PROTOCOL_VERSION, } from "@opendatalabs/vana-sdk/protocol/jobs";
|
|
5
|
+
import { createBodyLimit } from "../middleware/body-limit.js";
|
|
6
|
+
import { JobFailure } from "../jobs/worker.js";
|
|
7
|
+
const MAX_JOB_BODY_BYTES = 256 * 1024;
|
|
8
|
+
const BEARER_PREFIX = "Bearer ";
|
|
9
|
+
export function enclaveJobRoutes(deps) {
|
|
10
|
+
const app = new Hono();
|
|
11
|
+
app.use("/execute", createBodyLimit(MAX_JOB_BODY_BYTES));
|
|
12
|
+
app.post("/execute", async (context) => {
|
|
13
|
+
if (!hasValidBearer(context.req.header("authorization"), deps.accessToken)) {
|
|
14
|
+
return context.json(jobError("AUTH_INVALID", "invalid bearer token"), 401);
|
|
15
|
+
}
|
|
16
|
+
let body;
|
|
17
|
+
try {
|
|
18
|
+
body = await context.req.json();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return context.json({ error: { message: "invalid request body" } }, 400);
|
|
22
|
+
}
|
|
23
|
+
if (!isJobEnvelope(body)) {
|
|
24
|
+
return context.json({ error: { message: "invalid request body" } }, 400);
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
return context.json(await deps.executeJob(body), 200);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (error instanceof JobFailure) {
|
|
31
|
+
return context.json(jobError(error.code, error.message, error.retryable), statusFor(error.code));
|
|
32
|
+
}
|
|
33
|
+
return context.json(jobError("INTERNAL", "job execution failed", true), 500);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return app;
|
|
37
|
+
}
|
|
38
|
+
function hasValidBearer(header, expected) {
|
|
39
|
+
if (!header?.startsWith(BEARER_PREFIX)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const received = Buffer.from(header.slice(BEARER_PREFIX.length));
|
|
43
|
+
const target = Buffer.from(expected);
|
|
44
|
+
if (received.length !== target.length) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return timingSafeEqual(received, target);
|
|
48
|
+
}
|
|
49
|
+
function isJobEnvelope(value) {
|
|
50
|
+
if (!isRecord(value) || !isRecord(value.request)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const request = value.request;
|
|
54
|
+
return (value.auth !== "" &&
|
|
55
|
+
typeof value.auth === "string" &&
|
|
56
|
+
request.v === JOB_PROTOCOL_VERSION &&
|
|
57
|
+
typeof request.jobId === "string" &&
|
|
58
|
+
isAddressValue(request.owner) &&
|
|
59
|
+
isAddressValue(request.builder) &&
|
|
60
|
+
isHexValue(request.builderPublicKey) &&
|
|
61
|
+
isHexValue(request.grantId) &&
|
|
62
|
+
typeof request.scope === "string" &&
|
|
63
|
+
JOB_OPERATIONS.some((operation) => operation === request.operation) &&
|
|
64
|
+
(request.pinnedVersion === null ||
|
|
65
|
+
typeof request.pinnedVersion === "string") &&
|
|
66
|
+
typeof request.deadline === "string");
|
|
67
|
+
}
|
|
68
|
+
function isAddressValue(value) {
|
|
69
|
+
return typeof value === "string" && isAddress(value);
|
|
70
|
+
}
|
|
71
|
+
function isHexValue(value) {
|
|
72
|
+
return typeof value === "string" && isHex(value);
|
|
73
|
+
}
|
|
74
|
+
function isRecord(value) {
|
|
75
|
+
return typeof value === "object" && value !== null;
|
|
76
|
+
}
|
|
77
|
+
function jobError(code, message, retryable = false) {
|
|
78
|
+
return { error: { code, message, retryable } };
|
|
79
|
+
}
|
|
80
|
+
function statusFor(code) {
|
|
81
|
+
switch (code) {
|
|
82
|
+
case "AUTH_INVALID":
|
|
83
|
+
return 401;
|
|
84
|
+
case "BUILDER_MISMATCH":
|
|
85
|
+
case "OWNER_MISMATCH":
|
|
86
|
+
case "GRANT_REVOKED":
|
|
87
|
+
case "GRANT_INVALID":
|
|
88
|
+
case "SIGNED_ARTIFACT_MISSING":
|
|
89
|
+
case "SIGNED_ARTIFACT_INVALID":
|
|
90
|
+
case "SERVER_NOT_REGISTERED":
|
|
91
|
+
case "RESULT_SIGNING_REFUSED":
|
|
92
|
+
return 403;
|
|
93
|
+
case "SCOPE_NOT_FOUND":
|
|
94
|
+
return 404;
|
|
95
|
+
case "VERSION_MISMATCH":
|
|
96
|
+
return 409;
|
|
97
|
+
case "DEADLINE_PASSED":
|
|
98
|
+
return 410;
|
|
99
|
+
case "RESULT_TOO_LARGE":
|
|
100
|
+
return 413;
|
|
101
|
+
case "RESULT_UPLOAD_FAILED":
|
|
102
|
+
case "INTERNAL":
|
|
103
|
+
return 500;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=enclave-jobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclave-jobs.js","sourceRoot":"","sources":["../../src/routes/enclave-jobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { McpConnectionRecord } from "@opendatalabs/personal-server-ts-core/mcp";
|
|
3
|
+
import { type Address } from "viem";
|
|
4
|
+
export declare function enclaveMcpRoutes(deps: {
|
|
5
|
+
accessToken: string;
|
|
6
|
+
serverOwner: Address;
|
|
7
|
+
execute(request: Request, connection: McpConnectionRecord): Promise<Response>;
|
|
8
|
+
}): Hono;
|
|
9
|
+
//# sourceMappingURL=enclave-mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclave-mcp.d.ts","sourceRoot":"","sources":["../../src/routes/enclave-mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAG/D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/E,GAAG,IAAI,CAoDP"}
|