palaryn 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 (607) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +716 -0
  3. package/dist/sdk/typescript/src/client.d.ts +71 -0
  4. package/dist/sdk/typescript/src/client.d.ts.map +1 -0
  5. package/dist/sdk/typescript/src/client.js +176 -0
  6. package/dist/sdk/typescript/src/client.js.map +1 -0
  7. package/dist/sdk/typescript/src/errors.d.ts +50 -0
  8. package/dist/sdk/typescript/src/errors.d.ts.map +1 -0
  9. package/dist/sdk/typescript/src/errors.js +103 -0
  10. package/dist/sdk/typescript/src/errors.js.map +1 -0
  11. package/dist/sdk/typescript/src/index.d.ts +4 -0
  12. package/dist/sdk/typescript/src/index.d.ts.map +1 -0
  13. package/dist/sdk/typescript/src/index.js +15 -0
  14. package/dist/sdk/typescript/src/index.js.map +1 -0
  15. package/dist/sdk/typescript/src/types.d.ts +101 -0
  16. package/dist/sdk/typescript/src/types.d.ts.map +1 -0
  17. package/dist/sdk/typescript/src/types.js +6 -0
  18. package/dist/sdk/typescript/src/types.js.map +1 -0
  19. package/dist/src/admin/index.d.ts +2 -0
  20. package/dist/src/admin/index.d.ts.map +1 -0
  21. package/dist/src/admin/index.js +6 -0
  22. package/dist/src/admin/index.js.map +1 -0
  23. package/dist/src/admin/routes.d.ts +5 -0
  24. package/dist/src/admin/routes.d.ts.map +1 -0
  25. package/dist/src/admin/routes.js +471 -0
  26. package/dist/src/admin/routes.js.map +1 -0
  27. package/dist/src/admin/templates.d.ts +51 -0
  28. package/dist/src/admin/templates.d.ts.map +1 -0
  29. package/dist/src/admin/templates.js +500 -0
  30. package/dist/src/admin/templates.js.map +1 -0
  31. package/dist/src/anomaly/detector.d.ts +141 -0
  32. package/dist/src/anomaly/detector.d.ts.map +1 -0
  33. package/dist/src/anomaly/detector.js +554 -0
  34. package/dist/src/anomaly/detector.js.map +1 -0
  35. package/dist/src/anomaly/index.d.ts +2 -0
  36. package/dist/src/anomaly/index.d.ts.map +1 -0
  37. package/dist/src/anomaly/index.js +7 -0
  38. package/dist/src/anomaly/index.js.map +1 -0
  39. package/dist/src/approval/manager.d.ts +147 -0
  40. package/dist/src/approval/manager.d.ts.map +1 -0
  41. package/dist/src/approval/manager.js +511 -0
  42. package/dist/src/approval/manager.js.map +1 -0
  43. package/dist/src/approval/webhook.d.ts +36 -0
  44. package/dist/src/approval/webhook.d.ts.map +1 -0
  45. package/dist/src/approval/webhook.js +135 -0
  46. package/dist/src/approval/webhook.js.map +1 -0
  47. package/dist/src/audit/logger.d.ts +70 -0
  48. package/dist/src/audit/logger.d.ts.map +1 -0
  49. package/dist/src/audit/logger.js +440 -0
  50. package/dist/src/audit/logger.js.map +1 -0
  51. package/dist/src/auth/index.d.ts +6 -0
  52. package/dist/src/auth/index.d.ts.map +1 -0
  53. package/dist/src/auth/index.js +22 -0
  54. package/dist/src/auth/index.js.map +1 -0
  55. package/dist/src/auth/password.d.ts +3 -0
  56. package/dist/src/auth/password.d.ts.map +1 -0
  57. package/dist/src/auth/password.js +25 -0
  58. package/dist/src/auth/password.js.map +1 -0
  59. package/dist/src/auth/pkce.d.ts +13 -0
  60. package/dist/src/auth/pkce.d.ts.map +1 -0
  61. package/dist/src/auth/pkce.js +58 -0
  62. package/dist/src/auth/pkce.js.map +1 -0
  63. package/dist/src/auth/providers.d.ts +28 -0
  64. package/dist/src/auth/providers.d.ts.map +1 -0
  65. package/dist/src/auth/providers.js +198 -0
  66. package/dist/src/auth/providers.js.map +1 -0
  67. package/dist/src/auth/routes.d.ts +14 -0
  68. package/dist/src/auth/routes.d.ts.map +1 -0
  69. package/dist/src/auth/routes.js +431 -0
  70. package/dist/src/auth/routes.js.map +1 -0
  71. package/dist/src/auth/session.d.ts +24 -0
  72. package/dist/src/auth/session.d.ts.map +1 -0
  73. package/dist/src/auth/session.js +105 -0
  74. package/dist/src/auth/session.js.map +1 -0
  75. package/dist/src/billing/index.d.ts +7 -0
  76. package/dist/src/billing/index.d.ts.map +1 -0
  77. package/dist/src/billing/index.js +14 -0
  78. package/dist/src/billing/index.js.map +1 -0
  79. package/dist/src/billing/plan-enforcer.d.ts +44 -0
  80. package/dist/src/billing/plan-enforcer.d.ts.map +1 -0
  81. package/dist/src/billing/plan-enforcer.js +110 -0
  82. package/dist/src/billing/plan-enforcer.js.map +1 -0
  83. package/dist/src/billing/routes.d.ts +15 -0
  84. package/dist/src/billing/routes.d.ts.map +1 -0
  85. package/dist/src/billing/routes.js +193 -0
  86. package/dist/src/billing/routes.js.map +1 -0
  87. package/dist/src/billing/stripe-client.d.ts +14 -0
  88. package/dist/src/billing/stripe-client.d.ts.map +1 -0
  89. package/dist/src/billing/stripe-client.js +51 -0
  90. package/dist/src/billing/stripe-client.js.map +1 -0
  91. package/dist/src/billing/webhook-handler.d.ts +19 -0
  92. package/dist/src/billing/webhook-handler.d.ts.map +1 -0
  93. package/dist/src/billing/webhook-handler.js +169 -0
  94. package/dist/src/billing/webhook-handler.js.map +1 -0
  95. package/dist/src/billing/webhook-routes.d.ts +5 -0
  96. package/dist/src/billing/webhook-routes.d.ts.map +1 -0
  97. package/dist/src/billing/webhook-routes.js +30 -0
  98. package/dist/src/billing/webhook-routes.js.map +1 -0
  99. package/dist/src/budget/manager.d.ts +95 -0
  100. package/dist/src/budget/manager.d.ts.map +1 -0
  101. package/dist/src/budget/manager.js +547 -0
  102. package/dist/src/budget/manager.js.map +1 -0
  103. package/dist/src/budget/usage-extractor.d.ts +38 -0
  104. package/dist/src/budget/usage-extractor.d.ts.map +1 -0
  105. package/dist/src/budget/usage-extractor.js +165 -0
  106. package/dist/src/budget/usage-extractor.js.map +1 -0
  107. package/dist/src/cli.d.ts +3 -0
  108. package/dist/src/cli.d.ts.map +1 -0
  109. package/dist/src/cli.js +115 -0
  110. package/dist/src/cli.js.map +1 -0
  111. package/dist/src/config/defaults.d.ts +3 -0
  112. package/dist/src/config/defaults.d.ts.map +1 -0
  113. package/dist/src/config/defaults.js +243 -0
  114. package/dist/src/config/defaults.js.map +1 -0
  115. package/dist/src/config/validate.d.ts +15 -0
  116. package/dist/src/config/validate.d.ts.map +1 -0
  117. package/dist/src/config/validate.js +105 -0
  118. package/dist/src/config/validate.js.map +1 -0
  119. package/dist/src/dlp/composite-scanner.d.ts +47 -0
  120. package/dist/src/dlp/composite-scanner.d.ts.map +1 -0
  121. package/dist/src/dlp/composite-scanner.js +186 -0
  122. package/dist/src/dlp/composite-scanner.js.map +1 -0
  123. package/dist/src/dlp/index.d.ts +10 -0
  124. package/dist/src/dlp/index.d.ts.map +1 -0
  125. package/dist/src/dlp/index.js +26 -0
  126. package/dist/src/dlp/index.js.map +1 -0
  127. package/dist/src/dlp/interfaces.d.ts +33 -0
  128. package/dist/src/dlp/interfaces.d.ts.map +1 -0
  129. package/dist/src/dlp/interfaces.js +3 -0
  130. package/dist/src/dlp/interfaces.js.map +1 -0
  131. package/dist/src/dlp/patterns.d.ts +9 -0
  132. package/dist/src/dlp/patterns.d.ts.map +1 -0
  133. package/dist/src/dlp/patterns.js +25 -0
  134. package/dist/src/dlp/patterns.js.map +1 -0
  135. package/dist/src/dlp/prompt-injection-backend.d.ts +68 -0
  136. package/dist/src/dlp/prompt-injection-backend.d.ts.map +1 -0
  137. package/dist/src/dlp/prompt-injection-backend.js +148 -0
  138. package/dist/src/dlp/prompt-injection-backend.js.map +1 -0
  139. package/dist/src/dlp/prompt-injection-patterns.d.ts +32 -0
  140. package/dist/src/dlp/prompt-injection-patterns.d.ts.map +1 -0
  141. package/dist/src/dlp/prompt-injection-patterns.js +290 -0
  142. package/dist/src/dlp/prompt-injection-patterns.js.map +1 -0
  143. package/dist/src/dlp/regex-backend.d.ts +32 -0
  144. package/dist/src/dlp/regex-backend.d.ts.map +1 -0
  145. package/dist/src/dlp/regex-backend.js +153 -0
  146. package/dist/src/dlp/regex-backend.js.map +1 -0
  147. package/dist/src/dlp/scanner.d.ts +122 -0
  148. package/dist/src/dlp/scanner.d.ts.map +1 -0
  149. package/dist/src/dlp/scanner.js +444 -0
  150. package/dist/src/dlp/scanner.js.map +1 -0
  151. package/dist/src/dlp/text-normalizer.d.ts +41 -0
  152. package/dist/src/dlp/text-normalizer.d.ts.map +1 -0
  153. package/dist/src/dlp/text-normalizer.js +203 -0
  154. package/dist/src/dlp/text-normalizer.js.map +1 -0
  155. package/dist/src/dlp/trufflehog-backend.d.ts +64 -0
  156. package/dist/src/dlp/trufflehog-backend.d.ts.map +1 -0
  157. package/dist/src/dlp/trufflehog-backend.js +151 -0
  158. package/dist/src/dlp/trufflehog-backend.js.map +1 -0
  159. package/dist/src/executor/http-executor.d.ts +25 -0
  160. package/dist/src/executor/http-executor.d.ts.map +1 -0
  161. package/dist/src/executor/http-executor.js +333 -0
  162. package/dist/src/executor/http-executor.js.map +1 -0
  163. package/dist/src/executor/index.d.ts +6 -0
  164. package/dist/src/executor/index.d.ts.map +1 -0
  165. package/dist/src/executor/index.js +12 -0
  166. package/dist/src/executor/index.js.map +1 -0
  167. package/dist/src/executor/interfaces.d.ts +11 -0
  168. package/dist/src/executor/interfaces.d.ts.map +1 -0
  169. package/dist/src/executor/interfaces.js +3 -0
  170. package/dist/src/executor/interfaces.js.map +1 -0
  171. package/dist/src/executor/noop-executor.d.ts +13 -0
  172. package/dist/src/executor/noop-executor.d.ts.map +1 -0
  173. package/dist/src/executor/noop-executor.js +21 -0
  174. package/dist/src/executor/noop-executor.js.map +1 -0
  175. package/dist/src/executor/registry.d.ts +30 -0
  176. package/dist/src/executor/registry.d.ts.map +1 -0
  177. package/dist/src/executor/registry.js +62 -0
  178. package/dist/src/executor/registry.js.map +1 -0
  179. package/dist/src/executor/slack-executor.d.ts +24 -0
  180. package/dist/src/executor/slack-executor.d.ts.map +1 -0
  181. package/dist/src/executor/slack-executor.js +147 -0
  182. package/dist/src/executor/slack-executor.js.map +1 -0
  183. package/dist/src/index.d.ts +25 -0
  184. package/dist/src/index.d.ts.map +1 -0
  185. package/dist/src/index.js +74 -0
  186. package/dist/src/index.js.map +1 -0
  187. package/dist/src/mcp/auth-verifier.d.ts +23 -0
  188. package/dist/src/mcp/auth-verifier.d.ts.map +1 -0
  189. package/dist/src/mcp/auth-verifier.js +162 -0
  190. package/dist/src/mcp/auth-verifier.js.map +1 -0
  191. package/dist/src/mcp/bridge.d.ts +132 -0
  192. package/dist/src/mcp/bridge.d.ts.map +1 -0
  193. package/dist/src/mcp/bridge.js +734 -0
  194. package/dist/src/mcp/bridge.js.map +1 -0
  195. package/dist/src/mcp/http-transport.d.ts +32 -0
  196. package/dist/src/mcp/http-transport.d.ts.map +1 -0
  197. package/dist/src/mcp/http-transport.js +538 -0
  198. package/dist/src/mcp/http-transport.js.map +1 -0
  199. package/dist/src/mcp/index.d.ts +10 -0
  200. package/dist/src/mcp/index.d.ts.map +1 -0
  201. package/dist/src/mcp/index.js +17 -0
  202. package/dist/src/mcp/index.js.map +1 -0
  203. package/dist/src/mcp/oauth-pages.d.ts +23 -0
  204. package/dist/src/mcp/oauth-pages.d.ts.map +1 -0
  205. package/dist/src/mcp/oauth-pages.js +121 -0
  206. package/dist/src/mcp/oauth-pages.js.map +1 -0
  207. package/dist/src/mcp/oauth-postgres-stores.d.ts +55 -0
  208. package/dist/src/mcp/oauth-postgres-stores.d.ts.map +1 -0
  209. package/dist/src/mcp/oauth-postgres-stores.js +226 -0
  210. package/dist/src/mcp/oauth-postgres-stores.js.map +1 -0
  211. package/dist/src/mcp/oauth-provider.d.ts +95 -0
  212. package/dist/src/mcp/oauth-provider.d.ts.map +1 -0
  213. package/dist/src/mcp/oauth-provider.js +360 -0
  214. package/dist/src/mcp/oauth-provider.js.map +1 -0
  215. package/dist/src/mcp/oauth-stores.d.ts +62 -0
  216. package/dist/src/mcp/oauth-stores.d.ts.map +1 -0
  217. package/dist/src/mcp/oauth-stores.js +154 -0
  218. package/dist/src/mcp/oauth-stores.js.map +1 -0
  219. package/dist/src/mcp/server.d.ts +18 -0
  220. package/dist/src/mcp/server.d.ts.map +1 -0
  221. package/dist/src/mcp/server.js +51 -0
  222. package/dist/src/mcp/server.js.map +1 -0
  223. package/dist/src/metrics/collector.d.ts +106 -0
  224. package/dist/src/metrics/collector.d.ts.map +1 -0
  225. package/dist/src/metrics/collector.js +311 -0
  226. package/dist/src/metrics/collector.js.map +1 -0
  227. package/dist/src/metrics/index.d.ts +2 -0
  228. package/dist/src/metrics/index.d.ts.map +1 -0
  229. package/dist/src/metrics/index.js +6 -0
  230. package/dist/src/metrics/index.js.map +1 -0
  231. package/dist/src/middleware/auth.d.ts +77 -0
  232. package/dist/src/middleware/auth.d.ts.map +1 -0
  233. package/dist/src/middleware/auth.js +720 -0
  234. package/dist/src/middleware/auth.js.map +1 -0
  235. package/dist/src/middleware/session.d.ts +18 -0
  236. package/dist/src/middleware/session.d.ts.map +1 -0
  237. package/dist/src/middleware/session.js +67 -0
  238. package/dist/src/middleware/session.js.map +1 -0
  239. package/dist/src/middleware/validate.d.ts +3 -0
  240. package/dist/src/middleware/validate.d.ts.map +1 -0
  241. package/dist/src/middleware/validate.js +85 -0
  242. package/dist/src/middleware/validate.js.map +1 -0
  243. package/dist/src/policy/engine.d.ts +107 -0
  244. package/dist/src/policy/engine.d.ts.map +1 -0
  245. package/dist/src/policy/engine.js +646 -0
  246. package/dist/src/policy/engine.js.map +1 -0
  247. package/dist/src/policy/index.d.ts +3 -0
  248. package/dist/src/policy/index.d.ts.map +1 -0
  249. package/dist/src/policy/index.js +8 -0
  250. package/dist/src/policy/index.js.map +1 -0
  251. package/dist/src/policy/opa-engine.d.ts +176 -0
  252. package/dist/src/policy/opa-engine.d.ts.map +1 -0
  253. package/dist/src/policy/opa-engine.js +790 -0
  254. package/dist/src/policy/opa-engine.js.map +1 -0
  255. package/dist/src/proxy/forward-proxy.d.ts +30 -0
  256. package/dist/src/proxy/forward-proxy.d.ts.map +1 -0
  257. package/dist/src/proxy/forward-proxy.js +580 -0
  258. package/dist/src/proxy/forward-proxy.js.map +1 -0
  259. package/dist/src/proxy/index.d.ts +2 -0
  260. package/dist/src/proxy/index.d.ts.map +1 -0
  261. package/dist/src/proxy/index.js +8 -0
  262. package/dist/src/proxy/index.js.map +1 -0
  263. package/dist/src/ratelimit/limiter.d.ts +45 -0
  264. package/dist/src/ratelimit/limiter.d.ts.map +1 -0
  265. package/dist/src/ratelimit/limiter.js +158 -0
  266. package/dist/src/ratelimit/limiter.js.map +1 -0
  267. package/dist/src/replay/engine.d.ts +40 -0
  268. package/dist/src/replay/engine.d.ts.map +1 -0
  269. package/dist/src/replay/engine.js +106 -0
  270. package/dist/src/replay/engine.js.map +1 -0
  271. package/dist/src/replay/index.d.ts +2 -0
  272. package/dist/src/replay/index.d.ts.map +1 -0
  273. package/dist/src/replay/index.js +6 -0
  274. package/dist/src/replay/index.js.map +1 -0
  275. package/dist/src/saas/index.d.ts +2 -0
  276. package/dist/src/saas/index.d.ts.map +1 -0
  277. package/dist/src/saas/index.js +18 -0
  278. package/dist/src/saas/index.js.map +1 -0
  279. package/dist/src/saas/routes.d.ts +18 -0
  280. package/dist/src/saas/routes.d.ts.map +1 -0
  281. package/dist/src/saas/routes.js +1566 -0
  282. package/dist/src/saas/routes.js.map +1 -0
  283. package/dist/src/server/app.d.ts +44 -0
  284. package/dist/src/server/app.d.ts.map +1 -0
  285. package/dist/src/server/app.js +854 -0
  286. package/dist/src/server/app.js.map +1 -0
  287. package/dist/src/server/errors.d.ts +32 -0
  288. package/dist/src/server/errors.d.ts.map +1 -0
  289. package/dist/src/server/errors.js +39 -0
  290. package/dist/src/server/errors.js.map +1 -0
  291. package/dist/src/server/gateway.d.ts +165 -0
  292. package/dist/src/server/gateway.d.ts.map +1 -0
  293. package/dist/src/server/gateway.js +964 -0
  294. package/dist/src/server/gateway.js.map +1 -0
  295. package/dist/src/server/index.d.ts +2 -0
  296. package/dist/src/server/index.d.ts.map +1 -0
  297. package/dist/src/server/index.js +295 -0
  298. package/dist/src/server/index.js.map +1 -0
  299. package/dist/src/server/logger.d.ts +33 -0
  300. package/dist/src/server/logger.d.ts.map +1 -0
  301. package/dist/src/server/logger.js +230 -0
  302. package/dist/src/server/logger.js.map +1 -0
  303. package/dist/src/server/stream-proxy.d.ts +32 -0
  304. package/dist/src/server/stream-proxy.d.ts.map +1 -0
  305. package/dist/src/server/stream-proxy.js +184 -0
  306. package/dist/src/server/stream-proxy.js.map +1 -0
  307. package/dist/src/storage/file-persistence.d.ts +48 -0
  308. package/dist/src/storage/file-persistence.d.ts.map +1 -0
  309. package/dist/src/storage/file-persistence.js +280 -0
  310. package/dist/src/storage/file-persistence.js.map +1 -0
  311. package/dist/src/storage/index.d.ts +5 -0
  312. package/dist/src/storage/index.d.ts.map +1 -0
  313. package/dist/src/storage/index.js +21 -0
  314. package/dist/src/storage/index.js.map +1 -0
  315. package/dist/src/storage/interfaces.d.ts +237 -0
  316. package/dist/src/storage/interfaces.d.ts.map +1 -0
  317. package/dist/src/storage/interfaces.js +3 -0
  318. package/dist/src/storage/interfaces.js.map +1 -0
  319. package/dist/src/storage/memory.d.ts +162 -0
  320. package/dist/src/storage/memory.d.ts.map +1 -0
  321. package/dist/src/storage/memory.js +603 -0
  322. package/dist/src/storage/memory.js.map +1 -0
  323. package/dist/src/storage/postgres.d.ts +267 -0
  324. package/dist/src/storage/postgres.d.ts.map +1 -0
  325. package/dist/src/storage/postgres.js +1555 -0
  326. package/dist/src/storage/postgres.js.map +1 -0
  327. package/dist/src/storage/redis.d.ts +202 -0
  328. package/dist/src/storage/redis.d.ts.map +1 -0
  329. package/dist/src/storage/redis.js +629 -0
  330. package/dist/src/storage/redis.js.map +1 -0
  331. package/dist/src/tracing/index.d.ts +2 -0
  332. package/dist/src/tracing/index.d.ts.map +1 -0
  333. package/dist/src/tracing/index.js +6 -0
  334. package/dist/src/tracing/index.js.map +1 -0
  335. package/dist/src/tracing/provider.d.ts +43 -0
  336. package/dist/src/tracing/provider.d.ts.map +1 -0
  337. package/dist/src/tracing/provider.js +74 -0
  338. package/dist/src/tracing/provider.js.map +1 -0
  339. package/dist/src/trust/calculator.d.ts +54 -0
  340. package/dist/src/trust/calculator.d.ts.map +1 -0
  341. package/dist/src/trust/calculator.js +102 -0
  342. package/dist/src/trust/calculator.js.map +1 -0
  343. package/dist/src/trust/index.d.ts +2 -0
  344. package/dist/src/trust/index.d.ts.map +1 -0
  345. package/dist/src/trust/index.js +7 -0
  346. package/dist/src/trust/index.js.map +1 -0
  347. package/dist/src/types/budget.d.ts +30 -0
  348. package/dist/src/types/budget.d.ts.map +1 -0
  349. package/dist/src/types/budget.js +3 -0
  350. package/dist/src/types/budget.js.map +1 -0
  351. package/dist/src/types/config.d.ts +176 -0
  352. package/dist/src/types/config.d.ts.map +1 -0
  353. package/dist/src/types/config.js +3 -0
  354. package/dist/src/types/config.js.map +1 -0
  355. package/dist/src/types/events.d.ts +24 -0
  356. package/dist/src/types/events.d.ts.map +1 -0
  357. package/dist/src/types/events.js +3 -0
  358. package/dist/src/types/events.js.map +1 -0
  359. package/dist/src/types/index.d.ts +8 -0
  360. package/dist/src/types/index.d.ts.map +1 -0
  361. package/dist/src/types/index.js +24 -0
  362. package/dist/src/types/index.js.map +1 -0
  363. package/dist/src/types/policy.d.ts +60 -0
  364. package/dist/src/types/policy.d.ts.map +1 -0
  365. package/dist/src/types/policy.js +3 -0
  366. package/dist/src/types/policy.js.map +1 -0
  367. package/dist/src/types/stripe-config.d.ts +12 -0
  368. package/dist/src/types/stripe-config.d.ts.map +1 -0
  369. package/dist/src/types/stripe-config.js +3 -0
  370. package/dist/src/types/stripe-config.js.map +1 -0
  371. package/dist/src/types/subscription.d.ts +24 -0
  372. package/dist/src/types/subscription.d.ts.map +1 -0
  373. package/dist/src/types/subscription.js +38 -0
  374. package/dist/src/types/subscription.js.map +1 -0
  375. package/dist/src/types/tool-call.d.ts +42 -0
  376. package/dist/src/types/tool-call.d.ts.map +1 -0
  377. package/dist/src/types/tool-call.js +3 -0
  378. package/dist/src/types/tool-call.js.map +1 -0
  379. package/dist/src/types/tool-result.d.ts +58 -0
  380. package/dist/src/types/tool-result.d.ts.map +1 -0
  381. package/dist/src/types/tool-result.js +3 -0
  382. package/dist/src/types/tool-result.js.map +1 -0
  383. package/dist/src/types/user.d.ts +101 -0
  384. package/dist/src/types/user.d.ts.map +1 -0
  385. package/dist/src/types/user.js +6 -0
  386. package/dist/src/types/user.js.map +1 -0
  387. package/dist/tests/integration/api.test.d.ts +2 -0
  388. package/dist/tests/integration/api.test.d.ts.map +1 -0
  389. package/dist/tests/integration/api.test.js +1199 -0
  390. package/dist/tests/integration/api.test.js.map +1 -0
  391. package/dist/tests/integration/proxy.test.d.ts +2 -0
  392. package/dist/tests/integration/proxy.test.d.ts.map +1 -0
  393. package/dist/tests/integration/proxy.test.js +251 -0
  394. package/dist/tests/integration/proxy.test.js.map +1 -0
  395. package/dist/tests/integration/storage.test.d.ts +16 -0
  396. package/dist/tests/integration/storage.test.d.ts.map +1 -0
  397. package/dist/tests/integration/storage.test.js +826 -0
  398. package/dist/tests/integration/storage.test.js.map +1 -0
  399. package/dist/tests/unit/admin.test.d.ts +2 -0
  400. package/dist/tests/unit/admin.test.d.ts.map +1 -0
  401. package/dist/tests/unit/admin.test.js +698 -0
  402. package/dist/tests/unit/admin.test.js.map +1 -0
  403. package/dist/tests/unit/anomaly-detector.test.d.ts +2 -0
  404. package/dist/tests/unit/anomaly-detector.test.d.ts.map +1 -0
  405. package/dist/tests/unit/anomaly-detector.test.js +903 -0
  406. package/dist/tests/unit/anomaly-detector.test.js.map +1 -0
  407. package/dist/tests/unit/approval-manager.test.d.ts +2 -0
  408. package/dist/tests/unit/approval-manager.test.d.ts.map +1 -0
  409. package/dist/tests/unit/approval-manager.test.js +528 -0
  410. package/dist/tests/unit/approval-manager.test.js.map +1 -0
  411. package/dist/tests/unit/approval-webhook.test.d.ts +2 -0
  412. package/dist/tests/unit/approval-webhook.test.d.ts.map +1 -0
  413. package/dist/tests/unit/approval-webhook.test.js +355 -0
  414. package/dist/tests/unit/approval-webhook.test.js.map +1 -0
  415. package/dist/tests/unit/audit-logger.test.d.ts +2 -0
  416. package/dist/tests/unit/audit-logger.test.d.ts.map +1 -0
  417. package/dist/tests/unit/audit-logger.test.js +635 -0
  418. package/dist/tests/unit/audit-logger.test.js.map +1 -0
  419. package/dist/tests/unit/auth-routes.test.d.ts +2 -0
  420. package/dist/tests/unit/auth-routes.test.d.ts.map +1 -0
  421. package/dist/tests/unit/auth-routes.test.js +281 -0
  422. package/dist/tests/unit/auth-routes.test.js.map +1 -0
  423. package/dist/tests/unit/auth.test.d.ts +2 -0
  424. package/dist/tests/unit/auth.test.d.ts.map +1 -0
  425. package/dist/tests/unit/auth.test.js +1382 -0
  426. package/dist/tests/unit/auth.test.js.map +1 -0
  427. package/dist/tests/unit/billing.test.d.ts +2 -0
  428. package/dist/tests/unit/billing.test.d.ts.map +1 -0
  429. package/dist/tests/unit/billing.test.js +579 -0
  430. package/dist/tests/unit/billing.test.js.map +1 -0
  431. package/dist/tests/unit/budget-manager.test.d.ts +2 -0
  432. package/dist/tests/unit/budget-manager.test.d.ts.map +1 -0
  433. package/dist/tests/unit/budget-manager.test.js +778 -0
  434. package/dist/tests/unit/budget-manager.test.js.map +1 -0
  435. package/dist/tests/unit/budget-race.test.d.ts +2 -0
  436. package/dist/tests/unit/budget-race.test.d.ts.map +1 -0
  437. package/dist/tests/unit/budget-race.test.js +58 -0
  438. package/dist/tests/unit/budget-race.test.js.map +1 -0
  439. package/dist/tests/unit/cli.test.d.ts +2 -0
  440. package/dist/tests/unit/cli.test.d.ts.map +1 -0
  441. package/dist/tests/unit/cli.test.js +93 -0
  442. package/dist/tests/unit/cli.test.js.map +1 -0
  443. package/dist/tests/unit/concurrency.test.d.ts +2 -0
  444. package/dist/tests/unit/concurrency.test.d.ts.map +1 -0
  445. package/dist/tests/unit/concurrency.test.js +1270 -0
  446. package/dist/tests/unit/concurrency.test.js.map +1 -0
  447. package/dist/tests/unit/config-validate.test.d.ts +2 -0
  448. package/dist/tests/unit/config-validate.test.d.ts.map +1 -0
  449. package/dist/tests/unit/config-validate.test.js +230 -0
  450. package/dist/tests/unit/config-validate.test.js.map +1 -0
  451. package/dist/tests/unit/defaults.test.d.ts +2 -0
  452. package/dist/tests/unit/defaults.test.d.ts.map +1 -0
  453. package/dist/tests/unit/defaults.test.js +364 -0
  454. package/dist/tests/unit/defaults.test.js.map +1 -0
  455. package/dist/tests/unit/dlp-backends.test.d.ts +2 -0
  456. package/dist/tests/unit/dlp-backends.test.d.ts.map +1 -0
  457. package/dist/tests/unit/dlp-backends.test.js +563 -0
  458. package/dist/tests/unit/dlp-backends.test.js.map +1 -0
  459. package/dist/tests/unit/dlp-scanner.test.d.ts +2 -0
  460. package/dist/tests/unit/dlp-scanner.test.d.ts.map +1 -0
  461. package/dist/tests/unit/dlp-scanner.test.js +739 -0
  462. package/dist/tests/unit/dlp-scanner.test.js.map +1 -0
  463. package/dist/tests/unit/error-responses.test.d.ts +2 -0
  464. package/dist/tests/unit/error-responses.test.d.ts.map +1 -0
  465. package/dist/tests/unit/error-responses.test.js +101 -0
  466. package/dist/tests/unit/error-responses.test.js.map +1 -0
  467. package/dist/tests/unit/executor-registry.test.d.ts +2 -0
  468. package/dist/tests/unit/executor-registry.test.d.ts.map +1 -0
  469. package/dist/tests/unit/executor-registry.test.js +390 -0
  470. package/dist/tests/unit/executor-registry.test.js.map +1 -0
  471. package/dist/tests/unit/forward-proxy.test.d.ts +2 -0
  472. package/dist/tests/unit/forward-proxy.test.d.ts.map +1 -0
  473. package/dist/tests/unit/forward-proxy.test.js +621 -0
  474. package/dist/tests/unit/forward-proxy.test.js.map +1 -0
  475. package/dist/tests/unit/gateway-features.test.d.ts +2 -0
  476. package/dist/tests/unit/gateway-features.test.d.ts.map +1 -0
  477. package/dist/tests/unit/gateway-features.test.js +753 -0
  478. package/dist/tests/unit/gateway-features.test.js.map +1 -0
  479. package/dist/tests/unit/http-executor.test.d.ts +2 -0
  480. package/dist/tests/unit/http-executor.test.d.ts.map +1 -0
  481. package/dist/tests/unit/http-executor.test.js +310 -0
  482. package/dist/tests/unit/http-executor.test.js.map +1 -0
  483. package/dist/tests/unit/mcp-bridge.test.d.ts +2 -0
  484. package/dist/tests/unit/mcp-bridge.test.d.ts.map +1 -0
  485. package/dist/tests/unit/mcp-bridge.test.js +1136 -0
  486. package/dist/tests/unit/mcp-bridge.test.js.map +1 -0
  487. package/dist/tests/unit/mcp-http-transport.test.d.ts +2 -0
  488. package/dist/tests/unit/mcp-http-transport.test.d.ts.map +1 -0
  489. package/dist/tests/unit/mcp-http-transport.test.js +899 -0
  490. package/dist/tests/unit/mcp-http-transport.test.js.map +1 -0
  491. package/dist/tests/unit/mcp-oauth.test.d.ts +2 -0
  492. package/dist/tests/unit/mcp-oauth.test.d.ts.map +1 -0
  493. package/dist/tests/unit/mcp-oauth.test.js +759 -0
  494. package/dist/tests/unit/mcp-oauth.test.js.map +1 -0
  495. package/dist/tests/unit/mcp-server.test.d.ts +15 -0
  496. package/dist/tests/unit/mcp-server.test.d.ts.map +1 -0
  497. package/dist/tests/unit/mcp-server.test.js +158 -0
  498. package/dist/tests/unit/mcp-server.test.js.map +1 -0
  499. package/dist/tests/unit/metrics.test.d.ts +2 -0
  500. package/dist/tests/unit/metrics.test.d.ts.map +1 -0
  501. package/dist/tests/unit/metrics.test.js +208 -0
  502. package/dist/tests/unit/metrics.test.js.map +1 -0
  503. package/dist/tests/unit/oauth.test.d.ts +2 -0
  504. package/dist/tests/unit/oauth.test.d.ts.map +1 -0
  505. package/dist/tests/unit/oauth.test.js +281 -0
  506. package/dist/tests/unit/oauth.test.js.map +1 -0
  507. package/dist/tests/unit/opa-circuit-breaker.test.d.ts +2 -0
  508. package/dist/tests/unit/opa-circuit-breaker.test.d.ts.map +1 -0
  509. package/dist/tests/unit/opa-circuit-breaker.test.js +297 -0
  510. package/dist/tests/unit/opa-circuit-breaker.test.js.map +1 -0
  511. package/dist/tests/unit/opa-engine.test.d.ts +2 -0
  512. package/dist/tests/unit/opa-engine.test.d.ts.map +1 -0
  513. package/dist/tests/unit/opa-engine.test.js +1813 -0
  514. package/dist/tests/unit/opa-engine.test.js.map +1 -0
  515. package/dist/tests/unit/pipeline-timing.test.d.ts +2 -0
  516. package/dist/tests/unit/pipeline-timing.test.d.ts.map +1 -0
  517. package/dist/tests/unit/pipeline-timing.test.js +528 -0
  518. package/dist/tests/unit/pipeline-timing.test.js.map +1 -0
  519. package/dist/tests/unit/policy-engine.test.d.ts +2 -0
  520. package/dist/tests/unit/policy-engine.test.d.ts.map +1 -0
  521. package/dist/tests/unit/policy-engine.test.js +1345 -0
  522. package/dist/tests/unit/policy-engine.test.js.map +1 -0
  523. package/dist/tests/unit/policy-store.test.d.ts +2 -0
  524. package/dist/tests/unit/policy-store.test.d.ts.map +1 -0
  525. package/dist/tests/unit/policy-store.test.js +60 -0
  526. package/dist/tests/unit/policy-store.test.js.map +1 -0
  527. package/dist/tests/unit/postgres-storage.test.d.ts +2 -0
  528. package/dist/tests/unit/postgres-storage.test.d.ts.map +1 -0
  529. package/dist/tests/unit/postgres-storage.test.js +614 -0
  530. package/dist/tests/unit/postgres-storage.test.js.map +1 -0
  531. package/dist/tests/unit/prompt-injection-backend.test.d.ts +2 -0
  532. package/dist/tests/unit/prompt-injection-backend.test.d.ts.map +1 -0
  533. package/dist/tests/unit/prompt-injection-backend.test.js +621 -0
  534. package/dist/tests/unit/prompt-injection-backend.test.js.map +1 -0
  535. package/dist/tests/unit/proxy-hardening.test.d.ts +2 -0
  536. package/dist/tests/unit/proxy-hardening.test.d.ts.map +1 -0
  537. package/dist/tests/unit/proxy-hardening.test.js +166 -0
  538. package/dist/tests/unit/proxy-hardening.test.js.map +1 -0
  539. package/dist/tests/unit/rate-limiter.test.d.ts +2 -0
  540. package/dist/tests/unit/rate-limiter.test.d.ts.map +1 -0
  541. package/dist/tests/unit/rate-limiter.test.js +443 -0
  542. package/dist/tests/unit/rate-limiter.test.js.map +1 -0
  543. package/dist/tests/unit/redis-storage.test.d.ts +2 -0
  544. package/dist/tests/unit/redis-storage.test.d.ts.map +1 -0
  545. package/dist/tests/unit/redis-storage.test.js +766 -0
  546. package/dist/tests/unit/redis-storage.test.js.map +1 -0
  547. package/dist/tests/unit/replay-engine.test.d.ts +2 -0
  548. package/dist/tests/unit/replay-engine.test.d.ts.map +1 -0
  549. package/dist/tests/unit/replay-engine.test.js +371 -0
  550. package/dist/tests/unit/replay-engine.test.js.map +1 -0
  551. package/dist/tests/unit/saas-routes.test.d.ts +2 -0
  552. package/dist/tests/unit/saas-routes.test.d.ts.map +1 -0
  553. package/dist/tests/unit/saas-routes.test.js +1399 -0
  554. package/dist/tests/unit/saas-routes.test.js.map +1 -0
  555. package/dist/tests/unit/session.test.d.ts +2 -0
  556. package/dist/tests/unit/session.test.d.ts.map +1 -0
  557. package/dist/tests/unit/session.test.js +532 -0
  558. package/dist/tests/unit/session.test.js.map +1 -0
  559. package/dist/tests/unit/slack-executor.test.d.ts +2 -0
  560. package/dist/tests/unit/slack-executor.test.d.ts.map +1 -0
  561. package/dist/tests/unit/slack-executor.test.js +209 -0
  562. package/dist/tests/unit/slack-executor.test.js.map +1 -0
  563. package/dist/tests/unit/storage-hardening.test.d.ts +2 -0
  564. package/dist/tests/unit/storage-hardening.test.d.ts.map +1 -0
  565. package/dist/tests/unit/storage-hardening.test.js +165 -0
  566. package/dist/tests/unit/storage-hardening.test.js.map +1 -0
  567. package/dist/tests/unit/storage.test.d.ts +2 -0
  568. package/dist/tests/unit/storage.test.d.ts.map +1 -0
  569. package/dist/tests/unit/storage.test.js +698 -0
  570. package/dist/tests/unit/storage.test.js.map +1 -0
  571. package/dist/tests/unit/text-normalizer.test.d.ts +2 -0
  572. package/dist/tests/unit/text-normalizer.test.d.ts.map +1 -0
  573. package/dist/tests/unit/text-normalizer.test.js +229 -0
  574. package/dist/tests/unit/text-normalizer.test.js.map +1 -0
  575. package/dist/tests/unit/tracing.test.d.ts +2 -0
  576. package/dist/tests/unit/tracing.test.d.ts.map +1 -0
  577. package/dist/tests/unit/tracing.test.js +611 -0
  578. package/dist/tests/unit/tracing.test.js.map +1 -0
  579. package/dist/tests/unit/trust-calculator.test.d.ts +2 -0
  580. package/dist/tests/unit/trust-calculator.test.d.ts.map +1 -0
  581. package/dist/tests/unit/trust-calculator.test.js +497 -0
  582. package/dist/tests/unit/trust-calculator.test.js.map +1 -0
  583. package/dist/tests/unit/ts-sdk.test.d.ts +2 -0
  584. package/dist/tests/unit/ts-sdk.test.d.ts.map +1 -0
  585. package/dist/tests/unit/ts-sdk.test.js +421 -0
  586. package/dist/tests/unit/ts-sdk.test.js.map +1 -0
  587. package/dist/tests/unit/usage-extractor-llm.test.d.ts +2 -0
  588. package/dist/tests/unit/usage-extractor-llm.test.d.ts.map +1 -0
  589. package/dist/tests/unit/usage-extractor-llm.test.js +139 -0
  590. package/dist/tests/unit/usage-extractor-llm.test.js.map +1 -0
  591. package/dist/tests/unit/usage-extractor.test.d.ts +2 -0
  592. package/dist/tests/unit/usage-extractor.test.d.ts.map +1 -0
  593. package/dist/tests/unit/usage-extractor.test.js +271 -0
  594. package/dist/tests/unit/usage-extractor.test.js.map +1 -0
  595. package/dist/tests/unit/user-stores.test.d.ts +2 -0
  596. package/dist/tests/unit/user-stores.test.d.ts.map +1 -0
  597. package/dist/tests/unit/user-stores.test.js +687 -0
  598. package/dist/tests/unit/user-stores.test.js.map +1 -0
  599. package/dist/tests/unit/validate.test.d.ts +2 -0
  600. package/dist/tests/unit/validate.test.d.ts.map +1 -0
  601. package/dist/tests/unit/validate.test.js +545 -0
  602. package/dist/tests/unit/validate.test.js.map +1 -0
  603. package/package.json +86 -0
  604. package/policy-packs/README.md +42 -0
  605. package/policy-packs/default.yaml +46 -0
  606. package/policy-packs/dev_fast.yaml +54 -0
  607. package/policy-packs/prod_strict.yaml +83 -0
