@airmcp-dev/core 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/LICENSE +17 -0
- package/dist/config/defaults.d.ts +3 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +11 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +4 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +59 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +5 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/request-context.d.ts +4 -0
- package/dist/context/request-context.d.ts.map +1 -0
- package/dist/context/request-context.js +14 -0
- package/dist/context/request-context.js.map +1 -0
- package/dist/context/server-context.d.ts +12 -0
- package/dist/context/server-context.d.ts.map +1 -0
- package/dist/context/server-context.js +25 -0
- package/dist/context/server-context.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/after-hook.d.ts +4 -0
- package/dist/middleware/after-hook.d.ts.map +1 -0
- package/dist/middleware/after-hook.js +18 -0
- package/dist/middleware/after-hook.js.map +1 -0
- package/dist/middleware/before-hook.d.ts +4 -0
- package/dist/middleware/before-hook.d.ts.map +1 -0
- package/dist/middleware/before-hook.js +40 -0
- package/dist/middleware/before-hook.js.map +1 -0
- package/dist/middleware/chain.d.ts +11 -0
- package/dist/middleware/chain.d.ts.map +1 -0
- package/dist/middleware/chain.js +84 -0
- package/dist/middleware/chain.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +27 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +63 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/index.d.ts +7 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +9 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/meter-middleware.d.ts +19 -0
- package/dist/middleware/meter-middleware.d.ts.map +1 -0
- package/dist/middleware/meter-middleware.js +139 -0
- package/dist/middleware/meter-middleware.js.map +1 -0
- package/dist/middleware/shield-middleware.d.ts +16 -0
- package/dist/middleware/shield-middleware.d.ts.map +1 -0
- package/dist/middleware/shield-middleware.js +163 -0
- package/dist/middleware/shield-middleware.js.map +1 -0
- package/dist/plugin/builtin/auth.d.ts +16 -0
- package/dist/plugin/builtin/auth.d.ts.map +1 -0
- package/dist/plugin/builtin/auth.js +60 -0
- package/dist/plugin/builtin/auth.js.map +1 -0
- package/dist/plugin/builtin/cache.d.ts +12 -0
- package/dist/plugin/builtin/cache.d.ts.map +1 -0
- package/dist/plugin/builtin/cache.js +65 -0
- package/dist/plugin/builtin/cache.js.map +1 -0
- package/dist/plugin/builtin/circuit-breaker.d.ts +12 -0
- package/dist/plugin/builtin/circuit-breaker.d.ts.map +1 -0
- package/dist/plugin/builtin/circuit-breaker.js +76 -0
- package/dist/plugin/builtin/circuit-breaker.js.map +1 -0
- package/dist/plugin/builtin/cors.d.ts +12 -0
- package/dist/plugin/builtin/cors.d.ts.map +1 -0
- package/dist/plugin/builtin/cors.js +29 -0
- package/dist/plugin/builtin/cors.js.map +1 -0
- package/dist/plugin/builtin/dedup.d.ts +8 -0
- package/dist/plugin/builtin/dedup.d.ts.map +1 -0
- package/dist/plugin/builtin/dedup.js +64 -0
- package/dist/plugin/builtin/dedup.js.map +1 -0
- package/dist/plugin/builtin/dryrun.d.ts +12 -0
- package/dist/plugin/builtin/dryrun.d.ts.map +1 -0
- package/dist/plugin/builtin/dryrun.js +61 -0
- package/dist/plugin/builtin/dryrun.js.map +1 -0
- package/dist/plugin/builtin/fallback.d.ts +5 -0
- package/dist/plugin/builtin/fallback.d.ts.map +1 -0
- package/dist/plugin/builtin/fallback.js +42 -0
- package/dist/plugin/builtin/fallback.js.map +1 -0
- package/dist/plugin/builtin/i18n.d.ts +12 -0
- package/dist/plugin/builtin/i18n.d.ts.map +1 -0
- package/dist/plugin/builtin/i18n.js +51 -0
- package/dist/plugin/builtin/i18n.js.map +1 -0
- package/dist/plugin/builtin/logger-json.d.ts +12 -0
- package/dist/plugin/builtin/logger-json.d.ts.map +1 -0
- package/dist/plugin/builtin/logger-json.js +52 -0
- package/dist/plugin/builtin/logger-json.js.map +1 -0
- package/dist/plugin/builtin/logger.d.ts +3 -0
- package/dist/plugin/builtin/logger.d.ts.map +1 -0
- package/dist/plugin/builtin/logger.js +22 -0
- package/dist/plugin/builtin/logger.js.map +1 -0
- package/dist/plugin/builtin/metrics.d.ts +14 -0
- package/dist/plugin/builtin/metrics.d.ts.map +1 -0
- package/dist/plugin/builtin/metrics.js +56 -0
- package/dist/plugin/builtin/metrics.js.map +1 -0
- package/dist/plugin/builtin/queue.d.ts +12 -0
- package/dist/plugin/builtin/queue.d.ts.map +1 -0
- package/dist/plugin/builtin/queue.js +98 -0
- package/dist/plugin/builtin/queue.js.map +1 -0
- package/dist/plugin/builtin/ratelimit-per-user.d.ts +12 -0
- package/dist/plugin/builtin/ratelimit-per-user.d.ts.map +1 -0
- package/dist/plugin/builtin/ratelimit-per-user.js +45 -0
- package/dist/plugin/builtin/ratelimit-per-user.js.map +1 -0
- package/dist/plugin/builtin/retry.d.ts +12 -0
- package/dist/plugin/builtin/retry.d.ts.map +1 -0
- package/dist/plugin/builtin/retry.js +51 -0
- package/dist/plugin/builtin/retry.js.map +1 -0
- package/dist/plugin/builtin/sanitizer.d.ts +14 -0
- package/dist/plugin/builtin/sanitizer.d.ts.map +1 -0
- package/dist/plugin/builtin/sanitizer.js +55 -0
- package/dist/plugin/builtin/sanitizer.js.map +1 -0
- package/dist/plugin/builtin/timeout.d.ts +3 -0
- package/dist/plugin/builtin/timeout.d.ts.map +1 -0
- package/dist/plugin/builtin/timeout.js +30 -0
- package/dist/plugin/builtin/timeout.js.map +1 -0
- package/dist/plugin/builtin/transform.d.ts +11 -0
- package/dist/plugin/builtin/transform.d.ts.map +1 -0
- package/dist/plugin/builtin/transform.js +51 -0
- package/dist/plugin/builtin/transform.js.map +1 -0
- package/dist/plugin/builtin/validator.d.ts +9 -0
- package/dist/plugin/builtin/validator.d.ts.map +1 -0
- package/dist/plugin/builtin/validator.js +43 -0
- package/dist/plugin/builtin/validator.js.map +1 -0
- package/dist/plugin/builtin/webhook.d.ts +16 -0
- package/dist/plugin/builtin/webhook.d.ts.map +1 -0
- package/dist/plugin/builtin/webhook.js +78 -0
- package/dist/plugin/builtin/webhook.js.map +1 -0
- package/dist/plugin/index.d.ts +23 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +34 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/plugin-hook.d.ts +11 -0
- package/dist/plugin/plugin-hook.d.ts.map +1 -0
- package/dist/plugin/plugin-hook.js +39 -0
- package/dist/plugin/plugin-hook.js.map +1 -0
- package/dist/plugin/plugin-manager.d.ts +22 -0
- package/dist/plugin/plugin-manager.d.ts.map +1 -0
- package/dist/plugin/plugin-manager.js +71 -0
- package/dist/plugin/plugin-manager.js.map +1 -0
- package/dist/plugin/plugin-schema.d.ts +6 -0
- package/dist/plugin/plugin-schema.d.ts.map +1 -0
- package/dist/plugin/plugin-schema.js +18 -0
- package/dist/plugin/plugin-schema.js.map +1 -0
- package/dist/prompt/define-prompt.d.ts +3 -0
- package/dist/prompt/define-prompt.d.ts.map +1 -0
- package/dist/prompt/define-prompt.js +17 -0
- package/dist/prompt/define-prompt.js.map +1 -0
- package/dist/prompt/index.d.ts +2 -0
- package/dist/prompt/index.d.ts.map +1 -0
- package/dist/prompt/index.js +4 -0
- package/dist/prompt/index.js.map +1 -0
- package/dist/resource/define-resource.d.ts +3 -0
- package/dist/resource/define-resource.d.ts.map +1 -0
- package/dist/resource/define-resource.js +19 -0
- package/dist/resource/define-resource.js.map +1 -0
- package/dist/resource/index.d.ts +3 -0
- package/dist/resource/index.d.ts.map +1 -0
- package/dist/resource/index.js +5 -0
- package/dist/resource/index.js.map +1 -0
- package/dist/resource/resource-template.d.ts +5 -0
- package/dist/resource/resource-template.d.ts.map +1 -0
- package/dist/resource/resource-template.js +17 -0
- package/dist/resource/resource-template.js.map +1 -0
- package/dist/server/define-server.d.ts +14 -0
- package/dist/server/define-server.d.ts.map +1 -0
- package/dist/server/define-server.js +175 -0
- package/dist/server/define-server.js.map +1 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lifecycle.d.ts +3 -0
- package/dist/server/lifecycle.d.ts.map +1 -0
- package/dist/server/lifecycle.js +32 -0
- package/dist/server/lifecycle.js.map +1 -0
- package/dist/server/server-runner.d.ts +42 -0
- package/dist/server/server-runner.d.ts.map +1 -0
- package/dist/server/server-runner.js +255 -0
- package/dist/server/server-runner.js.map +1 -0
- package/dist/storage/file-store.d.ts +25 -0
- package/dist/storage/file-store.d.ts.map +1 -0
- package/dist/storage/file-store.js +177 -0
- package/dist/storage/file-store.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/memory-store.d.ts +18 -0
- package/dist/storage/memory-store.d.ts.map +1 -0
- package/dist/storage/memory-store.js +80 -0
- package/dist/storage/memory-store.js.map +1 -0
- package/dist/storage/storage-adapter.d.ts +4 -0
- package/dist/storage/storage-adapter.d.ts.map +1 -0
- package/dist/storage/storage-adapter.js +32 -0
- package/dist/storage/storage-adapter.js.map +1 -0
- package/dist/telemetry/index.d.ts +3 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/telemetry.d.ts +56 -0
- package/dist/telemetry/telemetry.d.ts.map +1 -0
- package/dist/telemetry/telemetry.js +95 -0
- package/dist/telemetry/telemetry.js.map +1 -0
- package/dist/tool/define-tool.d.ts +23 -0
- package/dist/tool/define-tool.d.ts.map +1 -0
- package/dist/tool/define-tool.js +28 -0
- package/dist/tool/define-tool.js.map +1 -0
- package/dist/tool/index.d.ts +5 -0
- package/dist/tool/index.d.ts.map +1 -0
- package/dist/tool/index.js +6 -0
- package/dist/tool/index.js.map +1 -0
- package/dist/tool/tool-result.d.ts +10 -0
- package/dist/tool/tool-result.d.ts.map +1 -0
- package/dist/tool/tool-result.js +34 -0
- package/dist/tool/tool-result.js.map +1 -0
- package/dist/tool/tool-schema.d.ts +7 -0
- package/dist/tool/tool-schema.d.ts.map +1 -0
- package/dist/tool/tool-schema.js +97 -0
- package/dist/tool/tool-schema.js.map +1 -0
- package/dist/transport/auto-detect.d.ts +4 -0
- package/dist/transport/auto-detect.d.ts.map +1 -0
- package/dist/transport/auto-detect.js +21 -0
- package/dist/transport/auto-detect.js.map +1 -0
- package/dist/transport/http-adapter.d.ts +4 -0
- package/dist/transport/http-adapter.d.ts.map +1 -0
- package/dist/transport/http-adapter.js +10 -0
- package/dist/transport/http-adapter.js.map +1 -0
- package/dist/transport/index.d.ts +5 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +7 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/sse-adapter.d.ts +3 -0
- package/dist/transport/sse-adapter.d.ts.map +1 -0
- package/dist/transport/sse-adapter.js +8 -0
- package/dist/transport/sse-adapter.js.map +1 -0
- package/dist/transport/stdio-adapter.d.ts +3 -0
- package/dist/transport/stdio-adapter.d.ts.map +1 -0
- package/dist/transport/stdio-adapter.js +8 -0
- package/dist/transport/stdio-adapter.js.map +1 -0
- package/dist/types/config.d.ts +101 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/middleware.d.ts +48 -0
- package/dist/types/middleware.d.ts.map +1 -0
- package/dist/types/middleware.js +4 -0
- package/dist/types/middleware.js.map +1 -0
- package/dist/types/plugin-manifest.d.ts +59 -0
- package/dist/types/plugin-manifest.d.ts.map +1 -0
- package/dist/types/plugin-manifest.js +9 -0
- package/dist/types/plugin-manifest.js.map +1 -0
- package/dist/types/plugin.d.ts +50 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +4 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/types/prompt.d.ts +21 -0
- package/dist/types/prompt.d.ts.map +1 -0
- package/dist/types/prompt.js +4 -0
- package/dist/types/prompt.js.map +1 -0
- package/dist/types/resource.d.ts +25 -0
- package/dist/types/resource.d.ts.map +1 -0
- package/dist/types/resource.js +4 -0
- package/dist/types/resource.js.map +1 -0
- package/dist/types/server.d.ts +54 -0
- package/dist/types/server.d.ts.map +1 -0
- package/dist/types/server.js +4 -0
- package/dist/types/server.js.map +1 -0
- package/dist/types/storage.d.ts +40 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +4 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/tool.d.ts +54 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +4 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/types/transport.d.ts +12 -0
- package/dist/types/transport.d.ts.map +1 -0
- package/dist/types/transport.js +4 -0
- package/dist/types/transport.js.map +1 -0
- package/package.json +23 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AirPlugin } from '../../types/plugin.js';
|
|
2
|
+
interface CircuitBreakerOptions {
|
|
3
|
+
/** 연속 실패 임계값 (기본: 5) */
|
|
4
|
+
failureThreshold?: number;
|
|
5
|
+
/** 서킷 오픈 후 반개방까지 대기 시간 ms (기본: 30000) */
|
|
6
|
+
resetTimeoutMs?: number;
|
|
7
|
+
/** 도구별 개별 서킷 (기본: true) */
|
|
8
|
+
perTool?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function circuitBreakerPlugin(options?: CircuitBreakerOptions): AirPlugin;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/circuit-breaker.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAKvD,UAAU,qBAAqB;IAC7B,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAQD,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAmE/E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/circuit-breaker.ts
|
|
3
|
+
//
|
|
4
|
+
// 서킷 브레이커 플러그인.
|
|
5
|
+
// 연속 에러가 임계값을 넘으면 도구 호출을 차단(open).
|
|
6
|
+
// 일정 시간 후 반개방(half-open)으로 전환하여 재시도.
|
|
7
|
+
//
|
|
8
|
+
// @example
|
|
9
|
+
// defineServer({
|
|
10
|
+
// use: [circuitBreakerPlugin({
|
|
11
|
+
// failureThreshold: 5,
|
|
12
|
+
// resetTimeoutMs: 30_000,
|
|
13
|
+
// })],
|
|
14
|
+
// });
|
|
15
|
+
export function circuitBreakerPlugin(options) {
|
|
16
|
+
const threshold = options?.failureThreshold ?? 5;
|
|
17
|
+
const resetTimeout = options?.resetTimeoutMs ?? 30_000;
|
|
18
|
+
const perTool = options?.perTool !== false;
|
|
19
|
+
const circuits = new Map();
|
|
20
|
+
function getCircuit(key) {
|
|
21
|
+
if (!circuits.has(key)) {
|
|
22
|
+
circuits.set(key, { state: 'closed', failures: 0, lastFailureAt: 0 });
|
|
23
|
+
}
|
|
24
|
+
return circuits.get(key);
|
|
25
|
+
}
|
|
26
|
+
const middleware = {
|
|
27
|
+
name: 'air:circuit-breaker',
|
|
28
|
+
before: async (ctx) => {
|
|
29
|
+
const key = perTool ? ctx.tool.name : '_global';
|
|
30
|
+
const circuit = getCircuit(key);
|
|
31
|
+
// 반개방 전환 체크
|
|
32
|
+
if (circuit.state === 'open') {
|
|
33
|
+
if (Date.now() - circuit.lastFailureAt > resetTimeout) {
|
|
34
|
+
circuit.state = 'half-open';
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
return {
|
|
38
|
+
abort: true,
|
|
39
|
+
abortResponse: {
|
|
40
|
+
content: [{ type: 'text', text: `[CircuitBreaker] "${ctx.tool.name}" is temporarily unavailable (circuit open). Retry in ${Math.ceil((resetTimeout - (Date.now() - circuit.lastFailureAt)) / 1000)}s.` }],
|
|
41
|
+
isError: true,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
ctx.meta._circuitKey = key;
|
|
47
|
+
},
|
|
48
|
+
after: async (ctx) => {
|
|
49
|
+
const key = ctx.meta._circuitKey;
|
|
50
|
+
if (!key)
|
|
51
|
+
return;
|
|
52
|
+
const circuit = getCircuit(key);
|
|
53
|
+
// 성공하면 서킷 리셋
|
|
54
|
+
circuit.state = 'closed';
|
|
55
|
+
circuit.failures = 0;
|
|
56
|
+
},
|
|
57
|
+
onError: async (ctx, error) => {
|
|
58
|
+
const key = ctx.meta._circuitKey;
|
|
59
|
+
if (!key)
|
|
60
|
+
return undefined;
|
|
61
|
+
const circuit = getCircuit(key);
|
|
62
|
+
circuit.failures++;
|
|
63
|
+
circuit.lastFailureAt = Date.now();
|
|
64
|
+
if (circuit.failures >= threshold) {
|
|
65
|
+
circuit.state = 'open';
|
|
66
|
+
console.warn(`[air:circuit-breaker] "${ctx.tool.name}" circuit OPEN after ${circuit.failures} failures`);
|
|
67
|
+
}
|
|
68
|
+
return undefined; // 에러는 다음 핸들러에 위임
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
meta: { name: 'air:circuit-breaker', version: '1.0.0' },
|
|
73
|
+
middleware: [middleware],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../../src/plugin/builtin/circuit-breaker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AirPlugin } from '../../types/plugin.js';
|
|
2
|
+
interface CorsOptions {
|
|
3
|
+
/** 허용 origin (기본: '*') */
|
|
4
|
+
origins?: string[];
|
|
5
|
+
/** 허용 메서드 */
|
|
6
|
+
methods?: string[];
|
|
7
|
+
/** 허용 헤더 */
|
|
8
|
+
headers?: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function corsPlugin(options?: CorsOptions): AirPlugin;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/cors.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,UAAU,WAAW;IACnB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY;IACZ,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAiB3D"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/cors.ts
|
|
3
|
+
//
|
|
4
|
+
// CORS 헤더 플러그인.
|
|
5
|
+
// HTTP/SSE transport 사용 시 브라우저에서 접근 가능하게 CORS를 설정.
|
|
6
|
+
// 서버 상태에 CORS 설정을 저장하여 HTTP 핸들러에서 참조.
|
|
7
|
+
//
|
|
8
|
+
// @example
|
|
9
|
+
// defineServer({
|
|
10
|
+
// use: [corsPlugin({ origins: ['http://localhost:3000'] })],
|
|
11
|
+
// });
|
|
12
|
+
export function corsPlugin(options) {
|
|
13
|
+
const origins = options?.origins || ['*'];
|
|
14
|
+
const methods = options?.methods || ['GET', 'POST', 'OPTIONS', 'DELETE'];
|
|
15
|
+
const headers = options?.headers || ['Content-Type', 'Accept', 'Mcp-Session-Id'];
|
|
16
|
+
return {
|
|
17
|
+
meta: { name: 'air:cors', version: '1.0.0' },
|
|
18
|
+
hooks: {
|
|
19
|
+
onInit: async (ctx) => {
|
|
20
|
+
ctx.state._cors = {
|
|
21
|
+
origins,
|
|
22
|
+
methods: methods.join(', '),
|
|
23
|
+
headers: headers.join(', '),
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../../src/plugin/builtin/cors.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,4CAA4C;AAC5C,EAAE;AACF,gBAAgB;AAChB,mDAAmD;AACnD,sCAAsC;AACtC,EAAE;AACF,WAAW;AACX,mBAAmB;AACnB,iEAAiE;AACjE,QAAQ;AAaR,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAEjF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE;QAC5C,KAAK,EAAE;YACL,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACpB,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG;oBAChB,OAAO;oBACP,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC3B,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;iBAC5B,CAAC;YACJ,CAAC;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/dedup.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,YAAY;IACpB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAwD7D"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/dedup.ts
|
|
3
|
+
//
|
|
4
|
+
// 중복 호출 방지 플러그인.
|
|
5
|
+
// 같은 파라미터로 동시에 여러 호출이 오면 하나만 실행하고 나머지는 같은 결과를 공유.
|
|
6
|
+
// (Request Deduplication / Coalescing)
|
|
7
|
+
//
|
|
8
|
+
// @example
|
|
9
|
+
// defineServer({
|
|
10
|
+
// use: [dedupPlugin()],
|
|
11
|
+
// });
|
|
12
|
+
export function dedupPlugin(options) {
|
|
13
|
+
const windowMs = options?.windowMs ?? 1000;
|
|
14
|
+
const inflight = new Map();
|
|
15
|
+
function makeKey(toolName, params) {
|
|
16
|
+
return `${toolName}:${JSON.stringify(params, Object.keys(params).sort())}`;
|
|
17
|
+
}
|
|
18
|
+
// 주기적으로 만료된 항목 정리
|
|
19
|
+
setInterval(() => {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
for (const [key, entry] of inflight.entries()) {
|
|
22
|
+
if (now - entry.timestamp > windowMs * 2)
|
|
23
|
+
inflight.delete(key);
|
|
24
|
+
}
|
|
25
|
+
}, windowMs * 5);
|
|
26
|
+
const middleware = {
|
|
27
|
+
name: 'air:dedup',
|
|
28
|
+
before: async (ctx) => {
|
|
29
|
+
const key = makeKey(ctx.tool.name, ctx.params);
|
|
30
|
+
const existing = inflight.get(key);
|
|
31
|
+
if (existing && Date.now() - existing.timestamp < windowMs) {
|
|
32
|
+
// 동일 호출이 진행 중 — 결과를 공유
|
|
33
|
+
const result = await existing.promise;
|
|
34
|
+
ctx.meta._deduped = true;
|
|
35
|
+
return {
|
|
36
|
+
abort: true,
|
|
37
|
+
abortResponse: result,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// 새 호출 — inflight에 등록 (promise는 after에서 resolve)
|
|
41
|
+
let resolveInflight;
|
|
42
|
+
const promise = new Promise((r) => { resolveInflight = r; });
|
|
43
|
+
inflight.set(key, { promise, timestamp: Date.now() });
|
|
44
|
+
ctx.meta._dedupKey = key;
|
|
45
|
+
ctx.meta._dedupResolve = resolveInflight;
|
|
46
|
+
},
|
|
47
|
+
after: async (ctx) => {
|
|
48
|
+
if (ctx.meta._deduped)
|
|
49
|
+
return;
|
|
50
|
+
const key = ctx.meta._dedupKey;
|
|
51
|
+
const resolve = ctx.meta._dedupResolve;
|
|
52
|
+
if (key && resolve) {
|
|
53
|
+
resolve(ctx.result);
|
|
54
|
+
// 짧은 시간 유지 후 삭제
|
|
55
|
+
setTimeout(() => inflight.delete(key), windowMs);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
meta: { name: 'air:dedup', version: '1.0.0' },
|
|
61
|
+
middleware: [middleware],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=dedup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../../src/plugin/builtin/dedup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AirPlugin } from '../../types/plugin.js';
|
|
2
|
+
interface DryrunOptions {
|
|
3
|
+
/** 드라이런 활성화 (기본: false) */
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
/** 파라미터에 _dryrun=true 가 있으면 해당 호출만 드라이런 */
|
|
6
|
+
perCall?: boolean;
|
|
7
|
+
/** 커스텀 드라이런 응답 생성기 */
|
|
8
|
+
mockResponse?: (toolName: string, params: Record<string, any>) => any;
|
|
9
|
+
}
|
|
10
|
+
export declare function dryrunPlugin(options?: DryrunOptions): AirPlugin;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=dryrun.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dryrun.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/dryrun.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,aAAa;IACrB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sBAAsB;IACtB,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC;CACvE;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CA2C/D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/dryrun.ts
|
|
3
|
+
//
|
|
4
|
+
// 드라이런 플러그인.
|
|
5
|
+
// 실제 핸들러를 실행하지 않고 파라미터 검증 + 예상 결과만 반환.
|
|
6
|
+
// 테스트, CI, 스키마 검증에 사용.
|
|
7
|
+
//
|
|
8
|
+
// 사용 방법:
|
|
9
|
+
// 1. 전역 모드: dryrunPlugin({ enabled: true }) — 모든 호출을 드라이런
|
|
10
|
+
// 2. 환경변수: dryrunPlugin({ enabled: process.env.DRY_RUN === 'true' })
|
|
11
|
+
// 3. callTool API: server.callTool('name', { _dryrun: true }) — MCP 프로토콜 우회 시
|
|
12
|
+
//
|
|
13
|
+
// NOTE: MCP SDK가 스키마에 없는 파라미터를 제거하기 때문에
|
|
14
|
+
// perCall 모드는 MCP 프로토콜 경유(클라이언트→서버) 시 동작하지 않음.
|
|
15
|
+
// server.callTool() 직접 호출 시에만 perCall이 동작.
|
|
16
|
+
//
|
|
17
|
+
// @example
|
|
18
|
+
// defineServer({
|
|
19
|
+
// use: [dryrunPlugin({ enabled: process.env.DRY_RUN === 'true' })],
|
|
20
|
+
// });
|
|
21
|
+
export function dryrunPlugin(options) {
|
|
22
|
+
const globalEnabled = options?.enabled ?? false;
|
|
23
|
+
const perCall = options?.perCall ?? true;
|
|
24
|
+
const mockFn = options?.mockResponse;
|
|
25
|
+
const middleware = {
|
|
26
|
+
name: 'air:dryrun',
|
|
27
|
+
before: async (ctx) => {
|
|
28
|
+
const isDryrun = globalEnabled || (perCall && (ctx.params._dryrun === true || ctx.params._dryrun === 'true'));
|
|
29
|
+
if (!isDryrun)
|
|
30
|
+
return;
|
|
31
|
+
// _dryrun 파라미터 제거
|
|
32
|
+
const { _dryrun, ...cleanParams } = ctx.params;
|
|
33
|
+
const response = mockFn
|
|
34
|
+
? mockFn(ctx.tool.name, cleanParams)
|
|
35
|
+
: {
|
|
36
|
+
dryrun: true,
|
|
37
|
+
tool: ctx.tool.name,
|
|
38
|
+
params: cleanParams,
|
|
39
|
+
description: ctx.tool.description,
|
|
40
|
+
schema: ctx.tool.params
|
|
41
|
+
? Object.entries(ctx.tool.params).map(([k, v]) => ({
|
|
42
|
+
name: k,
|
|
43
|
+
type: typeof v === 'string' ? v : v.type || 'any',
|
|
44
|
+
provided: k in cleanParams,
|
|
45
|
+
value: cleanParams[k] ?? null,
|
|
46
|
+
}))
|
|
47
|
+
: [],
|
|
48
|
+
message: `[Dryrun] "${ctx.tool.name}" would be called with: ${JSON.stringify(cleanParams)}`,
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
abort: true,
|
|
52
|
+
abortResponse: typeof response === 'string' ? response : JSON.stringify(response, null, 2),
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
meta: { name: 'air:dryrun', version: '1.0.0' },
|
|
58
|
+
middleware: [middleware],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=dryrun.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dryrun.js","sourceRoot":"","sources":["../../../src/plugin/builtin/dryrun.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,8CAA8C;AAC9C,EAAE;AACF,aAAa;AACb,uCAAuC;AACvC,uBAAuB;AACvB,EAAE;AACF,SAAS;AACT,4DAA4D;AAC5D,uEAAuE;AACvE,gFAAgF;AAChF,EAAE;AACF,wCAAwC;AACxC,+CAA+C;AAC/C,2CAA2C;AAC3C,EAAE;AACF,WAAW;AACX,mBAAmB;AACnB,wEAAwE;AACxE,QAAQ;AAcR,MAAM,UAAU,YAAY,CAAC,OAAuB;IAClD,MAAM,aAAa,GAAG,OAAO,EAAE,OAAO,IAAI,KAAK,CAAC;IAChD,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,EAAE,YAAY,CAAC;IAErC,MAAM,UAAU,GAAkB;QAChC,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,MAAM,QAAQ,GAAG,aAAa,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC;YAC9G,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAEtB,kBAAkB;YAClB,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;YAE/C,MAAM,QAAQ,GAAG,MAAM;gBACrB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;gBACpC,CAAC,CAAC;oBACE,MAAM,EAAE,IAAI;oBACZ,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;oBACnB,MAAM,EAAE,WAAW;oBACnB,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW;oBACjC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;wBACrB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC/C,IAAI,EAAE,CAAC;4BACP,IAAI,EAAE,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAS,CAAC,IAAI,IAAI,KAAK;4BAC1D,QAAQ,EAAE,CAAC,IAAI,WAAW;4BAC1B,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI;yBAC9B,CAAC,CAAC;wBACL,CAAC,CAAC,EAAE;oBACN,OAAO,EAAE,aAAa,GAAG,CAAC,IAAI,CAAC,IAAI,2BAA2B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE;iBAC5F,CAAC;YAEN,OAAO;gBACL,KAAK,EAAE,IAAI;gBACX,aAAa,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;aAC3F,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE;QAC9C,UAAU,EAAE,CAAC,UAAU,CAAC;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/fallback.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1C,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,CA6BhE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/fallback.ts
|
|
3
|
+
//
|
|
4
|
+
// 도구 폴백 플러그인.
|
|
5
|
+
// 특정 도구가 에러나면 대체 도구를 자동으로 호출.
|
|
6
|
+
//
|
|
7
|
+
// @example
|
|
8
|
+
// defineServer({
|
|
9
|
+
// use: [fallbackPlugin({
|
|
10
|
+
// 'search_primary': 'search_backup',
|
|
11
|
+
// 'fetch_api': 'fetch_cached',
|
|
12
|
+
// })],
|
|
13
|
+
// });
|
|
14
|
+
export function fallbackPlugin(fallbacks) {
|
|
15
|
+
const middleware = {
|
|
16
|
+
name: 'air:fallback',
|
|
17
|
+
onError: async (ctx, error) => {
|
|
18
|
+
const fallbackTool = fallbacks[ctx.tool.name];
|
|
19
|
+
if (!fallbackTool)
|
|
20
|
+
return undefined;
|
|
21
|
+
console.warn(`[air:fallback] "${ctx.tool.name}" failed, trying "${fallbackTool}"`);
|
|
22
|
+
// 같은 서버의 도구 목록에서 폴백 도구를 찾아 실행
|
|
23
|
+
// ctx.meta에 서버의 callTool이 있으면 사용
|
|
24
|
+
if (ctx.meta._serverCallTool) {
|
|
25
|
+
try {
|
|
26
|
+
const result = await ctx.meta._serverCallTool(fallbackTool, ctx.params);
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
catch (fallbackError) {
|
|
30
|
+
console.error(`[air:fallback] Fallback "${fallbackTool}" also failed: ${fallbackError.message}`);
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
meta: { name: 'air:fallback', version: '1.0.0' },
|
|
39
|
+
middleware: [middleware],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback.js","sourceRoot":"","sources":["../../../src/plugin/builtin/fallback.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,gDAAgD;AAChD,EAAE;AACF,cAAc;AACd,8BAA8B;AAC9B,EAAE;AACF,WAAW;AACX,mBAAmB;AACnB,6BAA6B;AAC7B,2CAA2C;AAC3C,qCAAqC;AACrC,WAAW;AACX,QAAQ;AAOR,MAAM,UAAU,cAAc,CAAC,SAAsB;IACnD,MAAM,UAAU,GAAkB;QAChC,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;YAC5B,MAAM,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,YAAY;gBAAE,OAAO,SAAS,CAAC;YAEpC,OAAO,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,IAAI,CAAC,IAAI,qBAAqB,YAAY,GAAG,CAAC,CAAC;YAEnF,8BAA8B;YAC9B,iCAAiC;YACjC,IAAI,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC7B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;oBACxE,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,aAAkB,EAAE,CAAC;oBAC5B,OAAO,CAAC,KAAK,CAAC,4BAA4B,YAAY,kBAAkB,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;oBACjG,OAAO,SAAS,CAAC;gBACnB,CAAC;YACH,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE;QAChD,UAAU,EAAE,CAAC,UAAU,CAAC;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AirPlugin } from '../../types/plugin.js';
|
|
2
|
+
interface I18nOptions {
|
|
3
|
+
/** 기본 언어 (기본: 'en') */
|
|
4
|
+
defaultLang?: string;
|
|
5
|
+
/** 번역 사전: key → { lang: text } */
|
|
6
|
+
translations?: Record<string, Record<string, string>>;
|
|
7
|
+
/** 언어 감지 파라미터 이름 (기본: '_lang') */
|
|
8
|
+
langParam?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function i18nPlugin(options?: I18nOptions): AirPlugin;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/i18n.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,WAAW;IACnB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAmC3D"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/i18n.ts
|
|
3
|
+
//
|
|
4
|
+
// 다국어 응답 변환 플러그인.
|
|
5
|
+
// 도구 응답을 사용자의 언어에 맞게 변환.
|
|
6
|
+
// 번역 사전을 등록하면 자동으로 매칭.
|
|
7
|
+
//
|
|
8
|
+
// @example
|
|
9
|
+
// defineServer({
|
|
10
|
+
// use: [i18nPlugin({
|
|
11
|
+
// defaultLang: 'ko',
|
|
12
|
+
// translations: {
|
|
13
|
+
// 'saved': { ko: '저장 완료', en: 'Saved', ja: '保存完了' },
|
|
14
|
+
// 'not_found': { ko: '찾을 수 없습니다', en: 'Not found', ja: '見つかりません' },
|
|
15
|
+
// },
|
|
16
|
+
// })],
|
|
17
|
+
// });
|
|
18
|
+
export function i18nPlugin(options) {
|
|
19
|
+
const defaultLang = options?.defaultLang ?? 'en';
|
|
20
|
+
const translations = options?.translations ?? {};
|
|
21
|
+
const langParam = options?.langParam ?? '_lang';
|
|
22
|
+
function translate(text, lang) {
|
|
23
|
+
let result = text;
|
|
24
|
+
for (const [key, dict] of Object.entries(translations)) {
|
|
25
|
+
const translated = dict[lang] || dict[defaultLang] || key;
|
|
26
|
+
result = result.replaceAll(`{{${key}}}`, translated);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
const middleware = {
|
|
31
|
+
name: 'air:i18n',
|
|
32
|
+
before: async (ctx) => {
|
|
33
|
+
// 언어 파라미터를 meta에 저장하고 params에서 제거
|
|
34
|
+
const lang = ctx.params[langParam] || defaultLang;
|
|
35
|
+
ctx.meta._lang = lang;
|
|
36
|
+
const { [langParam]: _, ...cleanParams } = ctx.params;
|
|
37
|
+
return { params: cleanParams };
|
|
38
|
+
},
|
|
39
|
+
after: async (ctx) => {
|
|
40
|
+
const lang = ctx.meta._lang || defaultLang;
|
|
41
|
+
if (typeof ctx.result === 'string') {
|
|
42
|
+
ctx.result = translate(ctx.result, lang);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
meta: { name: 'air:i18n', version: '1.0.0' },
|
|
48
|
+
middleware: [middleware],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=i18n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../../src/plugin/builtin/i18n.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,4CAA4C;AAC5C,EAAE;AACF,kBAAkB;AAClB,yBAAyB;AACzB,uBAAuB;AACvB,EAAE;AACF,WAAW;AACX,mBAAmB;AACnB,yBAAyB;AACzB,2BAA2B;AAC3B,wBAAwB;AACxB,6DAA6D;AAC7D,4EAA4E;AAC5E,WAAW;AACX,WAAW;AACX,QAAQ;AAcR,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC;IACjD,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,OAAO,CAAC;IAEhD,SAAS,SAAS,CAAC,IAAY,EAAE,IAAY;QAC3C,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACvD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC;YAC1D,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,UAAU,GAAkB;QAChC,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,kCAAkC;YAClC,MAAM,IAAI,GAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAY,IAAI,WAAW,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YACtB,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;YACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACjC,CAAC;QACD,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACnB,MAAM,IAAI,GAAI,GAAG,CAAC,IAAI,CAAC,KAAgB,IAAI,WAAW,CAAC;YACvD,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACnC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;KACF,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE;QAC5C,UAAU,EAAE,CAAC,UAAU,CAAC;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AirPlugin } from '../../types/plugin.js';
|
|
2
|
+
interface JsonLoggerOptions {
|
|
3
|
+
/** 출력 대상 (기본: 'stderr') */
|
|
4
|
+
output?: 'stderr' | 'stdout';
|
|
5
|
+
/** 추가 필드 */
|
|
6
|
+
extraFields?: Record<string, any>;
|
|
7
|
+
/** 파라미터를 로그에 포함할지 (기본: false) */
|
|
8
|
+
logParams?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function jsonLoggerPlugin(options?: JsonLoggerOptions): AirPlugin;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=logger-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-json.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/logger-json.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,iBAAiB;IACzB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,YAAY;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,iCAAiC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAyCvE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/logger-json.ts
|
|
3
|
+
//
|
|
4
|
+
// JSON 구조화 로깅 플러그인.
|
|
5
|
+
// 프로덕션 환경에서 JSON 형태로 도구 호출 로그를 출력.
|
|
6
|
+
// ELK, Datadog, CloudWatch 등 로그 수집기와 호환.
|
|
7
|
+
//
|
|
8
|
+
// @example
|
|
9
|
+
// defineServer({
|
|
10
|
+
// use: [jsonLoggerPlugin({ output: 'stderr' })],
|
|
11
|
+
// });
|
|
12
|
+
export function jsonLoggerPlugin(options) {
|
|
13
|
+
const logFn = options?.output === 'stdout' ? console.log : console.error;
|
|
14
|
+
const extra = options?.extraFields || {};
|
|
15
|
+
const logParams = options?.logParams ?? false;
|
|
16
|
+
const middleware = {
|
|
17
|
+
name: 'air:json-logger',
|
|
18
|
+
after: async (ctx) => {
|
|
19
|
+
const entry = {
|
|
20
|
+
level: 'info',
|
|
21
|
+
event: 'tool.call',
|
|
22
|
+
tool: ctx.tool.name,
|
|
23
|
+
duration_ms: ctx.duration,
|
|
24
|
+
request_id: ctx.requestId,
|
|
25
|
+
server: ctx.serverName,
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
...(logParams ? { params: ctx.params } : {}),
|
|
28
|
+
...extra,
|
|
29
|
+
};
|
|
30
|
+
logFn(JSON.stringify(entry));
|
|
31
|
+
},
|
|
32
|
+
onError: async (ctx, error) => {
|
|
33
|
+
const entry = {
|
|
34
|
+
level: 'error',
|
|
35
|
+
event: 'tool.error',
|
|
36
|
+
tool: ctx.tool.name,
|
|
37
|
+
error: error.message,
|
|
38
|
+
request_id: ctx.requestId,
|
|
39
|
+
server: ctx.serverName,
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
...extra,
|
|
42
|
+
};
|
|
43
|
+
logFn(JSON.stringify(entry));
|
|
44
|
+
return undefined;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
meta: { name: 'air:json-logger', version: '1.0.0' },
|
|
49
|
+
middleware: [middleware],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=logger-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-json.js","sourceRoot":"","sources":["../../../src/plugin/builtin/logger-json.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,mDAAmD;AACnD,EAAE;AACF,oBAAoB;AACpB,mCAAmC;AACnC,yCAAyC;AACzC,EAAE;AACF,WAAW;AACX,mBAAmB;AACnB,qDAAqD;AACrD,QAAQ;AAcR,MAAM,UAAU,gBAAgB,CAAC,OAA2B;IAC1D,MAAM,KAAK,GAAG,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,KAAK,CAAC;IAE9C,MAAM,UAAU,GAAkB;QAChC,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACnB,MAAM,KAAK,GAAG;gBACZ,KAAK,EAAE,MAAM;gBACb,KAAK,EAAE,WAAW;gBAClB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;gBACnB,WAAW,EAAE,GAAG,CAAC,QAAQ;gBACzB,UAAU,EAAE,GAAG,CAAC,SAAS;gBACzB,MAAM,EAAE,GAAG,CAAC,UAAU;gBACtB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5C,GAAG,KAAK;aACT,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;YAC5B,MAAM,KAAK,GAAG;gBACZ,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,YAAY;gBACnB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;gBACnB,KAAK,EAAE,KAAK,CAAC,OAAO;gBACpB,UAAU,EAAE,GAAG,CAAC,SAAS;gBACzB,MAAM,EAAE,GAAG,CAAC,UAAU;gBACtB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,GAAG,KAAK;aACT,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,EAAE;QACnD,UAAU,EAAE,CAAC,UAAU,CAAC;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/logger.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,wBAAgB,mBAAmB,CAAC,KAAK,GAAE,MAAe,GAAG,SAAS,CAiBrE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
|
|
2
|
+
// @airmcp-dev/core — plugin/builtin/logger.ts
|
|
3
|
+
// 내장 로깅 플러그인 — core만 설치해도 기본 로깅 동작
|
|
4
|
+
import { loggingMiddleware } from '../../middleware/after-hook.js';
|
|
5
|
+
export function builtinLoggerPlugin(level = 'info') {
|
|
6
|
+
const shouldLog = (msgLevel) => {
|
|
7
|
+
const levels = ['debug', 'info', 'warn', 'error', 'silent'];
|
|
8
|
+
return levels.indexOf(msgLevel) >= levels.indexOf(level);
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
meta: { name: 'air:builtin-logger', version: '0.1.0', description: 'Built-in logging' },
|
|
12
|
+
middleware: [
|
|
13
|
+
loggingMiddleware((msg) => {
|
|
14
|
+
if (shouldLog('info')) {
|
|
15
|
+
const ts = new Date().toISOString().slice(11, 23);
|
|
16
|
+
console.log(`${ts} ${msg}`);
|
|
17
|
+
}
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/plugin/builtin/logger.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,8CAA8C;AAC9C,mCAAmC;AAGnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,MAAM,UAAU,mBAAmB,CAAC,QAAgB,MAAM;IACxD,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE;QACvF,UAAU,EAAE;YACV,iBAAiB,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxB,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;oBACtB,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBAClD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC,CAAC;SACH;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AirPlugin } from '../../types/plugin.js';
|
|
2
|
+
interface ToolMetric {
|
|
3
|
+
calls: number;
|
|
4
|
+
errors: number;
|
|
5
|
+
totalDuration: number;
|
|
6
|
+
lastCalledAt: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function getMetrics(): Record<string, ToolMetric & {
|
|
9
|
+
avgDuration: number;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function resetMetrics(): void;
|
|
12
|
+
export declare function builtinMetricsPlugin(): AirPlugin;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/metrics.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CASjF;AAED,wBAAgB,YAAY,SAE3B;AAED,wBAAgB,oBAAoB,IAAI,SAAS,CAsChD"}
|