@openguardrails/gateway 1.0.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 (41) hide show
  1. package/dist/config.d.ts +13 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +100 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/handlers/anthropic.d.ts +12 -0
  6. package/dist/handlers/anthropic.d.ts.map +1 -0
  7. package/dist/handlers/anthropic.js +150 -0
  8. package/dist/handlers/anthropic.js.map +1 -0
  9. package/dist/handlers/gemini.d.ts +12 -0
  10. package/dist/handlers/gemini.d.ts.map +1 -0
  11. package/dist/handlers/gemini.js +80 -0
  12. package/dist/handlers/gemini.js.map +1 -0
  13. package/dist/handlers/openai.d.ts +13 -0
  14. package/dist/handlers/openai.d.ts.map +1 -0
  15. package/dist/handlers/openai.js +145 -0
  16. package/dist/handlers/openai.js.map +1 -0
  17. package/dist/index.d.ts +16 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +136 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/restorer.d.ts +21 -0
  22. package/dist/restorer.d.ts.map +1 -0
  23. package/dist/restorer.js +91 -0
  24. package/dist/restorer.js.map +1 -0
  25. package/dist/sanitizer.d.ts +17 -0
  26. package/dist/sanitizer.d.ts.map +1 -0
  27. package/dist/sanitizer.js +226 -0
  28. package/dist/sanitizer.js.map +1 -0
  29. package/dist/types.d.ts +35 -0
  30. package/dist/types.d.ts.map +1 -0
  31. package/dist/types.js +5 -0
  32. package/dist/types.js.map +1 -0
  33. package/package.json +55 -0
  34. package/src/config.ts +122 -0
  35. package/src/handlers/anthropic.ts +195 -0
  36. package/src/handlers/gemini.ts +99 -0
  37. package/src/handlers/openai.ts +188 -0
  38. package/src/index.ts +159 -0
  39. package/src/restorer.ts +101 -0
  40. package/src/sanitizer.ts +278 -0
  41. package/src/types.ts +43 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Gateway configuration management
