@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,63 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // @airmcp-dev/core — middleware/error-handler.ts
3
+ // 에러 → MCP 프로토콜 형식 자동 변환
4
+ //
5
+ // MCP 프로토콜 에러 코드:
6
+ // -32700: Parse error
7
+ // -32600: Invalid Request
8
+ // -32601: Method not found
9
+ // -32602: Invalid params
10
+ // -32603: Internal error
11
+ // -32000 ~ -32099: Server error (implementation-defined)
12
+ /** air 전용 에러 클래스 — 에러 코드와 메타데이터를 포함 */
13
+ export class AirError extends Error {
14
+ code;
15
+ details;
16
+ constructor(message, code = -32603, details) {
17
+ super(message);
18
+ this.name = 'AirError';
19
+ this.code = code;
20
+ this.details = details;
21
+ }
22
+ }
23
+ /** MCP 표준 에러 팩토리 */
24
+ export const McpErrors = {
25
+ /** 도구를 찾을 수 없음 */
26
+ toolNotFound: (name) => new AirError(`Tool "${name}" not found`, -32601, { tool: name }),
27
+ /** 파라미터 검증 실패 */
28
+ invalidParams: (message, params) => new AirError(`Invalid params: ${message}`, -32602, params),
29
+ /** 내부 서버 에러 */
30
+ internal: (message, cause) => new AirError(`Internal error: ${message}`, -32603, { cause: cause?.message }),
31
+ /** 접근 거부 */
32
+ forbidden: (message) => new AirError(message, -32000, { type: 'forbidden' }),
33
+ /** 레이트 리밋 초과 */
34
+ rateLimited: (tool, retryAfterMs) => new AirError(`Rate limit exceeded for "${tool}"`, -32001, { tool, retryAfterMs }),
35
+ /** 위협 감지 */
36
+ threatDetected: (type, severity) => new AirError(`Threat detected: ${type}`, -32002, { threatType: type, severity }),
37
+ /** 타임아웃 */
38
+ timeout: (tool, timeoutMs) => new AirError(`Tool "${tool}" timed out after ${timeoutMs}ms`, -32003, { tool, timeoutMs }),
39
+ };
40
+ /** 에러를 MCP 프로토콜 형식으로 변환 */
41
+ function formatError(error) {
42
+ const message = error instanceof AirError
43
+ ? `[${error.code}] ${error.message}`
44
+ : `Error: ${error.message}`;
45
+ return {
46
+ content: [{ type: 'text', text: message }],
47
+ isError: true,
48
+ };
49
+ }
50
+ /** 에러 → MCP 응답 변환 미들웨어 */
51
+ export function errorBoundaryMiddleware() {
52
+ return {
53
+ name: 'air:error-boundary',
54
+ onError: async (ctx, error) => {
55
+ // 에러 로그 (stderr로 출력, stdout은 MCP 프로토콜 전용)
56
+ const toolName = ctx.tool?.name || 'unknown';
57
+ const requestId = ctx.requestId || 'no-id';
58
+ console.error(`[air:error] ${toolName} (${requestId}): ${error.message}`);
59
+ return formatError(error);
60
+ },
61
+ };
62
+ }
63
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,iDAAiD;AACjD,yBAAyB;AACzB,EAAE;AACF,kBAAkB;AAClB,sBAAsB;AACtB,0BAA0B;AAC1B,2BAA2B;AAC3B,yBAAyB;AACzB,yBAAyB;AACzB,yDAAyD;AAIzD,uCAAuC;AACvC,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,IAAI,CAAS;IACb,OAAO,CAAuB;IAE9B,YAAY,OAAe,EAAE,OAAe,CAAC,KAAK,EAAE,OAA6B;QAC/E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,oBAAoB;AACpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,kBAAkB;IAClB,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAC7B,IAAI,QAAQ,CAAC,SAAS,IAAI,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAElE,iBAAiB;IACjB,aAAa,EAAE,CAAC,OAAe,EAAE,MAA4B,EAAE,EAAE,CAC/D,IAAI,QAAQ,CAAC,mBAAmB,OAAO,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;IAE5D,eAAe;IACf,QAAQ,EAAE,CAAC,OAAe,EAAE,KAAa,EAAE,EAAE,CAC3C,IAAI,QAAQ,CAAC,mBAAmB,OAAO,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAE/E,YAAY;IACZ,SAAS,EAAE,CAAC,OAAe,EAAE,EAAE,CAC7B,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAEtD,gBAAgB;IAChB,WAAW,EAAE,CAAC,IAAY,EAAE,YAAqB,EAAE,EAAE,CACnD,IAAI,QAAQ,CAAC,4BAA4B,IAAI,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAEnF,YAAY;IACZ,cAAc,EAAE,CAAC,IAAY,EAAE,QAAgB,EAAE,EAAE,CACjD,IAAI,QAAQ,CAAC,oBAAoB,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAElF,WAAW;IACX,OAAO,EAAE,CAAC,IAAY,EAAE,SAAiB,EAAE,EAAE,CAC3C,IAAI,QAAQ,CAAC,SAAS,IAAI,qBAAqB,SAAS,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;CAC7F,CAAC;AAEF,2BAA2B;AAC3B,SAAS,WAAW,CAAC,KAAY;IAI/B,MAAM,OAAO,GAAG,KAAK,YAAY,QAAQ;QACvC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE;QACpC,CAAC,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC;IAE9B,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,KAAK,EAAE,GAAsB,EAAE,KAAY,EAAE,EAAE;YACtD,0CAA0C;YAC1C,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,SAAS,CAAC;YAC7C,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC;YAC3C,OAAO,CAAC,KAAK,CACX,eAAe,QAAQ,KAAK,SAAS,MAAM,KAAK,CAAC,OAAO,EAAE,CAC3D,CAAC;YAEF,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { MiddlewareChain } from './chain.js';
2
+ export { validationMiddleware } from './before-hook.js';
3
+ export { loggingMiddleware } from './after-hook.js';
4
+ export { errorBoundaryMiddleware, AirError, McpErrors } from './error-handler.js';
5
+ export { createShieldMiddleware, getAuditLog, clearAuditLog } from './shield-middleware.js';
6
+ export { createMeterMiddleware, getMetricsSnapshot, resetMetricsHistory } from './meter-middleware.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,9 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // @airmcp-dev/core — middleware/index.ts (re-export only)
3
+ export { MiddlewareChain } from './chain.js';
4
+ export { validationMiddleware } from './before-hook.js';
5
+ export { loggingMiddleware } from './after-hook.js';
6
+ export { errorBoundaryMiddleware, AirError, McpErrors } from './error-handler.js';
7
+ export { createShieldMiddleware, getAuditLog, clearAuditLog } from './shield-middleware.js';
8
+ export { createMeterMiddleware, getMetricsSnapshot, resetMetricsHistory } from './meter-middleware.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,0DAA0D;AAE1D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { AirMiddleware } from '../types/middleware.js';
2
+ import type { MeterConfig } from '../types/config.js';
3
+ type Layer = 'L1' | 'L2' | 'L3' | 'L4' | 'L5' | 'L6' | 'L7';
4
+ /**
5
+ * MeterConfig로부터 측정 미들웨어를 생성한다.
6
+ */
7
+ export declare function createMeterMiddleware(config: MeterConfig): AirMiddleware;
8
+ /** 메트릭 스냅샷 조회 */
9
+ export declare function getMetricsSnapshot(): {
10
+ totalCalls: number;
11
+ successRate: number;
12
+ avgLatencyMs: number;
13
+ layerDistribution: Record<Layer, number>;
14
+ toolCounts: Record<string, number>;
15
+ };
16
+ /** 메트릭 초기화 */
17
+ export declare function resetMetricsHistory(): void;
18
+ export {};
19
+ //# sourceMappingURL=meter-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter-middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/meter-middleware.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAuC,MAAM,wBAAwB,CAAC;AACjG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,KAAK,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AA2D5D;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAmDxE;AAED,iBAAiB;AACjB,wBAAgB,kBAAkB,IAAI;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAgCA;AAED,cAAc;AACd,wBAAgB,mBAAmB,SAIlC"}
@@ -0,0 +1,139 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // @airmcp-dev/core — middleware/meter-middleware.ts
3
+ //
4
+ // MeterConfig → AirMiddleware 자동 생성.
5
+ // defineServer에서 meter 설정이 있으면 이 미들웨어가 체인에 자동 등록된다.
6
+ //
7
+ // 담당: 7-Layer 분류, 호출 추적, 지연시간 측정
8
+ const CLASSIFY_RULES = [
9
+ { match: (n) => /^(ping|health|version|echo)$/i.test(n), layer: 'L1' },
10
+ { match: (n) => /^(get|read|find|lookup|list|show)$/i.test(n), layer: 'L2' },
11
+ { match: (n) => /^(convert|transform|format|parse|encode|decode)$/i.test(n), layer: 'L3' },
12
+ { match: (n) => /^(compute|calculate|aggregate|analyze|summarize)$/i.test(n), layer: 'L4' },
13
+ {
14
+ match: (n, p) => {
15
+ if (/^(fetch|request|call_api|webhook|http|post|put|delete)$/i.test(n))
16
+ return true;
17
+ if (p)
18
+ return Object.values(p).some((v) => typeof v === 'string' && /^https?:\/\//.test(v));
19
+ return false;
20
+ },
21
+ layer: 'L5',
22
+ },
23
+ { match: (n) => /^(generate|complete|chat|embed|infer|predict)$/i.test(n), layer: 'L6' },
24
+ { match: (n) => /^(agent|think|plan|execute|reason|chain|orchestrate)$/i.test(n), layer: 'L7' },
25
+ ];
26
+ function classify(toolName, params) {
27
+ for (const rule of CLASSIFY_RULES) {
28
+ if (rule.match(toolName, params))
29
+ return rule.layer;
30
+ }
31
+ return 'L4'; // 기본값
32
+ }
33
+ const MAX_HISTORY = 10_000;
34
+ const callBuffer = new Array(MAX_HISTORY).fill(null);
35
+ let bufferHead = 0;
36
+ let bufferCount = 0;
37
+ function pushRecord(record) {
38
+ callBuffer[bufferHead] = record;
39
+ bufferHead = (bufferHead + 1) % MAX_HISTORY;
40
+ if (bufferCount < MAX_HISTORY)
41
+ bufferCount++;
42
+ }
43
+ function getRecords() {
44
+ const result = [];
45
+ const start = bufferCount < MAX_HISTORY ? 0 : bufferHead;
46
+ for (let i = 0; i < bufferCount; i++) {
47
+ const idx = (start + i) % MAX_HISTORY;
48
+ if (callBuffer[idx])
49
+ result.push(callBuffer[idx]);
50
+ }
51
+ return result;
52
+ }
53
+ /**
54
+ * MeterConfig로부터 측정 미들웨어를 생성한다.
55
+ */
56
+ export function createMeterMiddleware(config) {
57
+ const classifyEnabled = config.classify !== false;
58
+ const trackEnabled = config.trackCalls !== false;
59
+ return {
60
+ name: 'air:meter',
61
+ before: async (ctx) => {
62
+ // 분류 결과를 meta에 저장 (after에서 사용)
63
+ if (classifyEnabled) {
64
+ const layer = classify(ctx.tool.name, ctx.params);
65
+ ctx.meta.meter = { layer, startedAt: Date.now() };
66
+ }
67
+ else {
68
+ ctx.meta.meter = { layer: 'L4', startedAt: Date.now() };
69
+ }
70
+ },
71
+ after: async (ctx) => {
72
+ if (!trackEnabled)
73
+ return;
74
+ const layer = ctx.meta.meter?.layer || 'L4';
75
+ const record = {
76
+ tool: ctx.tool.name,
77
+ layer,
78
+ latencyMs: ctx.duration,
79
+ success: true,
80
+ timestamp: Date.now(),
81
+ };
82
+ pushRecord(record);
83
+ },
84
+ onError: async (ctx, error) => {
85
+ if (!trackEnabled)
86
+ return undefined;
87
+ const layer = ctx.meta.meter?.layer || 'L4';
88
+ const latency = Date.now() - (ctx.meta.meter?.startedAt || ctx.startedAt);
89
+ pushRecord({
90
+ tool: ctx.tool.name,
91
+ layer,
92
+ latencyMs: latency,
93
+ success: false,
94
+ timestamp: Date.now(),
95
+ });
96
+ // 에러는 처리하지 않고 다음으로 넘김
97
+ return undefined;
98
+ },
99
+ };
100
+ }
101
+ /** 메트릭 스냅샷 조회 */
102
+ export function getMetricsSnapshot() {
103
+ const records = getRecords();
104
+ const total = records.length;
105
+ if (total === 0) {
106
+ return {
107
+ totalCalls: 0,
108
+ successRate: 1,
109
+ avgLatencyMs: 0,
110
+ layerDistribution: { L1: 0, L2: 0, L3: 0, L4: 0, L5: 0, L6: 0, L7: 0 },
111
+ toolCounts: {},
112
+ };
113
+ }
114
+ let successCount = 0;
115
+ let latencySum = 0;
116
+ const layers = { L1: 0, L2: 0, L3: 0, L4: 0, L5: 0, L6: 0, L7: 0 };
117
+ const tools = {};
118
+ for (const r of records) {
119
+ if (r.success)
120
+ successCount++;
121
+ latencySum += r.latencyMs;
122
+ layers[r.layer]++;
123
+ tools[r.tool] = (tools[r.tool] || 0) + 1;
124
+ }
125
+ return {
126
+ totalCalls: total,
127
+ successRate: successCount / total,
128
+ avgLatencyMs: latencySum / total,
129
+ layerDistribution: layers,
130
+ toolCounts: tools,
131
+ };
132
+ }
133
+ /** 메트릭 초기화 */
134
+ export function resetMetricsHistory() {
135
+ callBuffer.fill(null);
136
+ bufferHead = 0;
137
+ bufferCount = 0;
138
+ }
139
+ //# sourceMappingURL=meter-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter-middleware.js","sourceRoot":"","sources":["../../src/middleware/meter-middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { AirMiddleware } from '../types/middleware.js';
2
+ import type { ShieldConfig } from '../types/config.js';
3
+ /**
4
+ * ShieldConfig로부터 보안 미들웨어를 생성한다.
5
+ */
6
+ export declare function createShieldMiddleware(config: ShieldConfig): AirMiddleware;
7
+ /** 감사 로그 조회 (외부에서 접근용) */
8
+ export declare function getAuditLog(): {
9
+ timestamp: string;
10
+ tool: string;
11
+ decision: "allowed" | "denied" | "threat" | "rate-limited";
12
+ reason?: string;
13
+ }[];
14
+ /** 감사 로그 초기화 */
15
+ export declare function clearAuditLog(): void;
16
+ //# sourceMappingURL=shield-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/shield-middleware.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAuC,MAAM,wBAAwB,CAAC;AACjG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAyCvD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CA0H1E;AAED,0BAA0B;AAC1B,wBAAgB,WAAW;eAtId,MAAM;UACX,MAAM;cACF,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc;aACjD,MAAM;IAqIhB;AAED,gBAAgB;AAChB,wBAAgB,aAAa,SAE5B"}
@@ -0,0 +1,163 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // @airmcp-dev/core — middleware/shield-middleware.ts
3
+ //
4
+ // ShieldConfig → AirMiddleware 자동 생성.
5
+ // defineServer에서 shield 설정이 있으면 이 미들웨어가 체인에 자동 등록된다.
6
+ //
7
+ // 담당: 정책 체크, 위협 탐지, 레이트 리밋, 감사 로그
8
+ // ── 내장 위협 패턴 (경량 버전) ──
9
+ const THREAT_PATTERNS = [
10
+ { pattern: /ignore\s+(all\s+)?previous\s+instructions/i, type: 'prompt-injection', severity: 'high', description: 'Prompt injection: ignore previous instructions' },
11
+ { pattern: /you\s+are\s+now\s+(a|an)\s+/i, type: 'prompt-injection', severity: 'high', description: 'Prompt injection: role reassignment' },
12
+ { pattern: /\bsystem\s*:\s*/i, type: 'prompt-injection', severity: 'medium', description: 'Prompt injection: system prompt attempt' },
13
+ { pattern: /\.\.\//g, type: 'path-traversal', severity: 'high', description: 'Path traversal: directory escape' },
14
+ { pattern: /\/etc\/(passwd|shadow|hosts)/i, type: 'path-traversal', severity: 'critical', description: 'Path traversal: sensitive system file' },
15
+ { pattern: /[;&|`$]\s*(rm|chmod|chown|curl|wget|nc|bash|sh|python|node)\b/i, type: 'command-injection', severity: 'critical', description: 'Command injection: shell command' },
16
+ { pattern: /\$\(.*\)/, type: 'command-injection', severity: 'high', description: 'Command injection: command substitution' },
17
+ { pattern: /<tool_description>|<function_call>/i, type: 'tool-poisoning', severity: 'high', description: 'Tool poisoning: embedded tool definition' },
18
+ ];
19
+ /** 정책 매칭 */
20
+ function matchesTarget(ruleTarget, toolName) {
21
+ if (ruleTarget === '*')
22
+ return true;
23
+ if (ruleTarget === toolName)
24
+ return true;
25
+ if (ruleTarget.endsWith('*') && toolName.startsWith(ruleTarget.slice(0, -1)))
26
+ return true;
27
+ return false;
28
+ }
29
+ /** 파라미터 값들을 재귀적으로 문자열 추출 */
30
+ function flattenValues(obj) {
31
+ if (typeof obj === 'string')
32
+ return [obj];
33
+ if (Array.isArray(obj))
34
+ return obj.flatMap(flattenValues);
35
+ if (obj && typeof obj === 'object')
36
+ return Object.values(obj).flatMap(flattenValues);
37
+ return [];
38
+ }
39
+ /** 레이트 리밋 윈도우 추적 */
40
+ const rateLimitWindows = new Map();
41
+ /** 감사 로그 저장소 */
42
+ const auditLog = [];
43
+ /**
44
+ * ShieldConfig로부터 보안 미들웨어를 생성한다.
45
+ */
46
+ export function createShieldMiddleware(config) {
47
+ // 정책 규칙을 우선순위 내림차순 정렬
48
+ const policies = (config.policies || [])
49
+ .sort((a, b) => (b.priority || 0) - (a.priority || 0));
50
+ const threatEnabled = config.threatDetection !== false;
51
+ const auditEnabled = config.audit !== false;
52
+ const defaultRateWindow = config.rateLimit?.windowMs || 60_000;
53
+ const defaultRateMax = config.rateLimit?.maxCalls || 100;
54
+ const perToolRate = config.rateLimit?.perTool || {};
55
+ return {
56
+ name: 'air:shield',
57
+ before: async (ctx) => {
58
+ const toolName = ctx.tool.name;
59
+ // ── 1. 정책 체크 ──
60
+ for (const rule of policies) {
61
+ if (!matchesTarget(rule.target, toolName))
62
+ continue;
63
+ if (rule.action === 'deny') {
64
+ if (auditEnabled) {
65
+ auditLog.push({
66
+ timestamp: new Date().toISOString(),
67
+ tool: toolName,
68
+ decision: 'denied',
69
+ reason: `Policy: ${rule.name}`,
70
+ });
71
+ }
72
+ return {
73
+ abort: true,
74
+ abortResponse: {
75
+ content: [{ type: 'text', text: `[Shield] Access denied: tool "${toolName}" is blocked by policy "${rule.name}". Contact the server administrator if you believe this is an error.` }],
76
+ isError: true,
77
+ },
78
+ meta: { shield: { decision: 'denied', rule: rule.name, code: -32000 } },
79
+ };
80
+ }
81
+ if (rule.action === 'allow')
82
+ break; // 허용이면 이후 규칙 스킵
83
+ }
84
+ // ── 2. 위협 탐지 ──
85
+ if (threatEnabled) {
86
+ const values = flattenValues(ctx.params);
87
+ for (const value of values) {
88
+ for (const tp of THREAT_PATTERNS) {
89
+ if (tp.pattern.test(value)) {
90
+ tp.pattern.lastIndex = 0; // global flag reset
91
+ if (auditEnabled) {
92
+ auditLog.push({
93
+ timestamp: new Date().toISOString(),
94
+ tool: toolName,
95
+ decision: 'threat',
96
+ reason: `${tp.type} (${tp.severity})`,
97
+ });
98
+ }
99
+ return {
100
+ abort: true,
101
+ abortResponse: {
102
+ content: [{ type: 'text', text: `[Shield] Threat detected in "${toolName}": ${tp.description} (severity: ${tp.severity}). The request has been blocked for security.` }],
103
+ isError: true,
104
+ },
105
+ meta: { shield: { decision: 'threat', type: tp.type, severity: tp.severity, code: -32002 } },
106
+ };
107
+ }
108
+ tp.pattern.lastIndex = 0;
109
+ }
110
+ }
111
+ }
112
+ // ── 3. 레이트 리밋 ──
113
+ if (config.rateLimit) {
114
+ const toolConfig = perToolRate[toolName];
115
+ const windowMs = toolConfig?.windowMs || defaultRateWindow;
116
+ const maxCalls = toolConfig?.maxCalls || defaultRateMax;
117
+ const now = Date.now();
118
+ const key = toolName;
119
+ const timestamps = rateLimitWindows.get(key) || [];
120
+ // 윈도우 밖의 오래된 타임스탬프 제거
121
+ const valid = timestamps.filter((t) => t > now - windowMs);
122
+ if (valid.length >= maxCalls) {
123
+ if (auditEnabled) {
124
+ auditLog.push({
125
+ timestamp: new Date().toISOString(),
126
+ tool: toolName,
127
+ decision: 'rate-limited',
128
+ reason: `${valid.length}/${maxCalls} in ${windowMs}ms`,
129
+ });
130
+ }
131
+ return {
132
+ abort: true,
133
+ abortResponse: {
134
+ content: [{ type: 'text', text: `[Shield] Rate limit exceeded for "${toolName}": ${maxCalls} calls per ${windowMs / 1000}s. Please wait and try again.` }],
135
+ isError: true,
136
+ },
137
+ meta: { shield: { decision: 'rate-limited', code: -32001 } },
138
+ };
139
+ }
140
+ valid.push(now);
141
+ rateLimitWindows.set(key, valid);
142
+ }
143
+ // ── 감사 로그: 허용 ──
144
+ if (auditEnabled) {
145
+ auditLog.push({
146
+ timestamp: new Date().toISOString(),
147
+ tool: toolName,
148
+ decision: 'allowed',
149
+ });
150
+ }
151
+ ctx.meta.shield = { decision: 'allowed' };
152
+ },
153
+ };
154
+ }
155
+ /** 감사 로그 조회 (외부에서 접근용) */
156
+ export function getAuditLog() {
157
+ return [...auditLog];
158
+ }
159
+ /** 감사 로그 초기화 */
160
+ export function clearAuditLog() {
161
+ auditLog.length = 0;
162
+ }
163
+ //# sourceMappingURL=shield-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-middleware.js","sourceRoot":"","sources":["../../src/middleware/shield-middleware.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,qDAAqD;AACrD,EAAE;AACF,sCAAsC;AACtC,qDAAqD;AACrD,EAAE;AACF,kCAAkC;AAKlC,yBAAyB;AACzB,MAAM,eAAe,GAAG;IACtB,EAAE,OAAO,EAAE,4CAA4C,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gDAAgD,EAAE;IACpK,EAAE,OAAO,EAAE,8BAA8B,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,qCAAqC,EAAE;IAC3I,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,yCAAyC,EAAE;IACrI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,kCAAkC,EAAE;IACjH,EAAE,OAAO,EAAE,+BAA+B,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,uCAAuC,EAAE;IAChJ,EAAE,OAAO,EAAE,gEAAgE,EAAE,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,kCAAkC,EAAE;IAC/K,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,yCAAyC,EAAE;IAC5H,EAAE,OAAO,EAAE,qCAAqC,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,0CAA0C,EAAE;CACtJ,CAAC;AAEF,YAAY;AACZ,SAAS,aAAa,CAAC,UAAkB,EAAE,QAAgB;IACzD,IAAI,UAAU,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,UAAU,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1F,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4BAA4B;AAC5B,SAAS,aAAa,CAAC,GAAQ;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1D,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACrF,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,oBAAoB;AACpB,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAoB,CAAC;AAErD,gBAAgB;AAChB,MAAM,QAAQ,GAKT,EAAE,CAAC;AAER;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAoB;IACzD,sBAAsB;IACtB,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;SACrC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;IAEzD,MAAM,aAAa,GAAG,MAAM,CAAC,eAAe,KAAK,KAAK,CAAC;IACvD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC;IAE5C,MAAM,iBAAiB,GAAG,MAAM,CAAC,SAAS,EAAE,QAAQ,IAAI,MAAM,CAAC;IAC/D,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,EAAE,QAAQ,IAAI,GAAG,CAAC;IACzD,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,EAAE,OAAO,IAAI,EAAE,CAAC;IAEpD,OAAO;QACL,IAAI,EAAE,YAAY;QAElB,MAAM,EAAE,KAAK,EAAE,GAAsB,EAAoC,EAAE;YACzE,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAE/B,iBAAiB;YACjB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;oBAAE,SAAS;gBAEpD,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;oBAC3B,IAAI,YAAY,EAAE,CAAC;wBACjB,QAAQ,CAAC,IAAI,CAAC;4BACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;4BACnC,IAAI,EAAE,QAAQ;4BACd,QAAQ,EAAE,QAAQ;4BAClB,MAAM,EAAE,WAAW,IAAI,CAAC,IAAI,EAAE;yBAC/B,CAAC,CAAC;oBACL,CAAC;oBACD,OAAO;wBACL,KAAK,EAAE,IAAI;wBACX,aAAa,EAAE;4BACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iCAAiC,QAAQ,2BAA2B,IAAI,CAAC,IAAI,sEAAsE,EAAE,CAAC;4BACtL,OAAO,EAAE,IAAI;yBACd;wBACD,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;qBACxE,CAAC;gBACJ,CAAC;gBAED,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO;oBAAE,MAAM,CAAC,gBAAgB;YACtD,CAAC;YAED,iBAAiB;YACjB,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;wBACjC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;4BAC3B,EAAE,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,oBAAoB;4BAE9C,IAAI,YAAY,EAAE,CAAC;gCACjB,QAAQ,CAAC,IAAI,CAAC;oCACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oCACnC,IAAI,EAAE,QAAQ;oCACd,QAAQ,EAAE,QAAQ;oCAClB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,QAAQ,GAAG;iCACtC,CAAC,CAAC;4BACL,CAAC;4BACD,OAAO;gCACL,KAAK,EAAE,IAAI;gCACX,aAAa,EAAE;oCACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gCAAgC,QAAQ,MAAM,EAAE,CAAC,WAAW,eAAe,EAAE,CAAC,QAAQ,+CAA+C,EAAE,CAAC;oCACxK,OAAO,EAAE,IAAI;iCACd;gCACD,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;6BAC7F,CAAC;wBACJ,CAAC;wBACD,EAAE,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;oBAC3B,CAAC;gBACH,CAAC;YACH,CAAC;YAED,kBAAkB;YAClB,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrB,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACzC,MAAM,QAAQ,GAAG,UAAU,EAAE,QAAQ,IAAI,iBAAiB,CAAC;gBAC3D,MAAM,QAAQ,GAAG,UAAU,EAAE,QAAQ,IAAI,cAAc,CAAC;gBAExD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,MAAM,GAAG,GAAG,QAAQ,CAAC;gBACrB,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBAEnD,sBAAsB;gBACtB,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,QAAQ,CAAC,CAAC;gBAE3D,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;oBAC7B,IAAI,YAAY,EAAE,CAAC;wBACjB,QAAQ,CAAC,IAAI,CAAC;4BACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;4BACnC,IAAI,EAAE,QAAQ;4BACd,QAAQ,EAAE,cAAc;4BACxB,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,QAAQ,OAAO,QAAQ,IAAI;yBACvD,CAAC,CAAC;oBACL,CAAC;oBACD,OAAO;wBACL,KAAK,EAAE,IAAI;wBACX,aAAa,EAAE;4BACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qCAAqC,QAAQ,MAAM,QAAQ,cAAc,QAAQ,GAAG,IAAI,+BAA+B,EAAE,CAAC;4BAC1J,OAAO,EAAE,IAAI;yBACd;wBACD,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;qBAC7D,CAAC;gBACJ,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAChB,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,CAAC;YAED,kBAAkB;YAClB,IAAI,YAAY,EAAE,CAAC;gBACjB,QAAQ,CAAC,IAAI,CAAC;oBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;YAED,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,aAAa;IAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AirPlugin } from '../../types/plugin.js';
2
+ interface AuthOptions {
3
+ /** 인증 방식 */
4
+ type: 'api-key' | 'bearer';
5
+ /** 허용할 키/토큰 목록 */
6
+ keys?: string[];
7
+ /** 커스텀 검증 함수 */
8
+ verify?: (token: string) => Promise<boolean> | boolean;
9
+ /** 인증 없이 허용할 도구 (기본: []) */
10
+ publicTools?: string[];
11
+ /** 인증 헤더/파라미터 이름 (기본: _auth) */
12
+ paramName?: string;
13
+ }
14
+ export declare function authPlugin(options: AuthOptions): AirPlugin;
15
+ export {};
16
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/auth.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,WAAW;IACnB,YAAY;IACZ,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,kBAAkB;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,gBAAgB;IAChB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACvD,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAgD1D"}
@@ -0,0 +1,60 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // @airmcp-dev/core — plugin/builtin/auth.ts
3
+ //
4
+ // 간단한 인증 플러그인.
5
+ // API 키 또는 Bearer 토큰으로 도구 접근을 제한.
6
+ // 프로덕션에서는 OAuth 2.1을 사용하되, 개발/내부용으로 이 플러그인 사용.
7
+ //
8
+ // @example
9
+ // defineServer({
10
+ // use: [authPlugin({
11
+ // type: 'api-key',
12
+ // keys: ['sk-abc123', 'sk-def456'],
13
+ // })],
14
+ // });
15
+ export function authPlugin(options) {
16
+ const publicTools = new Set(options.publicTools || []);
17
+ const validKeys = new Set(options.keys || []);
18
+ const paramName = options.paramName || '_auth';
19
+ async function isValid(token) {
20
+ if (options.verify)
21
+ return options.verify(token);
22
+ return validKeys.has(token);
23
+ }
24
+ const middleware = {
25
+ name: 'air:auth',
26
+ before: async (ctx) => {
27
+ // 공개 도구는 인증 스킵
28
+ if (publicTools.has(ctx.tool.name))
29
+ return;
30
+ const token = ctx.params[paramName];
31
+ if (!token) {
32
+ return {
33
+ abort: true,
34
+ abortResponse: {
35
+ content: [{ type: 'text', text: `[Auth] Authentication required for "${ctx.tool.name}". Pass "${paramName}" parameter.` }],
36
+ isError: true,
37
+ },
38
+ };
39
+ }
40
+ const valid = await isValid(token);
41
+ if (!valid) {
42
+ return {
43
+ abort: true,
44
+ abortResponse: {
45
+ content: [{ type: 'text', text: `[Auth] Invalid credentials for "${ctx.tool.name}".` }],
46
+ isError: true,
47
+ },
48
+ };
49
+ }
50
+ // 인증 성공 — _auth 파라미터를 제거하여 핸들러에 전달하지 않음
51
+ const { [paramName]: _, ...cleanParams } = ctx.params;
52
+ return { params: cleanParams, meta: { authenticated: true } };
53
+ },
54
+ };
55
+ return {
56
+ meta: { name: 'air:auth', version: '1.0.0' },
57
+ middleware: [middleware],
58
+ };
59
+ }
60
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/plugin/builtin/auth.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,4CAA4C;AAC5C,EAAE;AACF,eAAe;AACf,kCAAkC;AAClC,+CAA+C;AAC/C,EAAE;AACF,WAAW;AACX,mBAAmB;AACnB,yBAAyB;AACzB,yBAAyB;AACzB,0CAA0C;AAC1C,WAAW;AACX,QAAQ;AAkBR,MAAM,UAAU,UAAU,CAAC,OAAoB;IAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;IAE/C,KAAK,UAAU,OAAO,CAAC,KAAa;QAClC,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjD,OAAO,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,UAAU,GAAkB;QAChC,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,eAAe;YACf,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YAE3C,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAW,CAAC;YAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;oBACL,KAAK,EAAE,IAAI;oBACX,aAAa,EAAE;wBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uCAAuC,GAAG,CAAC,IAAI,CAAC,IAAI,YAAY,SAAS,cAAc,EAAE,CAAC;wBAC1H,OAAO,EAAE,IAAI;qBACd;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;oBACL,KAAK,EAAE,IAAI;oBACX,aAAa,EAAE;wBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;wBACvF,OAAO,EAAE,IAAI;qBACd;iBACF,CAAC;YACJ,CAAC;YAED,wCAAwC;YACxC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;YACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,CAAC;QAChE,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 CacheOptions {
3
+ /** 캐시 유지 시간 ms (기본: 60000) */
4
+ ttlMs?: number;
5
+ /** 캐시 최대 항목 수 (기본: 1000) */
6
+ maxEntries?: number;
7
+ /** 캐시 제외 도구 */
8
+ exclude?: string[];
9
+ }
10
+ export declare function cachePlugin(options?: CacheOptions): AirPlugin;
11
+ export {};
12
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/plugin/builtin/cache.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,UAAU,YAAY;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAOD,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CA2D7D"}
@@ -0,0 +1,65 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // @airmcp-dev/core — plugin/builtin/cache.ts
3
+ //
4
+ // 도구 결과 캐시 플러그인.
5
+ // 같은 파라미터로 같은 도구를 호출하면 캐시된 결과를 반환.
6
+ //
7
+ // @example
8
+ // defineServer({
9
+ // use: [cachePlugin({ ttlMs: 60_000 })],
10
+ // });
11
+ export function cachePlugin(options) {
12
+ const ttlMs = options?.ttlMs ?? 60_000;
13
+ const maxEntries = options?.maxEntries ?? 1000;
14
+ const exclude = new Set(options?.exclude || []);
15
+ const cache = new Map();
16
+ function makeKey(toolName, params) {
17
+ return `${toolName}:${JSON.stringify(params, Object.keys(params).sort())}`;
18
+ }
19
+ function evictExpired() {
20
+ const now = Date.now();
21
+ for (const [key, entry] of cache.entries()) {
22
+ if (now - entry.cachedAt > ttlMs) {
23
+ cache.delete(key);
24
+ }
25
+ }
26
+ }
27
+ const middleware = {
28
+ name: 'air:cache',
29
+ before: async (ctx) => {
30
+ if (exclude.has(ctx.tool.name))
31
+ return;
32
+ evictExpired();
33
+ const key = makeKey(ctx.tool.name, ctx.params);
34
+ const entry = cache.get(key);
35
+ if (entry && Date.now() - entry.cachedAt <= ttlMs) {
36
+ ctx.meta._cached = true;
37
+ return {
38
+ abort: true,
39
+ abortResponse: entry.result,
40
+ };
41
+ }
42
+ ctx.meta._cacheKey = key;
43
+ },
44
+ after: async (ctx) => {
45
+ if (exclude.has(ctx.tool.name))
46
+ return;
47
+ if (ctx.meta._cached)
48
+ return;
49
+ const key = ctx.meta._cacheKey;
50
+ if (!key)
51
+ return;
52
+ if (cache.size >= maxEntries) {
53
+ const firstKey = cache.keys().next().value;
54
+ if (firstKey)
55
+ cache.delete(firstKey);
56
+ }
57
+ cache.set(key, { result: ctx.result, cachedAt: Date.now() });
58
+ },
59
+ };
60
+ return {
61
+ meta: { name: 'air:cache', version: '1.0.0' },
62
+ middleware: [middleware],
63
+ };
64
+ }
65
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/plugin/builtin/cache.ts"],"names":[],"mappings":"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"}