@stage-labs/metro 0.1.0-beta.53 → 0.1.0-beta.55
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/serve.js +56 -7
- package/package.json +1 -1
- package/runtime/node_modules/@metro-labs/mcp/package.json +1 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +5 -5
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-connector-api.ts +9 -6
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +6 -13
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-serve.ts +1 -2
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +4 -7
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/bundle-api.ts +5 -6
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/claude-api.ts +3 -7
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connect-hint.ts +4 -2
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-api.ts +5 -5
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth.ts +1 -1
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/http.ts +2 -2
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity-key.ts +33 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity-registry.ts +13 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity-routes.ts +54 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-mode.ts +1 -2
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/{session-config.ts → return-to.ts} +0 -1
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-api.ts +9 -7
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +2 -2
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/signed-identity.ts +36 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +87 -24
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/update-api.ts +2 -5
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/upload-api.ts +1 -2
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/vault-api.ts +2 -32
- package/runtime/node_modules/@metro-labs/mcp/src/db/file-admin.ts +0 -10
- package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -6
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/index.ts +1 -2
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +2 -28
- package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +2 -5
- package/runtime/runtime.json +1 -1
- package/runtime/stations.json +1 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-secret.ts +0 -21
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -96
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/siwe-auth.ts +0 -73
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/siwe-nonces.ts +0 -43
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/siwe-routes.ts +0 -86
- package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -41
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { log } from './log.js';
|
|
3
|
-
import {
|
|
4
|
-
apiFailure,
|
|
5
|
-
bodyField,
|
|
6
|
-
cors,
|
|
7
|
-
readJsonBody,
|
|
8
|
-
sendJson,
|
|
9
|
-
} from './api-http.js';
|
|
10
|
-
import { mintNonce, takeNonce } from './siwe-nonces.js';
|
|
11
|
-
import { verifySiweLogin } from './siwe-auth.js';
|
|
12
|
-
import { signSession } from './session.js';
|
|
13
|
-
import { SESSION_TTL_SEC } from './session-config.js';
|
|
14
|
-
|
|
15
|
-
const NONCE_PATH = '/auth/siwe/nonce';
|
|
16
|
-
const VERIFY_PATH = '/auth/siwe/verify';
|
|
17
|
-
|
|
18
|
-
export interface SiweRouteDeps {
|
|
19
|
-
ensureUser: (address: string) => Promise<string>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function handleVerify(
|
|
23
|
-
req: IncomingMessage,
|
|
24
|
-
res: ServerResponse,
|
|
25
|
-
secret: string,
|
|
26
|
-
deps: SiweRouteDeps,
|
|
27
|
-
): Promise<void> {
|
|
28
|
-
const body = await readJsonBody(req);
|
|
29
|
-
const message = bodyField(body, 'message');
|
|
30
|
-
const signature = bodyField(body, 'signature');
|
|
31
|
-
if (typeof message !== 'string' || typeof signature !== 'string') {
|
|
32
|
-
sendJson(req, res, 400, { error: 'message and signature are required' });
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const address = await verifySiweLogin({ message, signature }, { takeNonce });
|
|
36
|
-
const userId = await deps.ensureUser(address);
|
|
37
|
-
log.info({ userId, address }, 'siwe: session issued');
|
|
38
|
-
const session = signSession({ subject: address, agentIds: [] }, secret, {
|
|
39
|
-
ttlSec: SESSION_TTL_SEC,
|
|
40
|
-
});
|
|
41
|
-
sendJson(req, res, 200, { session, address });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const ROUTES: Record<string, string> = {
|
|
45
|
-
[NONCE_PATH]: 'GET',
|
|
46
|
-
[VERIFY_PATH]: 'POST',
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
function refused(
|
|
50
|
-
req: IncomingMessage,
|
|
51
|
-
res: ServerResponse,
|
|
52
|
-
path: string,
|
|
53
|
-
): boolean {
|
|
54
|
-
if (req.method === 'OPTIONS') {
|
|
55
|
-
res.writeHead(204, cors(req)).end();
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
if (req.method !== ROUTES[path]) {
|
|
59
|
-
sendJson(req, res, 405, { error: 'method not allowed' });
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function handleSiweAuthRequest(
|
|
66
|
-
req: IncomingMessage,
|
|
67
|
-
res: ServerResponse,
|
|
68
|
-
deps: SiweRouteDeps,
|
|
69
|
-
): boolean {
|
|
70
|
-
const path = (req.url ?? '').split('?')[0] ?? '';
|
|
71
|
-
if (ROUTES[path] === undefined) return false;
|
|
72
|
-
if (refused(req, res, path)) return true;
|
|
73
|
-
const secret = process.env.METRO_SESSION_SECRET?.trim() ?? '';
|
|
74
|
-
if (secret === '') {
|
|
75
|
-
sendJson(req, res, 503, { error: 'sign-in is not configured' });
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
if (path === NONCE_PATH) {
|
|
79
|
-
sendJson(req, res, 200, { nonce: mintNonce() });
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
handleVerify(req, res, secret, deps).catch((err: unknown) => {
|
|
83
|
-
apiFailure(req, res, err, 'siwe');
|
|
84
|
-
});
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { eq } from 'drizzle-orm';
|
|
2
|
-
import { ApiError } from '../daemon/api-error.js';
|
|
3
|
-
import { getDb } from './client.js';
|
|
4
|
-
import { newId } from './ids.js';
|
|
5
|
-
import { users } from './schema.js';
|
|
6
|
-
import { normalizeAddress } from './address.js';
|
|
7
|
-
|
|
8
|
-
const UNIQUE_VIOLATION = '23505';
|
|
9
|
-
|
|
10
|
-
export class UserError extends ApiError {}
|
|
11
|
-
|
|
12
|
-
const CAUSE_DEPTH = 5;
|
|
13
|
-
|
|
14
|
-
export function isUniqueViolation(err: unknown): boolean {
|
|
15
|
-
let current: unknown = err;
|
|
16
|
-
for (let depth = 0; depth < CAUSE_DEPTH; depth += 1) {
|
|
17
|
-
if (typeof current !== 'object' || current === null) return false;
|
|
18
|
-
const { code, cause } = current as { code?: unknown; cause?: unknown };
|
|
19
|
-
if (code === UNIQUE_VIOLATION) return true;
|
|
20
|
-
current = cause;
|
|
21
|
-
}
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export async function ensureUserByAddress(raw: string): Promise<string> {
|
|
27
|
-
const address = normalizeAddress(raw);
|
|
28
|
-
if (address === null) throw new UserError('an Ethereum address is required', 400);
|
|
29
|
-
const db = getDb();
|
|
30
|
-
const inserted = await db
|
|
31
|
-
.insert(users)
|
|
32
|
-
.values({ id: newId(), address })
|
|
33
|
-
.onConflictDoNothing({ target: users.address })
|
|
34
|
-
.returning({ id: users.id });
|
|
35
|
-
const id = inserted[0]?.id;
|
|
36
|
-
if (id !== undefined) return id;
|
|
37
|
-
const rows = await db.select({ id: users.id }).from(users).where(eq(users.address, address));
|
|
38
|
-
const existing = rows[0]?.id;
|
|
39
|
-
if (existing === undefined) throw new UserError('user lookup returned no id', 500);
|
|
40
|
-
return existing;
|
|
41
|
-
}
|