3
+ */
4
+ import type { GatewayConfig } from "./types.js";
5
+ /**
6
+ * Load gateway configuration from file or environment
7
+ */
8
+ export declare function loadConfig(configPath?: string): GatewayConfig;
9
+ /**
10
+ * Validate configuration
11
+ */
12
+ export declare function validateConfig(config: GatewayConfig): void;
13
+ //# 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;AAIhD;;GAEG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAyB7D;AA6DD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAkB1D"}
package/dist/config.js ADDED
@@ -0,0 +1,100 @@
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 DEFAULT_CONFIG_PATH = join(homedir(), ".openguardrails", "gateway.json");
8
+ /**
9
+ * Load gateway configuration from file or environment
10
+ */
11
+ export function loadConfig(configPath) {
12
+ const path = configPath || DEFAULT_CONFIG_PATH;
13
+ // Default configuration
14
+ const defaultConfig = {
15
+ port: parseInt(process.env.GATEWAY_PORT || "8900", 10),
16
+ backends: {},
17
+ };
18
+ // Try to load from file
19
+ if (existsSync(path)) {
20
+ try {
21
+ const fileContent = readFileSync(path, "utf-8");
22
+ const fileConfig = JSON.parse(fileContent);
23
+ return mergeConfig(defaultConfig, fileConfig);
24
+ }
25
+ catch (error) {
26
+ console.warn(`[ai-security-gateway] Failed to load config from ${path}:`, error);
27
+ }
28
+ }
29
+ // Load from environment variables
30
+ return loadFromEnv(defaultConfig);
31
+ }
32
+ /**
33
+ * Load backend configs from environment variables
34
+ */
35
+ function loadFromEnv(config) {
36
+ // Anthropic
37
+ if (process.env.ANTHROPIC_API_KEY) {
38
+ config.backends.anthropic = {
39
+ baseUrl: process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com",
40
+ apiKey: process.env.ANTHROPIC_API_KEY,
41
+ };
42
+ }
43
+ // OpenAI
44
+ if (process.env.OPENAI_API_KEY) {
45
+ config.backends.openai = {
46
+ baseUrl: process.env.OPENAI_BASE_URL || "https://api.openai.com",
47
+ apiKey: process.env.OPENAI_API_KEY,
48
+ };
49
+ }
50
+ // Kimi (Moonshot)
51
+ if (process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY) {
52
+ config.backends.openai = {
53
+ baseUrl: process.env.KIMI_BASE_URL || "https://api.moonshot.cn",
54
+ apiKey: process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY || "",
55
+ };
56
+ }
57
+ // Gemini
58
+ if (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) {
59
+ config.backends.gemini = {
60
+ baseUrl: process.env.GEMINI_BASE_URL ||
61
+ "https://generativelanguage.googleapis.com",
62
+ apiKey: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || "",
63
+ };
64
+ }
65
+ return config;
66
+ }
67
+ /**
68
+ * Merge file config with default config
69
+ */
70
+ function mergeConfig(defaultConfig, fileConfig) {
71
+ return {
72
+ port: fileConfig.port ?? defaultConfig.port,
73
+ backends: {
74
+ ...defaultConfig.backends,
75
+ ...fileConfig.backends,
76
+ },
77
+ routing: fileConfig.routing,
78
+ };
79
+ }
80
+ /**
81
+ * Validate configuration
82
+ */
83
+ export function validateConfig(config) {
84
+ if (config.port < 1 || config.port > 65535) {
85
+ throw new Error(`Invalid port: ${config.port}`);
86
+ }
87
+ // Note: Backends are now optional. Gateway will act as transparent proxy.
88
+ // If no backends configured, gateway will forward requests based on routing rules
89
+ // or pass through to the original target.
90
+ // Validate each backend (if any)
91
+ for (const [name, backend] of Object.entries(config.backends)) {
92
+ if (!backend.baseUrl) {
93
+ throw new Error(`Backend ${name} missing baseUrl`);
94
+ }
95
+ if (!backend.apiKey) {
96
+ throw new Error(`Backend ${name} missing apiKey`);
97
+ }
98
+ }
99
+ }
100
+ //# 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,12 @@
1
+ /**
2
+ * AI Security Gateway - Anthropic Messages API handler
3
+ *
4
+ * Handles POST /v1/messages requests in Anthropic's native format.
5
+ */
6
+ import type { IncomingMessage, ServerResponse } from "node:http";
7
+ import type { GatewayConfig } from "../types.js";
8
+ /**
9
+ * Handle Anthropic API request
10
+ */
11
+ export declare function handleAnthropicRequest(req: IncomingMessage, res: ServerResponse, config: GatewayConfig): Promise<void>;
12
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/handlers/anthropic.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAI/D;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAmFf"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * AI Security Gateway - Anthropic Messages API handler
3
+ *
4
+ * Handles POST /v1/messages requests in Anthropic's native format.
5
+ */
6
+ import { sanitize } from "../sanitizer.js";
7
+ import { restore, restoreSSELine } from "../restorer.js";
8
+ /**
9
+ * Handle Anthropic API request
10
+ */
11
+ export async function handleAnthropicRequest(req, res, config) {
12
+ try {
13
+ // 1. Parse request body
14
+ const body = await readBody(req);
15
+ const requestData = JSON.parse(body);
16
+ const { model, messages, system, tools, max_tokens, temperature, stream = false, ...rest } = requestData;
17
+ // 2. Sanitize messages
18
+ const { sanitized: sanitizedMessages, mappingTable } = sanitize(messages);
19
+ // 3. Sanitize system prompt if present
20
+ const sanitizedSystem = system
21
+ ? sanitize(system).sanitized
22
+ : system;
23
+ // Note: We reuse the same mapping table so placeholders are consistent
24
+ // 4. Build sanitized request
25
+ const sanitizedRequest = {
26
+ model,
27
+ messages: sanitizedMessages,
28
+ ...(system && { system: sanitizedSystem }),
29
+ ...(tools && { tools }),
30
+ max_tokens,
31
+ ...(temperature !== undefined && { temperature }),
32
+ stream,
33
+ ...rest,
34
+ };
35
+ // 5. Get backend config
36
+ const backend = config.backends.anthropic;
37
+ if (!backend) {
38
+ res.writeHead(500, { "Content-Type": "application/json" });
39
+ res.end(JSON.stringify({ error: "Anthropic backend not configured" }));
40
+ return;
41
+ }
42
+ // 6. Forward to real Anthropic API
43
+ const apiUrl = `${backend.baseUrl}/v1/messages`;
44
+ const response = await fetch(apiUrl, {
45
+ method: "POST",
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ "anthropic-version": req.headers["anthropic-version"] || "2023-06-01",
49
+ "x-api-key": backend.apiKey,
50
+ },
51
+ body: JSON.stringify(sanitizedRequest),
52
+ });
53
+ if (!response.ok) {
54
+ // Forward error response
55
+ res.writeHead(response.status, { "Content-Type": "application/json" });
56
+ const errorBody = await response.text();
57
+ res.end(errorBody);
58
+ return;
59
+ }
60
+ // 7. Handle streaming response
61
+ if (stream) {
62
+ await handleAnthropicStream(response, res, mappingTable);
63
+ }
64
+ else {
65
+ await handleAnthropicNonStream(response, res, mappingTable);
66
+ }
67
+ }
68
+ catch (error) {
69
+ console.error("[ai-security-gateway] Anthropic handler error:", error);
70
+ res.writeHead(500, { "Content-Type": "application/json" });
71
+ res.end(JSON.stringify({
72
+ error: "Internal gateway error",
73
+ message: error instanceof Error ? error.message : String(error),
74
+ }));
75
+ }
76
+ }
77
+ /**
78
+ * Handle streaming response
79
+ */
80
+ async function handleAnthropicStream(response, res, mappingTable) {
81
+ // Set SSE headers
82
+ res.writeHead(200, {
83
+ "Content-Type": "text/event-stream",
84
+ "Cache-Control": "no-cache",
85
+ "Connection": "keep-alive",
86
+ });
87
+ const reader = response.body?.getReader();
88
+ if (!reader) {
89
+ res.end();
90
+ return;
91
+ }
92
+ const decoder = new TextDecoder();
93
+ let buffer = "";
94
+ try {
95
+ while (true) {
96
+ const { done, value } = await reader.read();
97
+ if (done)
98
+ break;
99
+ // Decode chunk
100
+ buffer += decoder.decode(value, { stream: true });
101
+ // Process complete lines
102
+ const lines = buffer.split("\n");
103
+ buffer = lines.pop() || ""; // Keep incomplete line in buffer
104
+ for (const line of lines) {
105
+ if (!line.trim()) {
106
+ res.write("\n");
107
+ continue;
108
+ }
109
+ // Restore placeholders in SSE line
110
+ const restoredLine = restoreSSELine(line, mappingTable);
111
+ res.write(restoredLine + "\n");
112
+ }
113
+ }
114
+ // Write any remaining buffer
115
+ if (buffer.trim()) {
116
+ const restoredLine = restoreSSELine(buffer, mappingTable);
117
+ res.write(restoredLine + "\n");
118
+ }
119
+ res.end();
120
+ }
121
+ catch (error) {
122
+ console.error("[ai-security-gateway] Stream error:", error);
123
+ res.end();
124
+ }
125
+ }
126
+ /**
127
+ * Handle non-streaming response
128
+ */
129
+ async function handleAnthropicNonStream(response, res, mappingTable) {
130
+ const responseBody = await response.text();
131
+ const responseData = JSON.parse(responseBody);
132
+ // Restore placeholders in response
133
+ const restoredData = restore(responseData, mappingTable);
134
+ res.writeHead(200, { "Content-Type": "application/json" });
135
+ res.end(JSON.stringify(restoredData));
136
+ }
137
+ /**
138
+ * Read request body as string
139
+ */
140
+ function readBody(req) {
141
+ return new Promise((resolve, reject) => {
142
+ let body = "";
143
+ req.on("data", (chunk) => {
144
+ body += chunk.toString();
145
+ });
146
+ req.on("end", () => resolve(body));
147
+ req.on("error", reject);
148
+ });
149
+ }
150
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/handlers/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * AI Security Gateway - Google Gemini API handler
3
+ *
4
+ * Handles POST /v1/models/:model:generateContent requests in Gemini's format.
5
+ */
6
+ import type { IncomingMessage, ServerResponse } from "node:http";
7
+ import type { GatewayConfig } from "../types.js";
8
+ /**
9
+ * Handle Gemini API request
10
+ */
11
+ export declare function handleGeminiRequest(req: IncomingMessage, res: ServerResponse, config: GatewayConfig, modelName: string): Promise<void>;
12
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/handlers/gemini.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAI/D;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAiEf"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * AI Security Gateway - Google Gemini API handler
3
+ *
4
+ * Handles POST /v1/models/:model:generateContent requests in Gemini's format.
5
+ */
6
+ import { sanitize } from "../sanitizer.js";
7
+ import { restore } from "../restorer.js";
8
+ /**
9
+ * Handle Gemini API request
10
+ */
11
+ export async function handleGeminiRequest(req, res, config, modelName) {
12
+ try {
13
+ // 1. Parse request body
14
+ const body = await readBody(req);
15
+ const requestData = JSON.parse(body);
16
+ const { contents, tools, generationConfig, ...rest } = requestData;
17
+ // 2. Sanitize contents (Gemini uses "contents" instead of "messages")
18
+ const { sanitized: sanitizedContents, mappingTable } = sanitize(contents);
19
+ // 3. Build sanitized request
20
+ const sanitizedRequest = {
21
+ contents: sanitizedContents,
22
+ ...(tools && { tools }),
23
+ ...(generationConfig && { generationConfig }),
24
+ ...rest,
25
+ };
26
+ // 4. Get backend config
27
+ const backend = config.backends.gemini;
28
+ if (!backend) {
29
+ res.writeHead(500, { "Content-Type": "application/json" });
30
+ res.end(JSON.stringify({ error: "Gemini backend not configured" }));
31
+ return;
32
+ }
33
+ // 5. Forward to Gemini API
34
+ const apiUrl = `${backend.baseUrl}/v1/models/${modelName}:generateContent`;
35
+ const response = await fetch(apiUrl, {
36
+ method: "POST",
37
+ headers: {
38
+ "Content-Type": "application/json",
39
+ "x-goog-api-key": backend.apiKey,
40
+ },
41
+ body: JSON.stringify(sanitizedRequest),
42
+ });
43
+ if (!response.ok) {
44
+ // Forward error response
45
+ res.writeHead(response.status, { "Content-Type": "application/json" });
46
+ const errorBody = await response.text();
47
+ res.end(errorBody);
48
+ return;
49
+ }
50
+ // 6. Handle response (Gemini typically doesn't stream in same way)
51
+ const responseBody = await response.text();
52
+ const responseData = JSON.parse(responseBody);
53
+ // Restore placeholders in response
54
+ const restoredData = restore(responseData, mappingTable);
55
+ res.writeHead(200, { "Content-Type": "application/json" });
56
+ res.end(JSON.stringify(restoredData));
57
+ }
58
+ catch (error) {
59
+ console.error("[ai-security-gateway] Gemini handler error:", error);
60
+ res.writeHead(500, { "Content-Type": "application/json" });
61
+ res.end(JSON.stringify({
62
+ error: "Internal gateway error",
63
+ message: error instanceof Error ? error.message : String(error),
64
+ }));
65
+ }
66
+ }
67
+ /**
68
+ * Read request body as string
69
+ */
70
+ function readBody(req) {
71
+ return new Promise((resolve, reject) => {
72
+ let body = "";
73
+ req.on("data", (chunk) => {
74
+ body += chunk.toString();
75
+ });
76
+ req.on("end", () => resolve(body));
77
+ req.on("error", reject);
78
+ });
79
+ }
80
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/handlers/gemini.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * AI Security Gateway - OpenAI Chat Completions API handler
3
+ *
4
+ * Handles POST /v1/chat/completions requests in OpenAI's format.
5
+ * Also compatible with OpenAI-compatible APIs (Kimi, DeepSeek, etc.)
6
+ */
7
+ import type { IncomingMessage, ServerResponse } from "node:http";
8
+ import type { GatewayConfig } from "../types.js";
9
+ /**
10
+ * Handle OpenAI API request
11
+ */
12
+ export declare function handleOpenAIRequest(req: IncomingMessage, res: ServerResponse, config: GatewayConfig): Promise<void>;
13
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/handlers/openai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAI/D;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CA2Ef"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * AI Security Gateway - OpenAI Chat Completions API handler
3
+ *
4
+ * Handles POST /v1/chat/completions requests in OpenAI's format.
5
+ * Also compatible with OpenAI-compatible APIs (Kimi, DeepSeek, etc.)
6
+ */
7
+ import { sanitize } from "../sanitizer.js";
8
+ import { restore, restoreSSELine } from "../restorer.js";
9
+ /**
10
+ * Handle OpenAI API request
11
+ */
12
+ export async function handleOpenAIRequest(req, res, config) {
13
+ try {
14
+ // 1. Parse request body
15
+ const body = await readBody(req);
16
+ const requestData = JSON.parse(body);
17
+ const { model, messages, tools, tool_choice, temperature, max_tokens, stream = false, ...rest } = requestData;
18
+ // 2. Sanitize messages
19
+ const { sanitized: sanitizedMessages, mappingTable } = sanitize(messages);
20
+ // 3. Build sanitized request
21
+ const sanitizedRequest = {
22
+ model,
23
+ messages: sanitizedMessages,
24
+ ...(tools && { tools }),
25
+ ...(tool_choice && { tool_choice }),
26
+ ...(temperature !== undefined && { temperature }),
27
+ ...(max_tokens && { max_tokens }),
28
+ stream,
29
+ ...rest,
30
+ };
31
+ // 4. Get backend config
32
+ const backend = config.backends.openai;
33
+ if (!backend) {
34
+ res.writeHead(500, { "Content-Type": "application/json" });
35
+ res.end(JSON.stringify({ error: "OpenAI backend not configured" }));
36
+ return;
37
+ }
38
+ // 5. Forward to OpenAI (or compatible) API
39
+ const apiUrl = `${backend.baseUrl}/v1/chat/completions`;
40
+ const response = await fetch(apiUrl, {
41
+ method: "POST",
42
+ headers: {
43
+ "Content-Type": "application/json",
44
+ "Authorization": `Bearer ${backend.apiKey}`,
45
+ },
46
+ body: JSON.stringify(sanitizedRequest),
47
+ });
48
+ if (!response.ok) {
49
+ // Forward error response
50
+ res.writeHead(response.status, { "Content-Type": "application/json" });
51
+ const errorBody = await response.text();
52
+ res.end(errorBody);
53
+ return;
54
+ }
55
+ // 6. Handle streaming or non-streaming response
56
+ if (stream) {
57
+ await handleOpenAIStream(response, res, mappingTable);
58
+ }
59
+ else {
60
+ await handleOpenAINonStream(response, res, mappingTable);
61
+ }
62
+ }
63
+ catch (error) {
64
+ console.error("[ai-security-gateway] OpenAI handler error:", error);
65
+ res.writeHead(500, { "Content-Type": "application/json" });
66
+ res.end(JSON.stringify({
67
+ error: "Internal gateway error",
68
+ message: error instanceof Error ? error.message : String(error),
69
+ }));
70
+ }
71
+ }
72
+ /**
73
+ * Handle streaming response (SSE)
74
+ */
75
+ async function handleOpenAIStream(response, res, mappingTable) {
76
+ // Set SSE headers
77
+ res.writeHead(200, {
78
+ "Content-Type": "text/event-stream",
79
+ "Cache-Control": "no-cache",
80
+ "Connection": "keep-alive",
81
+ });
82
+ const reader = response.body?.getReader();
83
+ if (!reader) {
84
+ res.end();
85
+ return;
86
+ }
87
+ const decoder = new TextDecoder();
88
+ let buffer = "";
89
+ try {
90
+ while (true) {
91
+ const { done, value } = await reader.read();
92
+ if (done)
93
+ break;
94
+ // Decode chunk
95
+ buffer += decoder.decode(value, { stream: true });
96
+ // Process complete lines
97
+ const lines = buffer.split("\n");
98
+ buffer = lines.pop() || ""; // Keep incomplete line in buffer
99
+ for (const line of lines) {
100
+ if (!line.trim()) {
101
+ res.write("\n");
102
+ continue;
103
+ }
104
+ // Restore placeholders in SSE line
105
+ const restoredLine = restoreSSELine(line, mappingTable);
106
+ res.write(restoredLine + "\n");
107
+ }
108
+ }
109
+ // Write any remaining buffer
110
+ if (buffer.trim()) {
111
+ const restoredLine = restoreSSELine(buffer, mappingTable);
112
+ res.write(restoredLine + "\n");
113
+ }
114
+ res.end();
115
+ }
116
+ catch (error) {
117
+ console.error("[ai-security-gateway] Stream error:", error);
118
+ res.end();
119
+ }
120
+ }
121
+ /**
122
+ * Handle non-streaming response
123
+ */
124
+ async function handleOpenAINonStream(response, res, mappingTable) {
125
+ const responseBody = await response.text();
126
+ const responseData = JSON.parse(responseBody);
127
+ // Restore placeholders in response
128
+ const restoredData = restore(responseData, mappingTable);
129
+ res.writeHead(200, { "Content-Type": "application/json" });
130
+ res.end(JSON.stringify(restoredData));
131
+ }
132
+ /**
133
+ * Read request body as string
134
+ */
135
+ function readBody(req) {
136
+ return new Promise((resolve, reject) => {
137
+ let body = "";
138
+ req.on("data", (chunk) => {
139
+ body += chunk.toString();
140
+ });
141
+ req.on("end", () => resolve(body));
142
+ req.on("error", reject);
143
+ });
144
+ }
145
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/handlers/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
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
+ /**
10
+ * Start gateway server
11
+ */
12
+ export declare function startGateway(configPath?: string): void;
13
+ export { sanitize, sanitizeMessages } from "./sanitizer.js";
14
+ export { restore, restoreJSON, restoreSSELine } from "./restorer.js";
15
+ export type { GatewayConfig, MappingTable, SanitizeResult, EntityMatch } from "./types.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAuFH;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAkDtD;AAGD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC5D,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"}