@inso_web/els-mcp 0.1.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 +482 -0
- package/dist/audit/prisma.d.ts +67 -0
- package/dist/audit/prisma.d.ts.map +1 -0
- package/dist/audit/prisma.js +65 -0
- package/dist/audit/prisma.js.map +1 -0
- package/dist/audit/service.d.ts +72 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +137 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/billing/limits.d.ts +34 -0
- package/dist/billing/limits.d.ts.map +1 -0
- package/dist/billing/limits.js +51 -0
- package/dist/billing/limits.js.map +1 -0
- package/dist/billing/tracker.d.ts +39 -0
- package/dist/billing/tracker.d.ts.map +1 -0
- package/dist/billing/tracker.js +92 -0
- package/dist/billing/tracker.js.map +1 -0
- package/dist/cache/cachedElsClient.d.ts +71 -0
- package/dist/cache/cachedElsClient.d.ts.map +1 -0
- package/dist/cache/cachedElsClient.js +167 -0
- package/dist/cache/cachedElsClient.js.map +1 -0
- package/dist/cache/index.d.ts +10 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/policies.d.ts +60 -0
- package/dist/cache/policies.d.ts.map +1 -0
- package/dist/cache/policies.js +90 -0
- package/dist/cache/policies.js.map +1 -0
- package/dist/cache/redis.d.ts +52 -0
- package/dist/cache/redis.d.ts.map +1 -0
- package/dist/cache/redis.js +134 -0
- package/dist/cache/redis.js.map +1 -0
- package/dist/cache/types.d.ts +32 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +32 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/cache/wrapper.d.ts +38 -0
- package/dist/cache/wrapper.d.ts.map +1 -0
- package/dist/cache/wrapper.js +109 -0
- package/dist/cache/wrapper.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +86 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +105 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +211 -0
- package/dist/config.js.map +1 -0
- package/dist/elsClient.d.ts +137 -0
- package/dist/elsClient.d.ts.map +1 -0
- package/dist/elsClient.js +285 -0
- package/dist/elsClient.js.map +1 -0
- package/dist/http/app.d.ts +40 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +135 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/jwks.d.ts +8 -0
- package/dist/http/jwks.d.ts.map +1 -0
- package/dist/http/jwks.js +34 -0
- package/dist/http/jwks.js.map +1 -0
- package/dist/http/middleware/auth.d.ts +11 -0
- package/dist/http/middleware/auth.d.ts.map +1 -0
- package/dist/http/middleware/auth.js +225 -0
- package/dist/http/middleware/auth.js.map +1 -0
- package/dist/http/middleware/dcrRateLimit.d.ts +29 -0
- package/dist/http/middleware/dcrRateLimit.d.ts.map +1 -0
- package/dist/http/middleware/dcrRateLimit.js +59 -0
- package/dist/http/middleware/dcrRateLimit.js.map +1 -0
- package/dist/http/middleware/errorHandler.d.ts +12 -0
- package/dist/http/middleware/errorHandler.d.ts.map +1 -0
- package/dist/http/middleware/errorHandler.js +26 -0
- package/dist/http/middleware/errorHandler.js.map +1 -0
- package/dist/http/middleware/originGuard.d.ts +28 -0
- package/dist/http/middleware/originGuard.d.ts.map +1 -0
- package/dist/http/middleware/originGuard.js +55 -0
- package/dist/http/middleware/originGuard.js.map +1 -0
- package/dist/http/middleware/requestId.d.ts +19 -0
- package/dist/http/middleware/requestId.d.ts.map +1 -0
- package/dist/http/middleware/requestId.js +23 -0
- package/dist/http/middleware/requestId.js.map +1 -0
- package/dist/http/routes/health.d.ts +24 -0
- package/dist/http/routes/health.d.ts.map +1 -0
- package/dist/http/routes/health.js +73 -0
- package/dist/http/routes/health.js.map +1 -0
- package/dist/http/routes/metrics.d.ts +18 -0
- package/dist/http/routes/metrics.d.ts.map +1 -0
- package/dist/http/routes/metrics.js +42 -0
- package/dist/http/routes/metrics.js.map +1 -0
- package/dist/http/routes/wellKnown.d.ts +15 -0
- package/dist/http/routes/wellKnown.d.ts.map +1 -0
- package/dist/http/routes/wellKnown.js +43 -0
- package/dist/http/routes/wellKnown.js.map +1 -0
- package/dist/http/types.d.ts +40 -0
- package/dist/http/types.d.ts.map +1 -0
- package/dist/http/types.js +9 -0
- package/dist/http/types.js.map +1 -0
- package/dist/instrumentation.d.ts +22 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +38 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/lib/cursor.d.ts +22 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +95 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/errors.d.ts +49 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +83 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/responseFormat.d.ts +14 -0
- package/dist/lib/responseFormat.d.ts.map +1 -0
- package/dist/lib/responseFormat.js +74 -0
- package/dist/lib/responseFormat.js.map +1 -0
- package/dist/middleware/withMiddleware.d.ts +53 -0
- package/dist/middleware/withMiddleware.d.ts.map +1 -0
- package/dist/middleware/withMiddleware.js +190 -0
- package/dist/middleware/withMiddleware.js.map +1 -0
- package/dist/observability/health.d.ts +51 -0
- package/dist/observability/health.d.ts.map +1 -0
- package/dist/observability/health.js +77 -0
- package/dist/observability/health.js.map +1 -0
- package/dist/observability/index.d.ts +8 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/logger.d.ts +45 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +75 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +49 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +184 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/tracing.d.ts +28 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +56 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/prompts/index.d.ts +20 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +202 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/redaction/argsRedactor.d.ts +22 -0
- package/dist/redaction/argsRedactor.d.ts.map +1 -0
- package/dist/redaction/argsRedactor.js +97 -0
- package/dist/redaction/argsRedactor.js.map +1 -0
- package/dist/redaction/fields.d.ts +64 -0
- package/dist/redaction/fields.d.ts.map +1 -0
- package/dist/redaction/fields.js +155 -0
- package/dist/redaction/fields.js.map +1 -0
- package/dist/redaction/index.d.ts +52 -0
- package/dist/redaction/index.d.ts.map +1 -0
- package/dist/redaction/index.js +160 -0
- package/dist/redaction/index.js.map +1 -0
- package/dist/redaction/promptInjection.d.ts +32 -0
- package/dist/redaction/promptInjection.d.ts.map +1 -0
- package/dist/redaction/promptInjection.js +68 -0
- package/dist/redaction/promptInjection.js.map +1 -0
- package/dist/redaction/url.d.ts +8 -0
- package/dist/redaction/url.d.ts.map +1 -0
- package/dist/redaction/url.js +26 -0
- package/dist/redaction/url.js.map +1 -0
- package/dist/redaction/userAgent.d.ts +9 -0
- package/dist/redaction/userAgent.d.ts.map +1 -0
- package/dist/redaction/userAgent.js +39 -0
- package/dist/redaction/userAgent.js.map +1 -0
- package/dist/resources/index.d.ts +24 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +150 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +37 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +35 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/baselineCompare.d.ts +36 -0
- package/dist/tools/baselineCompare.d.ts.map +1 -0
- package/dist/tools/baselineCompare.js +69 -0
- package/dist/tools/baselineCompare.js.map +1 -0
- package/dist/tools/errorHeatmap.d.ts +40 -0
- package/dist/tools/errorHeatmap.d.ts.map +1 -0
- package/dist/tools/errorHeatmap.js +69 -0
- package/dist/tools/errorHeatmap.js.map +1 -0
- package/dist/tools/errorHistogram.d.ts +39 -0
- package/dist/tools/errorHistogram.d.ts.map +1 -0
- package/dist/tools/errorHistogram.js +61 -0
- package/dist/tools/errorHistogram.js.map +1 -0
- package/dist/tools/errorStatsBreakdown.d.ts +43 -0
- package/dist/tools/errorStatsBreakdown.d.ts.map +1 -0
- package/dist/tools/errorStatsBreakdown.js +77 -0
- package/dist/tools/errorStatsBreakdown.js.map +1 -0
- package/dist/tools/errorsInSession.d.ts +44 -0
- package/dist/tools/errorsInSession.d.ts.map +1 -0
- package/dist/tools/errorsInSession.js +91 -0
- package/dist/tools/errorsInSession.js.map +1 -0
- package/dist/tools/explainError.d.ts +35 -0
- package/dist/tools/explainError.d.ts.map +1 -0
- package/dist/tools/explainError.js +98 -0
- package/dist/tools/explainError.js.map +1 -0
- package/dist/tools/findCorrelatedErrors.d.ts +43 -0
- package/dist/tools/findCorrelatedErrors.d.ts.map +1 -0
- package/dist/tools/findCorrelatedErrors.js +59 -0
- package/dist/tools/findCorrelatedErrors.js.map +1 -0
- package/dist/tools/findSimilarErrors.d.ts +44 -0
- package/dist/tools/findSimilarErrors.d.ts.map +1 -0
- package/dist/tools/findSimilarErrors.js +59 -0
- package/dist/tools/findSimilarErrors.js.map +1 -0
- package/dist/tools/getLogDetails.d.ts +30 -0
- package/dist/tools/getLogDetails.d.ts.map +1 -0
- package/dist/tools/getLogDetails.js +49 -0
- package/dist/tools/getLogDetails.js.map +1 -0
- package/dist/tools/groupedErrors.d.ts +46 -0
- package/dist/tools/groupedErrors.d.ts.map +1 -0
- package/dist/tools/groupedErrors.js +71 -0
- package/dist/tools/groupedErrors.js.map +1 -0
- package/dist/tools/impactAnalysis.d.ts +42 -0
- package/dist/tools/impactAnalysis.d.ts.map +1 -0
- package/dist/tools/impactAnalysis.js +61 -0
- package/dist/tools/impactAnalysis.js.map +1 -0
- package/dist/tools/index.d.ts +41 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +83 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/listApps.d.ts +27 -0
- package/dist/tools/listApps.d.ts.map +1 -0
- package/dist/tools/listApps.js +78 -0
- package/dist/tools/listApps.js.map +1 -0
- package/dist/tools/queryLogsJql.d.ts +44 -0
- package/dist/tools/queryLogsJql.d.ts.map +1 -0
- package/dist/tools/queryLogsJql.js +107 -0
- package/dist/tools/queryLogsJql.js.map +1 -0
- package/dist/tools/searchLogs.d.ts +60 -0
- package/dist/tools/searchLogs.d.ts.map +1 -0
- package/dist/tools/searchLogs.js +127 -0
- package/dist/tools/searchLogs.js.map +1 -0
- package/dist/tools/topErrorMessages.d.ts +42 -0
- package/dist/tools/topErrorMessages.d.ts.map +1 -0
- package/dist/tools/topErrorMessages.js +63 -0
- package/dist/tools/topErrorMessages.js.map +1 -0
- package/dist/tools/trafficStats.d.ts +39 -0
- package/dist/tools/trafficStats.d.ts.map +1 -0
- package/dist/tools/trafficStats.js +57 -0
- package/dist/tools/trafficStats.js.map +1 -0
- package/dist/tools/triageRecentCritical.d.ts +26 -0
- package/dist/tools/triageRecentCritical.d.ts.map +1 -0
- package/dist/tools/triageRecentCritical.js +81 -0
- package/dist/tools/triageRecentCritical.js.map +1 -0
- package/dist/tools/versionRegression.d.ts +29 -0
- package/dist/tools/versionRegression.d.ts.map +1 -0
- package/dist/tools/versionRegression.js +80 -0
- package/dist/tools/versionRegression.js.map +1 -0
- package/dist/transports/http-server.d.ts +25 -0
- package/dist/transports/http-server.d.ts.map +1 -0
- package/dist/transports/http-server.js +84 -0
- package/dist/transports/http-server.js.map +1 -0
- package/dist/transports/http.d.ts +71 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +315 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/stdio.d.ts +13 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +16 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { checkLiveness, checkReadiness, } from '../../observability/health.js';
|
|
4
|
+
export function createHealthRouter(opts = {}) {
|
|
5
|
+
const router = Router();
|
|
6
|
+
router.get('/health', insoHealthHandler()); // INSO Uptime contract
|
|
7
|
+
router.get('/healthz', livenessHandler()); // legacy
|
|
8
|
+
router.get('/ready', readinessHandler(opts)); // INSO Uptime contract
|
|
9
|
+
router.get('/readyz', readinessHandler(opts)); // legacy
|
|
10
|
+
return router;
|
|
11
|
+
}
|
|
12
|
+
function livenessHandler() {
|
|
13
|
+
return function handler(_req, res) {
|
|
14
|
+
const liv = checkLiveness();
|
|
15
|
+
res.status(200).json({ status: liv.status, uptimeSec: liv.uptimeSec, version: liv.version });
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* INSO Uptime contract — формат идентичный другим микросервисам платформы
|
|
20
|
+
* (см. error-logs-service/src/routes/health.routes.ts). LK health-monitor
|
|
21
|
+
* парсит поле `version` (`BUILD_VERSION` из CI build timestamp).
|
|
22
|
+
*/
|
|
23
|
+
function insoHealthHandler() {
|
|
24
|
+
return function handler(_req, res) {
|
|
25
|
+
const liv = checkLiveness();
|
|
26
|
+
res.status(200).json({
|
|
27
|
+
status: liv.status,
|
|
28
|
+
uptime: liv.uptimeSec,
|
|
29
|
+
hostname: os.hostname(),
|
|
30
|
+
version: process.env.BUILD_VERSION || liv.version,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function readinessHandler(opts) {
|
|
35
|
+
return async function handler(_req, res) {
|
|
36
|
+
// checks: { els: 'ok' | 'fail' | 'skip', redis: ... }
|
|
37
|
+
// Используем Phase 4 checkReadiness с тем же контрактом.
|
|
38
|
+
const checks = {};
|
|
39
|
+
let allOk = true;
|
|
40
|
+
if (opts.elsClient || opts.redis) {
|
|
41
|
+
const result = await checkReadiness({
|
|
42
|
+
...(opts.elsClient ? { elsClient: opts.elsClient } : {}),
|
|
43
|
+
...(opts.redis ? { redis: opts.redis } : {}),
|
|
44
|
+
...(opts.log ? { log: opts.log } : {}),
|
|
45
|
+
timeoutMs: 2000,
|
|
46
|
+
});
|
|
47
|
+
checks.els = opts.elsClient ? (result.checks.upstream.ok ? 'ok' : 'fail') : 'skip';
|
|
48
|
+
checks.redis = opts.redis ? (result.checks.redis.ok ? 'ok' : 'fail') : 'skip';
|
|
49
|
+
if (result.status !== 'ready')
|
|
50
|
+
allOk = false;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
checks.els = 'skip';
|
|
54
|
+
checks.redis = 'skip';
|
|
55
|
+
}
|
|
56
|
+
for (const probe of opts.probes ?? []) {
|
|
57
|
+
try {
|
|
58
|
+
await probe.check();
|
|
59
|
+
checks[probe.name] = 'ok';
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
opts.log?.warn?.({ err: errMsg(err), probe: probe.name }, 'readyz: probe failed');
|
|
63
|
+
checks[probe.name] = 'fail';
|
|
64
|
+
allOk = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
res.status(allOk ? 200 : 503).json({ status: allOk ? 'ok' : 'degraded', checks });
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function errMsg(err) {
|
|
71
|
+
return err instanceof Error ? err.message : String(err);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/http/routes/health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { type ReadinessDeps } from '../../observability/health.js';
|
|
3
|
+
/**
|
|
4
|
+
* Lightweight HTTP handlers для Express-like транспорта (Phase 3).
|
|
5
|
+
*
|
|
6
|
+
* Каждый handler — `(req, res) => Promise<void>` (совместимо с Node http
|
|
7
|
+
* и Express `(req, res, next?)`). Phase 3 их подцепит:
|
|
8
|
+
*
|
|
9
|
+
* app.get('/els/metrics', metricsHandler);
|
|
10
|
+
* app.get('/els/healthz', healthzHandler);
|
|
11
|
+
* app.get('/els/readyz', readyzHandler(deps));
|
|
12
|
+
*
|
|
13
|
+
* Phase 4 предоставляет реализацию; Phase 3 — wiring.
|
|
14
|
+
*/
|
|
15
|
+
export declare function metricsHandler(_req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
16
|
+
export declare function healthzHandler(_req: IncomingMessage, res: ServerResponse): void;
|
|
17
|
+
export declare function readyzHandler(deps: ReadinessDeps): (_req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
18
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../src/http/routes/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,EAAiC,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAElG;;;;;;;;;;;GAWG;AAEH,wBAAsB,cAAc,CAClC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAK/E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,IACjC,MAAM,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CAMzE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { getMetricsContentType, getMetricsText } from '../../observability/metrics.js';
|
|
2
|
+
import { checkLiveness, checkReadiness } from '../../observability/health.js';
|
|
3
|
+
/**
|
|
4
|
+
* Lightweight HTTP handlers для Express-like транспорта (Phase 3).
|
|
5
|
+
*
|
|
6
|
+
* Каждый handler — `(req, res) => Promise<void>` (совместимо с Node http
|
|
7
|
+
* и Express `(req, res, next?)`). Phase 3 их подцепит:
|
|
8
|
+
*
|
|
9
|
+
* app.get('/els/metrics', metricsHandler);
|
|
10
|
+
* app.get('/els/healthz', healthzHandler);
|
|
11
|
+
* app.get('/els/readyz', readyzHandler(deps));
|
|
12
|
+
*
|
|
13
|
+
* Phase 4 предоставляет реализацию; Phase 3 — wiring.
|
|
14
|
+
*/
|
|
15
|
+
export async function metricsHandler(_req, res) {
|
|
16
|
+
try {
|
|
17
|
+
const body = await getMetricsText();
|
|
18
|
+
res.statusCode = 200;
|
|
19
|
+
res.setHeader('content-type', getMetricsContentType());
|
|
20
|
+
res.end(body);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
res.statusCode = 500;
|
|
24
|
+
res.setHeader('content-type', 'text/plain; charset=utf-8');
|
|
25
|
+
res.end(`# metrics error: ${err.message}\n`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function healthzHandler(_req, res) {
|
|
29
|
+
const body = checkLiveness();
|
|
30
|
+
res.statusCode = 200;
|
|
31
|
+
res.setHeader('content-type', 'application/json');
|
|
32
|
+
res.end(JSON.stringify(body));
|
|
33
|
+
}
|
|
34
|
+
export function readyzHandler(deps) {
|
|
35
|
+
return async (_req, res) => {
|
|
36
|
+
const result = await checkReadiness(deps);
|
|
37
|
+
res.statusCode = result.status === 'ready' ? 200 : 503;
|
|
38
|
+
res.setHeader('content-type', 'application/json');
|
|
39
|
+
res.end(JSON.stringify(result));
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/http/routes/metrics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAsB,MAAM,+BAA+B,CAAC;AAElG;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAqB,EACrB,GAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAC;QACpC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACvD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,2BAA2B,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,oBAAqB,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAqB,EAAE,GAAmB;IACvE,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;IACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAmB;IAC/C,OAAO,KAAK,EAAE,IAAqB,EAAE,GAAmB,EAAiB,EAAE;QACzE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACvD,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import type { Config } from '../../config.js';
|
|
3
|
+
/**
|
|
4
|
+
* Well-known discovery endpoints:
|
|
5
|
+
* - `/.well-known/oauth-protected-resource` (RFC 9728)
|
|
6
|
+
* - `/.well-known/mcp` (MCP-specific discovery)
|
|
7
|
+
*
|
|
8
|
+
* Оба статичны (зависят только от config), отдаются без auth.
|
|
9
|
+
*/
|
|
10
|
+
export interface CreateWellKnownOptions {
|
|
11
|
+
config: Config;
|
|
12
|
+
toolNames: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function createWellKnownRouter(opts: CreateWellKnownOptions): Router;
|
|
15
|
+
//# sourceMappingURL=wellKnown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wellKnown.d.ts","sourceRoot":"","sources":["../../../src/http/routes/wellKnown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAuB,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;;;;GAMG;AAEH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAK1E"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
export function createWellKnownRouter(opts) {
|
|
3
|
+
const router = Router();
|
|
4
|
+
router.get('/oauth-protected-resource', protectedResource(opts.config));
|
|
5
|
+
router.get('/mcp', mcpDiscovery(opts.config, opts.toolNames));
|
|
6
|
+
return router;
|
|
7
|
+
}
|
|
8
|
+
function protectedResource(config) {
|
|
9
|
+
// Trailing slash для `resource` — стандартное представление "tenant boundary"
|
|
10
|
+
// в RFC 9728. Должно совпадать с тем, что отдаётся в WWW-Authenticate.
|
|
11
|
+
const resource = `${config.publicUrl}/`;
|
|
12
|
+
const body = {
|
|
13
|
+
resource,
|
|
14
|
+
authorization_servers: [config.oidcIssuer],
|
|
15
|
+
scopes_supported: ['errors:mcp-read'],
|
|
16
|
+
bearer_methods_supported: ['header'],
|
|
17
|
+
};
|
|
18
|
+
return function handler(_req, res) {
|
|
19
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
20
|
+
res.status(200).json(body);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function mcpDiscovery(config, toolNames) {
|
|
24
|
+
const body = {
|
|
25
|
+
protocolVersion: '2025-03-26',
|
|
26
|
+
transports: ['streamable-http'],
|
|
27
|
+
tools: toolNames,
|
|
28
|
+
auth: {
|
|
29
|
+
type: 'oauth2',
|
|
30
|
+
authorizationServer: config.oidcIssuer,
|
|
31
|
+
resource: `${config.publicUrl}/`,
|
|
32
|
+
},
|
|
33
|
+
endpoints: {
|
|
34
|
+
mcp: `${config.publicUrl}/mcp`,
|
|
35
|
+
},
|
|
36
|
+
documentation: `${config.publicUrl}/docs`,
|
|
37
|
+
};
|
|
38
|
+
return function handler(_req, res) {
|
|
39
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
40
|
+
res.status(200).json(body);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=wellKnown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wellKnown.js","sourceRoot":"","sources":["../../../src/http/routes/wellKnown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAuB,MAAM,SAAS,CAAC;AAgBtD,MAAM,UAAU,qBAAqB,CAAC,IAA4B;IAChE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,2BAA2B,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACxE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC9D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAc;IACvC,8EAA8E;IAC9E,uEAAuE;IACvE,MAAM,QAAQ,GAAG,GAAG,MAAM,CAAC,SAAS,GAAG,CAAC;IACxC,MAAM,IAAI,GAAG;QACX,QAAQ;QACR,qBAAqB,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC;QAC1C,gBAAgB,EAAE,CAAC,iBAAiB,CAAC;QACrC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACrC,CAAC;IACF,OAAO,SAAS,OAAO,CAAC,IAAI,EAAE,GAAG;QAC/B,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;QACtD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,SAAmB;IACvD,MAAM,IAAI,GAAG;QACX,eAAe,EAAE,YAAY;QAC7B,UAAU,EAAE,CAAC,iBAAiB,CAAC;QAC/B,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,mBAAmB,EAAE,MAAM,CAAC,UAAU;YACtC,QAAQ,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG;SACjC;QACD,SAAS,EAAE;YACT,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,MAAM;SAC/B;QACD,aAAa,EAAE,GAAG,MAAM,CAAC,SAAS,OAAO;KAC1C,CAAC;IACF,OAAO,SAAS,OAAO,CAAC,IAAI,EAAE,GAAG;QAC/B,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;QACtD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Типы для HTTP-транспорта.
|
|
3
|
+
*
|
|
4
|
+
* `RequestContext` собирается в auth middleware и потом доступен в
|
|
5
|
+
* Express handler'ах через `req.context`. Декларация augmentation модуля
|
|
6
|
+
* `express-serve-static-core` лежит ниже — она добавляет `context` к Request.
|
|
7
|
+
*/
|
|
8
|
+
export type AuthMethod = 'els-key' | 'oidc';
|
|
9
|
+
export interface RequestContext {
|
|
10
|
+
/** Способ аутентификации, по которому пользователь прошёл. */
|
|
11
|
+
authMethod: AuthMethod;
|
|
12
|
+
/** Только для `els-key`: оригинальный Bearer-ключ для проксирования в ELS. */
|
|
13
|
+
elsApiKey?: string;
|
|
14
|
+
/** Только для `oidc`: `sub` claim из JWT. */
|
|
15
|
+
oidcSub?: string;
|
|
16
|
+
/** Только для `oidc`: scope claim (raw array). */
|
|
17
|
+
scopes?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Slug приложения, к которому привязан этот запрос. Для `els-key` пока
|
|
20
|
+
* `unknown` (на Phase 3 не дёргаем ELS resolver); для `oidc` — берётся
|
|
21
|
+
* из MCP_OIDC_DEMO_APP_SLUG (TODO Phase 4: реальный LK resolver).
|
|
22
|
+
*/
|
|
23
|
+
appSlug: string;
|
|
24
|
+
/** Короткий identifier для логов: первые 8 chars ELS-key или OIDC sub. */
|
|
25
|
+
keyId: string;
|
|
26
|
+
ip: string;
|
|
27
|
+
userAgent: string;
|
|
28
|
+
/** MCP `Mcp-Session-Id` header (если есть). */
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
/** request-id middleware: уникален per-запрос. */
|
|
31
|
+
requestId: string;
|
|
32
|
+
}
|
|
33
|
+
declare module 'express-serve-static-core' {
|
|
34
|
+
interface Request {
|
|
35
|
+
context?: RequestContext;
|
|
36
|
+
/** Per-request child logger (pino). Заполняется в requestId middleware. */
|
|
37
|
+
log?: import('pino').Logger;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/http/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,UAAU,EAAE,UAAU,CAAC;IACvB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,OAAO,QAAQ,2BAA2B,CAAC;IACzC,UAAU,OAAO;QACf,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,2EAA2E;QAC3E,GAAG,CAAC,EAAE,OAAO,MAAM,EAAE,MAAM,CAAC;KAC7B;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Типы для HTTP-транспорта.
|
|
3
|
+
*
|
|
4
|
+
* `RequestContext` собирается в auth middleware и потом доступен в
|
|
5
|
+
* Express handler'ах через `req.context`. Декларация augmentation модуля
|
|
6
|
+
* `express-serve-static-core` лежит ниже — она добавляет `context` к Request.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/http/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 6: OpenTelemetry instrumentation entry-point.
|
|
3
|
+
*
|
|
4
|
+
* Этот файл должен импортироваться **первым** в `cli.ts` (до любых других
|
|
5
|
+
* модулей, которые делают `import` HTTP/Redis-клиентов). OTel SDK
|
|
6
|
+
* патчит prototype'ы зависимостей при старте — это работает корректно
|
|
7
|
+
* только если он стартовал ДО создания этих instance'ов.
|
|
8
|
+
*
|
|
9
|
+
* Если `OTEL_EXPORTER_OTLP_ENDPOINT` не задан — функция возвращает no-op
|
|
10
|
+
* handle (tracing disabled, нулевой overhead).
|
|
11
|
+
*
|
|
12
|
+
* Идея взята из `observability/tracing.ts` (Phase 4), но вынесена отдельно,
|
|
13
|
+
* чтобы был чёткий "earliest possible" entry-point.
|
|
14
|
+
*/
|
|
15
|
+
import { type TracingHandle } from './observability/tracing.js';
|
|
16
|
+
/**
|
|
17
|
+
* Инициализирует OTel SDK, если задан endpoint.
|
|
18
|
+
* Безопасно вызывать несколько раз — повторные вызовы — no-op.
|
|
19
|
+
*/
|
|
20
|
+
export declare function initInstrumentation(): Promise<TracingHandle>;
|
|
21
|
+
export declare function getInstrumentationHandle(): TracingHandle | null;
|
|
22
|
+
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAI9E;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAYlE;AAED,wBAAgB,wBAAwB,IAAI,aAAa,GAAG,IAAI,CAE/D"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 6: OpenTelemetry instrumentation entry-point.
|
|
3
|
+
*
|
|
4
|
+
* Этот файл должен импортироваться **первым** в `cli.ts` (до любых других
|
|
5
|
+
* модулей, которые делают `import` HTTP/Redis-клиентов). OTel SDK
|
|
6
|
+
* патчит prototype'ы зависимостей при старте — это работает корректно
|
|
7
|
+
* только если он стартовал ДО создания этих instance'ов.
|
|
8
|
+
*
|
|
9
|
+
* Если `OTEL_EXPORTER_OTLP_ENDPOINT` не задан — функция возвращает no-op
|
|
10
|
+
* handle (tracing disabled, нулевой overhead).
|
|
11
|
+
*
|
|
12
|
+
* Идея взята из `observability/tracing.ts` (Phase 4), но вынесена отдельно,
|
|
13
|
+
* чтобы был чёткий "earliest possible" entry-point.
|
|
14
|
+
*/
|
|
15
|
+
import { setupTracing } from './observability/tracing.js';
|
|
16
|
+
let handle = null;
|
|
17
|
+
/**
|
|
18
|
+
* Инициализирует OTel SDK, если задан endpoint.
|
|
19
|
+
* Безопасно вызывать несколько раз — повторные вызовы — no-op.
|
|
20
|
+
*/
|
|
21
|
+
export async function initInstrumentation() {
|
|
22
|
+
if (handle)
|
|
23
|
+
return handle;
|
|
24
|
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
25
|
+
if (!endpoint) {
|
|
26
|
+
handle = {
|
|
27
|
+
enabled: false,
|
|
28
|
+
shutdown: async () => { },
|
|
29
|
+
};
|
|
30
|
+
return handle;
|
|
31
|
+
}
|
|
32
|
+
handle = await setupTracing();
|
|
33
|
+
return handle;
|
|
34
|
+
}
|
|
35
|
+
export function getInstrumentationHandle() {
|
|
36
|
+
return handle;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=instrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAsB,MAAM,4BAA4B,CAAC;AAE9E,IAAI,MAAM,GAAyB,IAAI,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;IACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,GAAG;YACP,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;SACzB,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CursorPayload } from '../types.js';
|
|
2
|
+
export declare function hashFilters(filters: unknown): string;
|
|
3
|
+
/**
|
|
4
|
+
* Кодирует cursor для следующей страницы.
|
|
5
|
+
*
|
|
6
|
+
* @param anchor — последний item текущей страницы (или null если страница пуста).
|
|
7
|
+
* @param filters — объект текущих фильтров для подсчёта hash.
|
|
8
|
+
* @param nextPage — Phase 1: следующий номер страницы для offset-pagination.
|
|
9
|
+
* @param limit — page size.
|
|
10
|
+
*/
|
|
11
|
+
export declare function encodeCursor(anchor: {
|
|
12
|
+
receivedAt: string;
|
|
13
|
+
id: string;
|
|
14
|
+
} | null, filters: unknown, nextPage: number, limit: number): string;
|
|
15
|
+
/**
|
|
16
|
+
* Декодирует cursor и валидирует filters-hash.
|
|
17
|
+
*
|
|
18
|
+
* Возвращает payload. Бросает ToolError('INVALID_ARGS') если cursor невалиден
|
|
19
|
+
* или фильтры между страницами изменились.
|
|
20
|
+
*/
|
|
21
|
+
export declare function decodeCursor(cursor: string, currentFilters: unknown): CursorPayload;
|
|
22
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/lib/cursor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAqCjD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EACjD,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAWR;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,aAAa,CAoCnF"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { ToolError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Seek-cursor utilities.
|
|
5
|
+
*
|
|
6
|
+
* Phase 1 — transitional: cursor wraps offset/page (т.к. ELS пока offset-based).
|
|
7
|
+
* Реальный seek-by-(receivedAt, id) появится в Phase 4 после изменения ELS.
|
|
8
|
+
* До этого момента:
|
|
9
|
+
* - `encodeCursor` берёт последний item страницы как anchor, и сохраняет
|
|
10
|
+
* page/limit для offset-pagination upstream;
|
|
11
|
+
* - `decodeCursor` разворачивает обратно и проверяет filtersHash,
|
|
12
|
+
* чтобы клиент не мог тащить cursor между разными filter-наборами.
|
|
13
|
+
*
|
|
14
|
+
* Контракт `filtersHash`: SHA-256 канонического JSON (отсортированные ключи)
|
|
15
|
+
* первых 16 hex-символов. Это компромисс между «защитой» и «коротким cursor'ом».
|
|
16
|
+
*/
|
|
17
|
+
const CURSOR_VERSION = 1;
|
|
18
|
+
/**
|
|
19
|
+
* Канонический JSON-сериализатор: ключи сортируются, undefined и пустые
|
|
20
|
+
* массивы выкидываются (чтобы `{ a: undefined }` и `{}` давали одинаковый hash).
|
|
21
|
+
*/
|
|
22
|
+
function canonicalJson(value) {
|
|
23
|
+
if (value === null || value === undefined)
|
|
24
|
+
return 'null';
|
|
25
|
+
if (typeof value !== 'object')
|
|
26
|
+
return JSON.stringify(value);
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
const compact = value.filter((v) => v !== undefined);
|
|
29
|
+
return '[' + compact.map(canonicalJson).join(',') + ']';
|
|
30
|
+
}
|
|
31
|
+
const entries = Object.entries(value)
|
|
32
|
+
.filter(([, v]) => v !== undefined && !(Array.isArray(v) && v.length === 0))
|
|
33
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
34
|
+
return '{' + entries.map(([k, v]) => JSON.stringify(k) + ':' + canonicalJson(v)).join(',') + '}';
|
|
35
|
+
}
|
|
36
|
+
export function hashFilters(filters) {
|
|
37
|
+
return createHash('sha256').update(canonicalJson(filters)).digest('hex').slice(0, 16);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Кодирует cursor для следующей страницы.
|
|
41
|
+
*
|
|
42
|
+
* @param anchor — последний item текущей страницы (или null если страница пуста).
|
|
43
|
+
* @param filters — объект текущих фильтров для подсчёта hash.
|
|
44
|
+
* @param nextPage — Phase 1: следующий номер страницы для offset-pagination.
|
|
45
|
+
* @param limit — page size.
|
|
46
|
+
*/
|
|
47
|
+
export function encodeCursor(anchor, filters, nextPage, limit) {
|
|
48
|
+
const payload = {
|
|
49
|
+
anchorReceivedAt: anchor?.receivedAt ?? new Date(0).toISOString(),
|
|
50
|
+
anchorId: anchor?.id ?? '',
|
|
51
|
+
filtersHash: hashFilters(filters),
|
|
52
|
+
v: CURSOR_VERSION,
|
|
53
|
+
page: nextPage,
|
|
54
|
+
limit,
|
|
55
|
+
};
|
|
56
|
+
const json = JSON.stringify(payload);
|
|
57
|
+
return Buffer.from(json, 'utf8').toString('base64url');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Декодирует cursor и валидирует filters-hash.
|
|
61
|
+
*
|
|
62
|
+
* Возвращает payload. Бросает ToolError('INVALID_ARGS') если cursor невалиден
|
|
63
|
+
* или фильтры между страницами изменились.
|
|
64
|
+
*/
|
|
65
|
+
export function decodeCursor(cursor, currentFilters) {
|
|
66
|
+
let payload;
|
|
67
|
+
try {
|
|
68
|
+
const json = Buffer.from(cursor, 'base64url').toString('utf8');
|
|
69
|
+
payload = JSON.parse(json);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
throw new ToolError('INVALID_ARGS', 'Malformed cursor (not valid base64url JSON)', {
|
|
73
|
+
cause: err,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (!payload || typeof payload !== 'object') {
|
|
77
|
+
throw new ToolError('INVALID_ARGS', 'Cursor payload is not an object');
|
|
78
|
+
}
|
|
79
|
+
const p = payload;
|
|
80
|
+
if (p.v !== CURSOR_VERSION) {
|
|
81
|
+
throw new ToolError('INVALID_ARGS', `Unsupported cursor version: ${String(p.v)}`);
|
|
82
|
+
}
|
|
83
|
+
if (typeof p.anchorReceivedAt !== 'string' || typeof p.anchorId !== 'string') {
|
|
84
|
+
throw new ToolError('INVALID_ARGS', 'Cursor missing anchor fields');
|
|
85
|
+
}
|
|
86
|
+
if (typeof p.filtersHash !== 'string') {
|
|
87
|
+
throw new ToolError('INVALID_ARGS', 'Cursor missing filtersHash');
|
|
88
|
+
}
|
|
89
|
+
const expected = hashFilters(currentFilters);
|
|
90
|
+
if (p.filtersHash !== expected) {
|
|
91
|
+
throw new ToolError('INVALID_ARGS', 'Filters changed between pages. Restart pagination without cursor.', { suggestedAction: 'Pass cursor=null and re-fetch the first page.' });
|
|
92
|
+
}
|
|
93
|
+
return p;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/lib/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Унифицированный класс ошибок для всех ELS-запросов и tool handler'ов.
|
|
3
|
+
*
|
|
4
|
+
* Мапится 1-в-1 в MCP-стандартный error shape:
|
|
5
|
+
* { isError: true, content: [{ type: 'text', text: <msg> }],
|
|
6
|
+
* _meta: { code, retryAfter?, suggestedAction? } }
|
|
7
|
+
*
|
|
8
|
+
* Коды (соответствуют todo/error-logs-service/mcp/03-tools-catalog.md §0.2):
|
|
9
|
+
* - RATE_LIMITED — 429 от ELS
|
|
10
|
+
* - UPSTREAM_UNAVAILABLE — 5xx от ELS (после retry)
|
|
11
|
+
* - INVALID_ARGS — 400 от ELS, либо локальная валидация
|
|
12
|
+
* - NOT_FOUND — 404 (отсутствует traceId, app и т.д.)
|
|
13
|
+
* - INSUFFICIENT_SCOPE — 403 от ELS
|
|
14
|
+
* - QUOTA_EXCEEDED — для AI-tools в будущем
|
|
15
|
+
* - INTERNAL — fallback для непредвиденных ситуаций
|
|
16
|
+
*/
|
|
17
|
+
export type ToolErrorCode = 'RATE_LIMITED' | 'UPSTREAM_UNAVAILABLE' | 'INVALID_ARGS' | 'NOT_FOUND' | 'INSUFFICIENT_SCOPE' | 'QUOTA_EXCEEDED' | 'TIER_QUOTA_EXCEEDED' | 'INTERNAL';
|
|
18
|
+
export declare class ToolError extends Error {
|
|
19
|
+
readonly code: ToolErrorCode;
|
|
20
|
+
readonly retryAfter?: number;
|
|
21
|
+
readonly suggestedAction?: string;
|
|
22
|
+
readonly meta?: Record<string, unknown>;
|
|
23
|
+
constructor(code: ToolErrorCode, message: string, options?: {
|
|
24
|
+
retryAfter?: number;
|
|
25
|
+
suggestedAction?: string;
|
|
26
|
+
meta?: Record<string, unknown>;
|
|
27
|
+
cause?: unknown;
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Сериализация в MCP-tool error response.
|
|
31
|
+
*/
|
|
32
|
+
toToolResult(): {
|
|
33
|
+
isError: true;
|
|
34
|
+
content: Array<{
|
|
35
|
+
type: 'text';
|
|
36
|
+
text: string;
|
|
37
|
+
}>;
|
|
38
|
+
structuredContent: Record<string, unknown>;
|
|
39
|
+
_meta: Record<string, unknown>;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Преобразовать HTTP-статус и тело ответа ELS в ToolError.
|
|
44
|
+
*
|
|
45
|
+
* `body` приходит как уже-распарсенный JSON (или string, если parse не удался).
|
|
46
|
+
* `retryAfterHeader` — содержимое заголовка Retry-After (секунды).
|
|
47
|
+
*/
|
|
48
|
+
export declare function mapHttpToToolError(status: number, body: unknown, retryAfterHeader?: string | null): ToolError;
|
|
49
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,aAAa,GACrB,cAAc,GACd,sBAAsB,GACtB,cAAc,GACd,WAAW,GACX,oBAAoB,GACpB,gBAAgB,GAChB,qBAAqB,GACrB,UAAU,CAAC;AAEf,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAgB,IAAI,EAAE,aAAa,CAAC;IACpC,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpC,SAAgB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAG7C,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;KACZ;IAcR;;OAEG;IACH,YAAY,IAAI;QACd,OAAO,EAAE,IAAI,CAAC;QACd,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC/C,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC;CAaF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,GAC/B,SAAS,CA4CX"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export class ToolError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
retryAfter;
|
|
4
|
+
suggestedAction;
|
|
5
|
+
meta;
|
|
6
|
+
constructor(code, message, options = {}) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'ToolError';
|
|
9
|
+
this.code = code;
|
|
10
|
+
if (typeof options.retryAfter === 'number')
|
|
11
|
+
this.retryAfter = options.retryAfter;
|
|
12
|
+
if (options.suggestedAction)
|
|
13
|
+
this.suggestedAction = options.suggestedAction;
|
|
14
|
+
if (options.meta)
|
|
15
|
+
this.meta = options.meta;
|
|
16
|
+
if (options.cause !== undefined) {
|
|
17
|
+
// Стандартный Error.cause — поддерживается Node 20+.
|
|
18
|
+
this.cause = options.cause;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Сериализация в MCP-tool error response.
|
|
23
|
+
*/
|
|
24
|
+
toToolResult() {
|
|
25
|
+
const _meta = { code: this.code };
|
|
26
|
+
if (typeof this.retryAfter === 'number')
|
|
27
|
+
_meta.retryAfter = this.retryAfter;
|
|
28
|
+
if (this.suggestedAction)
|
|
29
|
+
_meta.suggestedAction = this.suggestedAction;
|
|
30
|
+
if (this.meta)
|
|
31
|
+
Object.assign(_meta, this.meta);
|
|
32
|
+
return {
|
|
33
|
+
isError: true,
|
|
34
|
+
content: [{ type: 'text', text: `[${this.code}] ${this.message}` }],
|
|
35
|
+
structuredContent: { code: this.code, message: this.message, ...(this.meta ?? {}) },
|
|
36
|
+
_meta,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Преобразовать HTTP-статус и тело ответа ELS в ToolError.
|
|
42
|
+
*
|
|
43
|
+
* `body` приходит как уже-распарсенный JSON (или string, если parse не удался).
|
|
44
|
+
* `retryAfterHeader` — содержимое заголовка Retry-After (секунды).
|
|
45
|
+
*/
|
|
46
|
+
export function mapHttpToToolError(status, body, retryAfterHeader) {
|
|
47
|
+
const bodyAny = body;
|
|
48
|
+
const upstreamMessage = (typeof bodyAny?.message === 'string' && bodyAny.message) ||
|
|
49
|
+
(typeof bodyAny?.error === 'string' && bodyAny.error) ||
|
|
50
|
+
`Upstream ELS returned ${status}`;
|
|
51
|
+
if (status === 429) {
|
|
52
|
+
const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : undefined;
|
|
53
|
+
return new ToolError('RATE_LIMITED', upstreamMessage, {
|
|
54
|
+
retryAfter: Number.isFinite(retryAfter) ? retryAfter : 60,
|
|
55
|
+
suggestedAction: 'Wait and retry after the specified number of seconds.',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (status === 404) {
|
|
59
|
+
return new ToolError('NOT_FOUND', upstreamMessage);
|
|
60
|
+
}
|
|
61
|
+
if (status === 403) {
|
|
62
|
+
return new ToolError('INSUFFICIENT_SCOPE', upstreamMessage, {
|
|
63
|
+
suggestedAction: 'API-key lacks required scope. Use a key with broader access.',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (status === 401) {
|
|
67
|
+
return new ToolError('INSUFFICIENT_SCOPE', `Unauthorized: ${upstreamMessage}`, {
|
|
68
|
+
suggestedAction: 'Check ELS_API_KEY env var.',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (status >= 400 && status < 500) {
|
|
72
|
+
return new ToolError('INVALID_ARGS', upstreamMessage, { meta: { status } });
|
|
73
|
+
}
|
|
74
|
+
if (status >= 500) {
|
|
75
|
+
return new ToolError('UPSTREAM_UNAVAILABLE', upstreamMessage, {
|
|
76
|
+
retryAfter: 5,
|
|
77
|
+
suggestedAction: 'Upstream is temporarily unavailable; retry in a few seconds.',
|
|
78
|
+
meta: { status },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return new ToolError('INTERNAL', upstreamMessage, { meta: { status } });
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
|