@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.
Files changed (290) hide show
  1. package/LICENSE +17 -0
  2. package/dist/config/defaults.d.ts +3 -0
  3. package/dist/config/defaults.d.ts.map +1 -0
  4. package/dist/config/defaults.js +11 -0
  5. package/dist/config/defaults.js.map +1 -0
  6. package/dist/config/index.d.ts +3 -0
  7. package/dist/config/index.d.ts.map +1 -0
  8. package/dist/config/index.js +5 -0
  9. package/dist/config/index.js.map +1 -0
  10. package/dist/config/loader.d.ts +4 -0
  11. package/dist/config/loader.d.ts.map +1 -0
  12. package/dist/config/loader.js +59 -0
  13. package/dist/config/loader.js.map +1 -0
  14. package/dist/context/index.d.ts +3 -0
  15. package/dist/context/index.d.ts.map +1 -0
  16. package/dist/context/index.js +5 -0
  17. package/dist/context/index.js.map +1 -0
  18. package/dist/context/request-context.d.ts +4 -0
  19. package/dist/context/request-context.d.ts.map +1 -0
  20. package/dist/context/request-context.js +14 -0
  21. package/dist/context/request-context.js.map +1 -0
  22. package/dist/context/server-context.d.ts +12 -0
  23. package/dist/context/server-context.d.ts.map +1 -0
  24. package/dist/context/server-context.js +25 -0
  25. package/dist/context/server-context.js.map +1 -0
  26. package/dist/index.d.ts +47 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +62 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/middleware/after-hook.d.ts +4 -0
  31. package/dist/middleware/after-hook.d.ts.map +1 -0
  32. package/dist/middleware/after-hook.js +18 -0
  33. package/dist/middleware/after-hook.js.map +1 -0
  34. package/dist/middleware/before-hook.d.ts +4 -0
  35. package/dist/middleware/before-hook.d.ts.map +1 -0
  36. package/dist/middleware/before-hook.js +40 -0
  37. package/dist/middleware/before-hook.js.map +1 -0
  38. package/dist/middleware/chain.d.ts +11 -0
  39. package/dist/middleware/chain.d.ts.map +1 -0
  40. package/dist/middleware/chain.js +84 -0
  41. package/dist/middleware/chain.js.map +1 -0
  42. package/dist/middleware/error-handler.d.ts +27 -0
  43. package/dist/middleware/error-handler.d.ts.map +1 -0
  44. package/dist/middleware/error-handler.js +63 -0
  45. package/dist/middleware/error-handler.js.map +1 -0
  46. package/dist/middleware/index.d.ts +7 -0
  47. package/dist/middleware/index.d.ts.map +1 -0
  48. package/dist/middleware/index.js +9 -0
  49. package/dist/middleware/index.js.map +1 -0
  50. package/dist/middleware/meter-middleware.d.ts +19 -0
  51. package/dist/middleware/meter-middleware.d.ts.map +1 -0
  52. package/dist/middleware/meter-middleware.js +139 -0
  53. package/dist/middleware/meter-middleware.js.map +1 -0
  54. package/dist/middleware/shield-middleware.d.ts +16 -0
  55. package/dist/middleware/shield-middleware.d.ts.map +1 -0
  56. package/dist/middleware/shield-middleware.js +163 -0
  57. package/dist/middleware/shield-middleware.js.map +1 -0
  58. package/dist/plugin/builtin/auth.d.ts +16 -0
  59. package/dist/plugin/builtin/auth.d.ts.map +1 -0
  60. package/dist/plugin/builtin/auth.js +60 -0
  61. package/dist/plugin/builtin/auth.js.map +1 -0
  62. package/dist/plugin/builtin/cache.d.ts +12 -0
  63. package/dist/plugin/builtin/cache.d.ts.map +1 -0
  64. package/dist/plugin/builtin/cache.js +65 -0
  65. package/dist/plugin/builtin/cache.js.map +1 -0
  66. package/dist/plugin/builtin/circuit-breaker.d.ts +12 -0
  67. package/dist/plugin/builtin/circuit-breaker.d.ts.map +1 -0
  68. package/dist/plugin/builtin/circuit-breaker.js +76 -0
  69. package/dist/plugin/builtin/circuit-breaker.js.map +1 -0
  70. package/dist/plugin/builtin/cors.d.ts +12 -0
  71. package/dist/plugin/builtin/cors.d.ts.map +1 -0
  72. package/dist/plugin/builtin/cors.js +29 -0
  73. package/dist/plugin/builtin/cors.js.map +1 -0
  74. package/dist/plugin/builtin/dedup.d.ts +8 -0
  75. package/dist/plugin/builtin/dedup.d.ts.map +1 -0
  76. package/dist/plugin/builtin/dedup.js +64 -0
  77. package/dist/plugin/builtin/dedup.js.map +1 -0
  78. package/dist/plugin/builtin/dryrun.d.ts +12 -0
  79. package/dist/plugin/builtin/dryrun.d.ts.map +1 -0
  80. package/dist/plugin/builtin/dryrun.js +61 -0
  81. package/dist/plugin/builtin/dryrun.js.map +1 -0
  82. package/dist/plugin/builtin/fallback.d.ts +5 -0
  83. package/dist/plugin/builtin/fallback.d.ts.map +1 -0
  84. package/dist/plugin/builtin/fallback.js +42 -0
  85. package/dist/plugin/builtin/fallback.js.map +1 -0
  86. package/dist/plugin/builtin/i18n.d.ts +12 -0
  87. package/dist/plugin/builtin/i18n.d.ts.map +1 -0
  88. package/dist/plugin/builtin/i18n.js +51 -0
  89. package/dist/plugin/builtin/i18n.js.map +1 -0
  90. package/dist/plugin/builtin/logger-json.d.ts +12 -0
  91. package/dist/plugin/builtin/logger-json.d.ts.map +1 -0
  92. package/dist/plugin/builtin/logger-json.js +52 -0
  93. package/dist/plugin/builtin/logger-json.js.map +1 -0
  94. package/dist/plugin/builtin/logger.d.ts +3 -0
  95. package/dist/plugin/builtin/logger.d.ts.map +1 -0
  96. package/dist/plugin/builtin/logger.js +22 -0
  97. package/dist/plugin/builtin/logger.js.map +1 -0
  98. package/dist/plugin/builtin/metrics.d.ts +14 -0
  99. package/dist/plugin/builtin/metrics.d.ts.map +1 -0
  100. package/dist/plugin/builtin/metrics.js +56 -0
  101. package/dist/plugin/builtin/metrics.js.map +1 -0
  102. package/dist/plugin/builtin/queue.d.ts +12 -0
  103. package/dist/plugin/builtin/queue.d.ts.map +1 -0
  104. package/dist/plugin/builtin/queue.js +98 -0
  105. package/dist/plugin/builtin/queue.js.map +1 -0
  106. package/dist/plugin/builtin/ratelimit-per-user.d.ts +12 -0
  107. package/dist/plugin/builtin/ratelimit-per-user.d.ts.map +1 -0
  108. package/dist/plugin/builtin/ratelimit-per-user.js +45 -0
  109. package/dist/plugin/builtin/ratelimit-per-user.js.map +1 -0
  110. package/dist/plugin/builtin/retry.d.ts +12 -0
  111. package/dist/plugin/builtin/retry.d.ts.map +1 -0
  112. package/dist/plugin/builtin/retry.js +51 -0
  113. package/dist/plugin/builtin/retry.js.map +1 -0
  114. package/dist/plugin/builtin/sanitizer.d.ts +14 -0
  115. package/dist/plugin/builtin/sanitizer.d.ts.map +1 -0
  116. package/dist/plugin/builtin/sanitizer.js +55 -0
  117. package/dist/plugin/builtin/sanitizer.js.map +1 -0
  118. package/dist/plugin/builtin/timeout.d.ts +3 -0
  119. package/dist/plugin/builtin/timeout.d.ts.map +1 -0
  120. package/dist/plugin/builtin/timeout.js +30 -0
  121. package/dist/plugin/builtin/timeout.js.map +1 -0
  122. package/dist/plugin/builtin/transform.d.ts +11 -0
  123. package/dist/plugin/builtin/transform.d.ts.map +1 -0
  124. package/dist/plugin/builtin/transform.js +51 -0
  125. package/dist/plugin/builtin/transform.js.map +1 -0
  126. package/dist/plugin/builtin/validator.d.ts +9 -0
  127. package/dist/plugin/builtin/validator.d.ts.map +1 -0
  128. package/dist/plugin/builtin/validator.js +43 -0
  129. package/dist/plugin/builtin/validator.js.map +1 -0
  130. package/dist/plugin/builtin/webhook.d.ts +16 -0
  131. package/dist/plugin/builtin/webhook.d.ts.map +1 -0
  132. package/dist/plugin/builtin/webhook.js +78 -0
  133. package/dist/plugin/builtin/webhook.js.map +1 -0
  134. package/dist/plugin/index.d.ts +23 -0
  135. package/dist/plugin/index.d.ts.map +1 -0
  136. package/dist/plugin/index.js +34 -0
  137. package/dist/plugin/index.js.map +1 -0
  138. package/dist/plugin/plugin-hook.d.ts +11 -0
  139. package/dist/plugin/plugin-hook.d.ts.map +1 -0
  140. package/dist/plugin/plugin-hook.js +39 -0
  141. package/dist/plugin/plugin-hook.js.map +1 -0
  142. package/dist/plugin/plugin-manager.d.ts +22 -0
  143. package/dist/plugin/plugin-manager.d.ts.map +1 -0
  144. package/dist/plugin/plugin-manager.js +71 -0
  145. package/dist/plugin/plugin-manager.js.map +1 -0
  146. package/dist/plugin/plugin-schema.d.ts +6 -0
  147. package/dist/plugin/plugin-schema.d.ts.map +1 -0
  148. package/dist/plugin/plugin-schema.js +18 -0
  149. package/dist/plugin/plugin-schema.js.map +1 -0
  150. package/dist/prompt/define-prompt.d.ts +3 -0
  151. package/dist/prompt/define-prompt.d.ts.map +1 -0
  152. package/dist/prompt/define-prompt.js +17 -0
  153. package/dist/prompt/define-prompt.js.map +1 -0
  154. package/dist/prompt/index.d.ts +2 -0
  155. package/dist/prompt/index.d.ts.map +1 -0
  156. package/dist/prompt/index.js +4 -0
  157. package/dist/prompt/index.js.map +1 -0
  158. package/dist/resource/define-resource.d.ts +3 -0
  159. package/dist/resource/define-resource.d.ts.map +1 -0
  160. package/dist/resource/define-resource.js +19 -0
  161. package/dist/resource/define-resource.js.map +1 -0
  162. package/dist/resource/index.d.ts +3 -0
  163. package/dist/resource/index.d.ts.map +1 -0
  164. package/dist/resource/index.js +5 -0
  165. package/dist/resource/index.js.map +1 -0
  166. package/dist/resource/resource-template.d.ts +5 -0
  167. package/dist/resource/resource-template.d.ts.map +1 -0
  168. package/dist/resource/resource-template.js +17 -0
  169. package/dist/resource/resource-template.js.map +1 -0
  170. package/dist/server/define-server.d.ts +14 -0
  171. package/dist/server/define-server.d.ts.map +1 -0
  172. package/dist/server/define-server.js +175 -0
  173. package/dist/server/define-server.js.map +1 -0
  174. package/dist/server/index.d.ts +4 -0
  175. package/dist/server/index.d.ts.map +1 -0
  176. package/dist/server/index.js +6 -0
  177. package/dist/server/index.js.map +1 -0
  178. package/dist/server/lifecycle.d.ts +3 -0
  179. package/dist/server/lifecycle.d.ts.map +1 -0
  180. package/dist/server/lifecycle.js +32 -0
  181. package/dist/server/lifecycle.js.map +1 -0
  182. package/dist/server/server-runner.d.ts +42 -0
  183. package/dist/server/server-runner.d.ts.map +1 -0
  184. package/dist/server/server-runner.js +255 -0
  185. package/dist/server/server-runner.js.map +1 -0
  186. package/dist/storage/file-store.d.ts +25 -0
  187. package/dist/storage/file-store.d.ts.map +1 -0
  188. package/dist/storage/file-store.js +177 -0
  189. package/dist/storage/file-store.js.map +1 -0
  190. package/dist/storage/index.d.ts +4 -0
  191. package/dist/storage/index.d.ts.map +1 -0
  192. package/dist/storage/index.js +6 -0
  193. package/dist/storage/index.js.map +1 -0
  194. package/dist/storage/memory-store.d.ts +18 -0
  195. package/dist/storage/memory-store.d.ts.map +1 -0
  196. package/dist/storage/memory-store.js +80 -0
  197. package/dist/storage/memory-store.js.map +1 -0
  198. package/dist/storage/storage-adapter.d.ts +4 -0
  199. package/dist/storage/storage-adapter.d.ts.map +1 -0
  200. package/dist/storage/storage-adapter.js +32 -0
  201. package/dist/storage/storage-adapter.js.map +1 -0
  202. package/dist/telemetry/index.d.ts +3 -0
  203. package/dist/telemetry/index.d.ts.map +1 -0
  204. package/dist/telemetry/index.js +4 -0
  205. package/dist/telemetry/index.js.map +1 -0
  206. package/dist/telemetry/telemetry.d.ts +56 -0
  207. package/dist/telemetry/telemetry.d.ts.map +1 -0
  208. package/dist/telemetry/telemetry.js +95 -0
  209. package/dist/telemetry/telemetry.js.map +1 -0
  210. package/dist/tool/define-tool.d.ts +23 -0
  211. package/dist/tool/define-tool.d.ts.map +1 -0
  212. package/dist/tool/define-tool.js +28 -0
  213. package/dist/tool/define-tool.js.map +1 -0
  214. package/dist/tool/index.d.ts +5 -0
  215. package/dist/tool/index.d.ts.map +1 -0
  216. package/dist/tool/index.js +6 -0
  217. package/dist/tool/index.js.map +1 -0
  218. package/dist/tool/tool-result.d.ts +10 -0
  219. package/dist/tool/tool-result.d.ts.map +1 -0
  220. package/dist/tool/tool-result.js +34 -0
  221. package/dist/tool/tool-result.js.map +1 -0
  222. package/dist/tool/tool-schema.d.ts +7 -0
  223. package/dist/tool/tool-schema.d.ts.map +1 -0
  224. package/dist/tool/tool-schema.js +97 -0
  225. package/dist/tool/tool-schema.js.map +1 -0
  226. package/dist/transport/auto-detect.d.ts +4 -0
  227. package/dist/transport/auto-detect.d.ts.map +1 -0
  228. package/dist/transport/auto-detect.js +21 -0
  229. package/dist/transport/auto-detect.js.map +1 -0
  230. package/dist/transport/http-adapter.d.ts +4 -0
  231. package/dist/transport/http-adapter.d.ts.map +1 -0
  232. package/dist/transport/http-adapter.js +10 -0
  233. package/dist/transport/http-adapter.js.map +1 -0
  234. package/dist/transport/index.d.ts +5 -0
  235. package/dist/transport/index.d.ts.map +1 -0
  236. package/dist/transport/index.js +7 -0
  237. package/dist/transport/index.js.map +1 -0
  238. package/dist/transport/sse-adapter.d.ts +3 -0
  239. package/dist/transport/sse-adapter.d.ts.map +1 -0
  240. package/dist/transport/sse-adapter.js +8 -0
  241. package/dist/transport/sse-adapter.js.map +1 -0
  242. package/dist/transport/stdio-adapter.d.ts +3 -0
  243. package/dist/transport/stdio-adapter.d.ts.map +1 -0
  244. package/dist/transport/stdio-adapter.js +8 -0
  245. package/dist/transport/stdio-adapter.js.map +1 -0
  246. package/dist/types/config.d.ts +101 -0
  247. package/dist/types/config.d.ts.map +1 -0
  248. package/dist/types/config.js +5 -0
  249. package/dist/types/config.js.map +1 -0
  250. package/dist/types/index.d.ts +12 -0
  251. package/dist/types/index.d.ts.map +1 -0
  252. package/dist/types/index.js +4 -0
  253. package/dist/types/index.js.map +1 -0
  254. package/dist/types/middleware.d.ts +48 -0
  255. package/dist/types/middleware.d.ts.map +1 -0
  256. package/dist/types/middleware.js +4 -0
  257. package/dist/types/middleware.js.map +1 -0
  258. package/dist/types/plugin-manifest.d.ts +59 -0
  259. package/dist/types/plugin-manifest.d.ts.map +1 -0
  260. package/dist/types/plugin-manifest.js +9 -0
  261. package/dist/types/plugin-manifest.js.map +1 -0
  262. package/dist/types/plugin.d.ts +50 -0
  263. package/dist/types/plugin.d.ts.map +1 -0
  264. package/dist/types/plugin.js +4 -0
  265. package/dist/types/plugin.js.map +1 -0
  266. package/dist/types/prompt.d.ts +21 -0
  267. package/dist/types/prompt.d.ts.map +1 -0
  268. package/dist/types/prompt.js +4 -0
  269. package/dist/types/prompt.js.map +1 -0
  270. package/dist/types/resource.d.ts +25 -0
  271. package/dist/types/resource.d.ts.map +1 -0
  272. package/dist/types/resource.js +4 -0
  273. package/dist/types/resource.js.map +1 -0
  274. package/dist/types/server.d.ts +54 -0
  275. package/dist/types/server.d.ts.map +1 -0
  276. package/dist/types/server.js +4 -0
  277. package/dist/types/server.js.map +1 -0
  278. package/dist/types/storage.d.ts +40 -0
  279. package/dist/types/storage.d.ts.map +1 -0
  280. package/dist/types/storage.js +4 -0
  281. package/dist/types/storage.js.map +1 -0
  282. package/dist/types/tool.d.ts +54 -0
  283. package/dist/types/tool.d.ts.map +1 -0
  284. package/dist/types/tool.js +4 -0
  285. package/dist/types/tool.js.map +1 -0
  286. package/dist/types/transport.d.ts +12 -0
  287. package/dist/types/transport.d.ts.map +1 -0
  288. package/dist/types/transport.js +4 -0
  289. package/dist/types/transport.js.map +1 -0
  290. 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,8 @@
1
+ import type { AirPlugin } from '../../types/plugin.js';
2
+ interface DedupOptions {
3
+ /** 중복 제거 윈도우 ms (기본: 1000) */
4
+ windowMs?: number;
5
+ }
6
+ export declare function dedupPlugin(options?: DedupOptions): AirPlugin;
7
+ export {};
8
+ //# sourceMappingURL=dedup.d.ts.map
@@ -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,5 @@
1
+ import type { AirPlugin } from '../../types/plugin.js';
2
+ type FallbackMap = Record<string, string>;
3
+ export declare function fallbackPlugin(fallbacks: FallbackMap): AirPlugin;
4
+ export {};
5
+ //# sourceMappingURL=fallback.d.ts.map
@@ -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,3 @@
1
+ import type { AirPlugin } from '../../types/plugin.js';
2
+ export declare function builtinLoggerPlugin(level?: string): AirPlugin;
3
+ //# sourceMappingURL=logger.d.ts.map
@@ -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"}