@opentrust/gateway 7.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 (66) hide show
  1. package/dist/config.d.ts +7 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +81 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/handlers/anthropic.d.ts +7 -0
  6. package/dist/handlers/anthropic.d.ts.map +1 -0
  7. package/dist/handlers/anthropic.js +49 -0
  8. package/dist/handlers/anthropic.js.map +1 -0
  9. package/dist/handlers/gemini.d.ts +7 -0
  10. package/dist/handlers/gemini.d.ts.map +1 -0
  11. package/dist/handlers/gemini.js +41 -0
  12. package/dist/handlers/gemini.js.map +1 -0
  13. package/dist/handlers/models.d.ts +7 -0
  14. package/dist/handlers/models.d.ts.map +1 -0
  15. package/dist/handlers/models.js +29 -0
  16. package/dist/handlers/models.js.map +1 -0
  17. package/dist/handlers/openai.d.ts +11 -0
  18. package/dist/handlers/openai.d.ts.map +1 -0
  19. package/dist/handlers/openai.js +45 -0
  20. package/dist/handlers/openai.js.map +1 -0
  21. package/dist/index.d.ts +12 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +126 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/restorer.d.ts +8 -0
  26. package/dist/restorer.d.ts.map +1 -0
  27. package/dist/restorer.js +54 -0
  28. package/dist/restorer.js.map +1 -0
  29. package/dist/sanitizer/core.d.ts +16 -0
  30. package/dist/sanitizer/core.d.ts.map +1 -0
  31. package/dist/sanitizer/core.js +77 -0
  32. package/dist/sanitizer/core.js.map +1 -0
  33. package/dist/sanitizer/index.d.ts +3 -0
  34. package/dist/sanitizer/index.d.ts.map +1 -0
  35. package/dist/sanitizer/index.js +3 -0
  36. package/dist/sanitizer/index.js.map +1 -0
  37. package/dist/sanitizer/reversible.d.ts +8 -0
  38. package/dist/sanitizer/reversible.d.ts.map +1 -0
  39. package/dist/sanitizer/reversible.js +62 -0
  40. package/dist/sanitizer/reversible.js.map +1 -0
  41. package/dist/types.d.ts +41 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +5 -0
  44. package/dist/types.js.map +1 -0
  45. package/dist/utils/http.d.ts +9 -0
  46. package/dist/utils/http.d.ts.map +1 -0
  47. package/dist/utils/http.js +35 -0
  48. package/dist/utils/http.js.map +1 -0
  49. package/dist/utils/stream.d.ts +14 -0
  50. package/dist/utils/stream.d.ts.map +1 -0
  51. package/dist/utils/stream.js +55 -0
  52. package/dist/utils/stream.js.map +1 -0
  53. package/package.json +53 -0
  54. package/src/config.ts +91 -0
  55. package/src/handlers/anthropic.ts +53 -0
  56. package/src/handlers/gemini.ts +46 -0
  57. package/src/handlers/models.ts +31 -0
  58. package/src/handlers/openai.ts +55 -0
  59. package/src/index.ts +115 -0
  60. package/src/restorer.ts +49 -0
  61. package/src/sanitizer/core.ts +102 -0
  62. package/src/sanitizer/index.ts +2 -0
  63. package/src/sanitizer/reversible.ts +78 -0
  64. package/src/types.ts +33 -0
  65. package/src/utils/http.ts +41 -0
  66. package/src/utils/stream.ts +64 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Gateway configuration management
