@congzhen/changewayguard 6.8.12

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 (329) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -0
  3. package/dashboard-dist/api/104.index.js +1420 -0
  4. package/dashboard-dist/api/104.index.js.map +1 -0
  5. package/dashboard-dist/api/113.index.js +496 -0
  6. package/dashboard-dist/api/113.index.js.map +1 -0
  7. package/dashboard-dist/api/18.index.js +67 -0
  8. package/dashboard-dist/api/18.index.js.map +1 -0
  9. package/dashboard-dist/api/217.index.js +44 -0
  10. package/dashboard-dist/api/217.index.js.map +1 -0
  11. package/dashboard-dist/api/222.index.js +90 -0
  12. package/dashboard-dist/api/222.index.js.map +1 -0
  13. package/dashboard-dist/api/25.index.js +3562 -0
  14. package/dashboard-dist/api/25.index.js.map +1 -0
  15. package/dashboard-dist/api/280.index.js +206 -0
  16. package/dashboard-dist/api/280.index.js.map +1 -0
  17. package/dashboard-dist/api/369.index.js +115 -0
  18. package/dashboard-dist/api/369.index.js.map +1 -0
  19. package/dashboard-dist/api/377.index.js +1176 -0
  20. package/dashboard-dist/api/377.index.js.map +1 -0
  21. package/dashboard-dist/api/411.index.js +4250 -0
  22. package/dashboard-dist/api/411.index.js.map +1 -0
  23. package/dashboard-dist/api/424.index.js +135 -0
  24. package/dashboard-dist/api/424.index.js.map +1 -0
  25. package/dashboard-dist/api/573.index.js +806 -0
  26. package/dashboard-dist/api/573.index.js.map +1 -0
  27. package/dashboard-dist/api/598.index.js +328 -0
  28. package/dashboard-dist/api/598.index.js.map +1 -0
  29. package/dashboard-dist/api/62.index.js +4151 -0
  30. package/dashboard-dist/api/62.index.js.map +1 -0
  31. package/dashboard-dist/api/67.index.js +23383 -0
  32. package/dashboard-dist/api/67.index.js.map +1 -0
  33. package/dashboard-dist/api/678.index.js +2734 -0
  34. package/dashboard-dist/api/678.index.js.map +1 -0
  35. package/dashboard-dist/api/698.index.js +1896 -0
  36. package/dashboard-dist/api/698.index.js.map +1 -0
  37. package/dashboard-dist/api/720.index.js +98 -0
  38. package/dashboard-dist/api/720.index.js.map +1 -0
  39. package/dashboard-dist/api/830.index.js +95 -0
  40. package/dashboard-dist/api/830.index.js.map +1 -0
  41. package/dashboard-dist/api/831.index.js +99 -0
  42. package/dashboard-dist/api/831.index.js.map +1 -0
  43. package/dashboard-dist/api/84.index.js +64 -0
  44. package/dashboard-dist/api/84.index.js.map +1 -0
  45. package/dashboard-dist/api/900.index.js +65 -0
  46. package/dashboard-dist/api/900.index.js.map +1 -0
  47. package/dashboard-dist/api/917.index.js +88 -0
  48. package/dashboard-dist/api/917.index.js.map +1 -0
  49. package/dashboard-dist/api/948.index.js +64 -0
  50. package/dashboard-dist/api/948.index.js.map +1 -0
  51. package/dashboard-dist/api/953.index.js +67 -0
  52. package/dashboard-dist/api/953.index.js.map +1 -0
  53. package/dashboard-dist/api/975.index.js +374 -0
  54. package/dashboard-dist/api/975.index.js.map +1 -0
  55. package/dashboard-dist/api/drizzle/sqlite/0000_short_captain_stacy.sql +70 -0
  56. package/dashboard-dist/api/drizzle/sqlite/0001_closed_magus.sql +10 -0
  57. package/dashboard-dist/api/drizzle/sqlite/0002_agent_capability_observation.sql +38 -0
  58. package/dashboard-dist/api/drizzle/sqlite/0003_auth_magic_link.sql +28 -0
  59. package/dashboard-dist/api/drizzle/sqlite/0004_static_scan_fields.sql +8 -0
  60. package/dashboard-dist/api/drizzle/sqlite/0005_gateway_activity.sql +24 -0
  61. package/dashboard-dist/api/drizzle/sqlite/0006_sour_marauders.sql +41 -0
  62. package/dashboard-dist/api/drizzle/sqlite/meta/0000_snapshot.json +460 -0
  63. package/dashboard-dist/api/drizzle/sqlite/meta/0001_snapshot.json +536 -0
  64. package/dashboard-dist/api/drizzle/sqlite/meta/0006_snapshot.json +1249 -0
  65. package/dashboard-dist/api/drizzle/sqlite/meta/_journal.json +55 -0
  66. package/dashboard-dist/api/index.js +27340 -0
  67. package/dashboard-dist/api/index.js.map +1 -0
  68. package/dashboard-dist/api/package.json +16 -0
  69. package/dashboard-dist/api/sourcemap-register.cjs +1 -0
  70. package/dashboard-dist/web/assets/index-CqWIeBTD.js +158 -0
  71. package/dashboard-dist/web/assets/index-Dw7--9q4.css +1 -0
  72. package/dashboard-dist/web/changeway-logo.png +0 -0
  73. package/dashboard-dist/web/favicon.svg +29 -0
  74. package/dashboard-dist/web/index.html +14 -0
  75. package/dashboard-dist/web/logo.svg +16 -0
  76. package/dist/agent/auth.d.ts +37 -0
  77. package/dist/agent/auth.d.ts.map +1 -0
  78. package/dist/agent/auth.js +151 -0
  79. package/dist/agent/auth.js.map +1 -0
  80. package/dist/agent/behavior-detector.d.ts +150 -0
  81. package/dist/agent/behavior-detector.d.ts.map +1 -0
  82. package/dist/agent/behavior-detector.js +573 -0
  83. package/dist/agent/behavior-detector.js.map +1 -0
  84. package/dist/agent/business-reporter.d.ts +114 -0
  85. package/dist/agent/business-reporter.d.ts.map +1 -0
  86. package/dist/agent/business-reporter.js +359 -0
  87. package/dist/agent/business-reporter.js.map +1 -0
  88. package/dist/agent/config-sync.d.ts +70 -0
  89. package/dist/agent/config-sync.d.ts.map +1 -0
  90. package/dist/agent/config-sync.js +133 -0
  91. package/dist/agent/config-sync.js.map +1 -0
  92. package/dist/agent/config.d.ts +97 -0
  93. package/dist/agent/config.d.ts.map +1 -0
  94. package/dist/agent/config.js +359 -0
  95. package/dist/agent/config.js.map +1 -0
  96. package/dist/agent/content-injection-scanner.d.ts +35 -0
  97. package/dist/agent/content-injection-scanner.d.ts.map +1 -0
  98. package/dist/agent/content-injection-scanner.js +270 -0
  99. package/dist/agent/content-injection-scanner.js.map +1 -0
  100. package/dist/agent/engine-log-writer.d.ts +6 -0
  101. package/dist/agent/engine-log-writer.d.ts.map +1 -0
  102. package/dist/agent/engine-log-writer.js +18 -0
  103. package/dist/agent/engine-log-writer.js.map +1 -0
  104. package/dist/agent/env.d.ts +19 -0
  105. package/dist/agent/env.d.ts.map +1 -0
  106. package/dist/agent/env.js +43 -0
  107. package/dist/agent/env.js.map +1 -0
  108. package/dist/agent/event-reporter.d.ts +87 -0
  109. package/dist/agent/event-reporter.d.ts.map +1 -0
  110. package/dist/agent/event-reporter.js +315 -0
  111. package/dist/agent/event-reporter.js.map +1 -0
  112. package/dist/agent/file-watcher.d.ts +50 -0
  113. package/dist/agent/file-watcher.d.ts.map +1 -0
  114. package/dist/agent/file-watcher.js +135 -0
  115. package/dist/agent/file-watcher.js.map +1 -0
  116. package/dist/agent/fs-utils.d.ts +22 -0
  117. package/dist/agent/fs-utils.d.ts.map +1 -0
  118. package/dist/agent/fs-utils.js +41 -0
  119. package/dist/agent/fs-utils.js.map +1 -0
  120. package/dist/agent/gateway-manager.d.ts +59 -0
  121. package/dist/agent/gateway-manager.d.ts.map +1 -0
  122. package/dist/agent/gateway-manager.js +583 -0
  123. package/dist/agent/gateway-manager.js.map +1 -0
  124. package/dist/agent/hook-types.d.ts +276 -0
  125. package/dist/agent/hook-types.d.ts.map +1 -0
  126. package/dist/agent/hook-types.js +51 -0
  127. package/dist/agent/hook-types.js.map +1 -0
  128. package/dist/agent/index.d.ts +8 -0
  129. package/dist/agent/index.d.ts.map +1 -0
  130. package/dist/agent/index.js +8 -0
  131. package/dist/agent/index.js.map +1 -0
  132. package/dist/agent/prompt-gate.d.ts +13 -0
  133. package/dist/agent/prompt-gate.d.ts.map +1 -0
  134. package/dist/agent/prompt-gate.js +28 -0
  135. package/dist/agent/prompt-gate.js.map +1 -0
  136. package/dist/agent/prompt-input.d.ts +9 -0
  137. package/dist/agent/prompt-input.d.ts.map +1 -0
  138. package/dist/agent/prompt-input.js +158 -0
  139. package/dist/agent/prompt-input.js.map +1 -0
  140. package/dist/agent/prompt-output.d.ts +4 -0
  141. package/dist/agent/prompt-output.d.ts.map +1 -0
  142. package/dist/agent/prompt-output.js +19 -0
  143. package/dist/agent/prompt-output.js.map +1 -0
  144. package/dist/agent/runner.d.ts +23 -0
  145. package/dist/agent/runner.d.ts.map +1 -0
  146. package/dist/agent/runner.js +154 -0
  147. package/dist/agent/runner.js.map +1 -0
  148. package/dist/agent/sanitizer.d.ts +10 -0
  149. package/dist/agent/sanitizer.d.ts.map +1 -0
  150. package/dist/agent/sanitizer.js +175 -0
  151. package/dist/agent/sanitizer.js.map +1 -0
  152. package/dist/agent/scan-activity.d.ts +18 -0
  153. package/dist/agent/scan-activity.d.ts.map +1 -0
  154. package/dist/agent/scan-activity.js +32 -0
  155. package/dist/agent/scan-activity.js.map +1 -0
  156. package/dist/agent/types.d.ts +177 -0
  157. package/dist/agent/types.d.ts.map +1 -0
  158. package/dist/agent/types.js +5 -0
  159. package/dist/agent/types.js.map +1 -0
  160. package/dist/agent/workspace-scanner.d.ts +35 -0
  161. package/dist/agent/workspace-scanner.d.ts.map +1 -0
  162. package/dist/agent/workspace-scanner.js +137 -0
  163. package/dist/agent/workspace-scanner.js.map +1 -0
  164. package/dist/dashboard-launcher.d.ts +52 -0
  165. package/dist/dashboard-launcher.d.ts.map +1 -0
  166. package/dist/dashboard-launcher.js +363 -0
  167. package/dist/dashboard-launcher.js.map +1 -0
  168. package/dist/gateway/activity.d.ts +52 -0
  169. package/dist/gateway/activity.d.ts.map +1 -0
  170. package/dist/gateway/activity.js +111 -0
  171. package/dist/gateway/activity.js.map +1 -0
  172. package/dist/gateway/config.d.ts +50 -0
  173. package/dist/gateway/config.d.ts.map +1 -0
  174. package/dist/gateway/config.js +200 -0
  175. package/dist/gateway/config.js.map +1 -0
  176. package/dist/gateway/gateway/activity.d.ts +52 -0
  177. package/dist/gateway/gateway/activity.d.ts.map +1 -0
  178. package/dist/gateway/gateway/activity.js +111 -0
  179. package/dist/gateway/gateway/activity.js.map +1 -0
  180. package/dist/gateway/gateway/config.d.ts +50 -0
  181. package/dist/gateway/gateway/config.d.ts.map +1 -0
  182. package/dist/gateway/gateway/config.js +200 -0
  183. package/dist/gateway/gateway/config.js.map +1 -0
  184. package/dist/gateway/gateway/handlers/anthropic.d.ts +12 -0
  185. package/dist/gateway/gateway/handlers/anthropic.d.ts.map +1 -0
  186. package/dist/gateway/gateway/handlers/anthropic.js +254 -0
  187. package/dist/gateway/gateway/handlers/anthropic.js.map +1 -0
  188. package/dist/gateway/gateway/handlers/gemini.d.ts +12 -0
  189. package/dist/gateway/gateway/handlers/gemini.d.ts.map +1 -0
  190. package/dist/gateway/gateway/handlers/gemini.js +101 -0
  191. package/dist/gateway/gateway/handlers/gemini.js.map +1 -0
  192. package/dist/gateway/gateway/handlers/models.d.ts +4 -0
  193. package/dist/gateway/gateway/handlers/models.d.ts.map +1 -0
  194. package/dist/gateway/gateway/handlers/models.js +36 -0
  195. package/dist/gateway/gateway/handlers/models.js.map +1 -0
  196. package/dist/gateway/gateway/handlers/openai.d.ts +16 -0
  197. package/dist/gateway/gateway/handlers/openai.d.ts.map +1 -0
  198. package/dist/gateway/gateway/handlers/openai.js +254 -0
  199. package/dist/gateway/gateway/handlers/openai.js.map +1 -0
  200. package/dist/gateway/gateway/index.d.ts +27 -0
  201. package/dist/gateway/gateway/index.d.ts.map +1 -0
  202. package/dist/gateway/gateway/index.js +293 -0
  203. package/dist/gateway/gateway/index.js.map +1 -0
  204. package/dist/gateway/gateway/mapping-store.d.ts +38 -0
  205. package/dist/gateway/gateway/mapping-store.d.ts.map +1 -0
  206. package/dist/gateway/gateway/mapping-store.js +74 -0
  207. package/dist/gateway/gateway/mapping-store.js.map +1 -0
  208. package/dist/gateway/gateway/restorer.d.ts +63 -0
  209. package/dist/gateway/gateway/restorer.d.ts.map +1 -0
  210. package/dist/gateway/gateway/restorer.js +284 -0
  211. package/dist/gateway/gateway/restorer.js.map +1 -0
  212. package/dist/gateway/gateway/sanitizer.d.ts +17 -0
  213. package/dist/gateway/gateway/sanitizer.d.ts.map +1 -0
  214. package/dist/gateway/gateway/sanitizer.js +228 -0
  215. package/dist/gateway/gateway/sanitizer.js.map +1 -0
  216. package/dist/gateway/gateway/types.d.ts +53 -0
  217. package/dist/gateway/gateway/types.d.ts.map +1 -0
  218. package/dist/gateway/gateway/types.js +5 -0
  219. package/dist/gateway/gateway/types.js.map +1 -0
  220. package/dist/gateway/handlers/anthropic.d.ts +12 -0
  221. package/dist/gateway/handlers/anthropic.d.ts.map +1 -0
  222. package/dist/gateway/handlers/anthropic.js +254 -0
  223. package/dist/gateway/handlers/anthropic.js.map +1 -0
  224. package/dist/gateway/handlers/gemini.d.ts +12 -0
  225. package/dist/gateway/handlers/gemini.d.ts.map +1 -0
  226. package/dist/gateway/handlers/gemini.js +101 -0
  227. package/dist/gateway/handlers/gemini.js.map +1 -0
  228. package/dist/gateway/handlers/models.d.ts +4 -0
  229. package/dist/gateway/handlers/models.d.ts.map +1 -0
  230. package/dist/gateway/handlers/models.js +36 -0
  231. package/dist/gateway/handlers/models.js.map +1 -0
  232. package/dist/gateway/handlers/openai.d.ts +16 -0
  233. package/dist/gateway/handlers/openai.d.ts.map +1 -0
  234. package/dist/gateway/handlers/openai.js +254 -0
  235. package/dist/gateway/handlers/openai.js.map +1 -0
  236. package/dist/gateway/index.d.ts +27 -0
  237. package/dist/gateway/index.d.ts.map +1 -0
  238. package/dist/gateway/index.js +293 -0
  239. package/dist/gateway/index.js.map +1 -0
  240. package/dist/gateway/mapping-store.d.ts +38 -0
  241. package/dist/gateway/mapping-store.d.ts.map +1 -0
  242. package/dist/gateway/mapping-store.js +74 -0
  243. package/dist/gateway/mapping-store.js.map +1 -0
  244. package/dist/gateway/restorer.d.ts +63 -0
  245. package/dist/gateway/restorer.d.ts.map +1 -0
  246. package/dist/gateway/restorer.js +284 -0
  247. package/dist/gateway/restorer.js.map +1 -0
  248. package/dist/gateway/sanitizer.d.ts +17 -0
  249. package/dist/gateway/sanitizer.d.ts.map +1 -0
  250. package/dist/gateway/sanitizer.js +228 -0
  251. package/dist/gateway/sanitizer.js.map +1 -0
  252. package/dist/gateway/types.d.ts +53 -0
  253. package/dist/gateway/types.d.ts.map +1 -0
  254. package/dist/gateway/types.js +5 -0
  255. package/dist/gateway/types.js.map +1 -0
  256. package/dist/index.d.ts +19 -0
  257. package/dist/index.d.ts.map +1 -0
  258. package/dist/index.js +2084 -0
  259. package/dist/index.js.map +1 -0
  260. package/dist/memory/index.d.ts +5 -0
  261. package/dist/memory/index.d.ts.map +1 -0
  262. package/dist/memory/index.js +5 -0
  263. package/dist/memory/index.js.map +1 -0
  264. package/dist/memory/store.d.ts +82 -0
  265. package/dist/memory/store.d.ts.map +1 -0
  266. package/dist/memory/store.js +194 -0
  267. package/dist/memory/store.js.map +1 -0
  268. package/dist/platform-client/index.d.ts +63 -0
  269. package/dist/platform-client/index.d.ts.map +1 -0
  270. package/dist/platform-client/index.js +294 -0
  271. package/dist/platform-client/index.js.map +1 -0
  272. package/dist/platform-client/types.d.ts +109 -0
  273. package/dist/platform-client/types.d.ts.map +1 -0
  274. package/dist/platform-client/types.js +3 -0
  275. package/dist/platform-client/types.js.map +1 -0
  276. package/gateway/activity.d.ts +52 -0
  277. package/gateway/activity.d.ts.map +1 -0
  278. package/gateway/activity.js +111 -0
  279. package/gateway/activity.js.map +1 -0
  280. package/gateway/config.d.ts +50 -0
  281. package/gateway/config.d.ts.map +1 -0
  282. package/gateway/config.js +200 -0
  283. package/gateway/config.js.map +1 -0
  284. package/gateway/handlers/anthropic.d.ts +12 -0
  285. package/gateway/handlers/anthropic.d.ts.map +1 -0
  286. package/gateway/handlers/anthropic.js +254 -0
  287. package/gateway/handlers/anthropic.js.map +1 -0
  288. package/gateway/handlers/gemini.d.ts +12 -0
  289. package/gateway/handlers/gemini.d.ts.map +1 -0
  290. package/gateway/handlers/gemini.js +101 -0
  291. package/gateway/handlers/gemini.js.map +1 -0
  292. package/gateway/handlers/models.d.ts +4 -0
  293. package/gateway/handlers/models.d.ts.map +1 -0
  294. package/gateway/handlers/models.js +36 -0
  295. package/gateway/handlers/models.js.map +1 -0
  296. package/gateway/handlers/openai.d.ts +16 -0
  297. package/gateway/handlers/openai.d.ts.map +1 -0
  298. package/gateway/handlers/openai.js +254 -0
  299. package/gateway/handlers/openai.js.map +1 -0
  300. package/gateway/index.d.ts +27 -0
  301. package/gateway/index.d.ts.map +1 -0
  302. package/gateway/index.js +293 -0
  303. package/gateway/index.js.map +1 -0
  304. package/gateway/mapping-store.d.ts +38 -0
  305. package/gateway/mapping-store.d.ts.map +1 -0
  306. package/gateway/mapping-store.js +74 -0
  307. package/gateway/mapping-store.js.map +1 -0
  308. package/gateway/restorer.d.ts +63 -0
  309. package/gateway/restorer.d.ts.map +1 -0
  310. package/gateway/restorer.js +284 -0
  311. package/gateway/restorer.js.map +1 -0
  312. package/gateway/sanitizer.d.ts +17 -0
  313. package/gateway/sanitizer.d.ts.map +1 -0
  314. package/gateway/sanitizer.js +228 -0
  315. package/gateway/sanitizer.js.map +1 -0
  316. package/gateway/types.d.ts +53 -0
  317. package/gateway/types.d.ts.map +1 -0
  318. package/gateway/types.js +5 -0
  319. package/gateway/types.js.map +1 -0
  320. package/openclaw.plugin.json +86 -0
  321. package/package.json +74 -0
  322. package/samples/Untitled +1 -0
  323. package/samples/clean-email.txt +20 -0
  324. package/samples/test-document.md +53 -0
  325. package/samples/test-email-popup.txt +44 -0
  326. package/samples/test-email.txt +32 -0
  327. package/samples/test-webpage.html +51 -0
  328. package/scripts/enterprise-enroll.sh +89 -0
  329. package/scripts/enterprise-unenroll.sh +75 -0
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenGuardrails AI Security Gateway
4
+ *
5
+ * Local HTTP proxy that intercepts LLM API calls, sanitizes sensitive data
6
+ * before sending to providers, and restores it in responses.
7
+ * Supports Anthropic, OpenAI, and Gemini protocols.
8
+ */
9
+ import { createServer } from "node:http";
10
+ import { loadConfig, validateConfig, findBackendByApiKey, findDefaultBackend, findBackendByPathPrefix } from "./config.js";
11
+ import { handleAnthropicRequest } from "./handlers/anthropic.js";
12
+ import { handleOpenAIRequest } from "./handlers/openai.js";
13
+ import { handleGeminiRequest } from "./handlers/gemini.js";
14
+ import { handleModelsRequest } from "./handlers/models.js";
15
+ let config;
16
+ let currentServer = null;
17
+ /**
18
+ * Extract API key from request headers
19
+ */
20
+ function extractApiKey(req) {
21
+ // Try x-api-key header (Anthropic style)
22
+ const xApiKey = req.headers["x-api-key"];
23
+ if (xApiKey && typeof xApiKey === "string") {
24
+ return xApiKey;
25
+ }
26
+ // Try Authorization: Bearer (OpenAI style)
27
+ const auth = req.headers["authorization"];
28
+ if (auth && typeof auth === "string" && auth.startsWith("Bearer ")) {
29
+ return auth.slice(7);
30
+ }
31
+ // Try x-goog-api-key (Gemini style)
32
+ const googKey = req.headers["x-goog-api-key"];
33
+ if (googKey && typeof googKey === "string") {
34
+ return googKey;
35
+ }
36
+ return null;
37
+ }
38
+ /**
39
+ * Resolve backend for a request based on path prefix, API key, or defaults
40
+ * Priority: pathPrefix > apiKey > defaultBackend
41
+ */
42
+ function resolveBackend(req, apiType) {
43
+ const url = req.url || "";
44
+ // 1. Try to find backend by path prefix (most specific)
45
+ const byPath = findBackendByPathPrefix(url, config);
46
+ if (byPath) {
47
+ return byPath;
48
+ }
49
+ // 2. Try to find backend by API key
50
+ const apiKey = extractApiKey(req);
51
+ if (apiKey) {
52
+ const byKey = findBackendByApiKey(apiKey, config);
53
+ if (byKey) {
54
+ return byKey;
55
+ }
56
+ }
57
+ // 3. Fall back to default backend for the API type
58
+ return findDefaultBackend(apiType, config);
59
+ }
60
+ /**
61
+ * Main request handler
62
+ */
63
+ async function handleRequest(req, res) {
64
+ const { method, url } = req;
65
+ // Log request (skip health checks to reduce noise)
66
+ if (url !== "/health") {
67
+ console.log(`[ai-security-gateway] ${method} ${url}`);
68
+ }
69
+ // CORS headers (for browser-based clients)
70
+ res.setHeader("Access-Control-Allow-Origin", "*");
71
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
72
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key, anthropic-version");
73
+ // Handle OPTIONS for CORS preflight
74
+ if (method === "OPTIONS") {
75
+ res.writeHead(204);
76
+ res.end();
77
+ return;
78
+ }
79
+ // Health check (allow GET)
80
+ if (url === "/health") {
81
+ res.writeHead(200, { "Content-Type": "application/json" });
82
+ res.end(JSON.stringify({ status: "ok", version: "1.0.0" }));
83
+ return;
84
+ }
85
+ // Handle GET /v1/models — proxy to configured backend's models endpoint
86
+ if (method === "GET" && url === "/v1/models") {
87
+ await handleModelsRequest(res, config);
88
+ return;
89
+ }
90
+ // Only allow POST for API endpoints
91
+ if (method !== "POST") {
92
+ res.writeHead(405, { "Content-Type": "application/json" });
93
+ res.end(JSON.stringify({ error: "Method not allowed" }));
94
+ return;
95
+ }
96
+ // Route to appropriate handler based on path suffix
97
+ // This allows flexible path prefixes (e.g., /v1/coding/chat/completions)
98
+ try {
99
+ if (url?.endsWith("/messages")) {
100
+ // Anthropic Messages API (matches /v1/messages, /v1/xxx/messages, etc.)
101
+ const resolved = resolveBackend(req, "anthropic");
102
+ if (!resolved) {
103
+ res.writeHead(500, { "Content-Type": "application/json" });
104
+ res.end(JSON.stringify({ error: "No Anthropic-compatible backend configured" }));
105
+ return;
106
+ }
107
+ await handleAnthropicRequest(req, res, resolved.backend);
108
+ }
109
+ else if (url?.endsWith("/chat/completions")) {
110
+ // OpenAI/OpenRouter Chat Completions API
111
+ // Try to extract backend name from URL: /backend/{name}/chat/completions
112
+ const backendMatch = url.match(/^\/backend\/([^/]+)\//);
113
+ let resolved = null;
114
+ if (backendMatch) {
115
+ const backendName = backendMatch[1];
116
+ const backend = config.backends[backendName];
117
+ if (backend) {
118
+ resolved = { name: backendName, backend };
119
+ console.log(`[ai-security-gateway] Backend from URL: ${backendName}`);
120
+ }
121
+ }
122
+ // Fallback to path prefix or default
123
+ if (!resolved) {
124
+ resolved = resolveBackend(req, "openai");
125
+ console.log(`[ai-security-gateway] Resolved backend: ${resolved?.name}`);
126
+ }
127
+ // Check explicit routing config
128
+ const explicitBackendName = config.routing?.["/v1/chat/completions"];
129
+ const backend = explicitBackendName
130
+ ? config.backends[explicitBackendName]
131
+ : resolved?.backend;
132
+ if (!backend) {
133
+ res.writeHead(500, { "Content-Type": "application/json" });
134
+ res.end(JSON.stringify({ error: "No OpenAI-compatible backend configured" }));
135
+ return;
136
+ }
137
+ const extraHeaders = {};
138
+ if (backend.referer) {
139
+ extraHeaders["HTTP-Referer"] = backend.referer;
140
+ }
141
+ if (backend.title) {
142
+ extraHeaders["X-Title"] = backend.title;
143
+ }
144
+ await handleOpenAIRequest(req, res, backend, extraHeaders);
145
+ }
146
+ else if (url?.match(/\/models\/(.+):generateContent$/)) {
147
+ // Gemini API (matches any path ending with /models/{model}:generateContent)
148
+ const match = url.match(/\/models\/(.+):generateContent$/);
149
+ const modelName = match?.[1];
150
+ if (modelName) {
151
+ const resolved = resolveBackend(req, "gemini");
152
+ if (!resolved) {
153
+ res.writeHead(500, { "Content-Type": "application/json" });
154
+ res.end(JSON.stringify({ error: "No Gemini backend configured" }));
155
+ return;
156
+ }
157
+ await handleGeminiRequest(req, res, resolved.backend, modelName);
158
+ }
159
+ else {
160
+ res.writeHead(404, { "Content-Type": "application/json" });
161
+ res.end(JSON.stringify({ error: "Model name required" }));
162
+ }
163
+ }
164
+ else {
165
+ // Unknown endpoint
166
+ res.writeHead(404, { "Content-Type": "application/json" });
167
+ res.end(JSON.stringify({ error: "Not found", url }));
168
+ }
169
+ }
170
+ catch (error) {
171
+ console.error("[ai-security-gateway] Request handler error:", error);
172
+ res.writeHead(500, { "Content-Type": "application/json" });
173
+ res.end(JSON.stringify({
174
+ error: "Internal server error",
175
+ message: error instanceof Error ? error.message : String(error),
176
+ }));
177
+ }
178
+ }
179
+ /**
180
+ * Stop the gateway server
181
+ */
182
+ export function stopGateway() {
183
+ return new Promise((resolve) => {
184
+ if (currentServer) {
185
+ currentServer.close(() => {
186
+ currentServer = null;
187
+ console.log("[ai-security-gateway] Server stopped");
188
+ resolve();
189
+ });
190
+ }
191
+ else {
192
+ resolve();
193
+ }
194
+ });
195
+ }
196
+ /**
197
+ * Check if gateway is running
198
+ */
199
+ export function isGatewayServerRunning() {
200
+ return currentServer !== null;
201
+ }
202
+ /**
203
+ * Start gateway server
204
+ * @param configPath - Path to config file
205
+ * @param embedded - If true, don't call process.exit on errors (for in-process use)
206
+ */
207
+ export function startGateway(configPath, embedded = false) {
208
+ // Stop existing server if running (same process)
209
+ if (currentServer) {
210
+ if (!embedded)
211
+ console.log("[ai-security-gateway] Stopping existing server for restart...");
212
+ currentServer.close();
213
+ currentServer = null;
214
+ }
215
+ try {
216
+ // Load and validate configuration
217
+ config = loadConfig(configPath);
218
+ validateConfig(config);
219
+ if (!embedded) {
220
+ console.log("[ai-security-gateway] Configuration loaded:");
221
+ console.log(` Port: ${config.port}`);
222
+ console.log(` Backends: ${Object.keys(config.backends).join(", ") || "(none)"}`);
223
+ }
224
+ // Create HTTP server
225
+ const server = createServer(handleRequest);
226
+ currentServer = server;
227
+ // Handle server errors
228
+ server.on("error", (err) => {
229
+ console.error("[ai-security-gateway] Server error:", err);
230
+ currentServer = null;
231
+ if (!embedded) {
232
+ process.exit(1);
233
+ return;
234
+ }
235
+ // Embedded mode: never crash host process on gateway bind/runtime errors.
236
+ // The plugin can continue running and other features remain available.
237
+ console.warn("[ai-security-gateway] Embedded mode: gateway error ignored");
238
+ });
239
+ // Start listening
240
+ server.listen(config.port, "127.0.0.1", () => {
241
+ if (!embedded) {
242
+ console.log(`[ai-security-gateway] Server listening on http://127.0.0.1:${config.port}`);
243
+ console.log("[ai-security-gateway] Ready to proxy requests");
244
+ console.log("");
245
+ console.log("Endpoints:");
246
+ console.log(` POST http://127.0.0.1:${config.port}/v1/messages - Anthropic`);
247
+ console.log(` POST http://127.0.0.1:${config.port}/v1/chat/completions - OpenAI / OpenRouter`);
248
+ console.log(` POST http://127.0.0.1:${config.port}/v1/models/:model:generateContent - Gemini`);
249
+ console.log(` GET http://127.0.0.1:${config.port}/v1/models - List models (OpenAI / OpenRouter)`);
250
+ console.log(` GET http://127.0.0.1:${config.port}/health - Health check`);
251
+ }
252
+ });
253
+ // In embedded mode, don't let the server prevent process exit
254
+ if (embedded) {
255
+ server.unref();
256
+ }
257
+ // Only register shutdown handlers if not embedded
258
+ if (!embedded) {
259
+ process.on("SIGINT", () => {
260
+ console.log("\n[ai-security-gateway] Shutting down...");
261
+ server.close(() => {
262
+ console.log("[ai-security-gateway] Server stopped");
263
+ process.exit(0);
264
+ });
265
+ });
266
+ process.on("SIGTERM", () => {
267
+ console.log("\n[ai-security-gateway] Shutting down...");
268
+ server.close(() => {
269
+ console.log("[ai-security-gateway] Server stopped");
270
+ process.exit(0);
271
+ });
272
+ });
273
+ }
274
+ }
275
+ catch (error) {
276
+ console.error("[ai-security-gateway] Failed to start:", error);
277
+ currentServer = null;
278
+ if (!embedded) {
279
+ process.exit(1);
280
+ }
281
+ throw error;
282
+ }
283
+ }
284
+ // Re-export for programmatic use
285
+ export { sanitize, sanitizeMessages } from "./sanitizer.js";
286
+ export { restore, restoreJSON, restoreSSELine } from "./restorer.js";
287
+ export { addActivityListener, removeActivityListener, clearActivityListeners, } from "./activity.js";
288
+ // Start if run directly
289
+ if (import.meta.url === `file://${process.argv[1]}`) {
290
+ const configPath = process.argv[2];
291
+ startGateway(configPath);
292
+ }
293
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Persistent Mapping Store
3
+ *
4
+ * Maintains a global mapping between original values and placeholders.
5
+ * This ensures the same sensitive data always gets the same placeholder,
6
+ * allowing restoration to work across multiple requests in a conversation.
7
+ */
8
+ import type { MappingTable } from "./types.js";
9
+ /**
10
+ * Get or create a placeholder for an original value
11
+ * If the value was seen before, returns the same placeholder
12
+ */
13
+ export declare function getOrCreatePlaceholder(originalValue: string, entityType: string): string;
14
+ /**
15
+ * Get the original value for a placeholder
16
+ */
17
+ export declare function getOriginalValue(placeholder: string): string | undefined;
18
+ /**
19
+ * Check if a string is a known placeholder
20
+ */
21
+ export declare function isKnownPlaceholder(text: string): boolean;
22
+ /**
23
+ * Get all placeholders and their original values as a MappingTable
24
+ * This is used for restoration
25
+ */
26
+ export declare function getGlobalMappingTable(): MappingTable;
27
+ /**
28
+ * Get current statistics
29
+ */
30
+ export declare function getMappingStats(): {
31
+ totalMappings: number;
32
+ byType: Record<string, number>;
33
+ };
34
+ /**
35
+ * Clear all mappings (for testing or reset)
36
+ */
37
+ export declare function clearMappings(): void;
38
+ //# sourceMappingURL=mapping-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapping-store.d.ts","sourceRoot":"","sources":["../src/mapping-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAW/C;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAmBxF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAExE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,YAAY,CAEpD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAS3F;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Persistent Mapping Store
3
+ *
4
+ * Maintains a global mapping between original values and placeholders.
5
+ * This ensures the same sensitive data always gets the same placeholder,
6
+ * allowing restoration to work across multiple requests in a conversation.
7
+ */
8
+ // Global mapping: original value -> placeholder
9
+ const originalToPlaceholder = new Map();
10
+ // Global mapping: placeholder -> original value (reverse lookup for restoration)
11
+ const placeholderToOriginal = new Map();
12
+ // Global counter per entity type
13
+ const typeCounters = new Map();
14
+ /**
15
+ * Get or create a placeholder for an original value
16
+ * If the value was seen before, returns the same placeholder
17
+ */
18
+ export function getOrCreatePlaceholder(originalValue, entityType) {
19
+ // Check if we already have a placeholder for this value
20
+ const existing = originalToPlaceholder.get(originalValue);
21
+ if (existing) {
22
+ return existing;
23
+ }
24
+ // Create a new placeholder
25
+ const counter = (typeCounters.get(entityType) ?? 0) + 1;
26
+ typeCounters.set(entityType, counter);
27
+ const paddedId = counter.toString().padStart(8, "0");
28
+ const placeholder = `__PII_${entityType}_${paddedId}__`;
29
+ // Store both directions
30
+ originalToPlaceholder.set(originalValue, placeholder);
31
+ placeholderToOriginal.set(placeholder, originalValue);
32
+ return placeholder;
33
+ }
34
+ /**
35
+ * Get the original value for a placeholder
36
+ */
37
+ export function getOriginalValue(placeholder) {
38
+ return placeholderToOriginal.get(placeholder);
39
+ }
40
+ /**
41
+ * Check if a string is a known placeholder
42
+ */
43
+ export function isKnownPlaceholder(text) {
44
+ return placeholderToOriginal.has(text);
45
+ }
46
+ /**
47
+ * Get all placeholders and their original values as a MappingTable
48
+ * This is used for restoration
49
+ */
50
+ export function getGlobalMappingTable() {
51
+ return new Map(placeholderToOriginal);
52
+ }
53
+ /**
54
+ * Get current statistics
55
+ */
56
+ export function getMappingStats() {
57
+ const byType = {};
58
+ for (const [type, count] of typeCounters.entries()) {
59
+ byType[type] = count;
60
+ }
61
+ return {
62
+ totalMappings: placeholderToOriginal.size,
63
+ byType,
64
+ };
65
+ }
66
+ /**
67
+ * Clear all mappings (for testing or reset)
68
+ */
69
+ export function clearMappings() {
70
+ originalToPlaceholder.clear();
71
+ placeholderToOriginal.clear();
72
+ typeCounters.clear();
73
+ }
74
+ //# sourceMappingURL=mapping-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapping-store.js","sourceRoot":"","sources":["../src/mapping-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,gDAAgD;AAChD,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAExD,iFAAiF;AACjF,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAExD,iCAAiC;AACjC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,aAAqB,EAAE,UAAkB;IAC9E,wDAAwD;IACxD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC1D,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,2BAA2B;IAC3B,MAAM,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,SAAS,UAAU,IAAI,QAAQ,IAAI,CAAC;IAExD,wBAAwB;IACxB,qBAAqB,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACtD,qBAAqB,CAAC,GAAG,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAEtD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,OAAO,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,GAAG,CAAC,qBAAqB,CAAC,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO;QACL,aAAa,EAAE,qBAAqB,CAAC,IAAI;QACzC,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,qBAAqB,CAAC,KAAK,EAAE,CAAC;IAC9B,qBAAqB,CAAC,KAAK,EAAE,CAAC;IAC9B,YAAY,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * AI Security Gateway - Content Restorer
3
+ *
4
+ * Restores sanitized placeholders back to original values.
5
+ * Handles LLM corruption patterns (missing underscores, case variations).
6
+ *
7
+ * Placeholder format: __PII_<ENTITY_TYPE>_<SERIAL_ID>__
8
+ */
9
+ import type { MappingTable } from "./types.js";
10
+ /**
11
+ * Restore any content (object, array, string) using the mapping table
12
+ */
13
+ export declare function restore(content: unknown, mappingTable: MappingTable): unknown;
14
+ /**
15
+ * Restore a JSON string
16
+ * Useful for SSE streaming where each chunk is a JSON string
17
+ */
18
+ export declare function restoreJSON(jsonString: string, mappingTable: MappingTable): string;
19
+ /**
20
+ * Restore SSE data line (for streaming responses)
21
+ * Format: "data: {...}\n"
22
+ */
23
+ export declare function restoreSSELine(line: string, mappingTable: MappingTable): string;
24
+ /**
25
+ * StreamRestorer - Stateful streaming restoration with smart buffering
26
+ *
27
+ * Only buffers when `__` is detected (potential placeholder start).
28
+ * Otherwise streams through immediately for best UX.
29
+ */
30
+ export declare class StreamRestorer {
31
+ private buffer;
32
+ private mappingTable;
33
+ constructor(mappingTable: MappingTable);
34
+ /**
35
+ * Process incoming text chunk
36
+ * Returns text that can be safely output (already restored or confirmed non-placeholder)
37
+ */
38
+ process(chunk: string): string;
39
+ /**
40
+ * Flush what we can safely output
41
+ * Keeps potential incomplete placeholders in buffer
42
+ */
43
+ private flush;
44
+ /**
45
+ * Check if text could be the start of a placeholder
46
+ * Returns true if it matches the beginning of __PII_<TYPE>_<ID>__
47
+ */
48
+ private couldBePlaceholder;
49
+ /**
50
+ * Finalize stream - flush any remaining buffer
51
+ * Call this at end of stream to ensure nothing is lost
52
+ */
53
+ finalize(): string;
54
+ /**
55
+ * Check if there's pending data in buffer
56
+ */
57
+ hasPendingData(): boolean;
58
+ }
59
+ /**
60
+ * Create a streaming restorer for a response
61
+ */
62
+ export declare function createStreamRestorer(mappingTable: MappingTable): StreamRestorer;
63
+ //# sourceMappingURL=restorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restorer.d.ts","sourceRoot":"","sources":["../src/restorer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAyG/C;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAG7E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,MAAM,CAWlF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,MAAM,CAe/E;AAYD;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAe;gBAEvB,YAAY,EAAE,YAAY;IAItC;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAU9B;;;OAGG;IACH,OAAO,CAAC,KAAK;IAqEb;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;OAGG;IACH,QAAQ,IAAI,MAAM;IASlB;;OAEG;IACH,cAAc,IAAI,OAAO;CAG1B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,YAAY,GAAG,cAAc,CAE/E"}