@kizenapps/cli 0.6.0 → 0.7.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 (43) hide show
  1. package/dist/electron/icon.png +0 -0
  2. package/dist/electron/main.js +38 -2
  3. package/dist/electron/main.js.map +1 -1
  4. package/dist/index.js +85 -9
  5. package/dist/index.js.map +1 -1
  6. package/dist/viewer/assets/index--m1PKX6N.js +17 -0
  7. package/dist/viewer/assets/index-2OcBnmZB.js +17 -0
  8. package/dist/viewer/assets/index-7ah1RuPy.js +17 -0
  9. package/dist/viewer/assets/index-B3gNsKTt.js +17 -0
  10. package/dist/viewer/assets/index-B40AtXqk.js +17 -0
  11. package/dist/viewer/assets/index-B4ikC-wc.js +17 -0
  12. package/dist/viewer/assets/index-BKOfPpLS.js +17 -0
  13. package/dist/viewer/assets/index-BM3JrC-1.js +17 -0
  14. package/dist/viewer/assets/index-BUnK11-F.js +17 -0
  15. package/dist/viewer/assets/index-Bc7IZVr6.js +17 -0
  16. package/dist/viewer/assets/index-C1KzcpVj.js +17 -0
  17. package/dist/viewer/assets/index-CBBwr2o_.js +17 -0
  18. package/dist/viewer/assets/index-CHtXWYIY.js +17 -0
  19. package/dist/viewer/assets/index-CN9NvJkQ.js +17 -0
  20. package/dist/viewer/assets/index-CNKPBxhv.js +17 -0
  21. package/dist/viewer/assets/index-C_6izRRh.js +17 -0
  22. package/dist/viewer/assets/index-CgzK6zig.js +17 -0
  23. package/dist/viewer/assets/index-Cw2cxYy2.js +17 -0
  24. package/dist/viewer/assets/index-D06uhGtQ.js +17 -0
  25. package/dist/viewer/assets/index-DAHWT-g0.js +17 -0
  26. package/dist/viewer/assets/index-DAxJgHat.js +17 -0
  27. package/dist/viewer/assets/index-DF_geUaW.js +17 -0
  28. package/dist/viewer/assets/index-DUgUEouL.css +2 -0
  29. package/dist/viewer/assets/index-DcGGXuA3.js +17 -0
  30. package/dist/viewer/assets/index-DlVmY-nR.js +17 -0
  31. package/dist/viewer/assets/index-FZw9Ev_R.js +17 -0
  32. package/dist/viewer/assets/index-M1Obm_99.js +17 -0
  33. package/dist/viewer/assets/index-_kM1Ri7v.js +17 -0
  34. package/dist/viewer/assets/index-aTt_sTlu.js +17 -0
  35. package/dist/viewer/assets/index-vYFGGFc2.js +17 -0
  36. package/dist/viewer/icon.png +0 -0
  37. package/dist/viewer/index.html +2 -2
  38. package/package.json +1 -1
  39. package/dist/viewer/1024.png +0 -0
  40. package/dist/viewer/assets/index-B0iU58_K.css +0 -2
  41. package/dist/viewer/assets/index-BLljooBS.js +0 -17
  42. package/dist/viewer/favicon.png +0 -0
  43. package/dist/viewer/favicon.svg +0 -4
