tracelattice 1.2.5

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 (294) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +112 -0
  3. package/dist/ServerConfig.d.ts +229 -0
  4. package/dist/ServerConfig.d.ts.map +1 -0
  5. package/dist/ServerConfig.js +121 -0
  6. package/dist/ServerConfig.js.map +1 -0
  7. package/dist/__tests__/base-registry.test.d.ts +2 -0
  8. package/dist/__tests__/base-registry.test.d.ts.map +1 -0
  9. package/dist/__tests__/base-transport-cov.test.d.ts +2 -0
  10. package/dist/__tests__/base-transport-cov.test.d.ts.map +1 -0
  11. package/dist/__tests__/base-transport.test.d.ts +2 -0
  12. package/dist/__tests__/base-transport.test.d.ts.map +1 -0
  13. package/dist/__tests__/config-loader.test.d.ts +2 -0
  14. package/dist/__tests__/config-loader.test.d.ts.map +1 -0
  15. package/dist/__tests__/connection-pool-cov.test.d.ts +2 -0
  16. package/dist/__tests__/connection-pool-cov.test.d.ts.map +1 -0
  17. package/dist/__tests__/connection-pool.test.d.ts +2 -0
  18. package/dist/__tests__/connection-pool.test.d.ts.map +1 -0
  19. package/dist/__tests__/container.test.d.ts +2 -0
  20. package/dist/__tests__/container.test.d.ts.map +1 -0
  21. package/dist/__tests__/crud.test.d.ts +2 -0
  22. package/dist/__tests__/crud.test.d.ts.map +1 -0
  23. package/dist/__tests__/discovery-cache.test.d.ts +2 -0
  24. package/dist/__tests__/discovery-cache.test.d.ts.map +1 -0
  25. package/dist/__tests__/errors.test.d.ts +2 -0
  26. package/dist/__tests__/errors.test.d.ts.map +1 -0
  27. package/dist/__tests__/factories.test.d.ts +2 -0
  28. package/dist/__tests__/factories.test.d.ts.map +1 -0
  29. package/dist/__tests__/health-checker-cov.test.d.ts +2 -0
  30. package/dist/__tests__/health-checker-cov.test.d.ts.map +1 -0
  31. package/dist/__tests__/health-checker.test.d.ts +2 -0
  32. package/dist/__tests__/health-checker.test.d.ts.map +1 -0
  33. package/dist/__tests__/helpers/factories.d.ts +36 -0
  34. package/dist/__tests__/helpers/factories.d.ts.map +1 -0
  35. package/dist/__tests__/helpers/index.d.ts +3 -0
  36. package/dist/__tests__/helpers/index.d.ts.map +1 -0
  37. package/dist/__tests__/helpers/timers.d.ts +4 -0
  38. package/dist/__tests__/helpers/timers.d.ts.map +1 -0
  39. package/dist/__tests__/history-manager.test.d.ts +2 -0
  40. package/dist/__tests__/history-manager.test.d.ts.map +1 -0
  41. package/dist/__tests__/http-helpers-cov.test.d.ts +2 -0
  42. package/dist/__tests__/http-helpers-cov.test.d.ts.map +1 -0
  43. package/dist/__tests__/http-transport-cov.test.d.ts +2 -0
  44. package/dist/__tests__/http-transport-cov.test.d.ts.map +1 -0
  45. package/dist/__tests__/http-transport.test.d.ts +2 -0
  46. package/dist/__tests__/http-transport.test.d.ts.map +1 -0
  47. package/dist/__tests__/input-normalizer.test.d.ts +8 -0
  48. package/dist/__tests__/input-normalizer.test.d.ts.map +1 -0
  49. package/dist/__tests__/integration.test.d.ts +2 -0
  50. package/dist/__tests__/integration.test.d.ts.map +1 -0
  51. package/dist/__tests__/lib-server.test.d.ts +2 -0
  52. package/dist/__tests__/lib-server.test.d.ts.map +1 -0
  53. package/dist/__tests__/memory-persistence.test.d.ts +2 -0
  54. package/dist/__tests__/memory-persistence.test.d.ts.map +1 -0
  55. package/dist/__tests__/metrics-integration.test.d.ts +2 -0
  56. package/dist/__tests__/metrics-integration.test.d.ts.map +1 -0
  57. package/dist/__tests__/persistence.test.d.ts +2 -0
  58. package/dist/__tests__/persistence.test.d.ts.map +1 -0
  59. package/dist/__tests__/reasoning-integration.test.d.ts +11 -0
  60. package/dist/__tests__/reasoning-integration.test.d.ts.map +1 -0
  61. package/dist/__tests__/reasoning-types.test.d.ts +2 -0
  62. package/dist/__tests__/reasoning-types.test.d.ts.map +1 -0
  63. package/dist/__tests__/request-context.test.d.ts +2 -0
  64. package/dist/__tests__/request-context.test.d.ts.map +1 -0
  65. package/dist/__tests__/sanitize.test.d.ts +2 -0
  66. package/dist/__tests__/sanitize.test.d.ts.map +1 -0
  67. package/dist/__tests__/schema.test.d.ts +2 -0
  68. package/dist/__tests__/schema.test.d.ts.map +1 -0
  69. package/dist/__tests__/sequentialthinking-tools.test.d.ts +2 -0
  70. package/dist/__tests__/sequentialthinking-tools.test.d.ts.map +1 -0
  71. package/dist/__tests__/server-config.test.d.ts +2 -0
  72. package/dist/__tests__/server-config.test.d.ts.map +1 -0
  73. package/dist/__tests__/skill-discovery.test.d.ts +2 -0
  74. package/dist/__tests__/skill-discovery.test.d.ts.map +1 -0
  75. package/dist/__tests__/skill-registry.test.d.ts +2 -0
  76. package/dist/__tests__/skill-registry.test.d.ts.map +1 -0
  77. package/dist/__tests__/skill-watcher.test.d.ts +2 -0
  78. package/dist/__tests__/skill-watcher.test.d.ts.map +1 -0
  79. package/dist/__tests__/sqlite-persistence.test.d.ts +2 -0
  80. package/dist/__tests__/sqlite-persistence.test.d.ts.map +1 -0
  81. package/dist/__tests__/sse-transport-cov.test.d.ts +2 -0
  82. package/dist/__tests__/sse-transport-cov.test.d.ts.map +1 -0
  83. package/dist/__tests__/sse-transport.test.d.ts +2 -0
  84. package/dist/__tests__/sse-transport.test.d.ts.map +1 -0
  85. package/dist/__tests__/streamable-http-cov.test.d.ts +2 -0
  86. package/dist/__tests__/streamable-http-cov.test.d.ts.map +1 -0
  87. package/dist/__tests__/streamable-http-transport.test.d.ts +2 -0
  88. package/dist/__tests__/streamable-http-transport.test.d.ts.map +1 -0
  89. package/dist/__tests__/structured-logger.test.d.ts +2 -0
  90. package/dist/__tests__/structured-logger.test.d.ts.map +1 -0
  91. package/dist/__tests__/thought-evaluator.test.d.ts +2 -0
  92. package/dist/__tests__/thought-evaluator.test.d.ts.map +1 -0
  93. package/dist/__tests__/thought-formatter.test.d.ts +2 -0
  94. package/dist/__tests__/thought-formatter.test.d.ts.map +1 -0
  95. package/dist/__tests__/thought-processor.test.d.ts +8 -0
  96. package/dist/__tests__/thought-processor.test.d.ts.map +1 -0
  97. package/dist/__tests__/tool-registry-cov.test.d.ts +2 -0
  98. package/dist/__tests__/tool-registry-cov.test.d.ts.map +1 -0
  99. package/dist/__tests__/tool-registry.test.d.ts +2 -0
  100. package/dist/__tests__/tool-registry.test.d.ts.map +1 -0
  101. package/dist/__tests__/tool-watcher.test.d.ts +2 -0
  102. package/dist/__tests__/tool-watcher.test.d.ts.map +1 -0
  103. package/dist/__tests__/worker-manager-cov.test.d.ts +2 -0
  104. package/dist/__tests__/worker-manager-cov.test.d.ts.map +1 -0
  105. package/dist/__tests__/worker-manager.test.d.ts +2 -0
  106. package/dist/__tests__/worker-manager.test.d.ts.map +1 -0
  107. package/dist/cache/DiscoveryCache.d.ts +269 -0
  108. package/dist/cache/DiscoveryCache.d.ts.map +1 -0
  109. package/dist/cache/DiscoveryCache.js +100 -0
  110. package/dist/cache/DiscoveryCache.js.map +1 -0
  111. package/dist/cli.d.ts +3 -0
  112. package/dist/cli.d.ts.map +1 -0
  113. package/dist/cli.js +114 -0
  114. package/dist/cli.js.map +1 -0
  115. package/dist/cluster/WorkerManager.d.ts +166 -0
  116. package/dist/cluster/WorkerManager.d.ts.map +1 -0
  117. package/dist/cluster/WorkerManager.js +202 -0
  118. package/dist/cluster/WorkerManager.js.map +1 -0
  119. package/dist/cluster/worker.d.ts +11 -0
  120. package/dist/cluster/worker.d.ts.map +1 -0
  121. package/dist/cluster/worker.js +36 -0
  122. package/dist/cluster/worker.js.map +1 -0
  123. package/dist/config/ConfigLoader.d.ts +224 -0
  124. package/dist/config/ConfigLoader.d.ts.map +1 -0
  125. package/dist/config/ConfigLoader.js +85 -0
  126. package/dist/config/ConfigLoader.js.map +1 -0
  127. package/dist/context/RequestContext.d.ts +61 -0
  128. package/dist/context/RequestContext.d.ts.map +1 -0
  129. package/dist/context/RequestContext.js +17 -0
  130. package/dist/context/RequestContext.js.map +1 -0
  131. package/dist/contracts/index.d.ts +10 -0
  132. package/dist/contracts/index.d.ts.map +1 -0
  133. package/dist/contracts/index.js +1 -0
  134. package/dist/contracts/interfaces.d.ts +107 -0
  135. package/dist/contracts/interfaces.d.ts.map +1 -0
  136. package/dist/contracts/interfaces.js +1 -0
  137. package/dist/core/HistoryManager.d.ts +514 -0
  138. package/dist/core/HistoryManager.d.ts.map +1 -0
  139. package/dist/core/HistoryManager.js +331 -0
  140. package/dist/core/HistoryManager.js.map +1 -0
  141. package/dist/core/IHistoryManager.d.ts +100 -0
  142. package/dist/core/IHistoryManager.d.ts.map +1 -0
  143. package/dist/core/IHistoryManager.js +1 -0
  144. package/dist/core/InputNormalizer.d.ts +139 -0
  145. package/dist/core/InputNormalizer.d.ts.map +1 -0
  146. package/dist/core/InputNormalizer.js +101 -0
  147. package/dist/core/InputNormalizer.js.map +1 -0
  148. package/dist/core/ThoughtEvaluator.d.ts +127 -0
  149. package/dist/core/ThoughtEvaluator.d.ts.map +1 -0
  150. package/dist/core/ThoughtEvaluator.js +346 -0
  151. package/dist/core/ThoughtEvaluator.js.map +1 -0
  152. package/dist/core/ThoughtFormatter.d.ts +133 -0
  153. package/dist/core/ThoughtFormatter.d.ts.map +1 -0
  154. package/dist/core/ThoughtFormatter.js +70 -0
  155. package/dist/core/ThoughtFormatter.js.map +1 -0
  156. package/dist/core/ThoughtProcessor.d.ts +218 -0
  157. package/dist/core/ThoughtProcessor.d.ts.map +1 -0
  158. package/dist/core/ThoughtProcessor.js +205 -0
  159. package/dist/core/ThoughtProcessor.js.map +1 -0
  160. package/dist/core/reasoning.d.ts +169 -0
  161. package/dist/core/reasoning.d.ts.map +1 -0
  162. package/dist/core/reasoning.js +1 -0
  163. package/dist/core/step.d.ts +45 -0
  164. package/dist/core/step.d.ts.map +1 -0
  165. package/dist/core/step.js +1 -0
  166. package/dist/core/thought.d.ts +190 -0
  167. package/dist/core/thought.d.ts.map +1 -0
  168. package/dist/core/thought.js +1 -0
  169. package/dist/di/Container.d.ts +226 -0
  170. package/dist/di/Container.d.ts.map +1 -0
  171. package/dist/di/Container.js +96 -0
  172. package/dist/di/Container.js.map +1 -0
  173. package/dist/di/ServiceRegistry.d.ts +32 -0
  174. package/dist/di/ServiceRegistry.d.ts.map +1 -0
  175. package/dist/di/ServiceRegistry.js +1 -0
  176. package/dist/errors.d.ts +482 -0
  177. package/dist/errors.d.ts.map +1 -0
  178. package/dist/errors.js +108 -0
  179. package/dist/errors.js.map +1 -0
  180. package/dist/health/HealthChecker.d.ts +73 -0
  181. package/dist/health/HealthChecker.d.ts.map +1 -0
  182. package/dist/health/HealthChecker.js +69 -0
  183. package/dist/health/HealthChecker.js.map +1 -0
  184. package/dist/index.d.ts +2 -0
  185. package/dist/index.d.ts.map +1 -0
  186. package/dist/index.js +1 -0
  187. package/dist/lib.d.ts +205 -0
  188. package/dist/lib.d.ts.map +1 -0
  189. package/dist/lib.js +219 -0
  190. package/dist/lib.js.map +1 -0
  191. package/dist/logger/NullLogger.d.ts +154 -0
  192. package/dist/logger/NullLogger.d.ts.map +1 -0
  193. package/dist/logger/NullLogger.js +24 -0
  194. package/dist/logger/NullLogger.js.map +1 -0
  195. package/dist/logger/StructuredLogger.d.ts +327 -0
  196. package/dist/logger/StructuredLogger.d.ts.map +1 -0
  197. package/dist/logger/StructuredLogger.js +72 -0
  198. package/dist/logger/StructuredLogger.js.map +1 -0
  199. package/dist/metrics/__tests__/metrics.test.d.ts +2 -0
  200. package/dist/metrics/__tests__/metrics.test.d.ts.map +1 -0
  201. package/dist/metrics/metrics.impl.d.ts +252 -0
  202. package/dist/metrics/metrics.impl.d.ts.map +1 -0
  203. package/dist/metrics/metrics.impl.js +197 -0
  204. package/dist/metrics/metrics.impl.js.map +1 -0
  205. package/dist/persistence/FilePersistence.d.ts +66 -0
  206. package/dist/persistence/FilePersistence.d.ts.map +1 -0
  207. package/dist/persistence/FilePersistence.js +132 -0
  208. package/dist/persistence/FilePersistence.js.map +1 -0
  209. package/dist/persistence/MemoryPersistence.d.ts +68 -0
  210. package/dist/persistence/MemoryPersistence.d.ts.map +1 -0
  211. package/dist/persistence/MemoryPersistence.js +51 -0
  212. package/dist/persistence/MemoryPersistence.js.map +1 -0
  213. package/dist/persistence/PersistenceBackend.d.ts +69 -0
  214. package/dist/persistence/PersistenceBackend.d.ts.map +1 -0
  215. package/dist/persistence/PersistenceBackend.js +1 -0
  216. package/dist/persistence/PersistenceFactory.d.ts +21 -0
  217. package/dist/persistence/PersistenceFactory.d.ts.map +1 -0
  218. package/dist/persistence/PersistenceFactory.js +25 -0
  219. package/dist/persistence/PersistenceFactory.js.map +1 -0
  220. package/dist/persistence/SqlitePersistence.d.ts +60 -0
  221. package/dist/persistence/SqlitePersistence.d.ts.map +1 -0
  222. package/dist/persistence/SqlitePersistence.js +136 -0
  223. package/dist/persistence/SqlitePersistence.js.map +1 -0
  224. package/dist/pool/ConnectionPool.d.ts +215 -0
  225. package/dist/pool/ConnectionPool.d.ts.map +1 -0
  226. package/dist/pool/ConnectionPool.js +187 -0
  227. package/dist/pool/ConnectionPool.js.map +1 -0
  228. package/dist/registry/BaseRegistry.d.ts +203 -0
  229. package/dist/registry/BaseRegistry.d.ts.map +1 -0
  230. package/dist/registry/BaseRegistry.js +165 -0
  231. package/dist/registry/BaseRegistry.js.map +1 -0
  232. package/dist/registry/SkillRegistry.d.ts +69 -0
  233. package/dist/registry/SkillRegistry.d.ts.map +1 -0
  234. package/dist/registry/SkillRegistry.js +88 -0
  235. package/dist/registry/SkillRegistry.js.map +1 -0
  236. package/dist/registry/ToolRegistry.d.ts +69 -0
  237. package/dist/registry/ToolRegistry.d.ts.map +1 -0
  238. package/dist/registry/ToolRegistry.js +93 -0
  239. package/dist/registry/ToolRegistry.js.map +1 -0
  240. package/dist/sanitize.d.ts +63 -0
  241. package/dist/sanitize.d.ts.map +1 -0
  242. package/dist/sanitize.js +14 -0
  243. package/dist/sanitize.js.map +1 -0
  244. package/dist/schema.d.ts +531 -0
  245. package/dist/schema.d.ts.map +1 -0
  246. package/dist/schema.js +204 -0
  247. package/dist/schema.js.map +1 -0
  248. package/dist/telemetry/Telemetry.d.ts +36 -0
  249. package/dist/telemetry/Telemetry.d.ts.map +1 -0
  250. package/dist/telemetry/Telemetry.js +68 -0
  251. package/dist/telemetry/Telemetry.js.map +1 -0
  252. package/dist/telemetry/__tests__/Telemetry.test.d.ts +2 -0
  253. package/dist/telemetry/__tests__/Telemetry.test.d.ts.map +1 -0
  254. package/dist/transport/BaseTransport.d.ts +184 -0
  255. package/dist/transport/BaseTransport.d.ts.map +1 -0
  256. package/dist/transport/BaseTransport.js +200 -0
  257. package/dist/transport/BaseTransport.js.map +1 -0
  258. package/dist/transport/HttpHelpers.d.ts +60 -0
  259. package/dist/transport/HttpHelpers.d.ts.map +1 -0
  260. package/dist/transport/HttpHelpers.js +50 -0
  261. package/dist/transport/HttpHelpers.js.map +1 -0
  262. package/dist/transport/HttpTransport.d.ts +134 -0
  263. package/dist/transport/HttpTransport.d.ts.map +1 -0
  264. package/dist/transport/HttpTransport.js +175 -0
  265. package/dist/transport/HttpTransport.js.map +1 -0
  266. package/dist/transport/SseTransport.d.ts +133 -0
  267. package/dist/transport/SseTransport.d.ts.map +1 -0
  268. package/dist/transport/SseTransport.js +318 -0
  269. package/dist/transport/SseTransport.js.map +1 -0
  270. package/dist/transport/StreamableHttpTransport.d.ts +224 -0
  271. package/dist/transport/StreamableHttpTransport.d.ts.map +1 -0
  272. package/dist/transport/StreamableHttpTransport.js +407 -0
  273. package/dist/transport/StreamableHttpTransport.js.map +1 -0
  274. package/dist/types/disposable.d.ts +22 -0
  275. package/dist/types/disposable.d.ts.map +1 -0
  276. package/dist/types/disposable.js +1 -0
  277. package/dist/types/server-config.d.ts +32 -0
  278. package/dist/types/server-config.d.ts.map +1 -0
  279. package/dist/types/server-config.js +1 -0
  280. package/dist/types/skill.d.ts +69 -0
  281. package/dist/types/skill.d.ts.map +1 -0
  282. package/dist/types/skill.js +1 -0
  283. package/dist/types/tool.d.ts +68 -0
  284. package/dist/types/tool.d.ts.map +1 -0
  285. package/dist/types/tool.js +1 -0
  286. package/dist/watchers/SkillWatcher.d.ts +132 -0
  287. package/dist/watchers/SkillWatcher.d.ts.map +1 -0
  288. package/dist/watchers/SkillWatcher.js +73 -0
  289. package/dist/watchers/SkillWatcher.js.map +1 -0
  290. package/dist/watchers/ToolWatcher.d.ts +109 -0
  291. package/dist/watchers/ToolWatcher.d.ts.map +1 -0
  292. package/dist/watchers/ToolWatcher.js +71 -0
  293. package/dist/watchers/ToolWatcher.js.map +1 -0
  294. package/package.json +95 -0
