@llmnative/react 1.25.4 → 1.27.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.
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5268 -5322
- package/dist/index.mjs.map +1 -1
- package/dist/modelIdentity-BEUaBIlb.js +2 -0
- package/dist/modelIdentity-BEUaBIlb.js.map +1 -0
- package/dist/modelIdentity-D93fYZOo.mjs +163 -0
- package/dist/modelIdentity-D93fYZOo.mjs.map +1 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +41 -0
- package/dist/server.mjs.map +1 -0
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/providers/ai/index.d.ts +26 -1
- package/dist/types/src/providers/ai/modelIdentity.d.ts +49 -0
- package/dist/types/src/providers/ai/server.d.ts +33 -0
- package/dist/types/src/providers/ai/serverCredentials.d.ts +22 -0
- package/dist/types/src/providers/proxy/vite.d.ts +4 -1
- package/dist/vite.js +2 -2
- package/dist/vite.js.map +1 -1
- package/dist/vite.mjs +54 -42
- package/dist/vite.mjs.map +1 -1
- package/llms-full.txt +1245 -1204
- package/package.json +173 -168
package/dist/vite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.js","names":["mkdir","appendFile","path","LLM_LOG_ID_HEADER","require_logHeader","node_fs_promises","node_path","PROXY_CALLER_HEADER","PROXY_PATH","readRequestBody","chunks","chunk","req","sanitizeLogId","logId","prettyJsonOrRaw","text","appendLogBlock","logOptions","block","target","requestBody","status","responseBody","error","writeProxyResponse","res","targetUrl","route","body","headers","skipHeaders","key","value","upstream","responseBuffer","createProxyPlugin","server"],"sources":["../src/providers/proxy/vite.ts"],"sourcesContent":["import { appendFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Plugin } from 'vite';\nimport { LLM_LOG_ID_HEADER } from './logHeader';\n\nconst PROXY_CALLER_HEADER = 'x-llmnative-proxy';\nexport const PROXY_PATH = '/api/proxy';\n\n/** Logging file di richiesta/risposta LLM — SOLO dev, mai attivo di default. Un file per\n * conversazione: il client (useAgent, CMS) genera un `logId` stabile per l'intera sessione e\n * lo manda su ogni chiamata come header `x-llmnative-log-id`; il proxy accoda ogni turno allo\n * stesso file, non lo sovrascrive. Vedi AICompleteRequest.logId per il lato client. */\nexport interface ProxyLogOptions {\n enabled: boolean;\n /** Cartella di destinazione, relativa alla cwd del dev server (il progetto consumer, es.\n * il CMS) o assoluta. Creata se assente. */\n dir: string;\n}\n\nconst readRequestBody = async (req: IncomingMessage): Promise<Buffer | undefined> => {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return chunks.length === 0 ? undefined : Buffer.concat(chunks);\n};\n\n/** Solo caratteri sicuri per un nome file — l'id è generato da noi (crypto.randomUUID() lato\n * client), ma niente path traversal per costruzione anche se un client si comportasse male. */\nfunction sanitizeLogId(logId: string): string {\n return logId.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128) || 'unknown';\n}\n\nfunction prettyJsonOrRaw(text: string): string {\n if (!text.trim()) return '(empty body)';\n try {\n return JSON.stringify(JSON.parse(text), null, 2);\n } catch {\n return text;\n }\n}\n\nasync function appendLogBlock(logOptions: ProxyLogOptions, logId: string, target: string, requestBody: string, status: number, responseBody: string) {\n try {\n await mkdir(logOptions.dir, { recursive: true });\n const block = [\n '',\n '='.repeat(80),\n `Turn @ ${new Date().toISOString()}`,\n `Target: ${target}`,\n '--- REQUEST BODY ---',\n prettyJsonOrRaw(requestBody),\n `--- RESPONSE BODY (status ${status}) ---`,\n prettyJsonOrRaw(responseBody),\n '='.repeat(80),\n '',\n ].join('\\n');\n await appendFile(path.join(logOptions.dir, `${sanitizeLogId(logId)}.txt`), block, 'utf-8');\n } catch (error) {\n // Un log fallito non deve mai far fallire la vera richiesta — solo un avviso in console.\n console.warn('[llmnative-dev-proxy] Failed to write LLM log:', error);\n }\n}\n\nconst writeProxyResponse = async (req: IncomingMessage, res: ServerResponse, route: string, logOptions?: ProxyLogOptions) => {\n const requestUrl = new URL(req.url || '/', 'http://localhost');\n const target = requestUrl.searchParams.get('url');\n\n if (req.headers[PROXY_CALLER_HEADER] !== '1') {\n res.statusCode = 403;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Proxy access denied.' }));\n return;\n }\n\n if (!target) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Missing \"url\" query parameter.' }));\n return;\n }\n\n try {\n const targetUrl = new URL(target);\n if (targetUrl.pathname.startsWith(route) && ['localhost', '127.0.0.1'].includes(targetUrl.hostname)) {\n res.statusCode = 508;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Recursive proxy target detected.', target }));\n return;\n }\n\n const body = await readRequestBody(req);\n const logId = req.headers[LLM_LOG_ID_HEADER];\n const headers = new Headers();\n // L'header di log è consumato QUI, mai inoltrato al provider upstream (stesso\n // trattamento del PROXY_CALLER_HEADER) — è un dettaglio nostro, non dell'API esterna.\n const skipHeaders = new Set([PROXY_CALLER_HEADER, LLM_LOG_ID_HEADER, 'host', 'origin', 'referer', 'content-length', 'transfer-encoding', 'connection']);\n\n Object.entries(req.headers).forEach(([key, value]) => {\n if (!value || skipHeaders.has(key.toLowerCase())) return;\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\n });\n\n const upstream = await fetch(target, {\n method: req.method || 'GET',\n headers,\n body: body && !['GET', 'HEAD'].includes((req.method || 'GET').toUpperCase())\n ? Uint8Array.from(body)\n : undefined,\n redirect: 'follow',\n });\n\n const responseBuffer = Buffer.from(await upstream.arrayBuffer());\n\n if (logOptions?.enabled && typeof logId === 'string' && logId) {\n void appendLogBlock(logOptions, logId, target, body?.toString('utf-8') ?? '', upstream.status, responseBuffer.toString('utf-8'));\n }\n\n res.statusCode = upstream.status;\n upstream.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'content-encoding') return;\n res.setHeader(key, value);\n });\n res.end(responseBuffer);\n } catch (error) {\n res.statusCode = 502;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Proxy request failed.' }));\n }\n};\n\nexport const createProxyPlugin = (route = PROXY_PATH, logOptions?: ProxyLogOptions): Plugin => ({\n name: 'llmnative-dev-proxy',\n configureServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n configurePreviewServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vite.js","names":["mkdir","appendFile","path","LLM_LOG_ID_HEADER","resolveServerCredentials","require_logHeader","require_server","node_fs_promises","node_path","PROXY_CALLER_HEADER","PROXY_PATH","readRequestBody","chunks","chunk","req","sanitizeLogId","logId","prettyJsonOrRaw","text","appendLogBlock","logOptions","block","target","requestBody","status","responseBody","error","writeProxyResponse","res","targetUrl","route","body","headers","skipHeaders","key","value","resolved","credentials","upstream","responseBuffer","createProxyPlugin","server"],"sources":["../src/providers/proxy/vite.ts"],"sourcesContent":["import { appendFile, mkdir } from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport type { IncomingMessage, ServerResponse } from 'node:http';\r\nimport type { Plugin } from 'vite';\r\nimport { LLM_LOG_ID_HEADER } from './logHeader';\r\nimport { resolveServerCredentials, type ServerCredentialLookup } from '../ai/server';\r\n\r\nconst PROXY_CALLER_HEADER = 'x-llmnative-proxy';\r\nexport const PROXY_PATH = '/api/proxy';\r\n\r\n/** Logging file di richiesta/risposta LLM — SOLO dev, mai attivo di default. Un file per\r\n * conversazione: il client (useAgent, CMS) genera un `logId` stabile per l'intera sessione e\r\n * lo manda su ogni chiamata come header `x-llmnative-log-id`; il proxy accoda ogni turno allo\r\n * stesso file, non lo sovrascrive. Vedi AICompleteRequest.logId per il lato client. */\r\nexport interface ProxyLogOptions {\r\n enabled: boolean;\r\n /** Cartella di destinazione, relativa alla cwd del dev server (il progetto consumer, es.\r\n * il CMS) o assoluta. Creata se assente. */\r\n dir: string;\r\n}\r\n\r\nconst readRequestBody = async (req: IncomingMessage): Promise<Buffer | undefined> => {\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of req) {\r\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\r\n }\r\n return chunks.length === 0 ? undefined : Buffer.concat(chunks);\r\n};\r\n\r\n/** Solo caratteri sicuri per un nome file — l'id è generato da noi (crypto.randomUUID() lato\r\n * client), ma niente path traversal per costruzione anche se un client si comportasse male. */\r\nfunction sanitizeLogId(logId: string): string {\r\n return logId.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128) || 'unknown';\r\n}\r\n\r\nfunction prettyJsonOrRaw(text: string): string {\r\n if (!text.trim()) return '(empty body)';\r\n try {\r\n return JSON.stringify(JSON.parse(text), null, 2);\r\n } catch {\r\n return text;\r\n }\r\n}\r\n\r\nasync function appendLogBlock(logOptions: ProxyLogOptions, logId: string, target: string, requestBody: string, status: number, responseBody: string) {\r\n try {\r\n await mkdir(logOptions.dir, { recursive: true });\r\n const block = [\r\n '',\r\n '='.repeat(80),\r\n `Turn @ ${new Date().toISOString()}`,\r\n `Target: ${target}`,\r\n '--- REQUEST BODY ---',\r\n prettyJsonOrRaw(requestBody),\r\n `--- RESPONSE BODY (status ${status}) ---`,\r\n prettyJsonOrRaw(responseBody),\r\n '='.repeat(80),\r\n '',\r\n ].join('\\n');\r\n await appendFile(path.join(logOptions.dir, `${sanitizeLogId(logId)}.txt`), block, 'utf-8');\r\n } catch (error) {\r\n // Un log fallito non deve mai far fallire la vera richiesta — solo un avviso in console.\r\n console.warn('[llmnative-dev-proxy] Failed to write LLM log:', error);\r\n }\r\n}\r\n\r\nconst writeProxyResponse = async (req: IncomingMessage, res: ServerResponse, route: string, logOptions?: ProxyLogOptions, credentials?: ServerCredentialLookup) => {\r\n const requestUrl = new URL(req.url || '/', 'http://localhost');\r\n const target = requestUrl.searchParams.get('url');\r\n\r\n if (req.headers[PROXY_CALLER_HEADER] !== '1') {\r\n res.statusCode = 403;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Proxy access denied.' }));\r\n return;\r\n }\r\n\r\n if (!target) {\r\n res.statusCode = 400;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Missing \"url\" query parameter.' }));\r\n return;\r\n }\r\n\r\n try {\r\n const targetUrl = new URL(target);\r\n if (targetUrl.pathname.startsWith(route) && ['localhost', '127.0.0.1'].includes(targetUrl.hostname)) {\r\n res.statusCode = 508;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Recursive proxy target detected.', target }));\r\n return;\r\n }\r\n\r\n const body = await readRequestBody(req);\r\n const logId = req.headers[LLM_LOG_ID_HEADER];\r\n const headers = new Headers();\r\n // L'header di log è consumato QUI, mai inoltrato al provider upstream (stesso\r\n // trattamento del PROXY_CALLER_HEADER) — è un dettaglio nostro, non dell'API esterna.\r\n const skipHeaders = new Set([PROXY_CALLER_HEADER, LLM_LOG_ID_HEADER, 'host', 'origin', 'referer', 'content-length', 'transfer-encoding', 'connection']);\r\n\r\n Object.entries(req.headers).forEach(([key, value]) => {\r\n if (!value || skipHeaders.has(key.toLowerCase())) return;\r\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\r\n });\r\n\r\n // Server-held AI credentials (CR-102): the placeholder becomes the key, only towards its\r\n // provider. Without a lookup a placeholder finds no key and the request is refused.\r\n const resolved = await resolveServerCredentials({ url: target, headers: Object.fromEntries(headers) }, credentials ?? (() => undefined));\r\n if (!resolved.ok) {\r\n res.statusCode = resolved.status;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: resolved.error, provider: resolved.provider }));\r\n return;\r\n }\r\n\r\n const upstream = await fetch(resolved.url, {\r\n method: req.method || 'GET',\r\n headers: new Headers(resolved.headers),\r\n body: body && !['GET', 'HEAD'].includes((req.method || 'GET').toUpperCase())\r\n ? Uint8Array.from(body)\r\n : undefined,\r\n redirect: 'follow',\r\n });\r\n\r\n const responseBuffer = Buffer.from(await upstream.arrayBuffer());\r\n\r\n if (logOptions?.enabled && typeof logId === 'string' && logId) {\r\n void appendLogBlock(logOptions, logId, target, body?.toString('utf-8') ?? '', upstream.status, responseBuffer.toString('utf-8'));\r\n }\r\n\r\n res.statusCode = upstream.status;\r\n upstream.headers.forEach((value, key) => {\r\n if (key.toLowerCase() === 'content-encoding') return;\r\n res.setHeader(key, value);\r\n });\r\n res.end(responseBuffer);\r\n } catch (error) {\r\n res.statusCode = 502;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Proxy request failed.' }));\r\n }\r\n};\r\n\r\n/** `credentials`: the keys of the providers held by the server (CR-102), for the adapters built\r\n * with createServerCredentialAIRegistry(). */\r\nexport const createProxyPlugin = (route = PROXY_PATH, logOptions?: ProxyLogOptions, credentials?: ServerCredentialLookup): Plugin => ({\r\n name: 'llmnative-dev-proxy',\r\n configureServer(server) {\r\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions, credentials); });\r\n },\r\n configurePreviewServer(server) {\r\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions, credentials); });\r\n },\r\n});\r\n"],"mappings":"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"}
|
package/dist/vite.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { t as e } from "./logHeader-Busbc8OO.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import r from "node:
|
|
2
|
+
import { resolveServerCredentials as t } from "./server.mjs";
|
|
3
|
+
import { appendFile as n, mkdir as r } from "node:fs/promises";
|
|
4
|
+
import i from "node:path";
|
|
4
5
|
//#region src/providers/proxy/vite.ts
|
|
5
|
-
var
|
|
6
|
+
var a = "x-llmnative-proxy", o = "/api/proxy", s = async (e) => {
|
|
6
7
|
let t = [];
|
|
7
8
|
for await (let n of e) t.push(Buffer.isBuffer(n) ? n : Buffer.from(n));
|
|
8
9
|
return t.length === 0 ? void 0 : Buffer.concat(t);
|
|
9
10
|
};
|
|
10
|
-
function
|
|
11
|
+
function c(e) {
|
|
11
12
|
return e.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 128) || "unknown";
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
+
function l(e) {
|
|
14
15
|
if (!e.trim()) return "(empty body)";
|
|
15
16
|
try {
|
|
16
17
|
return JSON.stringify(JSON.parse(e), null, 2);
|
|
@@ -18,47 +19,47 @@ function c(e) {
|
|
|
18
19
|
return e;
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
|
-
async function
|
|
22
|
+
async function u(e, t, a, o, s, u) {
|
|
22
23
|
try {
|
|
23
|
-
await
|
|
24
|
+
await r(e.dir, { recursive: !0 });
|
|
24
25
|
let d = [
|
|
25
26
|
"",
|
|
26
27
|
"=".repeat(80),
|
|
27
28
|
`Turn @ ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
28
29
|
`Target: ${a}`,
|
|
29
30
|
"--- REQUEST BODY ---",
|
|
30
|
-
|
|
31
|
-
`--- RESPONSE BODY (status ${
|
|
32
|
-
|
|
31
|
+
l(o),
|
|
32
|
+
`--- RESPONSE BODY (status ${s}) ---`,
|
|
33
|
+
l(u),
|
|
33
34
|
"=".repeat(80),
|
|
34
35
|
""
|
|
35
36
|
].join("\n");
|
|
36
|
-
await
|
|
37
|
+
await n(i.join(e.dir, `${c(t)}.txt`), d, "utf-8");
|
|
37
38
|
} catch (e) {
|
|
38
39
|
console.warn("[llmnative-dev-proxy] Failed to write LLM log:", e);
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
|
-
var
|
|
42
|
-
let
|
|
43
|
-
if (
|
|
44
|
-
|
|
42
|
+
var d = async (n, r, i, o, c) => {
|
|
43
|
+
let l = new URL(n.url || "/", "http://localhost").searchParams.get("url");
|
|
44
|
+
if (n.headers[a] !== "1") {
|
|
45
|
+
r.statusCode = 403, r.setHeader("Content-Type", "application/json"), r.end(JSON.stringify({ error: "Proxy access denied." }));
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
|
-
if (!
|
|
48
|
-
|
|
48
|
+
if (!l) {
|
|
49
|
+
r.statusCode = 400, r.setHeader("Content-Type", "application/json"), r.end(JSON.stringify({ error: "Missing \"url\" query parameter." }));
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
try {
|
|
52
|
-
let
|
|
53
|
-
if (
|
|
54
|
-
|
|
53
|
+
let d = new URL(l);
|
|
54
|
+
if (d.pathname.startsWith(i) && ["localhost", "127.0.0.1"].includes(d.hostname)) {
|
|
55
|
+
r.statusCode = 508, r.setHeader("Content-Type", "application/json"), r.end(JSON.stringify({
|
|
55
56
|
error: "Recursive proxy target detected.",
|
|
56
|
-
target:
|
|
57
|
+
target: l
|
|
57
58
|
}));
|
|
58
59
|
return;
|
|
59
60
|
}
|
|
60
|
-
let
|
|
61
|
-
|
|
61
|
+
let f = await s(n), p = n.headers[e], m = new Headers(), h = /* @__PURE__ */ new Set([
|
|
62
|
+
a,
|
|
62
63
|
e,
|
|
63
64
|
"host",
|
|
64
65
|
"origin",
|
|
@@ -67,35 +68,46 @@ var u = async (t, n, r, a) => {
|
|
|
67
68
|
"transfer-encoding",
|
|
68
69
|
"connection"
|
|
69
70
|
]);
|
|
70
|
-
Object.entries(
|
|
71
|
-
t && !
|
|
71
|
+
Object.entries(n.headers).forEach(([e, t]) => {
|
|
72
|
+
t && !h.has(e.toLowerCase()) && m.set(e, Array.isArray(t) ? t.join(", ") : t);
|
|
72
73
|
});
|
|
73
|
-
let
|
|
74
|
-
|
|
75
|
-
headers:
|
|
76
|
-
|
|
74
|
+
let g = await t({
|
|
75
|
+
url: l,
|
|
76
|
+
headers: Object.fromEntries(m)
|
|
77
|
+
}, c ?? (() => void 0));
|
|
78
|
+
if (!g.ok) {
|
|
79
|
+
r.statusCode = g.status, r.setHeader("Content-Type", "application/json"), r.end(JSON.stringify({
|
|
80
|
+
error: g.error,
|
|
81
|
+
provider: g.provider
|
|
82
|
+
}));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
let _ = await fetch(g.url, {
|
|
86
|
+
method: n.method || "GET",
|
|
87
|
+
headers: new Headers(g.headers),
|
|
88
|
+
body: f && !["GET", "HEAD"].includes((n.method || "GET").toUpperCase()) ? Uint8Array.from(f) : void 0,
|
|
77
89
|
redirect: "follow"
|
|
78
|
-
}),
|
|
79
|
-
|
|
80
|
-
t.toLowerCase() !== "content-encoding" &&
|
|
81
|
-
}),
|
|
90
|
+
}), v = Buffer.from(await _.arrayBuffer());
|
|
91
|
+
o?.enabled && typeof p == "string" && p && u(o, p, l, f?.toString("utf-8") ?? "", _.status, v.toString("utf-8")), r.statusCode = _.status, _.headers.forEach((e, t) => {
|
|
92
|
+
t.toLowerCase() !== "content-encoding" && r.setHeader(t, e);
|
|
93
|
+
}), r.end(v);
|
|
82
94
|
} catch (e) {
|
|
83
|
-
|
|
95
|
+
r.statusCode = 502, r.setHeader("Content-Type", "application/json"), r.end(JSON.stringify({ error: e instanceof Error ? e.message : "Proxy request failed." }));
|
|
84
96
|
}
|
|
85
|
-
},
|
|
97
|
+
}, f = (e = o, t, n) => ({
|
|
86
98
|
name: "llmnative-dev-proxy",
|
|
87
|
-
configureServer(
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
configureServer(r) {
|
|
100
|
+
r.middlewares.use(e, (r, i) => {
|
|
101
|
+
d(r, i, e, t, n);
|
|
90
102
|
});
|
|
91
103
|
},
|
|
92
|
-
configurePreviewServer(
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
configurePreviewServer(r) {
|
|
105
|
+
r.middlewares.use(e, (r, i) => {
|
|
106
|
+
d(r, i, e, t, n);
|
|
95
107
|
});
|
|
96
108
|
}
|
|
97
109
|
});
|
|
98
110
|
//#endregion
|
|
99
|
-
export {
|
|
111
|
+
export { o as PROXY_PATH, f as createProxyPlugin };
|
|
100
112
|
|
|
101
113
|
//# sourceMappingURL=vite.mjs.map
|
package/dist/vite.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.mjs","names":["LLM_LOG_ID_HEADER","path","PROXY_CALLER_HEADER","PROXY_PATH","readRequestBody","chunks","chunk","req","sanitizeLogId","logId","prettyJsonOrRaw","text","appendLogBlock","mkdir","logOptions","block","target","requestBody","status","responseBody","appendFile","error","writeProxyResponse","res","targetUrl","route","body","headers","skipHeaders","key","value","upstream","responseBuffer","createProxyPlugin"],"sources":["../src/providers/proxy/vite.ts"],"sourcesContent":["import { appendFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Plugin } from 'vite';\nimport { LLM_LOG_ID_HEADER } from './logHeader';\n\nconst PROXY_CALLER_HEADER = 'x-llmnative-proxy';\nexport const PROXY_PATH = '/api/proxy';\n\n/** Logging file di richiesta/risposta LLM — SOLO dev, mai attivo di default. Un file per\n * conversazione: il client (useAgent, CMS) genera un `logId` stabile per l'intera sessione e\n * lo manda su ogni chiamata come header `x-llmnative-log-id`; il proxy accoda ogni turno allo\n * stesso file, non lo sovrascrive. Vedi AICompleteRequest.logId per il lato client. */\nexport interface ProxyLogOptions {\n enabled: boolean;\n /** Cartella di destinazione, relativa alla cwd del dev server (il progetto consumer, es.\n * il CMS) o assoluta. Creata se assente. */\n dir: string;\n}\n\nconst readRequestBody = async (req: IncomingMessage): Promise<Buffer | undefined> => {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return chunks.length === 0 ? undefined : Buffer.concat(chunks);\n};\n\n/** Solo caratteri sicuri per un nome file — l'id è generato da noi (crypto.randomUUID() lato\n * client), ma niente path traversal per costruzione anche se un client si comportasse male. */\nfunction sanitizeLogId(logId: string): string {\n return logId.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128) || 'unknown';\n}\n\nfunction prettyJsonOrRaw(text: string): string {\n if (!text.trim()) return '(empty body)';\n try {\n return JSON.stringify(JSON.parse(text), null, 2);\n } catch {\n return text;\n }\n}\n\nasync function appendLogBlock(logOptions: ProxyLogOptions, logId: string, target: string, requestBody: string, status: number, responseBody: string) {\n try {\n await mkdir(logOptions.dir, { recursive: true });\n const block = [\n '',\n '='.repeat(80),\n `Turn @ ${new Date().toISOString()}`,\n `Target: ${target}`,\n '--- REQUEST BODY ---',\n prettyJsonOrRaw(requestBody),\n `--- RESPONSE BODY (status ${status}) ---`,\n prettyJsonOrRaw(responseBody),\n '='.repeat(80),\n '',\n ].join('\\n');\n await appendFile(path.join(logOptions.dir, `${sanitizeLogId(logId)}.txt`), block, 'utf-8');\n } catch (error) {\n // Un log fallito non deve mai far fallire la vera richiesta — solo un avviso in console.\n console.warn('[llmnative-dev-proxy] Failed to write LLM log:', error);\n }\n}\n\nconst writeProxyResponse = async (req: IncomingMessage, res: ServerResponse, route: string, logOptions?: ProxyLogOptions) => {\n const requestUrl = new URL(req.url || '/', 'http://localhost');\n const target = requestUrl.searchParams.get('url');\n\n if (req.headers[PROXY_CALLER_HEADER] !== '1') {\n res.statusCode = 403;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Proxy access denied.' }));\n return;\n }\n\n if (!target) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Missing \"url\" query parameter.' }));\n return;\n }\n\n try {\n const targetUrl = new URL(target);\n if (targetUrl.pathname.startsWith(route) && ['localhost', '127.0.0.1'].includes(targetUrl.hostname)) {\n res.statusCode = 508;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Recursive proxy target detected.', target }));\n return;\n }\n\n const body = await readRequestBody(req);\n const logId = req.headers[LLM_LOG_ID_HEADER];\n const headers = new Headers();\n // L'header di log è consumato QUI, mai inoltrato al provider upstream (stesso\n // trattamento del PROXY_CALLER_HEADER) — è un dettaglio nostro, non dell'API esterna.\n const skipHeaders = new Set([PROXY_CALLER_HEADER, LLM_LOG_ID_HEADER, 'host', 'origin', 'referer', 'content-length', 'transfer-encoding', 'connection']);\n\n Object.entries(req.headers).forEach(([key, value]) => {\n if (!value || skipHeaders.has(key.toLowerCase())) return;\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\n });\n\n const upstream = await fetch(target, {\n method: req.method || 'GET',\n headers,\n body: body && !['GET', 'HEAD'].includes((req.method || 'GET').toUpperCase())\n ? Uint8Array.from(body)\n : undefined,\n redirect: 'follow',\n });\n\n const responseBuffer = Buffer.from(await upstream.arrayBuffer());\n\n if (logOptions?.enabled && typeof logId === 'string' && logId) {\n void appendLogBlock(logOptions, logId, target, body?.toString('utf-8') ?? '', upstream.status, responseBuffer.toString('utf-8'));\n }\n\n res.statusCode = upstream.status;\n upstream.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'content-encoding') return;\n res.setHeader(key, value);\n });\n res.end(responseBuffer);\n } catch (error) {\n res.statusCode = 502;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Proxy request failed.' }));\n }\n};\n\nexport const createProxyPlugin = (route = PROXY_PATH, logOptions?: ProxyLogOptions): Plugin => ({\n name: 'llmnative-dev-proxy',\n configureServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n configurePreviewServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n});\n"],"mappings":";;;;AAMA,IAAME,IAAsB,qBACfC,IAAa,cAapBC,IAAkB,OAAO,MAAsD;CACjF,IAAMC,IAAmB,CAAC;CAC1B,WAAW,IAAMC,KAASC,GACtB,EAAO,KAAK,OAAO,SAASD,CAAK,IAAIA,IAAQ,OAAO,KAAKA,CAAK,CAAC;CAEnE,OAAOD,EAAO,WAAW,IAAI,KAAA,IAAY,OAAO,OAAOA,CAAM;AACjE;AAIA,SAASG,EAAc,GAAuB;CAC1C,OAAOC,EAAM,QAAQ,mBAAmB,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG,KAAK;AACjE;AAEA,SAASC,EAAgB,GAAsB;CAC3C,IAAI,CAACC,EAAK,KAAK,GAAG,OAAO;CACzB,IAAI;EACA,OAAO,KAAK,UAAU,KAAK,MAAMA,CAAI,GAAG,MAAM,CAAC;CACnD,QAAQ;EACJ,OAAOA;CACX;AACJ;AAEA,eAAeC,EAAe,GAA6B,GAAe,GAAgB,GAAqB,GAAgB,GAAsB;CACjJ,IAAI;EACA,MAAMC,EAAMC,EAAW,KAAK,EAAE,WAAW,GAAK,CAAC;EAC/C,IAAMC,IAAQ;GACV;GACA,IAAI,OAAO,EAAE;GACb,2BAAU,IAAI,KAAK,EAAA,CAAE,YAAY;GACjC,WAAWC;GACX;GACAN,EAAgBO,CAAW;GAC3B,6BAA6BC,EAAO;GACpCR,EAAgBS,CAAY;GAC5B,IAAI,OAAO,EAAE;GACb;EACJ,CAAC,CAAC,KAAK,IAAI;EACX,MAAMC,EAAWnB,EAAK,KAAKa,EAAW,KAAK,GAAGN,EAAcC,CAAK,EAAE,KAAK,GAAGM,GAAO,OAAO;CAC7F,SAASM,GAAO;EAEZ,QAAQ,KAAK,kDAAkDA,CAAK;CACxE;AACJ;AAEA,IAAMC,IAAqB,OAAO,GAAsB,GAAqB,GAAe,MAAiC;CAEzH,IAAMN,IAAS,IADQ,IAAIT,EAAI,OAAO,KAAK,kBAC5B,CAAA,CAAW,aAAa,IAAI,KAAK;CAEhD,IAAIA,EAAI,QAAQL,OAAyB,KAAK;EAG1C,AAFA,EAAI,aAAa,KACjBqB,EAAI,UAAU,gBAAgB,kBAAkB,GAChDA,EAAI,IAAI,KAAK,UAAU,EAAE,OAAO,uBAAuB,CAAC,CAAC;EACzD;CACJ;CAEA,IAAI,CAACP,GAAQ;EAGT,AAFA,EAAI,aAAa,KACjBO,EAAI,UAAU,gBAAgB,kBAAkB,GAChDA,EAAI,IAAI,KAAK,UAAU,EAAE,OAAO,mCAAiC,CAAC,CAAC;EACnE;CACJ;CAEA,IAAI;EACA,IAAMC,IAAY,IAAI,IAAIR,CAAM;EAChC,IAAIQ,EAAU,SAAS,WAAWC,CAAK,KAAK,CAAC,aAAa,WAAW,CAAC,CAAC,SAASD,EAAU,QAAQ,GAAG;GAGjG,AAFA,EAAI,aAAa,KACjBD,EAAI,UAAU,gBAAgB,kBAAkB,GAChDA,EAAI,IAAI,KAAK,UAAU;IAAE,OAAO;IAAoC;GAAO,CAAC,CAAC;GAC7E;EACJ;EAEA,IAAMG,IAAO,MAAMtB,EAAgBG,CAAG,GAChCE,IAAQF,EAAI,QAAQP,IACpB2B,IAAU,IAAI,QAAQ,GAGtBC,oBAAc,IAAI,IAAI;GAAC1B;GAAqBF;GAAmB;GAAQ;GAAU;GAAW;GAAkB;GAAqB;EAAY,CAAC;EAEtJ,OAAO,QAAQO,EAAI,OAAO,CAAC,CAAC,SAAS,CAACsB,GAAKC,OAAW;GAClD,AAAKA,KAAS,GAAY,IAAID,EAAI,YAAY,CAAC,KAC/CF,EAAQ,IAAIE,GAAK,MAAM,QAAQC,CAAK,IAAIA,EAAM,KAAK,IAAI,IAAIA,CAAK;EACpE,CAAC;EAED,IAAMC,IAAW,MAAM,MAAMf,GAAQ;GACjC,QAAQT,EAAI,UAAU;GACtB;GACA,MAAMmB,KAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,UAAUnB,EAAI,UAAU,MAAA,CAAO,YAAY,CAAC,IACrE,WAAW,KAAKmB,CAAI,IACpB,KAAA;GACN,UAAU;EACd,CAAC,GAEKM,IAAiB,OAAO,KAAK,MAAMD,EAAS,YAAY,CAAC;EAW/D,AATIjB,GAAY,WAAW,OAAOL,KAAU,YAAYA,KACpDG,EAAoBE,GAAYL,GAAOO,GAAQU,GAAM,SAAS,OAAO,KAAK,IAAIK,EAAS,QAAQC,EAAe,SAAS,OAAO,CAAC,GAGnI,EAAI,aAAaD,EAAS,QAC1BA,EAAS,QAAQ,SAAS,GAAO,MAAQ;GACrC,AAAIF,EAAI,YAAY,MAAM,sBAC1BN,EAAI,UAAUM,GAAKC,CAAK;EAC5B,CAAC,GACDP,EAAI,IAAIS,CAAc;CAC1B,SAASX,GAAO;EAGZ,AAFA,EAAI,aAAa,KACjBE,EAAI,UAAU,gBAAgB,kBAAkB,GAChDA,EAAI,IAAI,KAAK,UAAU,EAAE,OAAOF,aAAiB,QAAQA,EAAM,UAAU,wBAAwB,CAAC,CAAC;CACvG;AACJ,GAEaY,KAAqB,IAAQ9B,GAAY,OAA0C;CAC5F,MAAM;CACN,gBAAgB,GAAQ;EACpB,EAAO,YAAY,IAAIsB,IAAQ,GAAK,MAAQ;GAAE,EAAwBlB,GAAKgB,GAAKE,GAAOX,CAAU;EAAG,CAAC;CACzG;CACA,uBAAuB,GAAQ;EAC3B,EAAO,YAAY,IAAIW,IAAQ,GAAK,MAAQ;GAAE,EAAwBlB,GAAKgB,GAAKE,GAAOX,CAAU;EAAG,CAAC;CACzG;AACJ"}
|
|
1
|
+
{"version":3,"file":"vite.mjs","names":["LLM_LOG_ID_HEADER","path","PROXY_CALLER_HEADER","PROXY_PATH","readRequestBody","chunks","chunk","req","sanitizeLogId","logId","prettyJsonOrRaw","text","appendLogBlock","mkdir","logOptions","block","target","requestBody","status","responseBody","appendFile","error","writeProxyResponse","res","targetUrl","route","body","headers","skipHeaders","key","value","resolved","resolveServerCredentials","credentials","upstream","responseBuffer","createProxyPlugin"],"sources":["../src/providers/proxy/vite.ts"],"sourcesContent":["import { appendFile, mkdir } from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport type { IncomingMessage, ServerResponse } from 'node:http';\r\nimport type { Plugin } from 'vite';\r\nimport { LLM_LOG_ID_HEADER } from './logHeader';\r\nimport { resolveServerCredentials, type ServerCredentialLookup } from '../ai/server';\r\n\r\nconst PROXY_CALLER_HEADER = 'x-llmnative-proxy';\r\nexport const PROXY_PATH = '/api/proxy';\r\n\r\n/** Logging file di richiesta/risposta LLM — SOLO dev, mai attivo di default. Un file per\r\n * conversazione: il client (useAgent, CMS) genera un `logId` stabile per l'intera sessione e\r\n * lo manda su ogni chiamata come header `x-llmnative-log-id`; il proxy accoda ogni turno allo\r\n * stesso file, non lo sovrascrive. Vedi AICompleteRequest.logId per il lato client. */\r\nexport interface ProxyLogOptions {\r\n enabled: boolean;\r\n /** Cartella di destinazione, relativa alla cwd del dev server (il progetto consumer, es.\r\n * il CMS) o assoluta. Creata se assente. */\r\n dir: string;\r\n}\r\n\r\nconst readRequestBody = async (req: IncomingMessage): Promise<Buffer | undefined> => {\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of req) {\r\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\r\n }\r\n return chunks.length === 0 ? undefined : Buffer.concat(chunks);\r\n};\r\n\r\n/** Solo caratteri sicuri per un nome file — l'id è generato da noi (crypto.randomUUID() lato\r\n * client), ma niente path traversal per costruzione anche se un client si comportasse male. */\r\nfunction sanitizeLogId(logId: string): string {\r\n return logId.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128) || 'unknown';\r\n}\r\n\r\nfunction prettyJsonOrRaw(text: string): string {\r\n if (!text.trim()) return '(empty body)';\r\n try {\r\n return JSON.stringify(JSON.parse(text), null, 2);\r\n } catch {\r\n return text;\r\n }\r\n}\r\n\r\nasync function appendLogBlock(logOptions: ProxyLogOptions, logId: string, target: string, requestBody: string, status: number, responseBody: string) {\r\n try {\r\n await mkdir(logOptions.dir, { recursive: true });\r\n const block = [\r\n '',\r\n '='.repeat(80),\r\n `Turn @ ${new Date().toISOString()}`,\r\n `Target: ${target}`,\r\n '--- REQUEST BODY ---',\r\n prettyJsonOrRaw(requestBody),\r\n `--- RESPONSE BODY (status ${status}) ---`,\r\n prettyJsonOrRaw(responseBody),\r\n '='.repeat(80),\r\n '',\r\n ].join('\\n');\r\n await appendFile(path.join(logOptions.dir, `${sanitizeLogId(logId)}.txt`), block, 'utf-8');\r\n } catch (error) {\r\n // Un log fallito non deve mai far fallire la vera richiesta — solo un avviso in console.\r\n console.warn('[llmnative-dev-proxy] Failed to write LLM log:', error);\r\n }\r\n}\r\n\r\nconst writeProxyResponse = async (req: IncomingMessage, res: ServerResponse, route: string, logOptions?: ProxyLogOptions, credentials?: ServerCredentialLookup) => {\r\n const requestUrl = new URL(req.url || '/', 'http://localhost');\r\n const target = requestUrl.searchParams.get('url');\r\n\r\n if (req.headers[PROXY_CALLER_HEADER] !== '1') {\r\n res.statusCode = 403;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Proxy access denied.' }));\r\n return;\r\n }\r\n\r\n if (!target) {\r\n res.statusCode = 400;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Missing \"url\" query parameter.' }));\r\n return;\r\n }\r\n\r\n try {\r\n const targetUrl = new URL(target);\r\n if (targetUrl.pathname.startsWith(route) && ['localhost', '127.0.0.1'].includes(targetUrl.hostname)) {\r\n res.statusCode = 508;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Recursive proxy target detected.', target }));\r\n return;\r\n }\r\n\r\n const body = await readRequestBody(req);\r\n const logId = req.headers[LLM_LOG_ID_HEADER];\r\n const headers = new Headers();\r\n // L'header di log è consumato QUI, mai inoltrato al provider upstream (stesso\r\n // trattamento del PROXY_CALLER_HEADER) — è un dettaglio nostro, non dell'API esterna.\r\n const skipHeaders = new Set([PROXY_CALLER_HEADER, LLM_LOG_ID_HEADER, 'host', 'origin', 'referer', 'content-length', 'transfer-encoding', 'connection']);\r\n\r\n Object.entries(req.headers).forEach(([key, value]) => {\r\n if (!value || skipHeaders.has(key.toLowerCase())) return;\r\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\r\n });\r\n\r\n // Server-held AI credentials (CR-102): the placeholder becomes the key, only towards its\r\n // provider. Without a lookup a placeholder finds no key and the request is refused.\r\n const resolved = await resolveServerCredentials({ url: target, headers: Object.fromEntries(headers) }, credentials ?? (() => undefined));\r\n if (!resolved.ok) {\r\n res.statusCode = resolved.status;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: resolved.error, provider: resolved.provider }));\r\n return;\r\n }\r\n\r\n const upstream = await fetch(resolved.url, {\r\n method: req.method || 'GET',\r\n headers: new Headers(resolved.headers),\r\n body: body && !['GET', 'HEAD'].includes((req.method || 'GET').toUpperCase())\r\n ? Uint8Array.from(body)\r\n : undefined,\r\n redirect: 'follow',\r\n });\r\n\r\n const responseBuffer = Buffer.from(await upstream.arrayBuffer());\r\n\r\n if (logOptions?.enabled && typeof logId === 'string' && logId) {\r\n void appendLogBlock(logOptions, logId, target, body?.toString('utf-8') ?? '', upstream.status, responseBuffer.toString('utf-8'));\r\n }\r\n\r\n res.statusCode = upstream.status;\r\n upstream.headers.forEach((value, key) => {\r\n if (key.toLowerCase() === 'content-encoding') return;\r\n res.setHeader(key, value);\r\n });\r\n res.end(responseBuffer);\r\n } catch (error) {\r\n res.statusCode = 502;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Proxy request failed.' }));\r\n }\r\n};\r\n\r\n/** `credentials`: the keys of the providers held by the server (CR-102), for the adapters built\r\n * with createServerCredentialAIRegistry(). */\r\nexport const createProxyPlugin = (route = PROXY_PATH, logOptions?: ProxyLogOptions, credentials?: ServerCredentialLookup): Plugin => ({\r\n name: 'llmnative-dev-proxy',\r\n configureServer(server) {\r\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions, credentials); });\r\n },\r\n configurePreviewServer(server) {\r\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions, credentials); });\r\n },\r\n});\r\n"],"mappings":"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"}
|