@zackbart/connecta 0.1.0 → 0.2.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/CHANGELOG.md +69 -0
- package/dist/connectors/remote-mcp.d.ts.map +1 -1
- package/dist/connectors/remote-mcp.js +2 -1
- package/dist/connectors/remote-mcp.js.map +1 -1
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +7 -0
- package/dist/execute.js.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +35 -0
- package/dist/meta-tools.js.map +1 -1
- package/dist/node.d.ts +20 -2
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +89 -10
- package/dist/node.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +35 -9
- package/dist/server.js.map +1 -1
- package/dist/storage/file.d.ts.map +1 -1
- package/dist/storage/file.js +20 -1
- package/dist/storage/file.js.map +1 -1
- package/dist/types.d.ts +38 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui.d.ts +6 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +34 -13
- package/dist/ui.js.map +1 -1
- package/dist/version.d.ts +8 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
- package/src/connectors/remote-mcp.ts +2 -1
- package/src/execute.ts +7 -0
- package/src/index.ts +7 -9
- package/src/meta-tools.ts +37 -0
- package/src/node.ts +119 -10
- package/src/server.ts +39 -9
- package/src/storage/file.ts +23 -1
- package/src/types.ts +41 -1
- package/src/ui.ts +42 -13
- package/src/version.ts +7 -0
package/dist/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAIA,8CAA8C;AAC9C,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;OAM7B,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package version, as a Workers-safe constant — no filesystem read, no
|
|
3
|
+
* import assertion. `test/version.test.ts` asserts it matches package.json, so
|
|
4
|
+
* a bump that forgets this file fails the build rather than shipping a stale
|
|
5
|
+
* version to `/health` and to downstream MCP handshakes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CONNECTA_VERSION = "0.2.0";
|
|
8
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package version, as a Workers-safe constant — no filesystem read, no
|
|
3
|
+
* import assertion. `test/version.test.ts` asserts it matches package.json, so
|
|
4
|
+
* a bump that forgets this file fails the build rather than shipping a stale
|
|
5
|
+
* version to `/health` and to downstream MCP handshakes.
|
|
6
|
+
*/
|
|
7
|
+
export const CONNECTA_VERSION = "0.2.0";
|
|
8
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|
|
4
4
|
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
5
5
|
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
|
|
6
6
|
import { KvOAuthProvider } from "../auth/downstream-oauth.js";
|
|
7
|
+
import { CONNECTA_VERSION } from "../version.js";
|
|
7
8
|
import type {
|
|
8
9
|
Connector,
|
|
9
10
|
ConnectorContext,
|
|
@@ -144,7 +145,7 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
144
145
|
// generation, so a remote such as Stripe fails during tools/list unless
|
|
145
146
|
// the SDK's edge-safe validator is selected explicitly.
|
|
146
147
|
const c = new Client(
|
|
147
|
-
{ name: "connecta", version:
|
|
148
|
+
{ name: "connecta", version: CONNECTA_VERSION },
|
|
148
149
|
{ jsonSchemaValidator: new CfWorkerJsonSchemaValidator() },
|
|
149
150
|
);
|
|
150
151
|
const t = buildTransport(ctx, state);
|
package/src/execute.ts
CHANGED
|
@@ -544,6 +544,13 @@ export function registerExecuteTool(
|
|
|
544
544
|
.string()
|
|
545
545
|
.describe("A JavaScript async arrow function to execute."),
|
|
546
546
|
},
|
|
547
|
+
// The sandbox exposes only tools that are explicitly read-only, and the
|
|
548
|
+
// executor grants no network, filesystem, env, or timer capabilities.
|
|
549
|
+
annotations: {
|
|
550
|
+
readOnlyHint: true,
|
|
551
|
+
destructiveHint: false,
|
|
552
|
+
openWorldHint: true,
|
|
553
|
+
},
|
|
547
554
|
},
|
|
548
555
|
async (args) => handler(args as { code: string }),
|
|
549
556
|
);
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { CredentialVault } from "./credentials.js";
|
|
|
2
2
|
import { Registry } from "./registry.js";
|
|
3
3
|
import { createFetchHandler } from "./server.js";
|
|
4
4
|
import { memoryStorage } from "./storage/memory.js";
|
|
5
|
+
import { CONNECTA_VERSION } from "./version.js";
|
|
5
6
|
import type { ActivityReadGate, ActivityStore } from "./activity.js";
|
|
6
7
|
import type {
|
|
7
8
|
Connector,
|
|
@@ -123,7 +124,7 @@ export function createConnecta(config: ConnectaConfig): Connecta {
|
|
|
123
124
|
publicUrl: config.publicUrl,
|
|
124
125
|
serverInfo: {
|
|
125
126
|
name: config.serverInfo?.name ?? "connecta",
|
|
126
|
-
version: config.serverInfo?.version ??
|
|
127
|
+
version: config.serverInfo?.version ?? CONNECTA_VERSION,
|
|
127
128
|
},
|
|
128
129
|
logger,
|
|
129
130
|
activity: config.activity,
|
|
@@ -150,14 +151,11 @@ export { remoteMcp } from "./connectors/remote-mcp.js";
|
|
|
150
151
|
export { api } from "./connectors/api.js";
|
|
151
152
|
export { bearerToken } from "./auth/bearer.js";
|
|
152
153
|
export { memoryStorage } from "./storage/memory.js";
|
|
153
|
-
export {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
createExecuteTool,
|
|
159
|
-
sanitizeIdentifier,
|
|
160
|
-
} from "./execute.js";
|
|
154
|
+
export { CONNECTA_VERSION } from "./version.js";
|
|
155
|
+
// Registry is reachable through `Connecta.registry`, so its type is public;
|
|
156
|
+
// the class itself, the credential vault, and the meta-tool/sandbox factories
|
|
157
|
+
// are internal factoring and are deliberately not part of the API surface.
|
|
158
|
+
export type { Registry } from "./registry.js";
|
|
161
159
|
|
|
162
160
|
export type { RemoteMcpOptions, RemoteMcpAuth } from "./connectors/remote-mcp.js";
|
|
163
161
|
export type { ApiOptions, ApiTool } from "./connectors/api.js";
|
package/src/meta-tools.ts
CHANGED
|
@@ -958,6 +958,26 @@ const AUTHORIZE_DESC =
|
|
|
958
958
|
const SKILLS_DESC =
|
|
959
959
|
'List or fetch concise guidance for choosing among Connecta meta-tools. Call skills({ name: "usage" }) once when the routing workflow is unfamiliar; do not refetch it in the same task.';
|
|
960
960
|
|
|
961
|
+
/**
|
|
962
|
+
* Connecta refuses downstream tools that are not explicitly annotated
|
|
963
|
+
* read-only, so its own meta-tools must carry the same hints — otherwise a
|
|
964
|
+
* host that gates on annotations prompts for every search, and a connecta
|
|
965
|
+
* aggregated behind another connecta would be refused by its own policy.
|
|
966
|
+
*/
|
|
967
|
+
const READ_ONLY_REMOTE = {
|
|
968
|
+
readOnlyHint: true,
|
|
969
|
+
destructiveHint: false,
|
|
970
|
+
openWorldHint: true,
|
|
971
|
+
} as const;
|
|
972
|
+
|
|
973
|
+
/** Read-only and served entirely from connecta's own storage. */
|
|
974
|
+
const READ_ONLY_LOCAL = {
|
|
975
|
+
readOnlyHint: true,
|
|
976
|
+
destructiveHint: false,
|
|
977
|
+
idempotentHint: true,
|
|
978
|
+
openWorldHint: false,
|
|
979
|
+
} as const;
|
|
980
|
+
|
|
961
981
|
/** Register the nine meta-tools onto an McpServer instance. */
|
|
962
982
|
export function registerMetaTools(
|
|
963
983
|
server: McpServer,
|
|
@@ -993,6 +1013,7 @@ export function registerMetaTools(
|
|
|
993
1013
|
{
|
|
994
1014
|
description: LIST_DESC,
|
|
995
1015
|
inputSchema: { probe: z.boolean().optional() },
|
|
1016
|
+
annotations: READ_ONLY_REMOTE,
|
|
996
1017
|
},
|
|
997
1018
|
async (args) => mt.listConnectors(args as ListArgs),
|
|
998
1019
|
);
|
|
@@ -1009,6 +1030,7 @@ export function registerMetaTools(
|
|
|
1009
1030
|
fullDescriptions: z.boolean().optional(),
|
|
1010
1031
|
includeSchemas: z.enum(["compact", "json"]).optional(),
|
|
1011
1032
|
},
|
|
1033
|
+
annotations: READ_ONLY_REMOTE,
|
|
1012
1034
|
},
|
|
1013
1035
|
async (args) => mt.searchTools(args as SearchArgs),
|
|
1014
1036
|
);
|
|
@@ -1022,6 +1044,7 @@ export function registerMetaTools(
|
|
|
1022
1044
|
format: z.enum(["compact", "json"]).optional(),
|
|
1023
1045
|
fullDescriptions: z.boolean().optional(),
|
|
1024
1046
|
},
|
|
1047
|
+
annotations: READ_ONLY_REMOTE,
|
|
1025
1048
|
},
|
|
1026
1049
|
async (args) => mt.describeTools(args as DescribeArgs),
|
|
1027
1050
|
);
|
|
@@ -1039,6 +1062,9 @@ export function registerMetaTools(
|
|
|
1039
1062
|
maxRetries: z.number().int().min(0).max(2).optional(),
|
|
1040
1063
|
diagnostics: z.boolean().optional(),
|
|
1041
1064
|
},
|
|
1065
|
+
// call_tool admits only tools that are themselves explicitly read-only;
|
|
1066
|
+
// anything else is refused and routed to call_destructive_tool.
|
|
1067
|
+
annotations: READ_ONLY_REMOTE,
|
|
1042
1068
|
},
|
|
1043
1069
|
async (args) => mt.callTool(args as CallArgs),
|
|
1044
1070
|
);
|
|
@@ -1073,6 +1099,13 @@ export function registerMetaTools(
|
|
|
1073
1099
|
connector: z.string(),
|
|
1074
1100
|
force: z.boolean().optional(),
|
|
1075
1101
|
},
|
|
1102
|
+
// Starts (or with force, resets) a downstream OAuth flow — it changes
|
|
1103
|
+
// stored connector auth state, so it is deliberately not read-only.
|
|
1104
|
+
annotations: {
|
|
1105
|
+
readOnlyHint: false,
|
|
1106
|
+
destructiveHint: false,
|
|
1107
|
+
openWorldHint: true,
|
|
1108
|
+
},
|
|
1076
1109
|
},
|
|
1077
1110
|
async (args) => mt.authorizeConnector(args as AuthorizeArgs),
|
|
1078
1111
|
);
|
|
@@ -1086,6 +1119,7 @@ export function registerMetaTools(
|
|
|
1086
1119
|
offset: z.number().int().nonnegative().optional(),
|
|
1087
1120
|
maxBytes: z.number().int().positive().optional(),
|
|
1088
1121
|
},
|
|
1122
|
+
annotations: READ_ONLY_LOCAL,
|
|
1089
1123
|
},
|
|
1090
1124
|
async (args) => mt.getResult(args as GetResultArgs),
|
|
1091
1125
|
);
|
|
@@ -1114,6 +1148,9 @@ export function registerMetaTools(
|
|
|
1114
1148
|
maxRetries: z.number().int().min(0).max(2).optional(),
|
|
1115
1149
|
diagnostics: z.boolean().optional(),
|
|
1116
1150
|
},
|
|
1151
|
+
// Same gate as call_tool: every call in the batch must be explicitly
|
|
1152
|
+
// read-only or the batch is refused.
|
|
1153
|
+
annotations: READ_ONLY_REMOTE,
|
|
1117
1154
|
},
|
|
1118
1155
|
async (args) => mt.batchCall(args as BatchArgs),
|
|
1119
1156
|
);
|
package/src/node.ts
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
2
|
import type { IncomingMessage, Server, ServerResponse } from "node:http";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import { pipeline } from "node:stream/promises";
|
|
3
5
|
import type { Connecta } from "./index.js";
|
|
4
6
|
|
|
5
7
|
export { fileStorage } from "./storage/file.js";
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
/** 10 MiB. Tool arguments are JSON; nothing legitimate approaches this. */
|
|
10
|
+
const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
11
|
+
|
|
12
|
+
export interface ListenOptions {
|
|
13
|
+
port: number;
|
|
14
|
+
/** Interface to bind. Defaults to Node's own (all interfaces). */
|
|
15
|
+
host?: string;
|
|
16
|
+
/** Reject request bodies larger than this with 413. Default 10 MiB. */
|
|
17
|
+
maxBodyBytes?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Stop accepting connections on SIGTERM/SIGINT, let in-flight requests
|
|
20
|
+
* finish, drain deferred work, then exit. Default true — Docker sends
|
|
21
|
+
* SIGTERM on every `compose up` recreate and Node's default is to die
|
|
22
|
+
* mid-request. Set false to install your own handlers.
|
|
23
|
+
*/
|
|
24
|
+
gracefulShutdown?: boolean;
|
|
25
|
+
/** Shutdown deadline before forcing exit. Default 10s (Docker's own grace). */
|
|
26
|
+
shutdownTimeoutMs?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const BODY_TOO_LARGE = Symbol("body-too-large");
|
|
30
|
+
|
|
31
|
+
async function toRequest(
|
|
32
|
+
req: IncomingMessage,
|
|
33
|
+
maxBodyBytes: number,
|
|
34
|
+
): Promise<Request | typeof BODY_TOO_LARGE> {
|
|
8
35
|
const host = req.headers.host ?? "localhost";
|
|
9
36
|
const proto =
|
|
10
37
|
(req.headers["x-forwarded-proto"] as string | undefined) ?? "http";
|
|
@@ -18,7 +45,14 @@ async function toRequest(req: IncomingMessage): Promise<Request> {
|
|
|
18
45
|
let body: Uint8Array | undefined;
|
|
19
46
|
if (method !== "GET" && method !== "HEAD") {
|
|
20
47
|
const chunks: Buffer[] = [];
|
|
21
|
-
|
|
48
|
+
let size = 0;
|
|
49
|
+
for await (const chunk of req) {
|
|
50
|
+
size += (chunk as Buffer).length;
|
|
51
|
+
// Stop reading as soon as the cap is passed rather than buffering the
|
|
52
|
+
// rest of a body we have already decided to reject.
|
|
53
|
+
if (size > maxBodyBytes) return BODY_TOO_LARGE;
|
|
54
|
+
chunks.push(chunk as Buffer);
|
|
55
|
+
}
|
|
22
56
|
if (chunks.length) body = new Uint8Array(Buffer.concat(chunks));
|
|
23
57
|
}
|
|
24
58
|
return new Request(url, {
|
|
@@ -36,27 +70,102 @@ async function writeResponse(
|
|
|
36
70
|
): Promise<void> {
|
|
37
71
|
res.statusCode = response.status;
|
|
38
72
|
response.headers.forEach((value, key) => res.setHeader(key, value));
|
|
39
|
-
|
|
40
|
-
|
|
73
|
+
if (!response.body) {
|
|
74
|
+
res.end();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Stream rather than buffer: a connector-served route may return a large
|
|
78
|
+
// proxied file body, and materializing it would hold the whole thing in
|
|
79
|
+
// memory before the first byte reaches the client.
|
|
80
|
+
await pipeline(
|
|
81
|
+
Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]),
|
|
82
|
+
res,
|
|
83
|
+
);
|
|
41
84
|
}
|
|
42
85
|
|
|
43
86
|
/**
|
|
44
87
|
* Serve a Connecta over node:http. Thin adapter: IncomingMessage → Request,
|
|
45
|
-
* Response → ServerResponse
|
|
88
|
+
* Response → ServerResponse, plus the process-level concerns a long-running
|
|
89
|
+
* container needs (body cap, response streaming, graceful shutdown). No
|
|
90
|
+
* dependencies beyond node core.
|
|
46
91
|
*/
|
|
47
|
-
export function listen(
|
|
92
|
+
export function listen(
|
|
93
|
+
connecta: Connecta,
|
|
94
|
+
portOrOptions: number | ListenOptions,
|
|
95
|
+
): Server {
|
|
96
|
+
const opts: ListenOptions =
|
|
97
|
+
typeof portOrOptions === "number" ? { port: portOrOptions } : portOrOptions;
|
|
98
|
+
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
99
|
+
|
|
100
|
+
// Node has no ExecutionContext, so deferred work (activity sinks) would
|
|
101
|
+
// otherwise be an untracked floating promise. Track it here and drain it on
|
|
102
|
+
// shutdown so both runtimes behave the same.
|
|
103
|
+
const pending = new Set<Promise<unknown>>();
|
|
104
|
+
const ctx = {
|
|
105
|
+
waitUntil(promise: Promise<unknown>): void {
|
|
106
|
+
pending.add(promise);
|
|
107
|
+
void promise.finally(() => pending.delete(promise));
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
48
111
|
const server = createServer((req, res) => {
|
|
49
112
|
void (async () => {
|
|
50
113
|
try {
|
|
51
|
-
const request = await toRequest(req);
|
|
52
|
-
|
|
114
|
+
const request = await toRequest(req, maxBodyBytes);
|
|
115
|
+
if (request === BODY_TOO_LARGE) {
|
|
116
|
+
res.statusCode = 413;
|
|
117
|
+
// The request stream was abandoned mid-body, so this connection
|
|
118
|
+
// cannot be reused — say so rather than leaving the client to
|
|
119
|
+
// discover it as a reset.
|
|
120
|
+
res.setHeader("Connection", "close");
|
|
121
|
+
res.end("Payload Too Large");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const response = await connecta.fetch(request, undefined, ctx);
|
|
53
125
|
await writeResponse(res, response);
|
|
54
|
-
} catch {
|
|
126
|
+
} catch (error) {
|
|
127
|
+
// A headless deployment has nothing else to go on; never swallow this.
|
|
128
|
+
console.error("[connecta] request failed", error);
|
|
129
|
+
if (res.headersSent) {
|
|
130
|
+
// Mid-stream failure: appending an error string here would corrupt
|
|
131
|
+
// the partial body the client has already begun reading. Cutting
|
|
132
|
+
// the connection is the only honest signal left.
|
|
133
|
+
res.destroy();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
55
136
|
res.statusCode = 500;
|
|
56
137
|
res.end("Internal Server Error");
|
|
57
138
|
}
|
|
58
139
|
})();
|
|
59
140
|
});
|
|
60
|
-
|
|
141
|
+
|
|
142
|
+
if (opts.gracefulShutdown !== false) {
|
|
143
|
+
const timeoutMs = opts.shutdownTimeoutMs ?? 10_000;
|
|
144
|
+
let shuttingDown = false;
|
|
145
|
+
const shutdown = (signal: string): void => {
|
|
146
|
+
if (shuttingDown) return;
|
|
147
|
+
shuttingDown = true;
|
|
148
|
+
console.info(`[connecta] ${signal} received, draining`);
|
|
149
|
+
const forced = setTimeout(() => {
|
|
150
|
+
console.warn("[connecta] shutdown timed out, exiting");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}, timeoutMs);
|
|
153
|
+
forced.unref?.();
|
|
154
|
+
// close() alone waits on idle keep-alive sockets, so a single browser
|
|
155
|
+
// tab would stall every shutdown until the force-exit deadline.
|
|
156
|
+
server.closeIdleConnections();
|
|
157
|
+
server.close(() => {
|
|
158
|
+
void Promise.allSettled([...pending]).then(() => {
|
|
159
|
+
clearTimeout(forced);
|
|
160
|
+
process.exit(0);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
165
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (opts.host) server.listen(opts.port, opts.host);
|
|
169
|
+
else server.listen(opts.port);
|
|
61
170
|
return server;
|
|
62
171
|
}
|
package/src/server.ts
CHANGED
|
@@ -72,16 +72,18 @@ function html(
|
|
|
72
72
|
branding?: ConnectaBranding,
|
|
73
73
|
): Response {
|
|
74
74
|
const brand = resolveBranding(branding);
|
|
75
|
-
const title = brand.
|
|
76
|
-
? `${brand.productName} — ${brand.ownerName}`
|
|
77
|
-
: brand.productName;
|
|
75
|
+
const title = brand.pageTitle;
|
|
78
76
|
const owner = brand.ownerName
|
|
79
77
|
? brand.ownerUrl
|
|
80
78
|
? `<a class="brand" href="${escapeHtml(brand.ownerUrl)}">${escapeHtml(brand.ownerName)}</a>`
|
|
81
79
|
: `<span class="brand">${escapeHtml(brand.ownerName)}</span>`
|
|
82
|
-
:
|
|
80
|
+
: brand.productUrl
|
|
81
|
+
? `<a class="brand" href="${escapeHtml(brand.productUrl)}">${escapeHtml(brand.productName)}</a>`
|
|
82
|
+
: `<span class="brand">${escapeHtml(brand.productName)}</span>`;
|
|
83
83
|
const product = brand.ownerName
|
|
84
|
-
?
|
|
84
|
+
? brand.productUrl
|
|
85
|
+
? `<a class="product" href="${escapeHtml(brand.productUrl)}">${escapeHtml(brand.productName)}</a>`
|
|
86
|
+
: `<span class="product">${escapeHtml(brand.productName)}</span>`
|
|
85
87
|
: "";
|
|
86
88
|
return new Response(
|
|
87
89
|
`<!doctype html>
|
|
@@ -89,8 +91,8 @@ function html(
|
|
|
89
91
|
<head>
|
|
90
92
|
<meta charset="utf-8">
|
|
91
93
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
92
|
-
<meta name="theme-color" content="
|
|
93
|
-
<link rel="icon" href="
|
|
94
|
+
<meta name="theme-color" content="${escapeHtml(brand.themeColor)}">
|
|
95
|
+
<link rel="icon" href="${escapeHtml(brand.faviconHref)}" type="image/svg+xml">
|
|
94
96
|
<link rel="shortcut icon" href="/favicon.ico">
|
|
95
97
|
<title>${escapeHtml(title)}</title>
|
|
96
98
|
<style>
|
|
@@ -587,8 +589,15 @@ export function createFetchHandler(
|
|
|
587
589
|
const url = new URL(request.url);
|
|
588
590
|
const baseUrl = publicUrl ?? url.origin;
|
|
589
591
|
const path = url.pathname;
|
|
592
|
+
// Container and orchestrator probes reach /health over plain HTTP on
|
|
593
|
+
// loopback, where no proxy has set X-Forwarded-Proto. Redirecting them to
|
|
594
|
+
// the public origin would make an internal liveness check depend on
|
|
595
|
+
// external DNS, TLS, and the tunnel in front of connecta — so /health is
|
|
596
|
+
// exempt. It is unauthenticated, returns no user data, and sets no
|
|
597
|
+
// cookies, so forcing HTTPS on it protects nothing.
|
|
590
598
|
if (
|
|
591
599
|
publicUrl &&
|
|
600
|
+
path !== "/health" &&
|
|
592
601
|
new URL(publicUrl).protocol === "https:" &&
|
|
593
602
|
url.protocol === "http:"
|
|
594
603
|
) {
|
|
@@ -655,7 +664,7 @@ export function createFetchHandler(
|
|
|
655
664
|
}
|
|
656
665
|
|
|
657
666
|
if (request.method === "GET" && path === "/favicon.svg") {
|
|
658
|
-
return new Response(CONNECTA_FAVICON_SVG, {
|
|
667
|
+
return new Response(opts.branding?.favicon?.svg ?? CONNECTA_FAVICON_SVG, {
|
|
659
668
|
headers: {
|
|
660
669
|
"Content-Type": "image/svg+xml",
|
|
661
670
|
"Cache-Control": "public, max-age=86400",
|
|
@@ -664,7 +673,7 @@ export function createFetchHandler(
|
|
|
664
673
|
}
|
|
665
674
|
|
|
666
675
|
if (request.method === "GET" && path === "/favicon.ico") {
|
|
667
|
-
return new Response(CONNECTA_FAVICON_ICO, {
|
|
676
|
+
return new Response(opts.branding?.favicon?.ico ?? CONNECTA_FAVICON_ICO, {
|
|
668
677
|
headers: {
|
|
669
678
|
"Content-Type": "image/x-icon",
|
|
670
679
|
"Cache-Control": "public, max-age=86400",
|
|
@@ -747,6 +756,27 @@ export function createFetchHandler(
|
|
|
747
756
|
return withMcpCors(response);
|
|
748
757
|
}
|
|
749
758
|
|
|
759
|
+
// Connector-owned public routes, dispatched last: a connector can add a
|
|
760
|
+
// route but never shadow one of connecta's own. A throw here is the
|
|
761
|
+
// connector's bug, not a missing route, so it surfaces as 500 rather
|
|
762
|
+
// than falling through to 404.
|
|
763
|
+
for (const connector of registry.listConnectors()) {
|
|
764
|
+
if (!connector.handleRequest) continue;
|
|
765
|
+
try {
|
|
766
|
+
const connectorResponse = await connector.handleRequest(
|
|
767
|
+
request,
|
|
768
|
+
registry.contextFor(connector.id, baseUrl),
|
|
769
|
+
);
|
|
770
|
+
if (connectorResponse) return connectorResponse;
|
|
771
|
+
} catch (error) {
|
|
772
|
+
opts.logger.error(
|
|
773
|
+
`[connecta] connector "${connector.id}" handleRequest failed`,
|
|
774
|
+
error,
|
|
775
|
+
);
|
|
776
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
750
780
|
return new Response("Not Found", { status: 404 });
|
|
751
781
|
};
|
|
752
782
|
return withSecurityHeaders(await route(), url, path);
|
package/src/storage/file.ts
CHANGED
|
@@ -23,7 +23,29 @@ export function fileStorage(path: string): KVStorage {
|
|
|
23
23
|
if (existsSync(path)) {
|
|
24
24
|
try {
|
|
25
25
|
data = JSON.parse(readFileSync(path, "utf8")) as Record<string, Entry>;
|
|
26
|
-
} catch {
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Never let a damaged state file be silently replaced by an empty one:
|
|
28
|
+
// the next set() would persist {} over irreplaceable downstream OAuth
|
|
29
|
+
// tokens and credential-vault entries. Quarantine the bytes so they
|
|
30
|
+
// survive for manual recovery, and refuse to start if even that fails —
|
|
31
|
+
// losing the file loudly beats losing it quietly.
|
|
32
|
+
const quarantine = `${path}.corrupt-${Date.now()}`;
|
|
33
|
+
try {
|
|
34
|
+
renameSync(path, quarantine);
|
|
35
|
+
} catch (renameError) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`[connecta] state file ${path} is not valid JSON and could not be ` +
|
|
38
|
+
`moved aside (${String(renameError)}). Refusing to start rather ` +
|
|
39
|
+
`than overwrite it. Move or repair the file, then restart.`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
console.error(
|
|
43
|
+
`[connecta] state file ${path} is not valid JSON ` +
|
|
44
|
+
`(${error instanceof Error ? error.message : String(error)}) — ` +
|
|
45
|
+
`moved to ${quarantine}, starting from empty state. Downstream ` +
|
|
46
|
+
`OAuth connectors must be re-authorized and stored credentials ` +
|
|
47
|
+
`re-entered.`,
|
|
48
|
+
);
|
|
27
49
|
data = {};
|
|
28
50
|
}
|
|
29
51
|
}
|
package/src/types.ts
CHANGED
|
@@ -181,6 +181,21 @@ export interface Connector {
|
|
|
181
181
|
verifyState?(state: string | null, ctx: ConnectorContext): Promise<boolean>;
|
|
182
182
|
/** Optional: complete a downstream OAuth flow (called by /oauth/callback/<id>). */
|
|
183
183
|
finishAuth?(code: string, ctx: ConnectorContext): Promise<void>;
|
|
184
|
+
/**
|
|
185
|
+
* Optional: serve a connector-owned HTTP route — for example a signed
|
|
186
|
+
* download link minted by one of the connector's tools. Called only after
|
|
187
|
+
* every built-in route misses, so a connector can never shadow `/mcp`,
|
|
188
|
+
* `/ui`, `/health`, or the credential API. The first connector to return a
|
|
189
|
+
* Response wins, in registration order; return null to decline.
|
|
190
|
+
*
|
|
191
|
+
* These routes are PUBLIC: connecta applies no auth gate to them. A
|
|
192
|
+
* connector that serves data here MUST authenticate the request itself — for
|
|
193
|
+
* example with a signed capability token in the URL.
|
|
194
|
+
*/
|
|
195
|
+
handleRequest?(
|
|
196
|
+
request: Request,
|
|
197
|
+
ctx: ConnectorContext,
|
|
198
|
+
): Promise<Response | null>;
|
|
184
199
|
}
|
|
185
200
|
|
|
186
201
|
/** Result of one sandboxed code execution. */
|
|
@@ -221,16 +236,41 @@ export type UiAuthConfig = {
|
|
|
221
236
|
signUpUrl?: string;
|
|
222
237
|
};
|
|
223
238
|
|
|
224
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Optional labels and marks used by the browser UI and OAuth result pages.
|
|
241
|
+
* Every deployment-identifying string and image is configurable here — nothing
|
|
242
|
+
* about the operator is baked into the package.
|
|
243
|
+
*/
|
|
225
244
|
export interface ConnectaBranding {
|
|
226
245
|
/** Product label. Defaults to "Connecta". */
|
|
227
246
|
productName?: string;
|
|
247
|
+
/** Optional link for the product label. */
|
|
248
|
+
productUrl?: string;
|
|
228
249
|
/** Organization or owner shown beside the product label. */
|
|
229
250
|
ownerName?: string;
|
|
230
251
|
/** Optional link for the organization or owner label. */
|
|
231
252
|
ownerUrl?: string;
|
|
232
253
|
/** Status-dashboard introduction. */
|
|
233
254
|
description?: string;
|
|
255
|
+
/**
|
|
256
|
+
* Browser tab title and page meta name. Defaults to
|
|
257
|
+
* `"<productName> — <ownerName>"`, or just `productName` when no owner is set.
|
|
258
|
+
*/
|
|
259
|
+
pageTitle?: string;
|
|
260
|
+
/**
|
|
261
|
+
* Replace the default monochrome "C" mark. `svg` is served at
|
|
262
|
+
* `/favicon.svg`, `ico` at `/favicon.ico`; omit either to keep the default
|
|
263
|
+
* for that format. Use `href` instead to point the page at an icon you host
|
|
264
|
+
* elsewhere (it replaces the `/favicon.svg` link in the page head; the
|
|
265
|
+
* `/favicon.*` routes still serve whatever `svg`/`ico` provide).
|
|
266
|
+
*/
|
|
267
|
+
favicon?: {
|
|
268
|
+
svg?: string;
|
|
269
|
+
ico?: Uint8Array;
|
|
270
|
+
href?: string;
|
|
271
|
+
};
|
|
272
|
+
/** `theme-color` meta value. Defaults to "#ffffff". */
|
|
273
|
+
themeColor?: string;
|
|
234
274
|
}
|
|
235
275
|
|
|
236
276
|
/** An inbound authentication provider (bearer token, Clerk, ...). */
|