@@ -0,0 +1,200 @@
1
+ class NoopLogger {
2
+ _level = 'info';
3
+ info(_message, _meta) {}
4
+ warn(_message, _meta) {}
5
+ error(_message, _meta) {}
6
+ debug(_message, _meta) {}
7
+ setLevel(level) {
8
+ this._level = level;
9
+ }
10
+ getLevel() {
11
+ return this._level;
12
+ }
13
+ }
14
+ const ALLOWED_QUERY_PARAMS = new Set([
15
+ 'session',
16
+ 'sessionId',
17
+ 'client',
18
+ 'clientId'
19
+ ]);
20
+ const MAX_SESSION_ID_LENGTH = 64;
21
+ const SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
22
+ const RATE_LIMIT_REQUESTS = 100;
23
+ const RATE_LIMIT_WINDOW_MS = 60000;
24
+ class BaseTransport {
25
+ _port;
26
+ _host;
27
+ _corsOrigin;
28
+ _enableCors;
29
+ _rateLimitEnabled;
30
+ _maxRequestsPerMinute;
31
+ _allowedHosts;
32
+ _rateLimitMap = new Map();
33
+ _rateLimitCleanupIntervalId = null;
34
+ _wasHostExplicitlySet;
35
+ _isShuttingDown = false;
36
+ _logger;
37
+ _healthChecker;
38
+ constructor(options = {}){
39
+ this._port = options.port ?? 9108;
40
+ this._host = options.host ?? '127.0.0.1';
41
+ this._wasHostExplicitlySet = void 0 !== options.host;
42
+ this._corsOrigin = options.corsOrigin ?? '*';
43
+ this._enableCors = options.enableCors ?? true;
44
+ this._rateLimitEnabled = options.enableRateLimit ?? true;
45
+ this._maxRequestsPerMinute = options.maxRequestsPerMinute ?? RATE_LIMIT_REQUESTS;
46
+ this._allowedHosts = this._buildAllowedHosts(options.allowedHosts);
47
+ this._isShuttingDown = false;
48
+ this._logger = options.logger ?? new NoopLogger();
49
+ this._healthChecker = options.healthChecker ?? null;
50
+ if (this._rateLimitEnabled) this._startRateLimitCleanup();
51
+ }
52
+ get serverUrl() {
53
+ const host = this._wasHostExplicitlySet || '127.0.0.1' !== this._host ? this._host : 'localhost';
54
+ return `http://${host}:${this._port}`;
55
+ }
56
+ validateSessionId(sessionId) {
57
+ if (sessionId.length > MAX_SESSION_ID_LENGTH) return false;
58
+ return SESSION_ID_PATTERN.test(sessionId);
59
+ }
60
+ sanitizeQueryParams(url) {
61
+ const sanitized = {};
62
+ for (const [key, value] of url.searchParams.entries())if (ALLOWED_QUERY_PARAMS.has(key)) sanitized[key] = value;
63
+ return sanitized;
64
+ }
65
+ checkRateLimit(ip) {
66
+ if (!this._rateLimitEnabled) return false;
67
+ const now = Date.now();
68
+ this._cleanupExpiredRateLimitEntries(now);
69
+ const record = this._rateLimitMap.get(ip);
70
+ if (!record || now > record.resetTime) {
71
+ this._rateLimitMap.set(ip, {
72
+ count: 1,
73
+ resetTime: now + RATE_LIMIT_WINDOW_MS
74
+ });
75
+ return false;
76
+ }
77
+ if (record.count >= this._maxRequestsPerMinute) return true;
78
+ record.count++;
79
+ return false;
80
+ }
81
+ _cleanupExpiredRateLimitEntries(now = Date.now()) {
82
+ for (const [ip, record] of this._rateLimitMap.entries())if (record.resetTime <= now) this._rateLimitMap.delete(ip);
83
+ }
84
+ _startRateLimitCleanup() {
85
+ if (null !== this._rateLimitCleanupIntervalId) clearInterval(this._rateLimitCleanupIntervalId);
86
+ this._rateLimitCleanupIntervalId = setInterval(()=>{
87
+ this._cleanupExpiredRateLimitEntries();
88
+ }, RATE_LIMIT_WINDOW_MS);
89
+ }
90
+ _stopRateLimitCleanup() {
91
+ if (null !== this._rateLimitCleanupIntervalId) {
92
+ clearInterval(this._rateLimitCleanupIntervalId);
93
+ this._rateLimitCleanupIntervalId = null;
94
+ }
95
+ }
96
+ getClientIp(req) {
97
+ const forwardedFor = req.headers['x-forwarded-for'];
98
+ if (forwardedFor && 'string' == typeof forwardedFor) return forwardedFor.split(',')[0].trim();
99
+ const remoteAddress = req.socket.remoteAddress;
100
+ return remoteAddress || 'unknown';
101
+ }
102
+ validateCorsOrigin(req) {
103
+ if ('*' === this._corsOrigin) return true;
104
+ const origin = req.headers.origin;
105
+ if (!origin) return true;
106
+ if (this._corsOrigin === origin) return true;
107
+ if (this._corsOrigin.includes('*')) {
108
+ const escaped = this._corsOrigin.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[a-zA-Z0-9.-]*');
109
+ const regex = new RegExp(`^${escaped}$`);
110
+ return regex.test(origin);
111
+ }
112
+ return false;
113
+ }
114
+ setCorsHeaders(res) {
115
+ if (this._enableCors) {
116
+ res.setHeader('Access-Control-Allow-Origin', this._corsOrigin);
117
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
118
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
119
+ }
120
+ }
121
+ validateHostHeader(req) {
122
+ const rawHost = req.headers.host;
123
+ if (!rawHost) return true;
124
+ const hostWithoutPort = rawHost.split(':')[0].trim().toLowerCase();
125
+ if (!hostWithoutPort) return false;
126
+ if (0 === this._allowedHosts.size) return true;
127
+ return this._allowedHosts.has(hostWithoutPort);
128
+ }
129
+ _buildAllowedHosts(configuredHosts) {
130
+ if (configuredHosts && configuredHosts.length > 0) return new Set(configuredHosts.map((host)=>host.toLowerCase().trim()).filter(Boolean));
131
+ const boundHost = this._host.toLowerCase();
132
+ const localHosts = [
133
+ 'localhost',
134
+ '127.0.0.1',
135
+ '::1'
136
+ ];
137
+ if (localHosts.includes(boundHost)) return new Set(localHosts);
138
+ if ('0.0.0.0' === boundHost || '::' === boundHost) return new Set(localHosts);
139
+ return new Set([
140
+ boundHost
141
+ ]);
142
+ }
143
+ log(level, message, meta) {
144
+ if ('info' === level) this._logger.info(message, meta);
145
+ else if ('warn' === level) this._logger.warn(message, meta);
146
+ else this._logger.error(message, meta);
147
+ }
148
+ isShuttingDown() {
149
+ return this._isShuttingDown;
150
+ }
151
+ handleHealthEndpoint(res, extraData) {
152
+ const healthData = {
153
+ status: 'healthy',
154
+ ...extraData
155
+ };
156
+ if (this._healthChecker) {
157
+ const liveness = this._healthChecker.checkLiveness();
158
+ healthData.liveness = liveness;
159
+ }
160
+ res.writeHead(200, {
161
+ 'Content-Type': 'application/json'
162
+ });
163
+ res.end(JSON.stringify(healthData));
164
+ }
165
+ async handleReadinessEndpoint(res) {
166
+ if (this._healthChecker) {
167
+ const readiness = await this._healthChecker.checkReadiness();
168
+ const statusCode = 'ok' === readiness.status ? 200 : 503;
169
+ res.writeHead(statusCode, {
170
+ 'Content-Type': 'application/json'
171
+ });
172
+ res.end(JSON.stringify(readiness));
173
+ } else {
174
+ res.writeHead(200, {
175
+ 'Content-Type': 'application/json'
176
+ });
177
+ res.end(JSON.stringify({
178
+ status: 'ok',
179
+ timestamp: new Date().toISOString(),
180
+ components: {}
181
+ }));
182
+ }
183
+ }
184
+ handleMetricsEndpoint(res, metricsProvider) {
185
+ if (!metricsProvider) {
186
+ res.writeHead(404, {
187
+ 'Content-Type': 'text/plain'
188
+ });
189
+ res.end('Not Found');
190
+ return;
191
+ }
192
+ res.writeHead(200, {
193
+ 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8'
194
+ });
195
+ res.end(metricsProvider());
196
+ }
197
+ }
198
+ export { BaseTransport };
199
+
200
+ //# sourceMappingURL=BaseTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport/BaseTransport.js","sources":["../../src/transport/BaseTransport.ts"],"sourcesContent":["/**\n * Base transport implementation.\n *\n * This class provides shared functionality for all transport implementations,\n * including session validation, rate limiting, CORS handling, and IP extraction.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { URL } from 'node:url';\nimport type { HealthChecker } from '../health/HealthChecker.js';\nimport type { Logger, LogLevel } from '../logger/StructuredLogger.js';\n\n/**\n * No-op logger that does nothing. Used when no logger is provided.\n */\nclass NoopLogger implements Logger {\n\tprivate _level: LogLevel = 'info';\n\n\tinfo(_message: string, _meta?: Record<string, unknown>): void {}\n\twarn(_message: string, _meta?: Record<string, unknown>): void {}\n\terror(_message: string, _meta?: Record<string, unknown>): void {}\n\tdebug(_message: string, _meta?: Record<string, unknown>): void {}\n\tsetLevel(level: LogLevel): void {\n\t\tthis._level = level;\n\t}\n\tgetLevel(): LogLevel {\n\t\treturn this._level;\n\t}\n}\n\n/**\n * Allowed query parameter names (whitelist for security).\n */\nconst ALLOWED_QUERY_PARAMS = new Set(['session', 'sessionId', 'client', 'clientId']);\n\n/**\n * Maximum session ID length.\n */\nconst MAX_SESSION_ID_LENGTH = 64;\n\n/**\n * Session ID validation pattern (alphanumeric, hyphens, underscores).\n */\nconst SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\n/**\n * Rate limit settings (requests per minute per IP).\n */\nconst RATE_LIMIT_REQUESTS = 100;\nconst RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minute\n\n/**\n * Transport interface contract for MCP server communication.\n * All transport implementations must implement this interface.\n */\nexport interface ITransport {\n\t/**\n\t * Connect the transport to an MCP server.\n\t */\n\tconnect(mcpServer: unknown): Promise<void>;\n\n\t/**\n\t * Stop the transport with graceful shutdown.\n\t * @param timeout - Maximum time to wait for in-flight requests (default: 30s)\n\t */\n\tstop(timeout?: number): Promise<void>;\n\n\t/**\n\t * Number of currently connected clients.\n\t */\n\treadonly clientCount: number;\n}\n\nexport interface TransportOptions {\n\tport?: number;\n\thost?: string;\n\tallowedHosts?: string[];\n\tcorsOrigin?: string;\n\tenableCors?: boolean;\n\tenableRateLimit?: boolean;\n\tmaxRequestsPerMinute?: number;\n\tlogger?: Logger;\n\thealthChecker?: HealthChecker;\n}\n\nexport abstract class BaseTransport implements ITransport {\n\tprotected _port: number;\n\tprotected _host: string;\n\tprotected _corsOrigin: string;\n\tprotected _enableCors: boolean;\n\tprotected _rateLimitEnabled: boolean;\n\tprotected _maxRequestsPerMinute: number;\n\tprotected _allowedHosts: Set<string>;\n\tprotected _rateLimitMap: Map<string, { count: number; resetTime: number }> = new Map();\n\tprotected _rateLimitCleanupIntervalId: NodeJS.Timeout | null = null;\n\tprotected _wasHostExplicitlySet: boolean;\n\t/** Shutdown state for graceful shutdown. */\n\tprotected _isShuttingDown: boolean = false;\n\tprivate _logger: Logger | NoopLogger;\n\tprotected _healthChecker: HealthChecker | null;\n\n\tconstructor(options: TransportOptions = {}) {\n\t\tthis._port = options.port ?? 9108;\n\t\tthis._host = options.host ?? '127.0.0.1';\n\t\tthis._wasHostExplicitlySet = options.host !== undefined;\n\t\tthis._corsOrigin = options.corsOrigin ?? '*';\n\t\tthis._enableCors = options.enableCors ?? true;\n\t\tthis._rateLimitEnabled = options.enableRateLimit ?? true;\n\t\tthis._maxRequestsPerMinute = options.maxRequestsPerMinute ?? RATE_LIMIT_REQUESTS;\n\t\tthis._allowedHosts = this._buildAllowedHosts(options.allowedHosts);\n\t\tthis._isShuttingDown = false;\n\t\tthis._logger = options.logger ?? new NoopLogger();\n\t\tthis._healthChecker = options.healthChecker ?? null;\n\n\t\tif (this._rateLimitEnabled) {\n\t\t\tthis._startRateLimitCleanup();\n\t\t}\n\t}\n\n\t/**\n\t * Get the server URL with localhost substitution for default host.\n\t */\n\tget serverUrl(): string {\n\t\tconst host =\n\t\t\t!this._wasHostExplicitlySet && this._host === '127.0.0.1' ? 'localhost' : this._host;\n\t\treturn `http://${host}:${this._port}`;\n\t}\n\n\t/**\n\t * Validate session ID format.\n\t *\n\t * @param sessionId - The session ID to validate\n\t * @returns true if valid, false otherwise\n\t */\n\tprotected validateSessionId(sessionId: string): boolean {\n\t\tif (sessionId.length > MAX_SESSION_ID_LENGTH) {\n\t\t\treturn false;\n\t\t}\n\t\treturn SESSION_ID_PATTERN.test(sessionId);\n\t}\n\n\t/**\n\t * Sanitize query parameters by removing any not in whitelist.\n\t *\n\t * @param url - The URL object containing query parameters\n\t * @returns A sanitized record of allowed query parameters\n\t */\n\tprotected sanitizeQueryParams(url: URL): Record<string, string> {\n\t\tconst sanitized: Record<string, string> = {};\n\n\t\tfor (const [key, value] of url.searchParams.entries()) {\n\t\t\tif (ALLOWED_QUERY_PARAMS.has(key)) {\n\t\t\t\tsanitized[key] = value;\n\t\t\t}\n\t\t}\n\n\t\treturn sanitized;\n\t}\n\n\t/**\n\t * Check rate limit for a given IP address.\n\t *\n\t * @param ip - The IP address to check\n\t * @returns true if rate limit exceeded, false otherwise\n\t */\n\tprotected checkRateLimit(ip: string): boolean {\n\t\tif (!this._rateLimitEnabled) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tthis._cleanupExpiredRateLimitEntries(now);\n\t\tconst record = this._rateLimitMap.get(ip);\n\n\t\tif (!record || now > record.resetTime) {\n\t\t\tthis._rateLimitMap.set(ip, {\n\t\t\t\tcount: 1,\n\t\t\t\tresetTime: now + RATE_LIMIT_WINDOW_MS,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tif (record.count >= this._maxRequestsPerMinute) {\n\t\t\treturn true; // Rate limit exceeded\n\t\t}\n\n\t\trecord.count++;\n\t\treturn false;\n\t}\n\n\tprotected _cleanupExpiredRateLimitEntries(now = Date.now()): void {\n\t\tfor (const [ip, record] of this._rateLimitMap.entries()) {\n\t\t\tif (record.resetTime <= now) {\n\t\t\t\tthis._rateLimitMap.delete(ip);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected _startRateLimitCleanup(): void {\n\t\tif (this._rateLimitCleanupIntervalId !== null) {\n\t\t\tclearInterval(this._rateLimitCleanupIntervalId);\n\t\t}\n\n\t\tthis._rateLimitCleanupIntervalId = setInterval(() => {\n\t\t\tthis._cleanupExpiredRateLimitEntries();\n\t\t}, RATE_LIMIT_WINDOW_MS);\n\t}\n\n\tprotected _stopRateLimitCleanup(): void {\n\t\tif (this._rateLimitCleanupIntervalId !== null) {\n\t\t\tclearInterval(this._rateLimitCleanupIntervalId);\n\t\t\tthis._rateLimitCleanupIntervalId = null;\n\t\t}\n\t}\n\n\t/**\n\t * Get client IP address from request.\n\t *\n\t * @param req - The incoming request\n\t * @returns The client IP address\n\t */\n\tprotected getClientIp(req: IncomingMessage): string {\n\t\tconst forwardedFor = req.headers['x-forwarded-for'];\n\t\tif (forwardedFor && typeof forwardedFor === 'string') {\n\t\t\treturn forwardedFor.split(',')[0]!.trim();\n\t\t}\n\t\tconst remoteAddress = req.socket.remoteAddress;\n\t\treturn remoteAddress || 'unknown';\n\t}\n\n\t/**\n\t * Validate CORS origin from request headers.\n\t *\n\t * @param req - The incoming request\n\t * @returns true if origin is valid, false otherwise\n\t */\n\tprotected validateCorsOrigin(req: IncomingMessage): boolean {\n\t\tif (this._corsOrigin === '*') {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst origin = req.headers.origin;\n\t\tif (!origin) {\n\t\t\treturn true; // No origin header is acceptable\n\t\t}\n\n\t\t// Exact match\n\t\tif (this._corsOrigin === origin) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if configured origin is a wildcard pattern\n\t\tif (this._corsOrigin.includes('*')) {\n\t\t\t// Escape all regex metacharacters EXCEPT *,\n\t\t\t// then replace * with a hostname-safe pattern (alphanumeric, hyphens, dots)\n\t\t\tconst escaped = this._corsOrigin\n\t\t\t\t.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // escape metacharacters (not *)\n\t\t\t\t.replace(/\\*/g, '[a-zA-Z0-9.-]*'); // * matches valid hostname chars only\n\t\t\tconst regex = new RegExp(`^${escaped}$`);\n\t\t\treturn regex.test(origin);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Set CORS headers on response.\n\t *\n\t * @param res - The server response\n\t */\n\tprotected setCorsHeaders(res: ServerResponse): void {\n\t\tif (this._enableCors) {\n\t\t\tres.setHeader('Access-Control-Allow-Origin', this._corsOrigin);\n\t\t\tres.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n\t\t\tres.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\t\t}\n\t}\n\n\tprotected validateHostHeader(req: IncomingMessage): boolean {\n\t\tconst rawHost = req.headers.host;\n\t\tif (!rawHost) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst hostWithoutPort = rawHost.split(':')[0]!.trim().toLowerCase();\n\t\tif (!hostWithoutPort) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._allowedHosts.size === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn this._allowedHosts.has(hostWithoutPort);\n\t}\n\n\tprivate _buildAllowedHosts(configuredHosts?: string[]): Set<string> {\n\t\tif (configuredHosts && configuredHosts.length > 0) {\n\t\t\treturn new Set(configuredHosts.map((host) => host.toLowerCase().trim()).filter(Boolean));\n\t\t}\n\n\t\tconst boundHost = this._host.toLowerCase();\n\t\tconst localHosts = ['localhost', '127.0.0.1', '::1'];\n\n\t\tif (localHosts.includes(boundHost)) {\n\t\t\treturn new Set(localHosts);\n\t\t}\n\n\t\tif (boundHost === '0.0.0.0' || boundHost === '::') {\n\t\t\treturn new Set(localHosts);\n\t\t}\n\n\t\treturn new Set([boundHost]);\n\t}\n\n\t/**\n\t * Log a message using the configured logger.\n\t *\n\t * @param level - Log level\n\t * @param message - Message to log\n\t * @param meta - Optional metadata\n\t */\n\tprotected log(\n\t\tlevel: 'info' | 'warn' | 'error',\n\t\tmessage: string,\n\t\tmeta?: Record<string, unknown>\n\t): void {\n\t\tif (level === 'info') {\n\t\t\tthis._logger.info(message, meta);\n\t\t} else if (level === 'warn') {\n\t\t\tthis._logger.warn(message, meta);\n\t\t} else {\n\t\t\tthis._logger.error(message, meta);\n\t\t}\n\t}\n\n\t/**\n\t * Check if transport is shutting down.\n\t * @returns true if in shutdown phase\n\t */\n\tprotected isShuttingDown(): boolean {\n\t\treturn this._isShuttingDown;\n\t}\n\n\t/**\n\t * Handle GET /health endpoint — liveness check.\n\t *\n\t * Builds a standard health response with optional liveness data from the health checker.\n\t * Transports can pass extra data (e.g. client counts, session info).\n\t *\n\t * @param res - The server response\n\t * @param extraData - Optional additional health metadata\n\t */\n\tprotected handleHealthEndpoint(res: ServerResponse, extraData?: Record<string, unknown>): void {\n\t\tconst healthData: Record<string, unknown> = { status: 'healthy', ...extraData };\n\t\tif (this._healthChecker) {\n\t\t\tconst liveness = this._healthChecker.checkLiveness();\n\t\t\thealthData.liveness = liveness;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify(healthData));\n\t}\n\n\t/**\n\t * Handle GET /ready endpoint — readiness check.\n\t *\n\t * Delegates to the health checker if available, otherwise returns a default OK response.\n\t *\n\t * @param res - The server response\n\t */\n\tprotected async handleReadinessEndpoint(res: ServerResponse): Promise<void> {\n\t\tif (this._healthChecker) {\n\t\t\tconst readiness = await this._healthChecker.checkReadiness();\n\t\t\tconst statusCode = readiness.status === 'ok' ? 200 : 503;\n\t\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify(readiness));\n\t\t} else {\n\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({ status: 'ok', timestamp: new Date().toISOString(), components: {} })\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handle GET /metrics endpoint — Prometheus metrics.\n\t *\n\t * Returns 404 if no metrics provider is configured.\n\t *\n\t * @param res - The server response\n\t * @param metricsProvider - Function that returns Prometheus-format metrics text\n\t */\n\tprotected handleMetricsEndpoint(res: ServerResponse, metricsProvider: (() => string) | null): void {\n\t\tif (!metricsProvider) {\n\t\t\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\t\t\tres.end('Not Found');\n\t\t\treturn;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' });\n\t\tres.end(metricsProvider());\n\t}\n\n\t/**\n\t * Connect to MCP server.\n\t */\n\tabstract connect(mcpServer: unknown): Promise<void>;\n\n\t/**\n\t * Stop transport server with graceful shutdown.\n\t *\n\t * This method should:\n\t * 1. Set shutdown flag to prevent new connections\n\t * 2. Wait for in-flight requests to complete (configurable timeout)\n\t * 3. Close server connections\n\t * 4. Release resources\n\t *\n\t * @param timeout - Maximum time to wait for requests to drain (default: 30 seconds)\n\t * @returns Promise that resolves when shutdown is complete\n\t */\n\tabstract stop(timeout?: number): Promise<void>;\n\n\t/**\n\t * Get number of clients connected.\n\t */\n\tabstract get clientCount(): number;\n\n}\n"],"names":["NoopLogger","_message","_meta","level","ALLOWED_QUERY_PARAMS","Set","MAX_SESSION_ID_LENGTH","SESSION_ID_PATTERN","RATE_LIMIT_REQUESTS","RATE_LIMIT_WINDOW_MS","BaseTransport","Map","options","undefined","host","sessionId","url","sanitized","key","value","ip","now","Date","record","clearInterval","setInterval","req","forwardedFor","remoteAddress","origin","escaped","regex","RegExp","res","rawHost","hostWithoutPort","configuredHosts","Boolean","boundHost","localHosts","message","meta","extraData","healthData","liveness","JSON","readiness","statusCode","metricsProvider"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Shared HTTP helper utilities for MCP transport implementations.
3
+ *
4
+ * Centralizes JSON-RPC response formatting, request body reading,
5
+ * and common HTTP response patterns to eliminate duplication across
6
+ * HttpTransport, StreamableHttpTransport, and SseTransport.
7
+ *
8
+ * @module transport/HttpHelpers
9
+ */
10
+ import type { IncomingMessage, ServerResponse } from 'node:http';
11
+ /**
12
+ * Send a JSON-RPC 2.0 error response.
13
+ *
14
+ * Standardizes error response formatting across all transport implementations.
15
+ * All JSON-RPC errors use the standard `{ jsonrpc, id, error }` shape.
16
+ *
17
+ * @param res - The server response to write to
18
+ * @param statusCode - HTTP status code (e.g. 400, 403, 429, 500)
19
+ * @param code - JSON-RPC error code (e.g. -32700, -32600, -32603)
20
+ * @param message - Human-readable error message
21
+ * @param id - Optional JSON-RPC request ID (defaults to null)
22
+ * @param data - Optional additional error data
23
+ */
24
+ export declare function sendJsonRpcError(res: ServerResponse, statusCode: number, code: number, message: string, id?: string | number | null, data?: unknown): void;
25
+ /**
26
+ * Send a JSON-RPC 2.0 success response.
27
+ *
28
+ * @param res - The server response to write to
29
+ * @param response - The JSON-RPC response object to send
30
+ * @param statusCode - HTTP status code (default: 200)
31
+ * @param headers - Optional additional response headers
32
+ */
33
+ export declare function sendJsonRpcResponse(res: ServerResponse, response: unknown, statusCode?: number, headers?: Record<string, string>): void;
34
+ /**
35
+ * Send a CORS preflight (OPTIONS) response.
36
+ *
37
+ * @param res - The server response to write to
38
+ * @param extraAllowHeaders - Optional extra Access-Control-Allow-Headers values
39
+ */
40
+ export declare function sendCorsPreflight(res: ServerResponse, extraAllowHeaders?: string[]): void;
41
+ /**
42
+ * Read the full request body with optional size limit enforcement.
43
+ *
44
+ * Streams the request body chunks, tracking total size.
45
+ * If the body exceeds `maxBodySize`, reading stops and `null` is returned
46
+ * to indicate the payload is too large.
47
+ *
48
+ * @param req - The incoming HTTP request
49
+ * @param maxBodySize - Maximum allowed body size in bytes (0 = unlimited)
50
+ * @returns The body string, or `null` if the body exceeded the size limit
51
+ */
52
+ export declare function readRequestBody(req: IncomingMessage, maxBodySize: number): Promise<string | null>;
53
+ /**
54
+ * Send a plain text 404 Not Found response.
55
+ *
56
+ * @param res - The server response to write to
57
+ * @param message - Optional custom message (default: 'Not Found')
58
+ */
59
+ export declare function sendNotFound(res: ServerResponse, message?: string): void;
60
+ //# sourceMappingURL=HttpHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpHelpers.d.ts","sourceRoot":"","sources":["../../src/transport/HttpHelpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW,EACjC,IAAI,CAAC,EAAE,OAAO,GACZ,IAAI,CAWN;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,OAAO,EACjB,UAAU,GAAE,MAAY,EACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAClC,IAAI,CAIN;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAMzF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACpC,GAAG,EAAE,eAAe,EACpB,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBxB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,GAAE,MAAoB,GAAG,IAAI,CAGrF"}
@@ -0,0 +1,50 @@
1
+ function sendJsonRpcError(res, statusCode, code, message, id = null, data) {
2
+ const body = {
3
+ jsonrpc: '2.0',
4
+ id,
5
+ error: {
6
+ code,
7
+ message
8
+ }
9
+ };
10
+ if (void 0 !== data) body.error.data = data;
11
+ res.writeHead(statusCode, {
12
+ 'Content-Type': 'application/json'
13
+ });
14
+ res.end(JSON.stringify(body));
15
+ }
16
+ function sendJsonRpcResponse(res, response, statusCode = 200, headers = {}) {
17
+ const defaultHeaders = {
18
+ 'Content-Type': 'application/json'
19
+ };
20
+ res.writeHead(statusCode, {
21
+ ...defaultHeaders,
22
+ ...headers
23
+ });
24
+ res.end(JSON.stringify(response));
25
+ }
26
+ function sendCorsPreflight(res, extraAllowHeaders) {
27
+ if (extraAllowHeaders && extraAllowHeaders.length > 0) res.setHeader('Access-Control-Allow-Headers', `Content-Type, ${extraAllowHeaders.join(', ')}`);
28
+ res.writeHead(204);
29
+ res.end();
30
+ }
31
+ async function readRequestBody(req, maxBodySize) {
32
+ let body = '';
33
+ let bodySize = 0;
34
+ for await (const chunk of req){
35
+ const chunkStr = 'string' == typeof chunk ? chunk : chunk.toString();
36
+ bodySize += chunkStr.length;
37
+ if (maxBodySize > 0 && bodySize > maxBodySize) return null;
38
+ body += chunkStr;
39
+ }
40
+ return body;
41
+ }
42
+ function sendNotFound(res, message = 'Not Found') {
43
+ res.writeHead(404, {
44
+ 'Content-Type': 'text/plain'
45
+ });
46
+ res.end(message);
47
+ }
48
+ export { readRequestBody, sendCorsPreflight, sendJsonRpcError, sendJsonRpcResponse, sendNotFound };
49
+
50
+ //# sourceMappingURL=HttpHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport/HttpHelpers.js","sources":["../../src/transport/HttpHelpers.ts"],"sourcesContent":["/**\n * Shared HTTP helper utilities for MCP transport implementations.\n *\n * Centralizes JSON-RPC response formatting, request body reading,\n * and common HTTP response patterns to eliminate duplication across\n * HttpTransport, StreamableHttpTransport, and SseTransport.\n *\n * @module transport/HttpHelpers\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/**\n * Send a JSON-RPC 2.0 error response.\n *\n * Standardizes error response formatting across all transport implementations.\n * All JSON-RPC errors use the standard `{ jsonrpc, id, error }` shape.\n *\n * @param res - The server response to write to\n * @param statusCode - HTTP status code (e.g. 400, 403, 429, 500)\n * @param code - JSON-RPC error code (e.g. -32700, -32600, -32603)\n * @param message - Human-readable error message\n * @param id - Optional JSON-RPC request ID (defaults to null)\n * @param data - Optional additional error data\n */\nexport function sendJsonRpcError(\n\tres: ServerResponse,\n\tstatusCode: number,\n\tcode: number,\n\tmessage: string,\n\tid: string | number | null = null,\n\tdata?: unknown\n): void {\n\tconst body: Record<string, unknown> = {\n\t\tjsonrpc: '2.0',\n\t\tid,\n\t\terror: { code, message },\n\t};\n\tif (data !== undefined) {\n\t\t(body.error as Record<string, unknown>).data = data;\n\t}\n\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\tres.end(JSON.stringify(body));\n}\n\n/**\n * Send a JSON-RPC 2.0 success response.\n *\n * @param res - The server response to write to\n * @param response - The JSON-RPC response object to send\n * @param statusCode - HTTP status code (default: 200)\n * @param headers - Optional additional response headers\n */\nexport function sendJsonRpcResponse(\n\tres: ServerResponse,\n\tresponse: unknown,\n\tstatusCode: number = 200,\n\theaders: Record<string, string> = {}\n): void {\n\tconst defaultHeaders: Record<string, string> = { 'Content-Type': 'application/json' };\n\tres.writeHead(statusCode, { ...defaultHeaders, ...headers });\n\tres.end(JSON.stringify(response));\n}\n\n/**\n * Send a CORS preflight (OPTIONS) response.\n *\n * @param res - The server response to write to\n * @param extraAllowHeaders - Optional extra Access-Control-Allow-Headers values\n */\nexport function sendCorsPreflight(res: ServerResponse, extraAllowHeaders?: string[]): void {\n\tif (extraAllowHeaders && extraAllowHeaders.length > 0) {\n\t\tres.setHeader('Access-Control-Allow-Headers', `Content-Type, ${extraAllowHeaders.join(', ')}`);\n\t}\n\tres.writeHead(204);\n\tres.end();\n}\n\n/**\n * Read the full request body with optional size limit enforcement.\n *\n * Streams the request body chunks, tracking total size.\n * If the body exceeds `maxBodySize`, reading stops and `null` is returned\n * to indicate the payload is too large.\n *\n * @param req - The incoming HTTP request\n * @param maxBodySize - Maximum allowed body size in bytes (0 = unlimited)\n * @returns The body string, or `null` if the body exceeded the size limit\n */\nexport async function readRequestBody(\n\treq: IncomingMessage,\n\tmaxBodySize: number\n): Promise<string | null> {\n\tlet body = '';\n\tlet bodySize = 0;\n\n\tfor await (const chunk of req) {\n\t\tconst chunkStr = typeof chunk === 'string' ? chunk : (chunk as Buffer).toString();\n\t\tbodySize += chunkStr.length;\n\n\t\tif (maxBodySize > 0 && bodySize > maxBodySize) {\n\t\t\treturn null;\n\t\t}\n\n\t\tbody += chunkStr;\n\t}\n\n\treturn body;\n}\n\n/**\n * Send a plain text 404 Not Found response.\n *\n * @param res - The server response to write to\n * @param message - Optional custom message (default: 'Not Found')\n */\nexport function sendNotFound(res: ServerResponse, message: string = 'Not Found'): void {\n\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\tres.end(message);\n}\n"],"names":["sendJsonRpcError","res","statusCode","code","message","id","data","body","undefined","JSON","sendJsonRpcResponse","response","headers","defaultHeaders","sendCorsPreflight","extraAllowHeaders","readRequestBody","req","maxBodySize","bodySize","chunk","chunkStr","sendNotFound"],"mappings":"AAyBO,SAASA,iBACfC,GAAmB,EACnBC,UAAkB,EAClBC,IAAY,EACZC,OAAe,EACfC,KAA6B,IAAI,EACjCC,IAAc;IAEd,MAAMC,OAAgC;QACrC,SAAS;QACTF;QACA,OAAO;YAAEF;YAAMC;QAAQ;IACxB;IACA,IAAIE,AAASE,WAATF,MACFC,KAAK,KAAK,CAA6B,IAAI,GAAGD;IAEhDL,IAAI,SAAS,CAACC,YAAY;QAAE,gBAAgB;IAAmB;IAC/DD,IAAI,GAAG,CAACQ,KAAK,SAAS,CAACF;AACxB;AAUO,SAASG,oBACfT,GAAmB,EACnBU,QAAiB,EACjBT,aAAqB,GAAG,EACxBU,UAAkC,CAAC,CAAC;IAEpC,MAAMC,iBAAyC;QAAE,gBAAgB;IAAmB;IACpFZ,IAAI,SAAS,CAACC,YAAY;QAAE,GAAGW,cAAc;QAAE,GAAGD,OAAO;IAAC;IAC1DX,IAAI,GAAG,CAACQ,KAAK,SAAS,CAACE;AACxB;AAQO,SAASG,kBAAkBb,GAAmB,EAAEc,iBAA4B;IAClF,IAAIA,qBAAqBA,kBAAkB,MAAM,GAAG,GACnDd,IAAI,SAAS,CAAC,gCAAgC,CAAC,cAAc,EAAEc,kBAAkB,IAAI,CAAC,OAAO;IAE9Fd,IAAI,SAAS,CAAC;IACdA,IAAI,GAAG;AACR;AAaO,eAAee,gBACrBC,GAAoB,EACpBC,WAAmB;IAEnB,IAAIX,OAAO;IACX,IAAIY,WAAW;IAEf,WAAW,MAAMC,SAASH,IAAK;QAC9B,MAAMI,WAAW,AAAiB,YAAjB,OAAOD,QAAqBA,QAASA,MAAiB,QAAQ;QAC/ED,YAAYE,SAAS,MAAM;QAE3B,IAAIH,cAAc,KAAKC,WAAWD,aACjC,OAAO;QAGRX,QAAQc;IACT;IAEA,OAAOd;AACR;AAQO,SAASe,aAAarB,GAAmB,EAAEG,UAAkB,WAAW;IAC9EH,IAAI,SAAS,CAAC,KAAK;QAAE,gBAAgB;IAAa;IAClDA,IAAI,GAAG,CAACG;AACT"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * HTTP Transport implementation.
3
+ *
4
+ * This transport provides a stateless, REST-like API interface for MCP tool invocations
5
+ * using standard HTTP request-response patterns.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const transport = new HttpTransport({
10
+ * port: 3000,
11
+ * host: 'localhost'
12
+ * });
13
+ * await transport.connect(server);
14
+ * ```
15
+ */
16
+ import type { McpServer } from 'tmcp';
17
+ import type { IMetrics } from '../contracts/index.js';
18
+ import { BaseTransport, type TransportOptions } from './BaseTransport.js';
19
+ export interface HttpTransportOptions extends TransportOptions {
20
+ /**
21
+ * Path for messages endpoint
22
+ * @default '/messages'
23
+ */
24
+ path?: string;
25
+ metrics?: IMetrics;
26
+ metricsProvider?: () => string;
27
+ /**
28
+ * Enable request body size limit
29
+ * @default true
30
+ */
31
+ enableBodySizeLimit?: boolean;
32
+ /**
33
+ * Maximum request body size in bytes
34
+ * @default 10485760 (10MB)
35
+ */
36
+ maxBodySize?: number;
37
+ /**
38
+ * Request timeout in milliseconds
39
+ * @default 30000 (30 seconds)
40
+ */
41
+ requestTimeout?: number;
42
+ }
43
+ /**
44
+ * HTTP Transport for MCP server.
45
+ *
46
+ * This transport provides a stateless, REST-like API interface for MCP tool invocations
47
+ * using standard HTTP request-response patterns.
48
+ *
49
+ * @remarks
50
+ * **Security Features:**
51
+ * - Session ID validation (alphanumeric, max 64 chars)
52
+ * - Query parameter sanitization (whitelist allowed keys)
53
+ * - Rate limiting per IP (configurable, default 100 req/min)
54
+ * - CORS origin validation
55
+ * - Request body size limits (configurable, default 10MB)
56
+ * - Request timeout (configurable, default 30s)
57
+ *
58
+ * **Rate Limiting:**
59
+ * - Tracks requests per IP address within a time window
60
+ * - Returns 429 Too Many Requests when limit exceeded
61
+ * - Can be disabled via `enableRateLimit: false`
62
+ *
63
+ * **HTTP Status Code Mapping:**
64
+ * - 200: Success (JSON-RPC response)
65
+ * - 204: CORS Preflight (empty body)
66
+ * - 400: Bad Request
67
+ * - 403: Forbidden (invalid CORS)
68
+ * - 404: Not Found
69
+ * - 413: Payload Too Large
70
+ * - 429: Too Many Requests
71
+ * - 500: Internal Server Error
72
+ * - 503: Server Not Ready
73
+ */
74
+ export declare class HttpTransport extends BaseTransport {
75
+ private _server;
76
+ private _mcpServer;
77
+ private _requestTimeout;
78
+ private _bodySizeLimitEnabled;
79
+ private _maxBodySize;
80
+ private _requestCount;
81
+ private _activeRequests;
82
+ private _path;
83
+ private _metrics?;
84
+ private _metricsProvider;
85
+ constructor(options?: HttpTransportOptions);
86
+ /**
87
+ * Get number of active HTTP connections.
88
+ */
89
+ get clientCount(): number;
90
+ /**
91
+ * Connects MCP server to this transport.
92
+ */
93
+ connect(mcpServer: McpServer): Promise<void>;
94
+ /**
95
+ * Track an error in metrics.
96
+ */
97
+ private _trackError;
98
+ /**
99
+ * Route and handle incoming HTTP requests.
100
+ *
101
+ * Performs security checks (host, shutdown, rate limit, CORS) then
102
+ * dispatches to the appropriate endpoint handler.
103
+ */
104
+ private _handleRequest;
105
+ /**
106
+ * Handle POST to the MCP messages endpoint.
107
+ *
108
+ * Reads the request body, validates JSON-RPC format, and delegates
109
+ * processing to the MCP server.
110
+ */
111
+ private _handlePostRequest;
112
+ /**
113
+ * Returns number of requests handled.
114
+ */
115
+ get requestCount(): number;
116
+ /**
117
+ * Stops transport server.
118
+ */
119
+ stop(): Promise<void>;
120
+ }
121
+ /**
122
+ * Create an HTTP transport with given options.
123
+ *
124
+ * @param options - Transport configuration
125
+ * @returns A configured HTTP transport
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * const transport = new HttpTransport({ port: 3000 });
130
+ * await transport.connect(server);
131
+ * ```
132
+ */
133
+ export declare function createHttpTransport(options?: HttpTransportOptions): HttpTransport;
134
+ //# sourceMappingURL=HttpTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/HttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAQ1E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,aAAc,SAAQ,aAAa;IAC/C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;gBAEpC,OAAO,GAAE,oBAAyB;IAY9C;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;OAKG;YACW,cAAc;IAiE5B;;;;;OAKG;YACW,kBAAkB;IAqFhC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAW3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAErF"}