@@ -0,0 +1,753 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const http = __importStar(require("http"));
37
+ const gateway_1 = require("../../src/server/gateway");
38
+ const memory_1 = require("../../src/storage/memory");
39
+ // ---------------------------------------------------------------------------
40
+ // Local test HTTP server for the HTTP executor
41
+ // ---------------------------------------------------------------------------
42
+ let testServer;
43
+ let testServerPort;
44
+ let httpRequestCount = 0;
45
+ beforeAll((done) => {
46
+ testServer = http.createServer((req, res) => {
47
+ httpRequestCount++;
48
+ if (req.url === '/api/data' && req.method === 'GET') {
49
+ res.writeHead(200, { 'Content-Type': 'application/json' });
50
+ res.end(JSON.stringify({ data: 'test response', items: [1, 2, 3] }));
51
+ }
52
+ else {
53
+ res.writeHead(404, { 'Content-Type': 'application/json' });
54
+ res.end(JSON.stringify({ error: 'not found' }));
55
+ }
56
+ });
57
+ testServer.listen(0, '127.0.0.1', () => {
58
+ testServerPort = testServer.address().port;
59
+ done();
60
+ });
61
+ });
62
+ afterAll((done) => {
63
+ testServer.close(done);
64
+ });
65
+ // ---------------------------------------------------------------------------
66
+ // Test config factory
67
+ // ---------------------------------------------------------------------------
68
+ function createTestConfig(overrides) {
69
+ return {
70
+ port: 0,
71
+ host: '127.0.0.1',
72
+ auth: {
73
+ enabled: false,
74
+ api_keys: {},
75
+ },
76
+ policy: {
77
+ pack_path: './policy-packs/dev_fast.yaml',
78
+ default_effect: 'DENY',
79
+ hot_reload: false,
80
+ },
81
+ dlp: {
82
+ enabled: true,
83
+ scan_args: true,
84
+ scan_output: true,
85
+ secrets_detection: true,
86
+ pii_detection: true,
87
+ default_redaction_method: 'mask',
88
+ },
89
+ budget: {
90
+ task_budget_usd: 2.0,
91
+ max_steps_per_task: 50,
92
+ max_retries_per_call: 3,
93
+ max_wall_clock_ms: 300000,
94
+ },
95
+ audit: {
96
+ enabled: true,
97
+ log_dir: '',
98
+ console_output: false,
99
+ retention_days: 30,
100
+ },
101
+ executor: {
102
+ http: {
103
+ timeout_ms: 5000,
104
+ max_retries: 1,
105
+ backoff_base_ms: 100,
106
+ },
107
+ cache: {
108
+ enabled: false,
109
+ ttl_ms: 60000,
110
+ },
111
+ },
112
+ approval: {
113
+ enabled: true,
114
+ token_secret: 'test-gateway-features-secret-key',
115
+ default_ttl_seconds: 3600,
116
+ },
117
+ rate_limit: {
118
+ enabled: true,
119
+ actor_max_per_window: 100,
120
+ workspace_max_per_window: 500,
121
+ window_ms: 60000,
122
+ },
123
+ ...overrides,
124
+ };
125
+ }
126
+ // ---------------------------------------------------------------------------
127
+ // Helper: build a valid ToolCall
128
+ // ---------------------------------------------------------------------------
129
+ /** Disable SSRF protection for test gateways hitting localhost */
130
+ function disableSSRF(gw) {
131
+ gw.getHttpExecutor().ssrfProtectionEnabled = false;
132
+ return gw;
133
+ }
134
+ let callCounter = 0;
135
+ function buildToolCall(overrides) {
136
+ callCounter++;
137
+ return {
138
+ tool_call_id: `tc-feat-${Date.now()}-${callCounter}`,
139
+ task_id: 'task-feat-001',
140
+ workspace_id: 'ws-test',
141
+ actor: { type: 'agent', id: 'test-agent', display: 'Test Agent' },
142
+ source: { platform: 'unit-test' },
143
+ tool: { name: 'http.request', capability: 'read' },
144
+ args: {
145
+ method: 'GET',
146
+ url: `http://127.0.0.1:${testServerPort}/api/data`,
147
+ },
148
+ ...overrides,
149
+ };
150
+ }
151
+ // ===========================================================================
152
+ // Tests
153
+ // ===========================================================================
154
+ describe('Gateway Features', () => {
155
+ // =========================================================================
156
+ // Idempotency
157
+ // =========================================================================
158
+ describe('Idempotency', () => {
159
+ let gateway;
160
+ beforeEach(() => {
161
+ httpRequestCount = 0;
162
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
163
+ });
164
+ afterEach(() => {
165
+ gateway.shutdown();
166
+ });
167
+ it('returns cached result for duplicate tool_call_id without making a second HTTP request', async () => {
168
+ const toolCall = buildToolCall({ tool_call_id: 'tc-idempotent-001' });
169
+ // First call -- hits the HTTP server
170
+ const result1 = await gateway.execute(toolCall);
171
+ expect(result1.status).toBe('ok');
172
+ expect(result1.output).toBeDefined();
173
+ expect(result1.output.http_status).toBe(200);
174
+ const requestsAfterFirst = httpRequestCount;
175
+ expect(requestsAfterFirst).toBeGreaterThanOrEqual(1);
176
+ // Second call with the same tool_call_id -- should return cached result
177
+ const result2 = await gateway.execute(toolCall);
178
+ expect(result2.status).toBe('ok');
179
+ expect(result2.tool_call_id).toBe(result1.tool_call_id);
180
+ expect(result2.task_id).toBe(result1.task_id);
181
+ expect(result2.output).toEqual(result1.output);
182
+ expect(result2.timing).toEqual(result1.timing);
183
+ // No additional HTTP request should have been made
184
+ expect(httpRequestCount).toBe(requestsAfterFirst);
185
+ });
186
+ it('does not return cached result for different tool_call_ids', async () => {
187
+ const toolCall1 = buildToolCall({ tool_call_id: 'tc-unique-aaa' });
188
+ const toolCall2 = buildToolCall({ tool_call_id: 'tc-unique-bbb' });
189
+ const result1 = await gateway.execute(toolCall1);
190
+ const requestsAfterFirst = httpRequestCount;
191
+ const result2 = await gateway.execute(toolCall2);
192
+ // Both should succeed and the second should have triggered a new HTTP request
193
+ expect(result1.status).toBe('ok');
194
+ expect(result2.status).toBe('ok');
195
+ expect(httpRequestCount).toBeGreaterThan(requestsAfterFirst);
196
+ });
197
+ it('cached result is byte-identical to original', async () => {
198
+ const toolCall = buildToolCall({ tool_call_id: 'tc-idempotent-exact' });
199
+ const result1 = await gateway.execute(toolCall);
200
+ const result2 = await gateway.execute(toolCall);
201
+ // Deep equality: the cached result should be the exact same object reference or identical
202
+ expect(JSON.stringify(result2)).toBe(JSON.stringify(result1));
203
+ });
204
+ });
205
+ // =========================================================================
206
+ // Rate Limiting
207
+ // =========================================================================
208
+ describe('Rate Limiting', () => {
209
+ describe('with low actor limit', () => {
210
+ let gateway;
211
+ beforeEach(() => {
212
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig({
213
+ rate_limit: {
214
+ enabled: true,
215
+ actor_max_per_window: 2,
216
+ workspace_max_per_window: 500,
217
+ window_ms: 60000,
218
+ },
219
+ })));
220
+ });
221
+ afterEach(() => {
222
+ gateway.shutdown();
223
+ });
224
+ it('allows requests within the rate limit', async () => {
225
+ const tc1 = buildToolCall();
226
+ const tc2 = buildToolCall();
227
+ const result1 = await gateway.execute(tc1);
228
+ const result2 = await gateway.execute(tc2);
229
+ expect(result1.status).toBe('ok');
230
+ expect(result2.status).toBe('ok');
231
+ });
232
+ it('blocks the 3rd request when actor limit is 2', async () => {
233
+ const tc1 = buildToolCall();
234
+ const tc2 = buildToolCall();
235
+ const tc3 = buildToolCall();
236
+ const result1 = await gateway.execute(tc1);
237
+ const result2 = await gateway.execute(tc2);
238
+ const result3 = await gateway.execute(tc3);
239
+ expect(result1.status).toBe('ok');
240
+ expect(result2.status).toBe('ok');
241
+ expect(result3.status).toBe('blocked');
242
+ expect(result3.error).toBeDefined();
243
+ expect(result3.error).toContain('Rate limit exceeded');
244
+ });
245
+ it('blocked result includes rate limit policy info', async () => {
246
+ // Exhaust the limit
247
+ await gateway.execute(buildToolCall());
248
+ await gateway.execute(buildToolCall());
249
+ const blocked = await gateway.execute(buildToolCall());
250
+ expect(blocked.status).toBe('blocked');
251
+ expect(blocked.policy.decision).toBe('deny');
252
+ expect(blocked.policy.rule_id).toBe('rate_limit');
253
+ expect(blocked.policy.reasons.length).toBeGreaterThan(0);
254
+ expect(blocked.policy.reasons[0]).toContain('Rate limit exceeded');
255
+ });
256
+ });
257
+ describe('with low workspace limit', () => {
258
+ let gateway;
259
+ beforeEach(() => {
260
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig({
261
+ rate_limit: {
262
+ enabled: true,
263
+ actor_max_per_window: 100,
264
+ workspace_max_per_window: 2,
265
+ window_ms: 60000,
266
+ },
267
+ })));
268
+ });
269
+ afterEach(() => {
270
+ gateway.shutdown();
271
+ });
272
+ it('blocks the 3rd request when workspace limit is 2', async () => {
273
+ const tc1 = buildToolCall();
274
+ const tc2 = buildToolCall();
275
+ const tc3 = buildToolCall();
276
+ await gateway.execute(tc1);
277
+ await gateway.execute(tc2);
278
+ const result3 = await gateway.execute(tc3);
279
+ expect(result3.status).toBe('blocked');
280
+ expect(result3.error).toContain('Rate limit exceeded');
281
+ });
282
+ });
283
+ describe('with rate limiting disabled', () => {
284
+ let gateway;
285
+ beforeEach(() => {
286
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig({
287
+ rate_limit: {
288
+ enabled: false,
289
+ actor_max_per_window: 1,
290
+ workspace_max_per_window: 1,
291
+ window_ms: 60000,
292
+ },
293
+ })));
294
+ });
295
+ afterEach(() => {
296
+ gateway.shutdown();
297
+ });
298
+ it('allows all requests when rate limiting is disabled', async () => {
299
+ const results = [];
300
+ for (let i = 0; i < 5; i++) {
301
+ results.push(await gateway.execute(buildToolCall()));
302
+ }
303
+ // All five should pass even though limits are set to 1
304
+ for (const result of results) {
305
+ expect(result.status).toBe('ok');
306
+ }
307
+ });
308
+ });
309
+ });
310
+ // =========================================================================
311
+ // Executor Registry
312
+ // =========================================================================
313
+ describe('Executor Registry', () => {
314
+ describe('custom NoopExecutor for noop.* pattern', () => {
315
+ let gateway;
316
+ let noopCallCount;
317
+ let lastNoopToolCall;
318
+ /** A custom executor that returns a static response without doing any I/O */
319
+ class NoopExecutor {
320
+ async execute(toolCall) {
321
+ noopCallCount++;
322
+ lastNoopToolCall = toolCall;
323
+ return {
324
+ http_status: 200,
325
+ body: { noop: true, tool: toolCall.tool.name },
326
+ };
327
+ }
328
+ }
329
+ beforeEach(() => {
330
+ noopCallCount = 0;
331
+ lastNoopToolCall = null;
332
+ httpRequestCount = 0;
333
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
334
+ // The Gateway constructor registers http.* and then * (catch-all).
335
+ // The registry matches in registration order, so the catch-all would
336
+ // swallow noop.* if we simply appended. We rebuild the registry with
337
+ // noop.* inserted before the catch-all by clearing and re-registering.
338
+ const registry = gateway.getExecutorRegistry();
339
+ // Resolve the existing http executor (used for http.* and fallback)
340
+ const httpExec = registry.resolve('http.request');
341
+ registry.clear();
342
+ registry.register('noop.*', new NoopExecutor());
343
+ registry.register('http.*', httpExec);
344
+ registry.register('*', httpExec); // catch-all last
345
+ });
346
+ afterEach(() => {
347
+ gateway.shutdown();
348
+ });
349
+ it('routes noop.* tool calls to the custom executor', async () => {
350
+ const toolCall = buildToolCall({
351
+ tool: { name: 'noop.test', capability: 'read' },
352
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
353
+ });
354
+ const result = await gateway.execute(toolCall);
355
+ expect(result.status).toBe('ok');
356
+ expect(noopCallCount).toBe(1);
357
+ expect(lastNoopToolCall).not.toBeNull();
358
+ expect(lastNoopToolCall.tool.name).toBe('noop.test');
359
+ expect(result.output).toBeDefined();
360
+ expect(result.output.body).toEqual({ noop: true, tool: 'noop.test' });
361
+ // The HTTP server should NOT have been hit
362
+ expect(httpRequestCount).toBe(0);
363
+ });
364
+ it('still routes http.* tool calls to the HTTP executor', async () => {
365
+ const toolCall = buildToolCall({
366
+ tool: { name: 'http.request', capability: 'read' },
367
+ });
368
+ const result = await gateway.execute(toolCall);
369
+ expect(result.status).toBe('ok');
370
+ expect(noopCallCount).toBe(0);
371
+ expect(httpRequestCount).toBeGreaterThanOrEqual(1);
372
+ });
373
+ it('routes noop.action and noop.ping to the custom executor', async () => {
374
+ const tc1 = buildToolCall({
375
+ tool: { name: 'noop.action', capability: 'read' },
376
+ args: {},
377
+ });
378
+ const tc2 = buildToolCall({
379
+ tool: { name: 'noop.ping', capability: 'read' },
380
+ args: {},
381
+ });
382
+ await gateway.execute(tc1);
383
+ await gateway.execute(tc2);
384
+ expect(noopCallCount).toBe(2);
385
+ });
386
+ });
387
+ describe('registerExecutor() public API', () => {
388
+ let gateway;
389
+ beforeEach(() => {
390
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
391
+ });
392
+ afterEach(() => {
393
+ gateway.shutdown();
394
+ });
395
+ it('adds an executor that is reflected in the registry', () => {
396
+ class DummyExecutor {
397
+ async execute(_toolCall) {
398
+ return { http_status: 200, body: { dummy: true } };
399
+ }
400
+ }
401
+ gateway.registerExecutor('custom.tool', new DummyExecutor());
402
+ // Verify via the getExecutorRegistry() introspection method
403
+ const registry = gateway.getExecutorRegistry();
404
+ expect(registry.has('custom.tool')).toBe(true);
405
+ expect(registry.listPatterns()).toContain('custom.tool');
406
+ });
407
+ it('registered executor is called when tool name matches', async () => {
408
+ let called = false;
409
+ class SpyExecutor {
410
+ async execute(_toolCall) {
411
+ called = true;
412
+ return { http_status: 200, body: { spy: true } };
413
+ }
414
+ }
415
+ // Rebuild registry so the new pattern is checked before the * catch-all
416
+ const registry = gateway.getExecutorRegistry();
417
+ const httpExec = registry.resolve('http.request');
418
+ registry.clear();
419
+ registry.register('spy.tool', new SpyExecutor());
420
+ registry.register('http.*', httpExec);
421
+ registry.register('*', httpExec);
422
+ const result = await gateway.execute(buildToolCall({
423
+ tool: { name: 'spy.tool', capability: 'read' },
424
+ args: {},
425
+ }));
426
+ expect(called).toBe(true);
427
+ expect(result.status).toBe('ok');
428
+ expect(result.output.body).toEqual({ spy: true });
429
+ });
430
+ });
431
+ });
432
+ // =========================================================================
433
+ // processApproval error handling
434
+ // =========================================================================
435
+ describe('processApproval error handling', () => {
436
+ let gateway;
437
+ beforeEach(() => {
438
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
439
+ });
440
+ afterEach(() => {
441
+ gateway.shutdown();
442
+ });
443
+ it('returns { success: false, error } for an invalid token instead of throwing', async () => {
444
+ const result = await gateway.processApproval('invalid.jwt.token', 'admin-001', true);
445
+ expect(result.success).toBe(false);
446
+ expect(result.error).toBeDefined();
447
+ expect(typeof result.error).toBe('string');
448
+ expect(result.error.length).toBeGreaterThan(0);
449
+ });
450
+ it('returns { success: false, error } for a completely garbage token', async () => {
451
+ const result = await gateway.processApproval('not-even-a-jwt', 'admin-001', true);
452
+ expect(result.success).toBe(false);
453
+ expect(result.error).toBeDefined();
454
+ });
455
+ it('returns { success: false, error } when denying with an invalid token', async () => {
456
+ const result = await gateway.processApproval('bad-token', 'admin-001', false, 'Not approved');
457
+ expect(result.success).toBe(false);
458
+ expect(result.error).toBeDefined();
459
+ });
460
+ it('returns { success: true } for a valid approval flow', async () => {
461
+ // Trigger a request that needs approval (delete capability)
462
+ const toolCall = buildToolCall({
463
+ tool: { name: 'http.request', capability: 'delete' },
464
+ args: { method: 'DELETE', url: `http://127.0.0.1:${testServerPort}/api/data` },
465
+ });
466
+ // Provide a requesting API key ID so approval has cryptographic identity
467
+ const execResult = await gateway.execute(toolCall, 'requester-key-001');
468
+ expect(execResult.status).toBe('needs_approval');
469
+ const token = execResult.approval.token;
470
+ // Approve with a different API key ID
471
+ const approvalResult = await gateway.processApproval(token, 'admin-001', true, undefined, 'approver-key-002');
472
+ expect(approvalResult.success).toBe(true);
473
+ expect(approvalResult.error).toBeUndefined();
474
+ });
475
+ it('returns { success: true } when denying a valid pending approval', async () => {
476
+ const toolCall = buildToolCall({
477
+ tool: { name: 'http.request', capability: 'admin' },
478
+ args: { method: 'DELETE', url: `http://127.0.0.1:${testServerPort}/api/data` },
479
+ });
480
+ const execResult = await gateway.execute(toolCall);
481
+ expect(execResult.status).toBe('needs_approval');
482
+ const token = execResult.approval.token;
483
+ const denyResult = await gateway.processApproval(token, 'admin-001', false, 'Not allowed');
484
+ expect(denyResult.success).toBe(true);
485
+ expect(denyResult.error).toBeUndefined();
486
+ });
487
+ it('returns error when trying to approve an already-approved request', async () => {
488
+ const toolCall = buildToolCall({
489
+ tool: { name: 'http.request', capability: 'delete' },
490
+ args: { method: 'DELETE', url: `http://127.0.0.1:${testServerPort}/api/data` },
491
+ });
492
+ // Provide a requesting API key ID so approval has cryptographic identity
493
+ const execResult = await gateway.execute(toolCall, 'requester-key-001');
494
+ const token = execResult.approval.token;
495
+ // First approval succeeds (different API key)
496
+ const first = await gateway.processApproval(token, 'admin-001', true, undefined, 'approver-key-002');
497
+ expect(first.success).toBe(true);
498
+ // Second approval should fail gracefully
499
+ const second = await gateway.processApproval(token, 'admin-002', true, undefined, 'approver-key-003');
500
+ expect(second.success).toBe(false);
501
+ expect(second.error).toBeDefined();
502
+ expect(second.error).toMatch(/already been approved|already been used/);
503
+ });
504
+ });
505
+ // =========================================================================
506
+ // Workspace Policy Evaluation
507
+ // =========================================================================
508
+ describe('Workspace Policy Evaluation', () => {
509
+ /** A workspace policy that denies all read requests */
510
+ function createDenyReadPack() {
511
+ return {
512
+ name: 'ws-deny-read',
513
+ version: '1.0.0',
514
+ rules: [
515
+ {
516
+ name: 'deny-read',
517
+ effect: 'DENY',
518
+ priority: 1,
519
+ conditions: { capabilities: ['read'] },
520
+ description: 'Workspace policy denies read capability',
521
+ },
522
+ ],
523
+ };
524
+ }
525
+ it('uses workspace policy when PolicyStore has one for the workspace', async () => {
526
+ const gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
527
+ const policyStore = new memory_1.InMemoryPolicyStore();
528
+ policyStore.set('ws-test', createDenyReadPack());
529
+ gateway.setStores({ policyStore });
530
+ const toolCall = buildToolCall({
531
+ workspace_id: 'ws-test',
532
+ tool: { name: 'http.request', capability: 'read' },
533
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
534
+ });
535
+ const result = await gateway.execute(toolCall);
536
+ expect(result.status).toBe('blocked');
537
+ expect(result.policy.decision).toBe('deny');
538
+ expect(result.policy.rule_id).toBe('deny-read');
539
+ gateway.shutdown();
540
+ });
541
+ it('falls back to global policy when workspace has no custom policy', async () => {
542
+ const gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
543
+ const policyStore = new memory_1.InMemoryPolicyStore();
544
+ // Store has a policy for a different workspace
545
+ policyStore.set('ws-other', createDenyReadPack());
546
+ gateway.setStores({ policyStore });
547
+ const toolCall = buildToolCall({
548
+ workspace_id: 'ws-test',
549
+ tool: { name: 'http.request', capability: 'read' },
550
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
551
+ });
552
+ const result = await gateway.execute(toolCall);
553
+ // Global dev_fast policy allows reads, so it should succeed
554
+ expect(result.status).toBe('ok');
555
+ gateway.shutdown();
556
+ });
557
+ it('uses global policy when no PolicyStore is set', async () => {
558
+ const gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
559
+ // No policyStore set at all
560
+ const toolCall = buildToolCall({
561
+ workspace_id: 'ws-test',
562
+ tool: { name: 'http.request', capability: 'read' },
563
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
564
+ });
565
+ const result = await gateway.execute(toolCall);
566
+ // Global dev_fast policy allows reads
567
+ expect(result.status).toBe('ok');
568
+ gateway.shutdown();
569
+ });
570
+ it('getWorkspacePolicy returns is_custom: true when workspace has custom policy', () => {
571
+ const gateway = new gateway_1.Gateway(createTestConfig());
572
+ const policyStore = new memory_1.InMemoryPolicyStore();
573
+ const customPack = createDenyReadPack();
574
+ policyStore.set('ws-custom', customPack);
575
+ gateway.setStores({ policyStore });
576
+ const result = gateway.getWorkspacePolicy('ws-custom');
577
+ expect(result.is_custom).toBe(true);
578
+ expect(result.policy.name).toBe('ws-deny-read');
579
+ gateway.shutdown();
580
+ });
581
+ it('getWorkspacePolicy returns is_custom: false when workspace has no custom policy', () => {
582
+ const gateway = new gateway_1.Gateway(createTestConfig());
583
+ const policyStore = new memory_1.InMemoryPolicyStore();
584
+ gateway.setStores({ policyStore });
585
+ const result = gateway.getWorkspacePolicy('ws-no-policy');
586
+ expect(result.is_custom).toBe(false);
587
+ // Should return the global policy
588
+ expect(result.policy).toBeDefined();
589
+ expect(result.policy.rules).toBeDefined();
590
+ gateway.shutdown();
591
+ });
592
+ it('getWorkspacePolicy returns global policy when no PolicyStore is set', () => {
593
+ const gateway = new gateway_1.Gateway(createTestConfig());
594
+ const result = gateway.getWorkspacePolicy('ws-any');
595
+ expect(result.is_custom).toBe(false);
596
+ expect(result.policy).toBeDefined();
597
+ gateway.shutdown();
598
+ });
599
+ it('getPolicyStore returns undefined when no store is set', () => {
600
+ const gateway = new gateway_1.Gateway(createTestConfig());
601
+ expect(gateway.getPolicyStore()).toBeUndefined();
602
+ gateway.shutdown();
603
+ });
604
+ it('getPolicyStore returns the store after setStores', () => {
605
+ const gateway = new gateway_1.Gateway(createTestConfig());
606
+ const policyStore = new memory_1.InMemoryPolicyStore();
607
+ gateway.setStores({ policyStore });
608
+ expect(gateway.getPolicyStore()).toBe(policyStore);
609
+ gateway.shutdown();
610
+ });
611
+ });
612
+ // =========================================================================
613
+ // A2: Idempotency with body hash
614
+ // =========================================================================
615
+ describe('Idempotency with body hash (A2)', () => {
616
+ let gateway;
617
+ beforeEach(() => {
618
+ httpRequestCount = 0;
619
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
620
+ });
621
+ afterEach(() => {
622
+ gateway.shutdown();
623
+ });
624
+ it('treats same tool_call_id with different args as separate requests', async () => {
625
+ const tc1 = buildToolCall({
626
+ tool_call_id: 'tc-same-id',
627
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
628
+ });
629
+ const tc2 = buildToolCall({
630
+ tool_call_id: 'tc-same-id',
631
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/other` },
632
+ });
633
+ const result1 = await gateway.execute(tc1);
634
+ const requestsAfterFirst = httpRequestCount;
635
+ const result2 = await gateway.execute(tc2);
636
+ // Both should execute (different body hash despite same tool_call_id)
637
+ expect(result1.status).toBe('ok');
638
+ // Second request should have triggered a new HTTP call
639
+ expect(httpRequestCount).toBeGreaterThan(requestsAfterFirst);
640
+ });
641
+ it('caches same tool_call_id with same args', async () => {
642
+ const tc1 = buildToolCall({
643
+ tool_call_id: 'tc-same-id-same-args',
644
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
645
+ });
646
+ const tc2 = buildToolCall({
647
+ tool_call_id: 'tc-same-id-same-args',
648
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
649
+ });
650
+ const result1 = await gateway.execute(tc1);
651
+ const requestsAfterFirst = httpRequestCount;
652
+ const result2 = await gateway.execute(tc2);
653
+ // Second should be cached (same tool_call_id + same args)
654
+ expect(httpRequestCount).toBe(requestsAfterFirst);
655
+ expect(JSON.stringify(result1)).toBe(JSON.stringify(result2));
656
+ });
657
+ });
658
+ // =========================================================================
659
+ // A3: Policy reload isolation
660
+ // =========================================================================
661
+ describe('Policy reload isolation (A3)', () => {
662
+ it('reloadPolicy creates a new engine and swaps atomically', () => {
663
+ const gateway = new gateway_1.Gateway(createTestConfig());
664
+ const engineBefore = gateway.getPolicyEngine();
665
+ const result = gateway.reloadPolicy();
666
+ expect(result.success).toBe(true);
667
+ // After reload, the engine reference should be different
668
+ const engineAfter = gateway.getPolicyEngine();
669
+ expect(engineAfter).not.toBe(engineBefore);
670
+ gateway.shutdown();
671
+ });
672
+ it('reloadPolicy preserves old engine on failure', () => {
673
+ const gateway = new gateway_1.Gateway(createTestConfig({
674
+ policy: {
675
+ pack_path: './policy-packs/dev_fast.yaml',
676
+ default_effect: 'DENY',
677
+ hot_reload: false,
678
+ },
679
+ }));
680
+ const engineBefore = gateway.getPolicyEngine();
681
+ // Temporarily change pack_path to invalid path to force failure
682
+ // This test verifies that the old engine is preserved if the new one fails
683
+ const result = gateway.reloadPolicy();
684
+ expect(result.success).toBe(true);
685
+ // Engine should be a new instance (loaded successfully)
686
+ const engineAfter = gateway.getPolicyEngine();
687
+ expect(engineAfter).not.toBe(engineBefore);
688
+ gateway.shutdown();
689
+ });
690
+ });
691
+ // =========================================================================
692
+ // S5: Budget reservation in gateway pipeline
693
+ // =========================================================================
694
+ describe('Budget reservation in gateway (S5)', () => {
695
+ let gateway;
696
+ beforeEach(() => {
697
+ gateway = disableSSRF(new gateway_1.Gateway(createTestConfig()));
698
+ });
699
+ afterEach(() => {
700
+ gateway.shutdown();
701
+ });
702
+ it('successful execution records budget correctly', async () => {
703
+ const toolCall = buildToolCall();
704
+ const result = await gateway.execute(toolCall);
705
+ expect(result.status).toBe('ok');
706
+ // Budget should reflect the cost
707
+ expect(result.budget).toBeDefined();
708
+ });
709
+ it('releases budget reservation on execution error', async () => {
710
+ // Register an executor that throws
711
+ class FailExecutor {
712
+ async execute() {
713
+ throw new Error('Intentional test failure');
714
+ }
715
+ }
716
+ const registry = gateway.getExecutorRegistry();
717
+ const httpExec = registry.resolve('http.request');
718
+ registry.clear();
719
+ registry.register('fail.*', new FailExecutor());
720
+ registry.register('http.*', httpExec);
721
+ registry.register('*', httpExec);
722
+ const tc1 = buildToolCall({
723
+ tool: { name: 'fail.test', capability: 'read' },
724
+ args: {},
725
+ });
726
+ const result = await gateway.execute(tc1);
727
+ expect(result.status).toBe('error');
728
+ // After the error, budget should be released — subsequent calls should work
729
+ const tc2 = buildToolCall({
730
+ tool: { name: 'http.request', capability: 'read' },
731
+ args: { method: 'GET', url: `http://127.0.0.1:${testServerPort}/api/data` },
732
+ });
733
+ const result2 = await gateway.execute(tc2);
734
+ expect(result2.status).toBe('ok');
735
+ });
736
+ });
737
+ // =========================================================================
738
+ // Graceful shutdown (S7)
739
+ // =========================================================================
740
+ describe('Graceful shutdown (S7)', () => {
741
+ it('gateway.shutdown() completes without errors', async () => {
742
+ const gateway = new gateway_1.Gateway(createTestConfig());
743
+ await expect(gateway.shutdown()).resolves.toBeUndefined();
744
+ });
745
+ it('gateway.isShuttingDown reflects shutdown state', async () => {
746
+ const gateway = new gateway_1.Gateway(createTestConfig());
747
+ expect(gateway.isShuttingDown).toBe(false);
748
+ await gateway.shutdown();
749
+ expect(gateway.isShuttingDown).toBe(true);
750
+ });
751
+ });
752
+ });
753
+ //# sourceMappingURL=gateway-features.test.js.map