@padua/cli 1.13.0 → 2.0.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/README.md +164 -11
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +85 -0
- package/dist/commands/doctor/index.js.map +1 -1
- package/dist/commands/doctor/mcp-checks.d.ts +36 -0
- package/dist/commands/doctor/mcp-checks.d.ts.map +1 -0
- package/dist/commands/doctor/mcp-checks.js +235 -0
- package/dist/commands/doctor/mcp-checks.js.map +1 -0
- package/dist/commands/doctor/mcp-service-checks.d.ts +35 -0
- package/dist/commands/doctor/mcp-service-checks.d.ts.map +1 -0
- package/dist/commands/doctor/mcp-service-checks.js +146 -0
- package/dist/commands/doctor/mcp-service-checks.js.map +1 -0
- package/dist/commands/doctor/types.d.ts +4 -1
- package/dist/commands/doctor/types.d.ts.map +1 -1
- package/dist/commands/doctor/types.js +1 -0
- package/dist/commands/doctor/types.js.map +1 -1
- package/dist/commands/init/sso-discovery.d.ts.map +1 -1
- package/dist/commands/init/sso-discovery.js +1 -0
- package/dist/commands/init/sso-discovery.js.map +1 -1
- package/dist/commands/login/index.d.ts +1 -1
- package/dist/commands/login/index.d.ts.map +1 -1
- package/dist/commands/login/index.js +44 -185
- package/dist/commands/login/index.js.map +1 -1
- package/dist/commands/login/mcp-steps.d.ts +38 -0
- package/dist/commands/login/mcp-steps.d.ts.map +1 -0
- package/dist/commands/login/mcp-steps.js +176 -0
- package/dist/commands/login/mcp-steps.js.map +1 -0
- package/dist/commands/login/npmrc.d.ts +10 -0
- package/dist/commands/login/npmrc.d.ts.map +1 -1
- package/dist/commands/login/npmrc.js +36 -3
- package/dist/commands/login/npmrc.js.map +1 -1
- package/dist/commands/login/orchestrator.d.ts +9 -0
- package/dist/commands/login/orchestrator.d.ts.map +1 -0
- package/dist/commands/login/orchestrator.js +251 -0
- package/dist/commands/login/orchestrator.js.map +1 -0
- package/dist/commands/login/types.d.ts +11 -0
- package/dist/commands/login/types.d.ts.map +1 -1
- package/dist/commands/login/types.js.map +1 -1
- package/dist/commands/status/aws-checks.d.ts +14 -0
- package/dist/commands/status/aws-checks.d.ts.map +1 -0
- package/dist/commands/status/aws-checks.js +145 -0
- package/dist/commands/status/aws-checks.js.map +1 -0
- package/dist/commands/status/checks.d.ts +9 -25
- package/dist/commands/status/checks.d.ts.map +1 -1
- package/dist/commands/status/checks.js +52 -254
- package/dist/commands/status/checks.js.map +1 -1
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +53 -1
- package/dist/commands/status/index.js.map +1 -1
- package/dist/commands/status/mcp-checks.d.ts +35 -0
- package/dist/commands/status/mcp-checks.d.ts.map +1 -0
- package/dist/commands/status/mcp-checks.js +175 -0
- package/dist/commands/status/mcp-checks.js.map +1 -0
- package/dist/commands/status/types.d.ts +34 -0
- package/dist/commands/status/types.d.ts.map +1 -1
- package/dist/mcp/config/index.d.ts +4 -0
- package/dist/mcp/config/index.d.ts.map +1 -0
- package/dist/mcp/config/index.js +14 -0
- package/dist/mcp/config/index.js.map +1 -0
- package/dist/mcp/config/loaders.d.ts +45 -0
- package/dist/mcp/config/loaders.d.ts.map +1 -0
- package/dist/mcp/config/loaders.js +149 -0
- package/dist/mcp/config/loaders.js.map +1 -0
- package/dist/mcp/config/types.d.ts +234 -0
- package/dist/mcp/config/types.d.ts.map +1 -0
- package/dist/mcp/config/types.js +45 -0
- package/dist/mcp/config/types.js.map +1 -0
- package/dist/mcp/daemon/entry-logic.d.ts +28 -0
- package/dist/mcp/daemon/entry-logic.d.ts.map +1 -0
- package/dist/mcp/daemon/entry-logic.js +82 -0
- package/dist/mcp/daemon/entry-logic.js.map +1 -0
- package/dist/mcp/daemon/entry.d.ts +8 -0
- package/dist/mcp/daemon/entry.d.ts.map +1 -0
- package/dist/mcp/daemon/entry.js +34 -0
- package/dist/mcp/daemon/entry.js.map +1 -0
- package/dist/mcp/daemon/fork.d.ts +21 -0
- package/dist/mcp/daemon/fork.d.ts.map +1 -0
- package/dist/mcp/daemon/fork.js +188 -0
- package/dist/mcp/daemon/fork.js.map +1 -0
- package/dist/mcp/daemon/health.d.ts +8 -0
- package/dist/mcp/daemon/health.d.ts.map +1 -0
- package/dist/mcp/daemon/health.js +50 -0
- package/dist/mcp/daemon/health.js.map +1 -0
- package/dist/mcp/daemon/index.d.ts +6 -0
- package/dist/mcp/daemon/index.d.ts.map +1 -0
- package/dist/mcp/daemon/index.js +22 -0
- package/dist/mcp/daemon/index.js.map +1 -0
- package/dist/mcp/daemon/types.d.ts +63 -0
- package/dist/mcp/daemon/types.d.ts.map +1 -0
- package/dist/mcp/daemon/types.js +18 -0
- package/dist/mcp/daemon/types.js.map +1 -0
- package/dist/mcp/errors/index.d.ts +3 -0
- package/dist/mcp/errors/index.d.ts.map +1 -0
- package/dist/mcp/errors/index.js +13 -0
- package/dist/mcp/errors/index.js.map +1 -0
- package/dist/mcp/errors/types.d.ts +83 -0
- package/dist/mcp/errors/types.d.ts.map +1 -0
- package/dist/mcp/errors/types.js +148 -0
- package/dist/mcp/errors/types.js.map +1 -0
- package/dist/mcp/providers/atlassian/auth.d.ts +34 -0
- package/dist/mcp/providers/atlassian/auth.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/auth.js +107 -0
- package/dist/mcp/providers/atlassian/auth.js.map +1 -0
- package/dist/mcp/providers/atlassian/client.d.ts +15 -0
- package/dist/mcp/providers/atlassian/client.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/client.js +38 -0
- package/dist/mcp/providers/atlassian/client.js.map +1 -0
- package/dist/mcp/providers/atlassian/index.d.ts +6 -0
- package/dist/mcp/providers/atlassian/index.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/index.js +11 -0
- package/dist/mcp/providers/atlassian/index.js.map +1 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/index.d.ts +17 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/index.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/index.js +29 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/index.js.map +1 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/nodes.d.ts +43 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/nodes.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/nodes.js +101 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/nodes.js.map +1 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/parser.d.ts +14 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/parser.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/parser.js +250 -0
- package/dist/mcp/providers/atlassian/markdown-to-adf/parser.js.map +1 -0
- package/dist/mcp/providers/atlassian/provider.d.ts +38 -0
- package/dist/mcp/providers/atlassian/provider.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/provider.js +101 -0
- package/dist/mcp/providers/atlassian/provider.js.map +1 -0
- package/dist/mcp/providers/atlassian/resources.d.ts +4 -0
- package/dist/mcp/providers/atlassian/resources.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/resources.js +67 -0
- package/dist/mcp/providers/atlassian/resources.js.map +1 -0
- package/dist/mcp/providers/atlassian/tools/confluence.d.ts +4 -0
- package/dist/mcp/providers/atlassian/tools/confluence.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/tools/confluence.js +169 -0
- package/dist/mcp/providers/atlassian/tools/confluence.js.map +1 -0
- package/dist/mcp/providers/atlassian/tools/jira.d.ts +4 -0
- package/dist/mcp/providers/atlassian/tools/jira.d.ts.map +1 -0
- package/dist/mcp/providers/atlassian/tools/jira.js +274 -0
- package/dist/mcp/providers/atlassian/tools/jira.js.map +1 -0
- package/dist/mcp/providers/gitlab/auth.d.ts +10 -0
- package/dist/mcp/providers/gitlab/auth.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/auth.js +23 -0
- package/dist/mcp/providers/gitlab/auth.js.map +1 -0
- package/dist/mcp/providers/gitlab/client.d.ts +23 -0
- package/dist/mcp/providers/gitlab/client.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/client.js +17 -0
- package/dist/mcp/providers/gitlab/client.js.map +1 -0
- package/dist/mcp/providers/gitlab/index.d.ts +5 -0
- package/dist/mcp/providers/gitlab/index.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/index.js +10 -0
- package/dist/mcp/providers/gitlab/index.js.map +1 -0
- package/dist/mcp/providers/gitlab/provider.d.ts +25 -0
- package/dist/mcp/providers/gitlab/provider.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/provider.js +48 -0
- package/dist/mcp/providers/gitlab/provider.js.map +1 -0
- package/dist/mcp/providers/gitlab/resources.d.ts +11 -0
- package/dist/mcp/providers/gitlab/resources.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/resources.js +54 -0
- package/dist/mcp/providers/gitlab/resources.js.map +1 -0
- package/dist/mcp/providers/gitlab/tools/issues.d.ts +4 -0
- package/dist/mcp/providers/gitlab/tools/issues.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/tools/issues.js +120 -0
- package/dist/mcp/providers/gitlab/tools/issues.js.map +1 -0
- package/dist/mcp/providers/gitlab/tools/merge-requests.d.ts +11 -0
- package/dist/mcp/providers/gitlab/tools/merge-requests.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/tools/merge-requests.js +282 -0
- package/dist/mcp/providers/gitlab/tools/merge-requests.js.map +1 -0
- package/dist/mcp/providers/gitlab/tools/pipelines.d.ts +10 -0
- package/dist/mcp/providers/gitlab/tools/pipelines.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/tools/pipelines.js +173 -0
- package/dist/mcp/providers/gitlab/tools/pipelines.js.map +1 -0
- package/dist/mcp/providers/gitlab/tools/repository.d.ts +4 -0
- package/dist/mcp/providers/gitlab/tools/repository.d.ts.map +1 -0
- package/dist/mcp/providers/gitlab/tools/repository.js +191 -0
- package/dist/mcp/providers/gitlab/tools/repository.js.map +1 -0
- package/dist/mcp/providers/index.d.ts +4 -0
- package/dist/mcp/providers/index.d.ts.map +1 -0
- package/dist/mcp/providers/index.js +6 -0
- package/dist/mcp/providers/index.js.map +1 -0
- package/dist/mcp/providers/registry.d.ts +90 -0
- package/dist/mcp/providers/registry.d.ts.map +1 -0
- package/dist/mcp/providers/registry.js +128 -0
- package/dist/mcp/providers/registry.js.map +1 -0
- package/dist/mcp/providers/tool-helpers.d.ts +14 -0
- package/dist/mcp/providers/tool-helpers.d.ts.map +1 -0
- package/dist/mcp/providers/tool-helpers.js +12 -0
- package/dist/mcp/providers/tool-helpers.js.map +1 -0
- package/dist/mcp/providers/types.d.ts +80 -0
- package/dist/mcp/providers/types.d.ts.map +1 -0
- package/dist/mcp/providers/types.js +13 -0
- package/dist/mcp/providers/types.js.map +1 -0
- package/dist/mcp/server/auth.d.ts +8 -0
- package/dist/mcp/server/auth.d.ts.map +1 -0
- package/dist/mcp/server/auth.js +36 -0
- package/dist/mcp/server/auth.js.map +1 -0
- package/dist/mcp/server/health.d.ts +24 -0
- package/dist/mcp/server/health.d.ts.map +1 -0
- package/dist/mcp/server/health.js +37 -0
- package/dist/mcp/server/health.js.map +1 -0
- package/dist/mcp/server/index.d.ts +11 -0
- package/dist/mcp/server/index.d.ts.map +1 -0
- package/dist/mcp/server/index.js +27 -0
- package/dist/mcp/server/index.js.map +1 -0
- package/dist/mcp/server/logging.d.ts +46 -0
- package/dist/mcp/server/logging.d.ts.map +1 -0
- package/dist/mcp/server/logging.js +109 -0
- package/dist/mcp/server/logging.js.map +1 -0
- package/dist/mcp/server/ratelimit.d.ts +3 -0
- package/dist/mcp/server/ratelimit.d.ts.map +1 -0
- package/dist/mcp/server/ratelimit.js +70 -0
- package/dist/mcp/server/ratelimit.js.map +1 -0
- package/dist/mcp/server/routes.d.ts +3 -0
- package/dist/mcp/server/routes.d.ts.map +1 -0
- package/dist/mcp/server/routes.js +8 -0
- package/dist/mcp/server/routes.js.map +1 -0
- package/dist/mcp/server/server.d.ts +21 -0
- package/dist/mcp/server/server.d.ts.map +1 -0
- package/dist/mcp/server/server.js +114 -0
- package/dist/mcp/server/server.js.map +1 -0
- package/dist/mcp/server/validation.d.ts +22 -0
- package/dist/mcp/server/validation.d.ts.map +1 -0
- package/dist/mcp/server/validation.js +32 -0
- package/dist/mcp/server/validation.js.map +1 -0
- package/dist/mcp/store/encrypt.d.ts +22 -0
- package/dist/mcp/store/encrypt.d.ts.map +1 -0
- package/dist/mcp/store/encrypt.js +66 -0
- package/dist/mcp/store/encrypt.js.map +1 -0
- package/dist/mcp/store/index.d.ts +12 -0
- package/dist/mcp/store/index.d.ts.map +1 -0
- package/dist/mcp/store/index.js +16 -0
- package/dist/mcp/store/index.js.map +1 -0
- package/dist/mcp/store/migrate.d.ts +70 -0
- package/dist/mcp/store/migrate.d.ts.map +1 -0
- package/dist/mcp/store/migrate.js +211 -0
- package/dist/mcp/store/migrate.js.map +1 -0
- package/dist/mcp/store/null-token-store.d.ts +22 -0
- package/dist/mcp/store/null-token-store.d.ts.map +1 -0
- package/dist/mcp/store/null-token-store.js +40 -0
- package/dist/mcp/store/null-token-store.js.map +1 -0
- package/dist/mcp/store/sqlite.d.ts +27 -0
- package/dist/mcp/store/sqlite.d.ts.map +1 -0
- package/dist/mcp/store/sqlite.js +100 -0
- package/dist/mcp/store/sqlite.js.map +1 -0
- package/dist/mcp/store/types.d.ts +183 -0
- package/dist/mcp/store/types.d.ts.map +1 -0
- package/dist/mcp/store/types.js +13 -0
- package/dist/mcp/store/types.js.map +1 -0
- package/dist/mcp/token/http-client.d.ts +3 -0
- package/dist/mcp/token/http-client.d.ts.map +1 -0
- package/dist/mcp/token/http-client.js +186 -0
- package/dist/mcp/token/http-client.js.map +1 -0
- package/dist/mcp/token/index.d.ts +5 -0
- package/dist/mcp/token/index.d.ts.map +1 -0
- package/dist/mcp/token/index.js +15 -0
- package/dist/mcp/token/index.js.map +1 -0
- package/dist/mcp/token/manager.d.ts +54 -0
- package/dist/mcp/token/manager.d.ts.map +1 -0
- package/dist/mcp/token/manager.js +194 -0
- package/dist/mcp/token/manager.js.map +1 -0
- package/dist/mcp/token/null-token-manager.d.ts +19 -0
- package/dist/mcp/token/null-token-manager.d.ts.map +1 -0
- package/dist/mcp/token/null-token-manager.js +50 -0
- package/dist/mcp/token/null-token-manager.js.map +1 -0
- package/dist/mcp/token/oauth.d.ts +44 -0
- package/dist/mcp/token/oauth.d.ts.map +1 -0
- package/dist/mcp/token/oauth.js +257 -0
- package/dist/mcp/token/oauth.js.map +1 -0
- package/dist/mcp/token/types.d.ts +81 -0
- package/dist/mcp/token/types.d.ts.map +1 -0
- package/dist/mcp/token/types.js +6 -0
- package/dist/mcp/token/types.js.map +1 -0
- package/package.json +10 -3
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMcpServer = createMcpServer;
|
|
4
|
+
const node_http_1 = require("node:http");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
7
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
8
|
+
const auth_1 = require("./auth");
|
|
9
|
+
const ratelimit_1 = require("./ratelimit");
|
|
10
|
+
const health_1 = require("./health");
|
|
11
|
+
const routes_1 = require("./routes");
|
|
12
|
+
const logging_1 = require("./logging");
|
|
13
|
+
function runMiddleware(req, res, middlewares, final) {
|
|
14
|
+
let index = 0;
|
|
15
|
+
function next() {
|
|
16
|
+
if (index >= middlewares.length) {
|
|
17
|
+
final();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const mw = middlewares[index++];
|
|
21
|
+
mw(req, res, next);
|
|
22
|
+
}
|
|
23
|
+
next();
|
|
24
|
+
}
|
|
25
|
+
function isPayloadTooLarge(req, maxBodySize) {
|
|
26
|
+
if (req.method !== 'POST')
|
|
27
|
+
return false;
|
|
28
|
+
const contentLength = parseInt(req.headers['content-length'] ?? '0', 10);
|
|
29
|
+
return contentLength > maxBodySize;
|
|
30
|
+
}
|
|
31
|
+
function sendPayloadTooLarge(res) {
|
|
32
|
+
res.writeHead(413, { 'Content-Type': 'application/json' });
|
|
33
|
+
res.end(JSON.stringify({
|
|
34
|
+
error: { code: 'PAYLOAD_TOO_LARGE', message: 'Request body exceeds 4MB limit' },
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
function sendNotFound(res, url) {
|
|
38
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
39
|
+
res.end(JSON.stringify({ error: { code: 'NOT_FOUND', message: `Route not found: ${url}` } }));
|
|
40
|
+
}
|
|
41
|
+
function isMcpRoute(url) {
|
|
42
|
+
return url === '/mcp' || url.startsWith('/mcp?');
|
|
43
|
+
}
|
|
44
|
+
async function handleMcpRequest(req, res, transport, logger, correlationId) {
|
|
45
|
+
try {
|
|
46
|
+
await transport.handleRequest(req, res);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
logger.error('MCP handler error', { error: String(err), correlationId });
|
|
50
|
+
if (!res.headersSent) {
|
|
51
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
52
|
+
res.end(JSON.stringify({ error: { code: 'INTERNAL_ERROR', message: 'Internal server error' } }));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function buildRequestHandler(authMiddleware, rateLimiter, transport, healthHandler, logger, maxBodySize) {
|
|
57
|
+
return async (req, res) => {
|
|
58
|
+
const correlationId = (0, node_crypto_1.randomUUID)();
|
|
59
|
+
res.setHeader('X-Correlation-Id', correlationId);
|
|
60
|
+
const url = req.url ?? '';
|
|
61
|
+
if ((0, routes_1.isHealthRoute)(url)) {
|
|
62
|
+
healthHandler(req, res);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (isPayloadTooLarge(req, maxBodySize)) {
|
|
66
|
+
sendPayloadTooLarge(res);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
runMiddleware(req, res, [authMiddleware, rateLimiter], async () => {
|
|
70
|
+
if (isMcpRoute(url)) {
|
|
71
|
+
await handleMcpRequest(req, res, transport, logger, correlationId);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
sendNotFound(res, url);
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function createMcpServer(config, getProviderStatuses) {
|
|
79
|
+
const logger = (0, logging_1.createLogger)(config.logDir);
|
|
80
|
+
const maxBodySize = config.maxBodySize ?? 4 * 1024 * 1024;
|
|
81
|
+
const startTime = Date.now();
|
|
82
|
+
const mcpServer = new mcp_js_1.McpServer({
|
|
83
|
+
name: 'padua-mcp',
|
|
84
|
+
version: config.version,
|
|
85
|
+
});
|
|
86
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
87
|
+
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
|
|
88
|
+
});
|
|
89
|
+
const authMiddleware = (0, auth_1.createAuthMiddleware)(config.bearerToken);
|
|
90
|
+
const rateLimiter = (0, ratelimit_1.createRateLimiter)(config.rateLimit?.ratePerSec ?? 10, config.rateLimit?.burst ?? 20);
|
|
91
|
+
const healthDeps = {
|
|
92
|
+
version: config.version,
|
|
93
|
+
startTime,
|
|
94
|
+
getProviderStatuses: () => getProviderStatuses(),
|
|
95
|
+
};
|
|
96
|
+
const healthHandler = (0, health_1.createHealthHandler)(healthDeps);
|
|
97
|
+
const requestHandler = buildRequestHandler(authMiddleware, rateLimiter, transport, healthHandler, logger, maxBodySize);
|
|
98
|
+
const httpServer = (0, node_http_1.createServer)(requestHandler);
|
|
99
|
+
function start() {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
mcpServer.connect(transport).then(() => {
|
|
102
|
+
httpServer.listen(config.port, '127.0.0.1', () => resolve());
|
|
103
|
+
httpServer.once('error', reject);
|
|
104
|
+
}).catch(reject);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function stop() {
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
httpServer.close((err) => (err ? reject(err) : resolve()));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return { httpServer, mcpServer, start, stop };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Jira issue key: 2-10 char uppercase project key + dash + digits */
|
|
3
|
+
export declare const JiraIssueKeySchema: z.ZodString;
|
|
4
|
+
/** GitLab project ID: positive integer */
|
|
5
|
+
export declare const GitLabProjectIdSchema: z.ZodNumber;
|
|
6
|
+
/** Search query: 1-256 characters */
|
|
7
|
+
export declare const SearchQuerySchema: z.ZodString;
|
|
8
|
+
/** File path: no path traversal, no absolute paths, no null bytes */
|
|
9
|
+
export declare const FilePathSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, string, string>;
|
|
10
|
+
/** Commit message: 1-10000 characters */
|
|
11
|
+
export declare const CommitMessageSchema: z.ZodString;
|
|
12
|
+
/** Pagination page number */
|
|
13
|
+
export declare const PageSchema: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
/** Pagination per-page count */
|
|
15
|
+
export declare const PerPageSchema: z.ZodDefault<z.ZodNumber>;
|
|
16
|
+
/** CQL query for Confluence search */
|
|
17
|
+
export declare const CqlQuerySchema: z.ZodString;
|
|
18
|
+
/** Confluence space key */
|
|
19
|
+
export declare const SpaceKeySchema: z.ZodString;
|
|
20
|
+
/** Branch name */
|
|
21
|
+
export declare const BranchNameSchema: z.ZodString;
|
|
22
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/mcp/server/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,aAG9B,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,qBAAqB,aAA8B,CAAC;AAEjE,qCAAqC;AACrC,eAAO,MAAM,iBAAiB,aAA6B,CAAC;AAE5D,qEAAqE;AACrE,eAAO,MAAM,cAAc,uGAGsC,CAAC;AAElE,yCAAyC;AACzC,eAAO,MAAM,mBAAmB,aAA+B,CAAC;AAEhE,6BAA6B;AAC7B,eAAO,MAAM,UAAU,2BAAqC,CAAC;AAE7D,gCAAgC;AAChC,eAAO,MAAM,aAAa,2BAA+C,CAAC;AAE1E,sCAAsC;AACtC,eAAO,MAAM,cAAc,aAA8B,CAAC;AAE1D,2BAA2B;AAC3B,eAAO,MAAM,cAAc,aAA6C,CAAC;AAEzE,kBAAkB;AAClB,eAAO,MAAM,gBAAgB,aAGlB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BranchNameSchema = exports.SpaceKeySchema = exports.CqlQuerySchema = exports.PerPageSchema = exports.PageSchema = exports.CommitMessageSchema = exports.FilePathSchema = exports.SearchQuerySchema = exports.GitLabProjectIdSchema = exports.JiraIssueKeySchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
/** Jira issue key: 2-10 char uppercase project key + dash + digits */
|
|
7
|
+
exports.JiraIssueKeySchema = zod_1.z.string().regex(/^[A-Z][A-Z0-9]{1,9}-\d+$/, 'Invalid JIRA issue key format (e.g., PROJ-123)');
|
|
8
|
+
/** GitLab project ID: positive integer */
|
|
9
|
+
exports.GitLabProjectIdSchema = zod_1.z.number().int().positive();
|
|
10
|
+
/** Search query: 1-256 characters */
|
|
11
|
+
exports.SearchQuerySchema = zod_1.z.string().min(1).max(256);
|
|
12
|
+
/** File path: no path traversal, no absolute paths, no null bytes */
|
|
13
|
+
exports.FilePathSchema = zod_1.z.string().min(1).max(4096)
|
|
14
|
+
.refine((val) => !(0, node_path_1.isAbsolute)(val), 'Absolute paths not allowed')
|
|
15
|
+
.refine((val) => !val.includes('..'), 'Path traversal not allowed')
|
|
16
|
+
.refine((val) => !val.includes('\0'), 'Null bytes not allowed');
|
|
17
|
+
/** Commit message: 1-10000 characters */
|
|
18
|
+
exports.CommitMessageSchema = zod_1.z.string().min(1).max(10000);
|
|
19
|
+
/** Pagination page number */
|
|
20
|
+
exports.PageSchema = zod_1.z.number().int().min(1).default(1);
|
|
21
|
+
/** Pagination per-page count */
|
|
22
|
+
exports.PerPageSchema = zod_1.z.number().int().min(1).max(100).default(20);
|
|
23
|
+
/** CQL query for Confluence search */
|
|
24
|
+
exports.CqlQuerySchema = zod_1.z.string().min(1).max(1000);
|
|
25
|
+
/** Confluence space key */
|
|
26
|
+
exports.SpaceKeySchema = zod_1.z.string().regex(/^[A-Z][A-Z0-9]{0,254}$/);
|
|
27
|
+
/** Branch name */
|
|
28
|
+
exports.BranchNameSchema = zod_1.z
|
|
29
|
+
.string()
|
|
30
|
+
.regex(/^[a-zA-Z0-9/_.\\-]+$/, 'Invalid branch name')
|
|
31
|
+
.max(255);
|
|
32
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/mcp/server/validation.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,yCAAuC;AAEvC,sEAAsE;AACzD,QAAA,kBAAkB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAChD,0BAA0B,EAC1B,gDAAgD,CACjD,CAAC;AAEF,0CAA0C;AAC7B,QAAA,qBAAqB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;AAEjE,qCAAqC;AACxB,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE5D,qEAAqE;AACxD,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;KACtD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAA,sBAAU,EAAC,GAAG,CAAC,EAAE,4BAA4B,CAAC;KAC/D,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,4BAA4B,CAAC;KAClE,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,wBAAwB,CAAC,CAAC;AAElE,yCAAyC;AAC5B,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAEhE,6BAA6B;AAChB,QAAA,UAAU,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7D,gCAAgC;AACnB,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAE1E,sCAAsC;AACzB,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAE1D,2BAA2B;AACd,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAEzE,kBAAkB;AACL,QAAA,gBAAgB,GAAG,OAAC;KAC9B,MAAM,EAAE;KACR,KAAK,CAAC,sBAAsB,EAAE,qBAAqB,CAAC;KACpD,GAAG,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AES-256-GCM encryption module for the MCP token store.
|
|
3
|
+
*
|
|
4
|
+
* Wire format (Go-compatible):
|
|
5
|
+
* [ nonce (12 bytes) ][ ciphertext (N bytes) ][ auth tag (16 bytes) ]
|
|
6
|
+
*
|
|
7
|
+
* This layout is byte-compatible with the Go implementation in
|
|
8
|
+
* padua-mcp/internal/store/encrypt.go.
|
|
9
|
+
*/
|
|
10
|
+
import type { Encryptor } from './types';
|
|
11
|
+
type NonceSource = (size: number) => Buffer;
|
|
12
|
+
/**
|
|
13
|
+
* Create an AES-256-GCM encryptor from a 64-character hex key (32 bytes).
|
|
14
|
+
*
|
|
15
|
+
* @param hexKey - 64 hex-character string representing the 32-byte AES key.
|
|
16
|
+
* @param _nonceSource - @internal — injectable nonce source for deterministic testing only.
|
|
17
|
+
* Must not be set in production code.
|
|
18
|
+
* @throws StoreError(ENCRYPTION_KEY_UNAVAILABLE) when the key is invalid.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createEncryptor(hexKey: string, _nonceSource?: NonceSource): Encryptor;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=encrypt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../../../src/mcp/store/encrypt.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAmBzC,KAAK,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAkC5C;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,WAAW,GAAG,SAAS,CAOrF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AES-256-GCM encryption module for the MCP token store.
|
|
4
|
+
*
|
|
5
|
+
* Wire format (Go-compatible):
|
|
6
|
+
* [ nonce (12 bytes) ][ ciphertext (N bytes) ][ auth tag (16 bytes) ]
|
|
7
|
+
*
|
|
8
|
+
* This layout is byte-compatible with the Go implementation in
|
|
9
|
+
* padua-mcp/internal/store/encrypt.go.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createEncryptor = createEncryptor;
|
|
13
|
+
const node_crypto_1 = require("node:crypto");
|
|
14
|
+
const errors_1 = require("../errors");
|
|
15
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
16
|
+
const NONCE_LEN = 12;
|
|
17
|
+
const TAG_LEN = 16;
|
|
18
|
+
const MIN_COMBINED_LEN = NONCE_LEN + TAG_LEN; // 28 bytes (nonce + empty ciphertext + tag)
|
|
19
|
+
const KEY_HEX_LEN = 64; // 32 bytes expressed as hex
|
|
20
|
+
const HEX_RE = /^[0-9a-fA-F]+$/;
|
|
21
|
+
function validateKey(hexKey) {
|
|
22
|
+
if (hexKey.length !== KEY_HEX_LEN || !HEX_RE.test(hexKey)) {
|
|
23
|
+
throw new errors_1.StoreError(`Encryption key must be exactly ${KEY_HEX_LEN} hex characters (32 bytes)`, errors_1.ErrorCodes.ENCRYPTION_KEY_UNAVAILABLE);
|
|
24
|
+
}
|
|
25
|
+
return Buffer.from(hexKey, 'hex');
|
|
26
|
+
}
|
|
27
|
+
function encrypt(key, plaintext, nonceSource) {
|
|
28
|
+
const nonce = nonceSource(NONCE_LEN);
|
|
29
|
+
const cipher = (0, node_crypto_1.createCipheriv)(ALGORITHM, key, nonce);
|
|
30
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
31
|
+
const tag = cipher.getAuthTag();
|
|
32
|
+
return Buffer.concat([nonce, ciphertext, tag]);
|
|
33
|
+
}
|
|
34
|
+
function decrypt(key, combined) {
|
|
35
|
+
if (combined.length < MIN_COMBINED_LEN) {
|
|
36
|
+
throw new errors_1.StoreError(`Combined buffer too short: expected at least ${MIN_COMBINED_LEN} bytes, got ${combined.length}`, errors_1.ErrorCodes.TOKEN_DECRYPTION_FAILED);
|
|
37
|
+
}
|
|
38
|
+
const nonce = combined.subarray(0, NONCE_LEN);
|
|
39
|
+
const tag = combined.subarray(combined.length - TAG_LEN);
|
|
40
|
+
const ciphertext = combined.subarray(NONCE_LEN, combined.length - TAG_LEN);
|
|
41
|
+
try {
|
|
42
|
+
const decipher = (0, node_crypto_1.createDecipheriv)(ALGORITHM, key, nonce);
|
|
43
|
+
decipher.setAuthTag(tag);
|
|
44
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new errors_1.StoreError('AES-256-GCM authentication tag verification failed', errors_1.ErrorCodes.TOKEN_DECRYPTION_FAILED);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create an AES-256-GCM encryptor from a 64-character hex key (32 bytes).
|
|
52
|
+
*
|
|
53
|
+
* @param hexKey - 64 hex-character string representing the 32-byte AES key.
|
|
54
|
+
* @param _nonceSource - @internal — injectable nonce source for deterministic testing only.
|
|
55
|
+
* Must not be set in production code.
|
|
56
|
+
* @throws StoreError(ENCRYPTION_KEY_UNAVAILABLE) when the key is invalid.
|
|
57
|
+
*/
|
|
58
|
+
function createEncryptor(hexKey, _nonceSource) {
|
|
59
|
+
const key = validateKey(hexKey);
|
|
60
|
+
const nonceSource = _nonceSource ?? node_crypto_1.randomBytes;
|
|
61
|
+
return {
|
|
62
|
+
encrypt: (plaintext) => encrypt(key, plaintext, nonceSource),
|
|
63
|
+
decrypt: (combined) => decrypt(key, combined),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=encrypt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypt.js","sourceRoot":"","sources":["../../../src/mcp/store/encrypt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for the store module.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all type definitions. Concrete implementations (SqliteTokenStore,
|
|
5
|
+
* createEncryptor, runMigrations) are exported from their own modules so
|
|
6
|
+
* callers that need only interfaces do not pull in better-sqlite3 or node:crypto
|
|
7
|
+
* at import time.
|
|
8
|
+
*/
|
|
9
|
+
export type { StoredToken, TokenStore, Encryptor, MigrationResult, ServiceName } from './types';
|
|
10
|
+
export { NullTokenStore } from './null-token-store';
|
|
11
|
+
export { SqliteTokenStore } from './sqlite';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/store/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Public API for the store module.
|
|
4
|
+
*
|
|
5
|
+
* Re-exports all type definitions. Concrete implementations (SqliteTokenStore,
|
|
6
|
+
* createEncryptor, runMigrations) are exported from their own modules so
|
|
7
|
+
* callers that need only interfaces do not pull in better-sqlite3 or node:crypto
|
|
8
|
+
* at import time.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.SqliteTokenStore = exports.NullTokenStore = void 0;
|
|
12
|
+
var null_token_store_1 = require("./null-token-store");
|
|
13
|
+
Object.defineProperty(exports, "NullTokenStore", { enumerable: true, get: function () { return null_token_store_1.NullTokenStore; } });
|
|
14
|
+
var sqlite_1 = require("./sqlite");
|
|
15
|
+
Object.defineProperty(exports, "SqliteTokenStore", { enumerable: true, get: function () { return sqlite_1.SqliteTokenStore; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/store/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAGH,uDAAoD;AAA3C,kHAAA,cAAc,OAAA;AACvB,mCAA4C;AAAnC,0GAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite schema migration module for the MCP token store.
|
|
3
|
+
*
|
|
4
|
+
* Applies versioned migrations to a better-sqlite3 database in a single
|
|
5
|
+
* transaction. Safe to call on every daemon startup — skips migrations that
|
|
6
|
+
* have already been applied.
|
|
7
|
+
*
|
|
8
|
+
* Also provides Go database migration: detectGoDatabase() and migrateFromGo()
|
|
9
|
+
* locate and migrate legacy padua-mcp SQLite token databases to the new
|
|
10
|
+
* tokens.db format. The wire format is byte-compatible between Go and TS.
|
|
11
|
+
*/
|
|
12
|
+
import Database from 'better-sqlite3';
|
|
13
|
+
import type { MigrationResult } from './types';
|
|
14
|
+
/**
|
|
15
|
+
* Apply any outstanding schema migrations to the given database.
|
|
16
|
+
*
|
|
17
|
+
* Wraps all migration statements in a single transaction. If any statement
|
|
18
|
+
* throws, the transaction is rolled back and no partial changes remain.
|
|
19
|
+
*
|
|
20
|
+
* @param db - An open better-sqlite3 database instance.
|
|
21
|
+
* @returns MigrationResult indicating whether migrations were applied.
|
|
22
|
+
* @throws StoreError(DB_WRITE_FAILED) if any database operation fails,
|
|
23
|
+
* including introspection queries and migration statements.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runMigrations(db: Database.Database): MigrationResult;
|
|
26
|
+
/**
|
|
27
|
+
* Result returned by migrateFromGo.
|
|
28
|
+
*
|
|
29
|
+
* Distinct from MigrationResult so that tokensCount is always present on
|
|
30
|
+
* success and reason is always present on skip, giving callers a typed
|
|
31
|
+
* discriminated union instead of a bag of optionals.
|
|
32
|
+
*/
|
|
33
|
+
export interface GoMigrationResult {
|
|
34
|
+
/** Whether tokens were actually migrated. */
|
|
35
|
+
migrated: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Machine-readable skip reason. Only set when migrated is false.
|
|
38
|
+
* 'no-legacy-db-found' — no Go database exists at any search path
|
|
39
|
+
* 'wal-files-present' — WAL file exists; Go process may still hold a lock
|
|
40
|
+
* 'decryption-failed' — provided key cannot decrypt the Go token data
|
|
41
|
+
*/
|
|
42
|
+
reason?: string;
|
|
43
|
+
/** Number of token rows migrated. Set when migrated is true. */
|
|
44
|
+
tokensCount?: number;
|
|
45
|
+
}
|
|
46
|
+
export declare const LEGACY_DB_PATHS: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* Return the first path in searchPaths that resolves to an existing file,
|
|
49
|
+
* or null when none exist.
|
|
50
|
+
*
|
|
51
|
+
* @param searchPaths - Ordered list of candidate paths. Defaults to LEGACY_DB_PATHS.
|
|
52
|
+
*/
|
|
53
|
+
export declare function detectGoDatabase(searchPaths?: string[]): string | null;
|
|
54
|
+
/**
|
|
55
|
+
* Migrate tokens from a legacy Go padua-mcp SQLite database to the new
|
|
56
|
+
* encrypted tokens.db.
|
|
57
|
+
*
|
|
58
|
+
* Steps:
|
|
59
|
+
* 1. Locate the Go database via detectGoDatabase.
|
|
60
|
+
* 2. Abort when a WAL file is present (Go process may still be running).
|
|
61
|
+
* 3. Open the Go database read-only and decrypt every row with the provided key.
|
|
62
|
+
* 4. Write all rows into the target store using SqliteTokenStore.
|
|
63
|
+
* 5. Rename the Go database to .bak so it is not migrated again.
|
|
64
|
+
*
|
|
65
|
+
* @param encryptionKey - 64-char hex AES-256 key (same key used by the Go app).
|
|
66
|
+
* @param targetDbPath - Absolute path to the destination tokens.db file.
|
|
67
|
+
* @param searchPaths - Override the default LEGACY_DB_PATHS (used in tests).
|
|
68
|
+
*/
|
|
69
|
+
export declare function migrateFromGo(encryptionKey: string, targetDbPath: string, searchPaths?: string[]): GoMigrationResult;
|
|
70
|
+
//# sourceMappingURL=migrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/mcp/store/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,SAAS,CAAC;AAyD5D;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,eAAe,CAUpE;AAiCD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkBD,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAG5C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,GAAE,MAAM,EAAyB,GAAG,MAAM,GAAG,IAAI,CAK5F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,iBAAiB,CAsEnB"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SQLite schema migration module for the MCP token store.
|
|
4
|
+
*
|
|
5
|
+
* Applies versioned migrations to a better-sqlite3 database in a single
|
|
6
|
+
* transaction. Safe to call on every daemon startup — skips migrations that
|
|
7
|
+
* have already been applied.
|
|
8
|
+
*
|
|
9
|
+
* Also provides Go database migration: detectGoDatabase() and migrateFromGo()
|
|
10
|
+
* locate and migrate legacy padua-mcp SQLite token databases to the new
|
|
11
|
+
* tokens.db format. The wire format is byte-compatible between Go and TS.
|
|
12
|
+
*/
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.LEGACY_DB_PATHS = void 0;
|
|
18
|
+
exports.runMigrations = runMigrations;
|
|
19
|
+
exports.detectGoDatabase = detectGoDatabase;
|
|
20
|
+
exports.migrateFromGo = migrateFromGo;
|
|
21
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
22
|
+
const node_fs_1 = require("node:fs");
|
|
23
|
+
const node_path_1 = require("node:path");
|
|
24
|
+
const node_os_1 = require("node:os");
|
|
25
|
+
const errors_1 = require("../errors");
|
|
26
|
+
const MIGRATIONS = [
|
|
27
|
+
{
|
|
28
|
+
version: 1,
|
|
29
|
+
description: 'Create tokens and schema_version tables',
|
|
30
|
+
up: [
|
|
31
|
+
`CREATE TABLE IF NOT EXISTS schema_version (
|
|
32
|
+
version INTEGER PRIMARY KEY,
|
|
33
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
34
|
+
)`,
|
|
35
|
+
`CREATE TABLE IF NOT EXISTS tokens (
|
|
36
|
+
service TEXT PRIMARY KEY,
|
|
37
|
+
data BLOB NOT NULL,
|
|
38
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
39
|
+
)`,
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Helpers
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
function schemaVersionTableExists(db) {
|
|
47
|
+
const row = db
|
|
48
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'`)
|
|
49
|
+
.get();
|
|
50
|
+
return row !== undefined;
|
|
51
|
+
}
|
|
52
|
+
function getCurrentVersion(db) {
|
|
53
|
+
const row = db
|
|
54
|
+
.prepare(`SELECT MAX(version) as version FROM schema_version`)
|
|
55
|
+
.get();
|
|
56
|
+
return row.version ?? 0;
|
|
57
|
+
}
|
|
58
|
+
function pendingMigrations(currentVersion) {
|
|
59
|
+
return MIGRATIONS.filter((m) => m.version > currentVersion);
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Public API
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
/**
|
|
65
|
+
* Apply any outstanding schema migrations to the given database.
|
|
66
|
+
*
|
|
67
|
+
* Wraps all migration statements in a single transaction. If any statement
|
|
68
|
+
* throws, the transaction is rolled back and no partial changes remain.
|
|
69
|
+
*
|
|
70
|
+
* @param db - An open better-sqlite3 database instance.
|
|
71
|
+
* @returns MigrationResult indicating whether migrations were applied.
|
|
72
|
+
* @throws StoreError(DB_WRITE_FAILED) if any database operation fails,
|
|
73
|
+
* including introspection queries and migration statements.
|
|
74
|
+
*/
|
|
75
|
+
function runMigrations(db) {
|
|
76
|
+
try {
|
|
77
|
+
return applyMigrations(db);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err instanceof errors_1.StoreError)
|
|
81
|
+
throw err;
|
|
82
|
+
throw new errors_1.StoreError(`Migration failed: ${err instanceof Error ? err.message : String(err)}`, errors_1.ErrorCodes.DB_WRITE_FAILED);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function applyMigrations(db) {
|
|
86
|
+
const alreadyInitialised = schemaVersionTableExists(db);
|
|
87
|
+
const currentVersion = alreadyInitialised ? getCurrentVersion(db) : 0;
|
|
88
|
+
const pending = pendingMigrations(currentVersion);
|
|
89
|
+
if (pending.length === 0) {
|
|
90
|
+
return {
|
|
91
|
+
migrated: false,
|
|
92
|
+
reason: `already at latest schema version (v${currentVersion})`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const applyAll = db.transaction(() => {
|
|
96
|
+
for (const migration of pending) {
|
|
97
|
+
for (const sql of migration.up) {
|
|
98
|
+
db.prepare(sql).run();
|
|
99
|
+
}
|
|
100
|
+
db.prepare(`INSERT INTO schema_version (version) VALUES (?)`).run(migration.version);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
applyAll();
|
|
104
|
+
return { migrated: true };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Legacy Go database paths checked by detectGoDatabase, in priority order.
|
|
108
|
+
* Exported for reference; tests override this via the searchPaths parameter.
|
|
109
|
+
*/
|
|
110
|
+
function isStoredToken(value) {
|
|
111
|
+
if (typeof value !== 'object' || value === null)
|
|
112
|
+
return false;
|
|
113
|
+
const obj = value;
|
|
114
|
+
return (typeof obj.accessToken === 'string' &&
|
|
115
|
+
typeof obj.refreshToken === 'string' &&
|
|
116
|
+
typeof obj.tokenType === 'string' &&
|
|
117
|
+
typeof obj.expiresAt === 'number' &&
|
|
118
|
+
Array.isArray(obj.scopes));
|
|
119
|
+
}
|
|
120
|
+
exports.LEGACY_DB_PATHS = [
|
|
121
|
+
(0, node_path_1.join)((0, node_os_1.homedir)(), '.config', 'padua-mcp', 'padua-mcp.db'),
|
|
122
|
+
(0, node_path_1.join)((0, node_os_1.homedir)(), '.padua', 'padua-mcp.db'),
|
|
123
|
+
];
|
|
124
|
+
/**
|
|
125
|
+
* Return the first path in searchPaths that resolves to an existing file,
|
|
126
|
+
* or null when none exist.
|
|
127
|
+
*
|
|
128
|
+
* @param searchPaths - Ordered list of candidate paths. Defaults to LEGACY_DB_PATHS.
|
|
129
|
+
*/
|
|
130
|
+
function detectGoDatabase(searchPaths = [...exports.LEGACY_DB_PATHS]) {
|
|
131
|
+
for (const p of searchPaths) {
|
|
132
|
+
if ((0, node_fs_1.existsSync)(p))
|
|
133
|
+
return p;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Migrate tokens from a legacy Go padua-mcp SQLite database to the new
|
|
139
|
+
* encrypted tokens.db.
|
|
140
|
+
*
|
|
141
|
+
* Steps:
|
|
142
|
+
* 1. Locate the Go database via detectGoDatabase.
|
|
143
|
+
* 2. Abort when a WAL file is present (Go process may still be running).
|
|
144
|
+
* 3. Open the Go database read-only and decrypt every row with the provided key.
|
|
145
|
+
* 4. Write all rows into the target store using SqliteTokenStore.
|
|
146
|
+
* 5. Rename the Go database to .bak so it is not migrated again.
|
|
147
|
+
*
|
|
148
|
+
* @param encryptionKey - 64-char hex AES-256 key (same key used by the Go app).
|
|
149
|
+
* @param targetDbPath - Absolute path to the destination tokens.db file.
|
|
150
|
+
* @param searchPaths - Override the default LEGACY_DB_PATHS (used in tests).
|
|
151
|
+
*/
|
|
152
|
+
function migrateFromGo(encryptionKey, targetDbPath, searchPaths) {
|
|
153
|
+
const goDbPath = detectGoDatabase(searchPaths);
|
|
154
|
+
if (!goDbPath) {
|
|
155
|
+
return { migrated: false, reason: 'no-legacy-db-found' };
|
|
156
|
+
}
|
|
157
|
+
if ((0, node_fs_1.existsSync)(goDbPath + '-wal')) {
|
|
158
|
+
return { migrated: false, reason: 'wal-files-present' };
|
|
159
|
+
}
|
|
160
|
+
// Import here to avoid circular dependency between migrate.ts and sqlite.ts.
|
|
161
|
+
// sqlite.ts imports migrate.ts (for runMigrations), so we must not import
|
|
162
|
+
// SqliteTokenStore at the module level in this file.
|
|
163
|
+
const { SqliteTokenStore } =
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
165
|
+
require('./sqlite');
|
|
166
|
+
const { createEncryptor } =
|
|
167
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
168
|
+
require('./encrypt');
|
|
169
|
+
const encryptor = createEncryptor(encryptionKey);
|
|
170
|
+
const goDb = new better_sqlite3_1.default(goDbPath, { readonly: true });
|
|
171
|
+
try {
|
|
172
|
+
const rows = goDb
|
|
173
|
+
.prepare(`SELECT service, data FROM tokens`)
|
|
174
|
+
.all();
|
|
175
|
+
// Attempt decryption of all rows before touching the target store.
|
|
176
|
+
// If any row fails, abort the entire migration.
|
|
177
|
+
let decryptedRows;
|
|
178
|
+
try {
|
|
179
|
+
decryptedRows = rows.map((row) => ({
|
|
180
|
+
service: row.service,
|
|
181
|
+
plaintext: encryptor.decrypt(Buffer.from(row.data)),
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return { migrated: false, reason: 'decryption-failed' };
|
|
186
|
+
}
|
|
187
|
+
const targetStore = SqliteTokenStore.create(targetDbPath, encryptor);
|
|
188
|
+
try {
|
|
189
|
+
for (const { service, plaintext } of decryptedRows) {
|
|
190
|
+
const parsed = JSON.parse(plaintext.toString('utf-8'));
|
|
191
|
+
if (!isStoredToken(parsed)) {
|
|
192
|
+
throw new errors_1.StoreError(`Invalid token structure for service "${service}"`, errors_1.ErrorCodes.DB_WRITE_FAILED);
|
|
193
|
+
}
|
|
194
|
+
targetStore.upsert(service, parsed);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
targetStore.close();
|
|
199
|
+
}
|
|
200
|
+
goDb.close();
|
|
201
|
+
(0, node_fs_1.renameSync)(goDbPath, goDbPath + '.bak');
|
|
202
|
+
return { migrated: true, tokensCount: rows.length };
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
goDb.close();
|
|
206
|
+
if (err instanceof errors_1.StoreError)
|
|
207
|
+
throw err;
|
|
208
|
+
throw new errors_1.StoreError(`Go database migration failed: ${err instanceof Error ? err.message : String(err)}`, errors_1.ErrorCodes.DB_WRITE_FAILED);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/mcp/store/migrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { TokenStore, StoredToken } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory TokenStore implementation used for testing and as a null-object
|
|
4
|
+
* fallback when no persistent store is configured.
|
|
5
|
+
*
|
|
6
|
+
* All operations are synchronous and operate on a plain Map. No I/O, no
|
|
7
|
+
* encryption, no external dependencies. Returned tokens are shallow-copied
|
|
8
|
+
* so callers cannot mutate internal store state through a returned reference.
|
|
9
|
+
*/
|
|
10
|
+
export declare class NullTokenStore implements TokenStore {
|
|
11
|
+
private readonly store;
|
|
12
|
+
static create(): NullTokenStore;
|
|
13
|
+
get(service: string): StoredToken | null;
|
|
14
|
+
upsert(service: string, token: StoredToken): void;
|
|
15
|
+
delete(service: string): void;
|
|
16
|
+
list(): Array<{
|
|
17
|
+
service: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}>;
|
|
20
|
+
close(): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=null-token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-token-store.d.ts","sourceRoot":"","sources":["../../../src/mcp/store/null-token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEvD;;;;;;;GAOG;AACH,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgE;IAEtF,MAAM,CAAC,MAAM,IAAI,cAAc;IAI/B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAKxC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAOjD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI7B,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAMrD,KAAK,IAAI,IAAI;CAGd"}
|