Binary file
@@ -107,6 +107,17 @@ void app.whenReady().then(() => {
107
107
  if (prop.type === "object" && prop.value === "null") {
108
108
  return null;
109
109
  }
110
+ if (prop.type === "object" && prop.valuePreview) {
111
+ const { valuePreview } = prop;
112
+ if (valuePreview.subtype === "array") {
113
+ return valuePreview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
114
+ }
115
+ const obj = {};
116
+ for (const p of valuePreview.properties) {
117
+ obj[p.name] = parseProp(p);
118
+ }
119
+ return obj;
120
+ }
110
121
  return prop.value ?? `[${prop.type}]`;
111
122
  }
112
123
  function serializeArg(arg) {
@@ -140,7 +151,28 @@ void app.whenReady().then(() => {
140
151
  waitForDebuggerOnStart: false,
141
152
  flatten: true
142
153
  });
143
- win.webContents.debugger.on("message", (_event, method, params) => {
154
+ async function serializeArgAsync(arg, sessionId) {
155
+ if (arg.type === "object" && arg.objectId) {
156
+ try {
157
+ const result = await win.webContents.debugger.sendCommand(
158
+ "Runtime.callFunctionOn",
159
+ {
160
+ objectId: arg.objectId,
161
+ functionDeclaration: 'function() { const seen = new WeakSet(); return JSON.stringify(this, function(k, v) { if (typeof v === "object" && v !== null) { if (seen.has(v)) return "[Circular]"; seen.add(v); } return v; }); }',
162
+ returnByValue: true
163
+ },
164
+ sessionId
165
+ );
166
+ const val = result.result.value;
167
+ if (typeof val === "string") {
168
+ return JSON.parse(val);
169
+ }
170
+ } catch {
171
+ }
172
+ }
173
+ return serializeArg(arg);
174
+ }
175
+ win.webContents.debugger.on("message", (_event, method, params, sessionId) => {
144
176
  if (method === "Target.attachedToTarget") {
145
177
  const { sessionId: childSessionId } = params;
146
178
  enableRuntime(childSessionId);
@@ -154,7 +186,11 @@ void app.whenReady().then(() => {
154
186
  return;
155
187
  }
156
188
  const level = type === "warning" ? "warn" : ["log", "warn", "error", "info"].includes(type) ? type : "log";
157
- win.webContents.send("console-message", { level, args: args2.map(serializeArg) });
189
+ void Promise.all(args2.map((arg) => serializeArgAsync(arg, sessionId))).then(
190
+ (serializedArgs) => {
191
+ win.webContents.send("console-message", { level, args: serializedArgs });
192
+ }
193
+ );
158
194
  });
159
195
  void win.loadURL(`http://localhost:${String(port)}`);
160
196
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/electron/main.ts"],"sourcesContent":["import { app, BrowserWindow, session, nativeImage, Menu, ipcMain } from 'electron';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst args = process.argv.slice(2);\nconst port = parseInt(args.find((a) => a.startsWith('--port='))?.slice(7) ?? '3121', 10);\nconst userDataDir = args.find((a) => a.startsWith('--user-data-dir='))?.slice(16);\n\nif (userDataDir) {\n app.setPath('userData', userDataDir);\n}\n\napp.setName('Kizen App Builder');\n\nconst CSP_HEADERS = new Set([\n 'content-security-policy',\n 'content-security-policy-report-only',\n 'x-frame-options',\n]);\n\nconst KIZEN_DOMAINS = ['kizen.dev', 'kizen.com'];\n\nfunction isKizenUrl(url: string): boolean {\n try {\n const { hostname } = new URL(url);\n return KIZEN_DOMAINS.some((d) => hostname === d || hostname.endsWith('.' + d));\n } catch {\n return false;\n }\n}\n\nfunction setupSession(): void {\n // Strip CSP headers and fix SameSite cookies on Kizen responses.\n session.defaultSession.webRequest.onHeadersReceived((details, callback) => {\n const headers: Record<string, string[]> = {};\n\n for (const [key, value] of Object.entries(details.responseHeaders ?? {})) {\n if (!CSP_HEADERS.has(key.toLowerCase())) {\n headers[key] = value;\n }\n }\n\n if (isKizenUrl(details.url) && headers['set-cookie']) {\n headers['set-cookie'] = headers['set-cookie'].map((cookie) => {\n if (!/SameSite=/i.test(cookie)) {\n return cookie + '; SameSite=None; Secure';\n }\n\n return cookie.replace(/SameSite=\\w+/i, 'SameSite=None');\n });\n }\n\n callback({ responseHeaders: headers });\n });\n\n // Periodically re-patch existing Kizen cookies that arrived without SameSite=None.\n // Needed for cookies set before the interceptor was active or via JS document.cookie.\n setInterval(() => {\n void (async () => {\n for (const domain of KIZEN_DOMAINS) {\n try {\n const cookies = await session.defaultSession.cookies.get({ domain });\n for (const cookie of cookies) {\n if (cookie.sameSite !== 'no_restriction') {\n const raw = cookie.domain ?? domain;\n const bare = raw.startsWith('.') ? raw.slice(1) : raw;\n await session.defaultSession.cookies.set({\n url: `https://${bare}`,\n name: cookie.name,\n value: cookie.value,\n domain: raw,\n path: cookie.path ?? '/',\n secure: true,\n ...(cookie.httpOnly !== undefined && { httpOnly: cookie.httpOnly }),\n ...(cookie.expirationDate !== undefined && {\n expirationDate: cookie.expirationDate,\n }),\n sameSite: 'no_restriction',\n });\n }\n }\n } catch {\n /* ignore */\n }\n }\n })();\n }, 2000);\n}\n\nvoid app.whenReady().then(() => {\n Menu.setApplicationMenu(null);\n\n setupSession();\n\n const iconPath = join(dirname(fileURLToPath(import.meta.url)), 'icon.png');\n const icon = nativeImage.createFromPath(iconPath);\n\n if (process.platform === 'darwin' && !icon.isEmpty()) {\n app.dock?.setIcon(icon);\n }\n\n const win = new BrowserWindow({\n width: 1920,\n height: 1080,\n title: 'Kizen App Builder',\n icon,\n webPreferences: {\n nodeIntegration: false,\n contextIsolation: true,\n sandbox: false,\n preload: join(dirname(fileURLToPath(import.meta.url)), 'preload.cjs'),\n },\n });\n\n ipcMain.on('open-devtools', () => {\n win.webContents.openDevTools();\n });\n\n interface PropertyPreview {\n name: string;\n type: string;\n value?: string;\n subtype?: string;\n }\n interface ObjectPreview {\n type: string;\n subtype?: string;\n overflow: boolean;\n properties: PropertyPreview[];\n }\n interface RemoteObject {\n type: string;\n subtype?: string;\n value?: unknown;\n description?: string;\n preview?: ObjectPreview;\n }\n interface ConsoleApiCalledParams {\n type: string;\n args: RemoteObject[];\n }\n\n function parseProp(prop: PropertyPreview): unknown {\n if (prop.type === 'number') {\n return Number(prop.value);\n }\n if (prop.type === 'boolean') {\n return prop.value === 'true';\n }\n if (prop.type === 'undefined') {\n return undefined;\n }\n if (prop.type === 'object' && prop.value === 'null') {\n return null;\n }\n return prop.value ?? `[${prop.type}]`;\n }\n\n function serializeArg(arg: RemoteObject): unknown {\n if (arg.value !== undefined) {\n return arg.value;\n }\n if (arg.preview) {\n const { preview } = arg;\n if (preview.subtype === 'array') {\n return preview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n const obj: Record<string, unknown> = {};\n for (const prop of preview.properties) {\n obj[prop.name] = parseProp(prop);\n }\n return obj;\n }\n return arg.description ?? `[${arg.type}]`;\n }\n\n const enableRuntime = (sessionId?: string): void => {\n void win.webContents.debugger.sendCommand(\n 'Runtime.enable',\n { generatePreview: true },\n sessionId,\n );\n };\n\n win.webContents.debugger.attach('1.3');\n enableRuntime();\n void win.webContents.debugger.sendCommand('Target.setAutoAttach', {\n autoAttach: true,\n waitForDebuggerOnStart: false,\n flatten: true,\n });\n\n win.webContents.debugger.on('message', (_event, method, params) => {\n if (method === 'Target.attachedToTarget') {\n const { sessionId: childSessionId } = params as { sessionId: string };\n enableRuntime(childSessionId);\n return;\n }\n\n if (method !== 'Runtime.consoleAPICalled') {\n return;\n }\n const { type, args } = params as ConsoleApiCalledParams;\n if (args[0]?.type === 'string' && String(args[0].value).includes('Electron Security Warning')) {\n return;\n }\n const level =\n type === 'warning' ? 'warn' : ['log', 'warn', 'error', 'info'].includes(type) ? type : 'log';\n win.webContents.send('console-message', { level, args: args.map(serializeArg) });\n });\n\n void win.loadURL(`http://localhost:${String(port)}`);\n});\n\napp.on('window-all-closed', () => {\n app.quit();\n});\n"],"mappings":"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","names":["args"]}
1
+ {"version":3,"sources":["../../src/electron/main.ts"],"sourcesContent":["import { app, BrowserWindow, session, nativeImage, Menu, ipcMain } from 'electron';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst args = process.argv.slice(2);\nconst port = parseInt(args.find((a) => a.startsWith('--port='))?.slice(7) ?? '3121', 10);\nconst userDataDir = args.find((a) => a.startsWith('--user-data-dir='))?.slice(16);\n\nif (userDataDir) {\n app.setPath('userData', userDataDir);\n}\n\napp.setName('Kizen App Builder');\n\nconst CSP_HEADERS = new Set([\n 'content-security-policy',\n 'content-security-policy-report-only',\n 'x-frame-options',\n]);\n\nconst KIZEN_DOMAINS = ['kizen.dev', 'kizen.com'];\n\nfunction isKizenUrl(url: string): boolean {\n try {\n const { hostname } = new URL(url);\n return KIZEN_DOMAINS.some((d) => hostname === d || hostname.endsWith('.' + d));\n } catch {\n return false;\n }\n}\n\nfunction setupSession(): void {\n // Strip CSP headers and fix SameSite cookies on Kizen responses.\n session.defaultSession.webRequest.onHeadersReceived((details, callback) => {\n const headers: Record<string, string[]> = {};\n\n for (const [key, value] of Object.entries(details.responseHeaders ?? {})) {\n if (!CSP_HEADERS.has(key.toLowerCase())) {\n headers[key] = value;\n }\n }\n\n if (isKizenUrl(details.url) && headers['set-cookie']) {\n headers['set-cookie'] = headers['set-cookie'].map((cookie) => {\n if (!/SameSite=/i.test(cookie)) {\n return cookie + '; SameSite=None; Secure';\n }\n\n return cookie.replace(/SameSite=\\w+/i, 'SameSite=None');\n });\n }\n\n callback({ responseHeaders: headers });\n });\n\n // Periodically re-patch existing Kizen cookies that arrived without SameSite=None.\n // Needed for cookies set before the interceptor was active or via JS document.cookie.\n setInterval(() => {\n void (async () => {\n for (const domain of KIZEN_DOMAINS) {\n try {\n const cookies = await session.defaultSession.cookies.get({ domain });\n for (const cookie of cookies) {\n if (cookie.sameSite !== 'no_restriction') {\n const raw = cookie.domain ?? domain;\n const bare = raw.startsWith('.') ? raw.slice(1) : raw;\n await session.defaultSession.cookies.set({\n url: `https://${bare}`,\n name: cookie.name,\n value: cookie.value,\n domain: raw,\n path: cookie.path ?? '/',\n secure: true,\n ...(cookie.httpOnly !== undefined && { httpOnly: cookie.httpOnly }),\n ...(cookie.expirationDate !== undefined && {\n expirationDate: cookie.expirationDate,\n }),\n sameSite: 'no_restriction',\n });\n }\n }\n } catch {\n /* ignore */\n }\n }\n })();\n }, 2000);\n}\n\nvoid app.whenReady().then(() => {\n Menu.setApplicationMenu(null);\n\n setupSession();\n\n const iconPath = join(dirname(fileURLToPath(import.meta.url)), 'icon.png');\n const icon = nativeImage.createFromPath(iconPath);\n\n if (process.platform === 'darwin' && !icon.isEmpty()) {\n app.dock?.setIcon(icon);\n }\n\n const win = new BrowserWindow({\n width: 1920,\n height: 1080,\n title: 'Kizen App Builder',\n icon,\n webPreferences: {\n nodeIntegration: false,\n contextIsolation: true,\n sandbox: false,\n preload: join(dirname(fileURLToPath(import.meta.url)), 'preload.cjs'),\n },\n });\n\n ipcMain.on('open-devtools', () => {\n win.webContents.openDevTools();\n });\n\n interface PropertyPreview {\n name: string;\n type: string;\n value?: string;\n subtype?: string;\n valuePreview?: ObjectPreview;\n }\n interface ObjectPreview {\n type: string;\n subtype?: string;\n overflow: boolean;\n properties: PropertyPreview[];\n }\n interface RemoteObject {\n type: string;\n subtype?: string;\n value?: unknown;\n description?: string;\n preview?: ObjectPreview;\n objectId?: string;\n }\n interface ConsoleApiCalledParams {\n type: string;\n args: RemoteObject[];\n }\n\n function parseProp(prop: PropertyPreview): unknown {\n if (prop.type === 'number') {\n return Number(prop.value);\n }\n if (prop.type === 'boolean') {\n return prop.value === 'true';\n }\n if (prop.type === 'undefined') {\n return undefined;\n }\n if (prop.type === 'object' && prop.value === 'null') {\n return null;\n }\n if (prop.type === 'object' && prop.valuePreview) {\n const { valuePreview } = prop;\n if (valuePreview.subtype === 'array') {\n return valuePreview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n const obj: Record<string, unknown> = {};\n for (const p of valuePreview.properties) {\n obj[p.name] = parseProp(p);\n }\n return obj;\n }\n return prop.value ?? `[${prop.type}]`;\n }\n\n function serializeArg(arg: RemoteObject): unknown {\n if (arg.value !== undefined) {\n return arg.value;\n }\n if (arg.preview) {\n const { preview } = arg;\n if (preview.subtype === 'array') {\n return preview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n const obj: Record<string, unknown> = {};\n for (const prop of preview.properties) {\n obj[prop.name] = parseProp(prop);\n }\n return obj;\n }\n return arg.description ?? `[${arg.type}]`;\n }\n\n const enableRuntime = (sessionId?: string): void => {\n void win.webContents.debugger.sendCommand(\n 'Runtime.enable',\n { generatePreview: true },\n sessionId,\n );\n };\n\n win.webContents.debugger.attach('1.3');\n enableRuntime();\n void win.webContents.debugger.sendCommand('Target.setAutoAttach', {\n autoAttach: true,\n waitForDebuggerOnStart: false,\n flatten: true,\n });\n\n async function serializeArgAsync(arg: RemoteObject, sessionId?: string): Promise<unknown> {\n if (arg.type === 'object' && arg.objectId) {\n try {\n const result: unknown = await win.webContents.debugger.sendCommand(\n 'Runtime.callFunctionOn',\n {\n objectId: arg.objectId,\n functionDeclaration:\n 'function() { const seen = new WeakSet(); return JSON.stringify(this, function(k, v) { if (typeof v === \"object\" && v !== null) { if (seen.has(v)) return \"[Circular]\"; seen.add(v); } return v; }); }',\n returnByValue: true,\n },\n sessionId,\n );\n const val = (result as { result: { value?: string } }).result.value;\n if (typeof val === 'string') {\n return JSON.parse(val);\n }\n } catch {\n // fall through to preview-based serialization\n }\n }\n return serializeArg(arg);\n }\n\n win.webContents.debugger.on('message', (_event, method, params, sessionId) => {\n if (method === 'Target.attachedToTarget') {\n const { sessionId: childSessionId } = params as { sessionId: string };\n enableRuntime(childSessionId);\n return;\n }\n\n if (method !== 'Runtime.consoleAPICalled') {\n return;\n }\n const { type, args } = params as ConsoleApiCalledParams;\n if (args[0]?.type === 'string' && String(args[0].value).includes('Electron Security Warning')) {\n return;\n }\n const level =\n type === 'warning' ? 'warn' : ['log', 'warn', 'error', 'info'].includes(type) ? type : 'log';\n void Promise.all(args.map((arg) => serializeArgAsync(arg, sessionId as string | undefined))).then(\n (serializedArgs) => {\n win.webContents.send('console-message', { level, args: serializedArgs });\n },\n );\n });\n\n void win.loadURL(`http://localhost:${String(port)}`);\n});\n\napp.on('window-all-closed', () => {\n app.quit();\n});\n"],"mappings":"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","names":["args"]}
package/dist/index.js CHANGED
@@ -238,6 +238,37 @@ import { dirname as dirname2, extname, join as join6 } from "path";
238
238
  import { fileURLToPath } from "url";
239
239
  import { WebSocketServer } from "ws";
240
240
 
241
+ // src/lib/proxyCache.ts
242
+ function createProxyCache() {
243
+ const cache = /* @__PURE__ */ new Map();
244
+ return {
245
+ get(key, fetcher) {
246
+ const existing = cache.get(key);
247
+ if (existing !== void 0) {
248
+ return existing.then((response) => ({ response, fromCache: true }));
249
+ }
250
+ const pending = fetcher().then(async (response) => {
251
+ const headers = Object.fromEntries(response.headers);
252
+ delete headers["content-encoding"];
253
+ delete headers["content-length"];
254
+ return {
255
+ status: response.status,
256
+ headers,
257
+ body: Buffer.from(await response.arrayBuffer())
258
+ };
259
+ }).catch((error) => {
260
+ cache.delete(key);
261
+ throw error;
262
+ });
263
+ cache.set(key, pending);
264
+ return pending.then((response) => ({ response, fromCache: false }));
265
+ },
266
+ clear() {
267
+ cache.clear();
268
+ }
269
+ };
270
+ }
271
+
241
272
  // src/lib/config.ts
242
273
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
243
274
  import { join as join4 } from "path";
@@ -506,6 +537,13 @@ var CredentialSetupUI = ({
506
537
 
507
538
  // src/ui/DevUI.tsx
508
539
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
540
+ function proxyLogEntryToString(entry) {
541
+ if (entry.kind === "info") {
542
+ return entry.message;
543
+ }
544
+ const cache = entry.fromCache ? " [cache]" : "";
545
+ return `${entry.method} ${entry.url} \u2192 ${String(entry.status)}${cache}`;
546
+ }
509
547
  var SKIP_WATCH_PREFIXES = [".kizenapp", ".git"];
510
548
  var LOG_LIMIT = 50;
511
549
  var LOG_DISPLAY = 8;
@@ -554,6 +592,7 @@ async function fileExists(filePath) {
554
592
  }
555
593
  }
556
594
  function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef) {
595
+ const proxyCache = createProxyCache();
557
596
  return (req, res) => {
558
597
  void (async () => {
559
598
  const url = req.url ?? "/";
@@ -576,6 +615,13 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
576
615
  }
577
616
  return;
578
617
  }
618
+ if (url === "/api/proxy-cache/clear") {
619
+ proxyCache.clear();
620
+ createProxyLog({ kind: "info", message: "Proxy cache cleared" });
621
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
622
+ res.end('{"ok":true}');
623
+ return;
624
+ }
579
625
  if (url.startsWith("/api/proxy")) {
580
626
  const proxyTarget = req.headers["x-proxy-target"];
581
627
  if (typeof proxyTarget !== "string") {
@@ -585,19 +631,46 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
585
631
  }
586
632
  const upstreamPath = url.slice("/api/proxy".length) || "/";
587
633
  const upstreamUrl = `${proxyTarget}${upstreamPath}`;
634
+ const method = req.method ?? "GET";
588
635
  const chunks = [];
589
636
  for await (const chunk of req) {
590
637
  chunks.push(chunk);
591
638
  }
592
- const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
593
639
  const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
640
+ if (method === "GET") {
641
+ const cacheKey = `GET::${upstreamUrl}`;
642
+ const { response: cached, fromCache } = await proxyCache.get(
643
+ cacheKey,
644
+ () => fetch(upstreamUrl, {
645
+ method: "GET",
646
+ headers: forwardHeaders
647
+ })
648
+ );
649
+ createProxyLog({
650
+ kind: "request",
651
+ method: "GET",
652
+ status: cached.status,
653
+ fromCache,
654
+ url: upstreamPath
655
+ });
656
+ res.writeHead(cached.status, cached.headers);
657
+ res.end(cached.body);
658
+ return;
659
+ }
660
+ const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
594
661
  const resolvedBody = body && body.length > 0 ? body : void 0;
595
662
  const upstream = await fetch(upstreamUrl, {
596
- ...req.method !== void 0 && { method: req.method },
663
+ method,
597
664
  headers: forwardHeaders,
598
665
  ...resolvedBody !== void 0 && { body: resolvedBody }
599
666
  });
600
- createProxyLog(`${req.method ?? "GET"} ${upstreamPath} \u2192 ${String(upstream.status)}`);
667
+ createProxyLog({
668
+ kind: "request",
669
+ method,
670
+ status: upstream.status,
671
+ fromCache: false,
672
+ url: upstreamPath
673
+ });
601
674
  const responseHeaders = Object.fromEntries(upstream.headers);
602
675
  delete responseHeaders["content-encoding"];
603
676
  delete responseHeaders["content-length"];
@@ -613,9 +686,10 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
613
686
  res.writeHead(200, { "Content-Type": mimeType });
614
687
  createReadStream(resolvedPath).pipe(res);
615
688
  } catch (err) {
616
- createProxyLog(
617
- `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
618
- );
689
+ createProxyLog({
690
+ kind: "info",
691
+ message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
692
+ });
619
693
  if (!res.headersSent) {
620
694
  res.writeHead(502);
621
695
  res.end("Bad Gateway");
@@ -708,11 +782,13 @@ var DevUI = ({
708
782
  [outputDir, broadcast]
709
783
  );
710
784
  const createProxyLog = useCallback2(
711
- (message) => {
785
+ (entry) => {
712
786
  setProxyLogHistory(
713
- (h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
787
+ (h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${proxyLogEntryToString(entry)}`].slice(
788
+ -LOG_LIMIT
789
+ )
714
790
  );
715
- broadcast({ type: "proxy-log", message });
791
+ broadcast({ type: "proxy-log", entry });
716
792
  },
717
793
  [broadcast]
718
794
  );