3
+ */
4
+ import type { GatewayConfig } from "./types.js";
5
+ export declare function loadConfig(configPath?: string): GatewayConfig;
6
+ export declare function validateConfig(config: GatewayConfig): void;
7
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAmB7D;AAqDD,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAM1D"}
package/dist/config.js ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Gateway configuration management
3
+ */
4
+ import { readFileSync, existsSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
+ const CONFIG_PATH = join(homedir(), ".opentrust", "gateway.json");
8
+ const LEGACY_CONFIG_PATH = join(homedir(), ".opentrust-legacy", "gateway.json");
9
+ export function loadConfig(configPath) {
10
+ const defaults = {
11
+ port: parseInt(process.env.GATEWAY_PORT || "8900", 10),
12
+ backends: {},
13
+ };
14
+ // Try explicit path, then new path, then legacy path
15
+ for (const p of [configPath, CONFIG_PATH, LEGACY_CONFIG_PATH]) {
16
+ if (p && existsSync(p)) {
17
+ try {
18
+ const file = JSON.parse(readFileSync(p, "utf-8"));
19
+ return applyEnvOverrides(merge(defaults, file));
20
+ }
21
+ catch (err) {
22
+ console.warn(`[opentrust-gateway] Failed to load config from ${p}:`, err);
23
+ }
24
+ }
25
+ }
26
+ return applyEnvOverrides(defaults);
27
+ }
28
+ function applyEnvOverrides(config) {
29
+ const env = process.env;
30
+ if (env.ANTHROPIC_API_KEY) {
31
+ config.backends.anthropic = {
32
+ baseUrl: env.ANTHROPIC_BASE_URL || "https://api.anthropic.com",
33
+ apiKey: env.ANTHROPIC_API_KEY,
34
+ };
35
+ }
36
+ if (env.OPENAI_API_KEY) {
37
+ config.backends.openai = {
38
+ baseUrl: env.OPENAI_BASE_URL || "https://api.openai.com",
39
+ apiKey: env.OPENAI_API_KEY,
40
+ };
41
+ }
42
+ if ((env.KIMI_API_KEY || env.MOONSHOT_API_KEY) && !config.backends.openai) {
43
+ config.backends.openai = {
44
+ baseUrl: env.KIMI_BASE_URL || "https://api.moonshot.cn",
45
+ apiKey: env.KIMI_API_KEY || env.MOONSHOT_API_KEY || "",
46
+ };
47
+ }
48
+ if (env.GEMINI_API_KEY || env.GOOGLE_API_KEY) {
49
+ config.backends.gemini = {
50
+ baseUrl: env.GEMINI_BASE_URL || "https://generativelanguage.googleapis.com",
51
+ apiKey: env.GEMINI_API_KEY || env.GOOGLE_API_KEY || "",
52
+ };
53
+ }
54
+ if (env.OPENROUTER_API_KEY) {
55
+ config.backends.openrouter = {
56
+ baseUrl: env.OPENROUTER_BASE_URL || "https://openrouter.ai/api",
57
+ apiKey: env.OPENROUTER_API_KEY,
58
+ ...(env.OPENROUTER_REFERER && { referer: env.OPENROUTER_REFERER }),
59
+ ...(env.OPENROUTER_TITLE && { title: env.OPENROUTER_TITLE }),
60
+ };
61
+ }
62
+ return config;
63
+ }
64
+ function merge(base, file) {
65
+ return {
66
+ port: file.port ?? base.port,
67
+ backends: { ...base.backends, ...file.backends },
68
+ routing: file.routing,
69
+ };
70
+ }
71
+ export function validateConfig(config) {
72
+ if (config.port < 1 || config.port > 65535)
73
+ throw new Error(`Invalid port: ${config.port}`);
74
+ for (const [name, backend] of Object.entries(config.backends)) {
75
+ if (!backend.baseUrl)
76
+ throw new Error(`Backend ${name} missing baseUrl`);
77
+ if (!backend.apiKey)
78
+ throw new Error(`Backend ${name} missing apiKey`);
79
+ }
80
+ }
81
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Anthropic Messages API handler — POST /v1/messages
3
+ */
4
+ import type { IncomingMessage, ServerResponse } from "node:http";
5
+ import type { GatewayConfig } from "../types.js";
6
+ export declare function handleAnthropicRequest(req: IncomingMessage, res: ServerResponse, config: GatewayConfig): Promise<void>;
7
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/handlers/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAsCf"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Anthropic Messages API handler — POST /v1/messages
3
+ */
4
+ import { sanitize } from "../sanitizer/index.js";
5
+ import { readBody, sendError, forwardError } from "../utils/http.js";
6
+ import { handleSSEStream, handleJSONResponse } from "../utils/stream.js";
7
+ export async function handleAnthropicRequest(req, res, config) {
8
+ try {
9
+ const { model, messages, system, tools, max_tokens, temperature, stream = false, ...rest } = JSON.parse(await readBody(req));
10
+ const { sanitized: sanitizedMessages, mappingTable } = sanitize(messages);
11
+ const sanitizedSystem = system ? sanitize(system).sanitized : system;
12
+ const backend = config.backends.anthropic;
13
+ if (!backend) {
14
+ sendError(res, 500, "Anthropic backend not configured");
15
+ return;
16
+ }
17
+ const response = await fetch(`${backend.baseUrl}/v1/messages`, {
18
+ method: "POST",
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ "anthropic-version": req.headers["anthropic-version"] || "2023-06-01",
22
+ "x-api-key": backend.apiKey,
23
+ },
24
+ body: JSON.stringify({
25
+ model,
26
+ messages: sanitizedMessages,
27
+ ...(system && { system: sanitizedSystem }),
28
+ ...(tools && { tools }),
29
+ max_tokens,
30
+ ...(temperature !== undefined && { temperature }),
31
+ stream,
32
+ ...rest,
33
+ }),
34
+ });
35
+ if (!response.ok) {
36
+ await forwardError(res, response);
37
+ return;
38
+ }
39
+ if (stream)
40
+ await handleSSEStream(response, res, mappingTable);
41
+ else
42
+ await handleJSONResponse(response, res, mappingTable);
43
+ }
44
+ catch (error) {
45
+ console.error("[opentrust-gateway] Anthropic handler error:", error);
46
+ sendError(res, 500, error instanceof Error ? error.message : String(error));
47
+ }
48
+ }
49
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/handlers/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,GAAoB,EACpB,GAAmB,EACnB,MAAqB;IAErB,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,GACxF,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAElC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1E,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QAErE,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;YAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,kCAAkC,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAElF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,cAAc,EAAE;YAC7D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,mBAAmB,EAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAY,IAAI,YAAY;gBACjF,WAAW,EAAE,OAAO,CAAC,MAAM;aAC5B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,QAAQ,EAAE,iBAAiB;gBAC3B,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;gBAC1C,GAAG,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC;gBACvB,UAAU;gBACV,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;gBACjD,MAAM;gBACN,GAAG,IAAI;aACR,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAAC,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAEhE,IAAI,MAAM;YAAE,MAAM,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;;YAC1D,MAAM,kBAAkB,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,CAAC;QACrE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Google Gemini handler — POST /v1/models/:model:generateContent
3
+ */
4
+ import type { IncomingMessage, ServerResponse } from "node:http";
5
+ import type { GatewayConfig } from "../types.js";
6
+ export declare function handleGeminiRequest(req: IncomingMessage, res: ServerResponse, config: GatewayConfig, modelName: string): Promise<void>;
7
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/handlers/gemini.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Google Gemini handler — POST /v1/models/:model:generateContent
3
+ */
4
+ import { sanitize } from "../sanitizer/index.js";
5
+ import { restore } from "../restorer.js";
6
+ import { readBody, sendError, forwardError, sendJSON } from "../utils/http.js";
7
+ export async function handleGeminiRequest(req, res, config, modelName) {
8
+ try {
9
+ const { contents, tools, generationConfig, ...rest } = JSON.parse(await readBody(req));
10
+ const { sanitized: sanitizedContents, mappingTable } = sanitize(contents);
11
+ const backend = config.backends.gemini;
12
+ if (!backend) {
13
+ sendError(res, 500, "Gemini backend not configured");
14
+ return;
15
+ }
16
+ const response = await fetch(`${backend.baseUrl}/v1/models/${modelName}:generateContent`, {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json",
20
+ "x-goog-api-key": backend.apiKey,
21
+ },
22
+ body: JSON.stringify({
23
+ contents: sanitizedContents,
24
+ ...(tools && { tools }),
25
+ ...(generationConfig && { generationConfig }),
26
+ ...rest,
27
+ }),
28
+ });
29
+ if (!response.ok) {
30
+ await forwardError(res, response);
31
+ return;
32
+ }
33
+ const data = JSON.parse(await response.text());
34
+ sendJSON(res, 200, restore(data, mappingTable));
35
+ }
36
+ catch (error) {
37
+ console.error("[opentrust-gateway] Gemini handler error:", error);
38
+ sendError(res, 500, error instanceof Error ? error.message : String(error));
39
+ }
40
+ }
41
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/handlers/gemini.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE/E,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAoB,EACpB,GAAmB,EACnB,MAAqB,EACrB,SAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QACvF,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE1E,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;YAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,+BAA+B,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAE/E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,cAAc,SAAS,kBAAkB,EAAE;YACxF,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,gBAAgB,EAAE,OAAO,CAAC,MAAM;aACjC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,QAAQ,EAAE,iBAAiB;gBAC3B,GAAG,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC;gBACvB,GAAG,CAAC,gBAAgB,IAAI,EAAE,gBAAgB,EAAE,CAAC;gBAC7C,GAAG,IAAI;aACR,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAAC,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAEhE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;QAClE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Model list proxy — GET /v1/models
3
+ */
4
+ import type { ServerResponse } from "node:http";
5
+ import type { GatewayConfig } from "../types.js";
6
+ export declare function handleModelsRequest(res: ServerResponse, config: GatewayConfig): Promise<void>;
7
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/handlers/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAmBf"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Model list proxy — GET /v1/models
3
+ */
4
+ import { sendError } from "../utils/http.js";
5
+ export async function handleModelsRequest(res, config) {
6
+ try {
7
+ const backend = config.backends.openrouter ?? config.backends.openai;
8
+ if (!backend) {
9
+ sendError(res, 500, "No OpenAI-compatible backend configured");
10
+ return;
11
+ }
12
+ const headers = { Authorization: `Bearer ${backend.apiKey}` };
13
+ if (config.backends.openrouter) {
14
+ const or = config.backends.openrouter;
15
+ if (or.referer)
16
+ headers["HTTP-Referer"] = or.referer;
17
+ if (or.title)
18
+ headers["X-Title"] = or.title;
19
+ }
20
+ const response = await fetch(`${backend.baseUrl}/v1/models`, { headers });
21
+ res.writeHead(response.status, { "Content-Type": "application/json" });
22
+ res.end(await response.text());
23
+ }
24
+ catch (error) {
25
+ console.error("[opentrust-gateway] Models request error:", error);
26
+ sendError(res, 500, error instanceof Error ? error.message : String(error));
27
+ }
28
+ }
29
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/handlers/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAmB,EACnB,MAAqB;IAErB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACrE,IAAI,CAAC,OAAO,EAAE,CAAC;YAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,yCAAyC,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAEzF,MAAM,OAAO,GAA2B,EAAE,aAAa,EAAE,UAAU,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACtF,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;YACtC,IAAI,EAAE,CAAC,OAAO;gBAAE,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;YACrD,IAAI,EAAE,CAAC,KAAK;gBAAE,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;QAC9C,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1E,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACvE,GAAG,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;QAClE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * OpenAI Chat Completions handler — POST /v1/chat/completions
3
+ * Also compatible with OpenRouter, Kimi, DeepSeek, etc.
4
+ */
5
+ import type { IncomingMessage, ServerResponse } from "node:http";
6
+ export type OpenAICompatibleBackend = {
7
+ baseUrl: string;
8
+ apiKey: string;
9
+ };
10
+ export declare function handleOpenAIRequest(req: IncomingMessage, res: ServerResponse, backend: OpenAICompatibleBackend, extraHeaders?: Record<string, string>): Promise<void>;
11
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/handlers/openai.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMjE,MAAM,MAAM,uBAAuB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,uBAAuB,EAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * OpenAI Chat Completions handler — POST /v1/chat/completions
3
+ * Also compatible with OpenRouter, Kimi, DeepSeek, etc.
4
+ */
5
+ import { sanitize } from "../sanitizer/index.js";
6
+ import { readBody, sendError, forwardError } from "../utils/http.js";
7
+ import { handleSSEStream, handleJSONResponse } from "../utils/stream.js";
8
+ export async function handleOpenAIRequest(req, res, backend, extraHeaders) {
9
+ try {
10
+ const { model, messages, tools, tool_choice, temperature, max_tokens, stream = false, ...rest } = JSON.parse(await readBody(req));
11
+ const { sanitized: sanitizedMessages, mappingTable } = sanitize(messages);
12
+ const headers = {
13
+ "Content-Type": "application/json",
14
+ Authorization: `Bearer ${backend.apiKey}`,
15
+ ...extraHeaders,
16
+ };
17
+ const response = await fetch(`${backend.baseUrl}/v1/chat/completions`, {
18
+ method: "POST",
19
+ headers,
20
+ body: JSON.stringify({
21
+ model,
22
+ messages: sanitizedMessages,
23
+ ...(tools && { tools }),
24
+ ...(tool_choice && { tool_choice }),
25
+ ...(temperature !== undefined && { temperature }),
26
+ ...(max_tokens && { max_tokens }),
27
+ stream,
28
+ ...rest,
29
+ }),
30
+ });
31
+ if (!response.ok) {
32
+ await forwardError(res, response);
33
+ return;
34
+ }
35
+ if (stream)
36
+ await handleSSEStream(response, res, mappingTable);
37
+ else
38
+ await handleJSONResponse(response, res, mappingTable);
39
+ }
40
+ catch (error) {
41
+ console.error("[opentrust-gateway] OpenAI handler error:", error);
42
+ sendError(res, 500, error instanceof Error ? error.message : String(error));
43
+ }
44
+ }
45
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/handlers/openai.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAIzE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAoB,EACpB,GAAmB,EACnB,OAAgC,EAChC,YAAqC;IAErC,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,GAC7F,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAElC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE1E,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,OAAO,CAAC,MAAM,EAAE;YACzC,GAAG,YAAY;SAChB,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,sBAAsB,EAAE;YACrE,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,QAAQ,EAAE,iBAAiB;gBAC3B,GAAG,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC;gBACvB,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;gBACnC,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;gBACjD,GAAG,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC;gBACjC,MAAM;gBACN,GAAG,IAAI;aACR,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAAC,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAEhE,IAAI,MAAM;YAAE,MAAM,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;;YAC1D,MAAM,kBAAkB,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;QAClE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenTrust 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
+ */
8
+ export declare function startGateway(configPath?: string): void;
9
+ export { sanitize, sanitizeMessages } from "./sanitizer/index.js";
10
+ export { restore, restoreJSON, restoreSSELine } from "./restorer.js";
11
+ export type { GatewayConfig, MappingTable, SanitizeResult, EntityMatch } from "./types.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAqEH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CA8BtD;AAGD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACrE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenTrust 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
+ */
8
+ import { createServer } from "node:http";
9
+ import { loadConfig, validateConfig } from "./config.js";
10
+ import { handleAnthropicRequest } from "./handlers/anthropic.js";
11
+ import { handleOpenAIRequest } from "./handlers/openai.js";
12
+ import { handleGeminiRequest } from "./handlers/gemini.js";
13
+ import { handleModelsRequest } from "./handlers/models.js";
14
+ import { sendJSON, sendError } from "./utils/http.js";
15
+ const LOG = "[opentrust-gateway]";
16
+ let config;
17
+ async function handleRequest(req, res) {
18
+ const { method, url } = req;
19
+ console.log(`${LOG} ${method} ${url}`);
20
+ // CORS
21
+ res.setHeader("Access-Control-Allow-Origin", "*");
22
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
23
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key, anthropic-version");
24
+ if (method === "OPTIONS") {
25
+ res.writeHead(204);
26
+ res.end();
27
+ return;
28
+ }
29
+ if (url === "/health") {
30
+ sendJSON(res, 200, { status: "ok", version: "7.0.0" });
31
+ return;
32
+ }
33
+ if (method === "GET" && url === "/v1/models") {
34
+ await handleModelsRequest(res, config);
35
+ return;
36
+ }
37
+ if (method !== "POST") {
38
+ sendError(res, 405, "Method not allowed");
39
+ return;
40
+ }
41
+ try {
42
+ if (url === "/v1/messages") {
43
+ await handleAnthropicRequest(req, res, config);
44
+ }
45
+ else if (url === "/v1/chat/completions") {
46
+ await routeOpenAI(req, res);
47
+ }
48
+ else if (url?.match(/^\/v1\/models\/(.+):generateContent$/)) {
49
+ const modelName = url.match(/^\/v1\/models\/(.+):generateContent$/)?.[1];
50
+ if (modelName)
51
+ await handleGeminiRequest(req, res, config, modelName);
52
+ else
53
+ sendError(res, 404, "Model name required");
54
+ }
55
+ else {
56
+ sendError(res, 404, `Not found: ${url}`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.error(`${LOG} Request handler error:`, error);
61
+ sendError(res, 500, error instanceof Error ? error.message : String(error));
62
+ }
63
+ }
64
+ async function routeOpenAI(req, res) {
65
+ const explicit = config.routing?.["/v1/chat/completions"];
66
+ if (explicit === "openrouter" || (!explicit && config.backends.openrouter)) {
67
+ const backend = config.backends.openrouter;
68
+ if (!backend) {
69
+ sendError(res, 500, "No OpenRouter backend configured");
70
+ return;
71
+ }
72
+ const extra = {};
73
+ if (backend.referer)
74
+ extra["HTTP-Referer"] = backend.referer;
75
+ if (backend.title)
76
+ extra["X-Title"] = backend.title;
77
+ await handleOpenAIRequest(req, res, backend, extra);
78
+ }
79
+ else if (explicit === "openai" || (!explicit && config.backends.openai)) {
80
+ const backend = config.backends.openai;
81
+ if (!backend) {
82
+ sendError(res, 500, "No OpenAI backend configured");
83
+ return;
84
+ }
85
+ await handleOpenAIRequest(req, res, backend);
86
+ }
87
+ else {
88
+ sendError(res, 500, "No OpenAI-compatible backend configured");
89
+ }
90
+ }
91
+ export function startGateway(configPath) {
92
+ try {
93
+ config = loadConfig(configPath);
94
+ validateConfig(config);
95
+ console.log(`${LOG} Configuration loaded:`);
96
+ console.log(` Port: ${config.port}`);
97
+ console.log(` Backends: ${Object.keys(config.backends).join(", ") || "(none)"}`);
98
+ const server = createServer(handleRequest);
99
+ const host = process.env.GATEWAY_HOST || "127.0.0.1";
100
+ server.listen(config.port, host, () => {
101
+ console.log(`${LOG} Listening on http://${host}:${config.port}`);
102
+ console.log(` POST /v1/messages — Anthropic`);
103
+ console.log(` POST /v1/chat/completions — OpenAI / OpenRouter`);
104
+ console.log(` POST /v1/models/:m:generate — Gemini`);
105
+ console.log(` GET /v1/models — List models`);
106
+ console.log(` GET /health — Health check`);
107
+ });
108
+ const shutdown = () => {
109
+ console.log(`\n${LOG} Shutting down...`);
110
+ server.close(() => process.exit(0));
111
+ };
112
+ process.on("SIGINT", shutdown);
113
+ process.on("SIGTERM", shutdown);
114
+ }
115
+ catch (error) {
116
+ console.error(`${LOG} Failed to start:`, error);
117
+ process.exit(1);
118
+ }
119
+ }
120
+ // Re-exports
121
+ export { sanitize, sanitizeMessages } from "./sanitizer/index.js";
122
+ export { restore, restoreJSON, restoreSSELine } from "./restorer.js";
123
+ if (import.meta.url === `file://${process.argv[1]}`) {
124
+ startGateway(process.argv[2]);
125
+ }
126
+ //# 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,8 @@
1
+ /**
2
+ * Content restorer — replaces placeholders back to original values.
3
+ */
4
+ import type { MappingTable } from "./types.js";
5
+ export declare function restore(content: any, map: MappingTable): any;
6
+ export declare function restoreJSON(jsonString: string, map: MappingTable): string;
7
+ export declare function restoreSSELine(line: string, map: MappingTable): string;
8
+ //# sourceMappingURL=restorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restorer.d.ts","sourceRoot":"","sources":["../src/restorer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAoB/C,wBAAgB,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,GAAG,CAG5D;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAOzE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAUtE"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Content restorer — replaces placeholders back to original values.
3
+ */
4
+ function restoreText(text, map) {
5
+ let out = text;
6
+ const keys = Array.from(map.keys()).sort((a, b) => b.length - a.length);
7
+ for (const k of keys)
8
+ out = out.split(k).join(map.get(k));
9
+ return out;
10
+ }
11
+ function restoreValue(value, map) {
12
+ if (typeof value === "string")
13
+ return restoreText(value, map);
14
+ if (Array.isArray(value))
15
+ return value.map((v) => restoreValue(v, map));
16
+ if (value !== null && typeof value === "object") {
17
+ const out = {};
18
+ for (const [k, v] of Object.entries(value))
19
+ out[k] = restoreValue(v, map);
20
+ return out;
21
+ }
22
+ return value;
23
+ }
24
+ export function restore(content, map) {
25
+ if (map.size === 0)
26
+ return content;
27
+ return restoreValue(content, map);
28
+ }
29
+ export function restoreJSON(jsonString, map) {
30
+ if (map.size === 0)
31
+ return jsonString;
32
+ try {
33
+ return JSON.stringify(restore(JSON.parse(jsonString), map));
34
+ }
35
+ catch {
36
+ return restoreText(jsonString, map);
37
+ }
38
+ }
39
+ export function restoreSSELine(line, map) {
40
+ if (map.size === 0)
41
+ return line;
42
+ if (!line.startsWith("data: "))
43
+ return line;
44
+ const data = line.slice(6);
45
+ if (data === "[DONE]")
46
+ return line;
47
+ try {
48
+ return `data: ${JSON.stringify(restore(JSON.parse(data), map))}\n`;
49
+ }
50
+ catch {
51
+ return `data: ${restoreText(data, map)}\n`;
52
+ }
53
+ }
54
+ //# sourceMappingURL=restorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restorer.js","sourceRoot":"","sources":["../src/restorer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,SAAS,WAAW,CAAC,IAAY,EAAE,GAAiB;IAClD,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACxE,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC;IAC3D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,KAAU,EAAE,GAAiB;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACxE,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,GAAG,GAAQ,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1E,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAY,EAAE,GAAiB;IACrD,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACnC,OAAO,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAAkB,EAAE,GAAiB;IAC/D,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,GAAiB;IAC5D,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,SAAS,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Sanitizer core — entity definitions, pattern matching, entropy detection.
3
+ * Shared between gateway (reversible) and guards (one-way).
4
+ */
5
+ import type { EntityMatch } from "../types.js";
6
+ type Entity = {
7
+ category: string;
8
+ categoryKey: string;
9
+ pattern: RegExp;
10
+ };
11
+ declare const ENTITIES: Entity[];
12
+ export declare const SECRET_PREFIXES: string[];
13
+ export declare function shannonEntropy(s: string): number;
14
+ export declare function collectMatches(content: string): EntityMatch[];
15
+ export { ENTITIES };
16
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/sanitizer/core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C,KAAK,MAAM,GAAG;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,QAAA,MAAM,QAAQ,EAAE,MAAM,EASrB,CAAC;AAMF,eAAO,MAAM,eAAe,UAG3B,CAAC;AAaF,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAUhD;AAMD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAmC7D;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}