@64mb/freelens-power 1.5.0 → 1.6.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 (71) hide show
  1. package/README.md +4 -1
  2. package/out/main/ai-ipc.js +34 -3
  3. package/out/main/ai-ipc.js.map +1 -1
  4. package/out/main/common/power-logs-limits.js +227 -0
  5. package/out/main/common/power-logs-limits.js.map +1 -0
  6. package/out/main/common/power-logs.js +32 -0
  7. package/out/main/common/power-logs.js.map +1 -0
  8. package/out/main/common/store/logs-preferences-store.js +45 -0
  9. package/out/main/common/store/logs-preferences-store.js.map +1 -0
  10. package/out/main/dashboard-icon-cache.js +1 -1
  11. package/out/main/index.js +4 -0
  12. package/out/main/index.js.map +1 -1
  13. package/out/main/power-logs-budget.js +126 -0
  14. package/out/main/power-logs-budget.js.map +1 -0
  15. package/out/main/power-logs-child.js +86 -0
  16. package/out/main/power-logs-child.js.map +1 -0
  17. package/out/main/power-logs-database.js +179 -0
  18. package/out/main/power-logs-database.js.map +1 -0
  19. package/out/main/power-logs-ipc.js +275 -0
  20. package/out/main/power-logs-ipc.js.map +1 -0
  21. package/out/main/power-logs-query-child.js +23 -0
  22. package/out/main/power-logs-query-child.js.map +1 -0
  23. package/out/main/power-logs-query.js +127 -0
  24. package/out/main/power-logs-query.js.map +1 -0
  25. package/out/main/power-logs-worker.js +215 -0
  26. package/out/main/power-logs-worker.js.map +1 -0
  27. package/out/main/resource-search.js +1 -1
  28. package/out/renderer/ai-logs-sql.js +27 -0
  29. package/out/renderer/ai-logs-sql.js.map +1 -0
  30. package/out/renderer/ai-message.js +48 -27
  31. package/out/renderer/ai-message.js.map +1 -1
  32. package/out/renderer/ai-terminal-context.js +50 -40
  33. package/out/renderer/ai-terminal-context.js.map +1 -1
  34. package/out/renderer/ai.js +15 -2
  35. package/out/renderer/ai.js.map +1 -1
  36. package/out/renderer/appearance.js +1 -0
  37. package/out/renderer/appearance.js.map +1 -1
  38. package/out/renderer/index.js +67 -29
  39. package/out/renderer/index.js.map +1 -1
  40. package/out/renderer/power-log-json.js +29 -0
  41. package/out/renderer/power-log-json.js.map +1 -0
  42. package/out/renderer/power-logs-client.js +35 -0
  43. package/out/renderer/power-logs-client.js.map +1 -0
  44. package/out/renderer/power-logs-collector.js +316 -0
  45. package/out/renderer/power-logs-collector.js.map +1 -0
  46. package/out/renderer/power-logs-entrypoints.js +201 -0
  47. package/out/renderer/power-logs-entrypoints.js.map +1 -0
  48. package/out/renderer/power-logs-sql-row.js +52 -0
  49. package/out/renderer/power-logs-sql-row.js.map +1 -0
  50. package/out/renderer/power-logs-transport.js +122 -0
  51. package/out/renderer/power-logs-transport.js.map +1 -0
  52. package/out/renderer/power-logs.css.js +116 -0
  53. package/out/renderer/power-logs.css.js.map +1 -0
  54. package/out/renderer/power-logs.js +1352 -0
  55. package/out/renderer/power-logs.js.map +1 -0
  56. package/out/renderer/preferences/logs-preferences.js +93 -0
  57. package/out/renderer/preferences/logs-preferences.js.map +1 -0
  58. package/out/renderer/preferences/preferences.js +23 -9
  59. package/out/renderer/preferences/preferences.js.map +1 -1
  60. package/out/renderer/resource-relationships.js +1 -1
  61. package/out/renderer/src/common/power-log-parser.js +114 -0
  62. package/out/renderer/src/common/power-log-parser.js.map +1 -0
  63. package/out/renderer/src/common/power-logs-ai.js +56 -0
  64. package/out/renderer/src/common/power-logs-ai.js.map +1 -0
  65. package/out/renderer/src/common/power-logs-limits.js +227 -0
  66. package/out/renderer/src/common/power-logs-limits.js.map +1 -0
  67. package/out/renderer/src/common/power-logs.js +32 -0
  68. package/out/renderer/src/common/power-logs.js.map +1 -0
  69. package/out/renderer/src/common/store/logs-preferences-store.js +45 -0
  70. package/out/renderer/src/common/store/logs-preferences-store.js.map +1 -0
  71. package/package.json +4 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-logs-collector.js","names":[],"sources":["../../src/renderer/power-logs-collector.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { LogLineDecoder, parseLogLine } from \"../common/power-log-parser\";\nimport { type LogRecord, type LogSource, type LogTarget, POWER_LOGS_LIMITS } from \"../common/power-logs\";\nexport type LogQuery = Record<string, string | number | boolean>;\nexport interface PowerLogsTransport {\n get<T>(path: string, query?: LogQuery, signal?: AbortSignal): Promise<T>;\n stream(path: string, query: LogQuery, signal?: AbortSignal, onOpen?: () => void): AsyncIterable<Uint8Array | string>;\n}\ninterface ObjectMetadata {\n name?: string;\n namespace?: string;\n uid?: string;\n ownerReferences?: { uid: string; controller?: boolean }[];\n}\ninterface Resource {\n metadata?: ObjectMetadata;\n spec?: { containers?: { name: string }[]; initContainers?: { name: string }[] };\n}\nconst resources = {\n Pod: [\"/api/v1\", \"pods\"],\n Deployment: [\"/apis/apps/v1\", \"deployments\"],\n ReplicaSet: [\"/apis/apps/v1\", \"replicasets\"],\n DaemonSet: [\"/apis/apps/v1\", \"daemonsets\"],\n StatefulSet: [\"/apis/apps/v1\", \"statefulsets\"],\n Job: [\"/apis/batch/v1\", \"jobs\"],\n CronJob: [\"/apis/batch/v1\", \"cronjobs\"],\n};\nconst pathFor = (kind: LogTarget[\"kind\"], namespace: string) =>\n `${resources[kind][0]}/namespaces/${encodeURIComponent(namespace)}/${resources[kind][1]}`;\nconst canceled = () => new Error(\"Log collection canceled\");\nfunction check(signal?: AbortSignal) {\n if (signal?.aborted) throw canceled();\n}\nasync function delay(ms: number, signal?: AbortSignal) {\n check(signal);\n await new Promise<void>((resolve, reject) => {\n const abort = () => {\n clearTimeout(timer);\n reject(canceled());\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", abort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", abort, { once: true });\n });\n}\nlet nextStart = 0;\nlet nextBytes = 0;\nasync function permit(signal?: AbortSignal) {\n const start = Math.max(Date.now(), nextStart);\n nextStart = start + 1000 / POWER_LOGS_LIMITS.requestsPerSecond;\n await delay(Math.max(0, start - Date.now()), signal);\n}\nasync function bytesPermit(bytes: number, signal?: AbortSignal) {\n const start = Math.max(Date.now(), nextBytes);\n nextBytes = start + (bytes / POWER_LOGS_LIMITS.bytesPerSecond) * 1000;\n await delay(Math.max(0, start - Date.now()), signal);\n}\nasync function request<T>(operation: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n for (let attempt = 0; ; attempt++) {\n await permit(signal);\n try {\n return await operation();\n } catch (error) {\n check(signal);\n const value = error as { status?: number; retryAfter?: string };\n if (attempt >= 2 || ![429, 503].includes(value.status ?? 0)) throw new Error(\"Log API request failed\");\n const seconds = Number(value.retryAfter);\n const wait = Number.isFinite(seconds) ? seconds * 1000 : Date.parse(value.retryAfter ?? \"\") - Date.now();\n await delay(Math.min(5000, Math.max(500, Number.isFinite(wait) ? wait : 1000)), signal);\n }\n }\n}\nexport async function resolveLogSources(\n target: LogTarget,\n transport: PowerLogsTransport,\n signal?: AbortSignal,\n): Promise<{ sources: LogSource[]; partial: boolean; notes: string[] }> {\n const root = await request(\n () =>\n transport.get<Resource>(\n `${pathFor(target.kind, target.namespace)}/${encodeURIComponent(target.name)}`,\n undefined,\n signal,\n ),\n signal,\n );\n if (root.metadata?.uid !== target.uid) throw new Error(\"The selected workload has changed\");\n const notes: string[] = [];\n async function list(kind: LogTarget[\"kind\"]): Promise<Resource[]> {\n const items: Resource[] = [];\n let continuation = \"\";\n const seen = new Set<string>();\n do {\n const page = await request(\n () =>\n transport.get<{ items?: Resource[]; metadata?: { continue?: string } }>(\n pathFor(kind, target.namespace),\n { limit: 200, ...(continuation ? { continue: continuation } : {}) },\n signal,\n ),\n signal,\n );\n items.push(...(page.items ?? []));\n continuation = page.metadata?.continue ?? \"\";\n if (continuation && seen.has(continuation)) throw new Error(\"Repeated resource page\");\n seen.add(continuation);\n if (items.length >= 10000 && continuation) {\n notes.push(\"Resource discovery reached its page budget\");\n break;\n }\n } while (continuation);\n return items;\n }\n let owners = new Set([target.uid]);\n const owned = (item: Resource) =>\n item.metadata?.ownerReferences?.some((owner) => owners.has(owner.uid) && owner.controller === true);\n if (target.kind === \"Deployment\" || target.kind === \"CronJob\") {\n const children = await list(target.kind === \"Deployment\" ? \"ReplicaSet\" : \"Job\");\n owners = new Set(children.filter(owned).flatMap((item) => (item.metadata?.uid ? [item.metadata.uid] : [])));\n }\n const pods = target.kind === \"Pod\" ? [root] : (await list(\"Pod\")).filter(owned);\n const sources: LogSource[] = [];\n for (const pod of pods) {\n if (\n !pod.metadata?.uid ||\n !pod.metadata.name ||\n (pod.metadata.namespace && pod.metadata.namespace !== target.namespace)\n )\n continue;\n for (const container of [...(pod.spec?.containers ?? []), ...(pod.spec?.initContainers ?? [])]) {\n if (sources.length >= POWER_LOGS_LIMITS.sources) {\n notes.push(`Only the first ${POWER_LOGS_LIMITS.sources} container sources are included`);\n return { sources, partial: true, notes };\n }\n sources.push({\n namespace: target.namespace,\n pod: pod.metadata.name,\n podUid: pod.metadata.uid,\n container: container.name,\n });\n }\n }\n return { sources, partial: notes.length > 0, notes };\n}\nexport interface CollectionOptions {\n onSourceActivity?(delta: number): void;\n initialRecords?: LogRecord[];\n signal?: AbortSignal;\n tailLines?: number;\n sinceSeconds?: number;\n limitBytes?: number;\n sinceTime?: string;\n onCoverage?(coverage: LiveLogCoverage): void;\n onRecords(records: LogRecord[]): void | Promise<void>;\n}\nlet historicalActive = 0;\nasync function historicalSlot(signal?: AbortSignal) {\n while (historicalActive >= POWER_LOGS_LIMITS.historyConcurrency) await delay(50, signal);\n check(signal);\n historicalActive++;\n}\nasync function consume(source: LogSource, transport: PowerLogsTransport, options: CollectionOptions, follow: boolean) {\n const podPath = `/api/v1/namespaces/${encodeURIComponent(source.namespace)}/pods/${encodeURIComponent(source.pod)}`;\n const pod = await request(() => transport.get<Resource>(podPath, undefined, options.signal), options.signal);\n if (pod.metadata?.uid !== source.podUid) throw new Error(\"The container source has changed\");\n const decoder = new LogLineDecoder();\n let bytes = 0;\n let lineCount = 0;\n const query: LogQuery = {\n container: source.container,\n timestamps: true,\n follow,\n tailLines: Math.max(\n 1,\n Math.min(\n Math.max(POWER_LOGS_LIMITS.historyLines, POWER_LOGS_LIMITS.captureSourceLines),\n options.tailLines ?? POWER_LOGS_LIMITS.historyLines,\n ),\n ),\n ...(!follow\n ? {\n limitBytes: Math.max(\n 1,\n Math.min(\n Math.max(POWER_LOGS_LIMITS.historyBytes, POWER_LOGS_LIMITS.captureSourceBytes),\n options.limitBytes ?? POWER_LOGS_LIMITS.historyBytes,\n ),\n ),\n }\n : {}),\n ...(source.previous ? { previous: true } : {}),\n ...(options.sinceTime\n ? { sinceTime: options.sinceTime }\n : options.sinceSeconds\n ? { sinceSeconds: options.sinceSeconds }\n : {}),\n };\n const path = `/api/v1/namespaces/${encodeURIComponent(source.namespace)}/pods/${encodeURIComponent(source.pod)}/log`;\n let started = false;\n let opened = false;\n try {\n await request(async () => {\n try {\n for await (const chunk of transport.stream(path, query, options.signal, () => {\n if (!opened) {\n opened = true;\n options.onSourceActivity?.(1);\n }\n })) {\n started = true;\n check(options.signal);\n const size = typeof chunk === \"string\" ? Buffer.byteLength(chunk) : chunk.byteLength;\n bytes += size;\n if (!follow && bytes > Number(query.limitBytes)) return;\n await bytesPermit(size, options.signal);\n const records = decoder.push(chunk).map((line) => parseLogLine(line, source));\n lineCount += records.length;\n if (records.length) await options.onRecords(records);\n }\n } catch (error) {\n if (started) throw new Error(\"Container log stream interrupted\");\n throw error;\n }\n const final = decoder.push(new Uint8Array(), true).map((line) => parseLogLine(line, source));\n lineCount += final.length;\n if (final.length) await options.onRecords(final);\n }, options.signal);\n } finally {\n if (opened) options.onSourceActivity?.(-1);\n }\n return (\n decoder.truncated ||\n (!follow && (bytes >= Number(query.limitBytes) || lineCount >= Number(query.tailLines))) ||\n (follow && started)\n );\n}\nexport async function collectHistoricalLogs(\n sources: LogSource[],\n transport: PowerLogsTransport,\n options: CollectionOptions,\n): Promise<{ partial: boolean; notes: string[] }> {\n const notes: string[] = [];\n let next = 0;\n await Promise.all(\n Array.from({ length: Math.min(POWER_LOGS_LIMITS.historyConcurrency, sources.length) }, async () => {\n while (next < sources.length) {\n const source = sources[next++];\n await historicalSlot(options.signal);\n try {\n if (await consume(source, transport, options, false))\n notes.push(\"Some source logs reached a collection limit\");\n } catch {\n check(options.signal);\n notes.push(\"A container log source was unavailable\");\n } finally {\n historicalActive--;\n }\n }\n }),\n );\n return { partial: notes.length > 0, notes: [...new Set(notes)] };\n}\nexport interface LiveLogCoverage {\n active: number;\n total: number;\n partial: boolean;\n notes: string[];\n}\nexport function startLiveLogs(sources: LogSource[], transport: PowerLogsTransport, options: CollectionOptions) {\n const controller = new AbortController();\n const stop = () => controller.abort();\n options.signal?.addEventListener(\"abort\", stop, { once: true });\n if (options.signal?.aborted) stop();\n const coverage: LiveLogCoverage = {\n active: 0,\n total: sources.length,\n partial: sources.length > POWER_LOGS_LIMITS.liveConcurrency,\n notes:\n sources.length > POWER_LOGS_LIMITS.liveConcurrency\n ? [\"All sources are polled in rotation; live coverage is delayed and bounded tails can omit busy-source logs\"]\n : [],\n };\n const notify = () => options.onCoverage?.({ ...coverage, notes: [...coverage.notes] });\n const note = (message: string) => {\n coverage.partial = true;\n if (!coverage.notes.includes(message)) coverage.notes.push(message);\n notify();\n };\n notify();\n const seen = new Map<string, true>();\n const cursors = new Map<string, number>();\n const sourceKey = (source: Pick<LogSource, \"podUid\" | \"container\" | \"previous\">) =>\n `${source.podUid}/${source.container}/${Boolean(source.previous)}`;\n const recordKey = (record: LogRecord) => {\n const projected = {\n timestamp: record.timestamp,\n pod: record.pod,\n podUid: record.podUid,\n container: record.container,\n level: record.level,\n message: record.message,\n fieldsJson: record.fieldsJson,\n previous: record.previous === true,\n };\n return createHash(\"sha256\").update(sourceKey(record)).update(JSON.stringify(projected)).digest(\"hex\");\n };\n const initialCounts = new Map<string, number>();\n for (const record of (options.initialRecords ?? []).slice(-POWER_LOGS_LIMITS.liveRows)) {\n const digest = recordKey(record),\n occurrence = (initialCounts.get(digest) ?? 0) + 1;\n initialCounts.set(digest, occurrence);\n seen.set(`${digest}/${occurrence}`, true);\n if (record.timestamp !== null)\n cursors.set(sourceKey(record), Math.max(cursors.get(sourceKey(record)) ?? 0, record.timestamp));\n }\n async function collect(source: LogSource, follow: boolean) {\n const key = sourceKey(source);\n const counts = new Map<string, number>();\n const cursor = cursors.get(key);\n return consume(\n source,\n transport,\n {\n ...options,\n signal: controller.signal,\n onSourceActivity: (delta) => {\n coverage.active = Math.max(0, coverage.active + delta);\n notify();\n },\n ...(cursor !== undefined ? { sinceTime: new Date(cursor).toISOString() } : {}),\n onRecords: async (records) => {\n const fresh: LogRecord[] = [];\n for (const record of records) {\n const digest = recordKey(record);\n const occurrence = (counts.get(digest) ?? 0) + 1;\n counts.set(digest, occurrence);\n const identity = `${digest}/${occurrence}`;\n if (!seen.has(identity)) {\n fresh.push(record);\n seen.set(identity, true);\n }\n if (record.timestamp !== null) cursors.set(key, Math.max(cursors.get(key) ?? 0, record.timestamp));\n while (seen.size > POWER_LOGS_LIMITS.liveRows) seen.delete(seen.keys().next().value!);\n if (counts.size > POWER_LOGS_LIMITS.liveRows) counts.delete(counts.keys().next().value!);\n }\n if (fresh.length) await options.onRecords(fresh);\n },\n },\n follow,\n );\n }\n const done = (async () => {\n if (sources.length > POWER_LOGS_LIMITS.liveConcurrency) {\n while (!controller.signal.aborted) {\n let next = 0;\n await Promise.all(\n Array.from({ length: POWER_LOGS_LIMITS.historyConcurrency }, async () => {\n while (next < sources.length && !controller.signal.aborted) {\n const source = sources[next++];\n await historicalSlot(controller.signal);\n try {\n if (await collect(source, false)) note(\"Some live polling tails reached their byte or line budget\");\n } catch {\n if (!controller.signal.aborted) note(\"A live container log source was unavailable\");\n } finally {\n historicalActive--;\n }\n }\n }),\n );\n await delay(5000, controller.signal);\n }\n } else {\n await Promise.all(\n sources.map(async (source) => {\n while (!controller.signal.aborted) {\n try {\n await collect(source, true);\n if (!controller.signal.aborted) note(\"A live source disconnected and is reconnecting\");\n } catch {\n if (!controller.signal.aborted) note(\"A live container log source was unavailable and is reconnecting\");\n }\n await delay(5000, controller.signal);\n }\n }),\n );\n }\n })()\n .catch(() => {\n if (!controller.signal.aborted) note(\"Live collection stopped unexpectedly\");\n })\n .finally(() => {\n options.signal?.removeEventListener(\"abort\", stop);\n coverage.active = 0;\n notify();\n });\n return { stop, coverage, done };\n}\n"],"mappings":"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"}
@@ -0,0 +1,201 @@
1
+ const require_extensions = require("./_virtual/_global-external_@freelensapp/extensions.js");
2
+ const require__global_external_mobx = require("./_virtual/_global-external_mobx.js");
3
+ const require__global_external_mobx_react = require("./_virtual/_global-external_mobx-react.js");
4
+ const require_extension_info = require("./src/common/extension-info.js");
5
+ const require_logs_preferences_store = require("./src/common/store/logs-preferences-store.js");
6
+ const require_power_preferences_store = require("./src/common/store/power-preferences-store.js");
7
+ const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
8
+ //#region src/renderer/power-logs-entrypoints.tsx
9
+ var kinds = /* @__PURE__ */ new Set([
10
+ "Pod",
11
+ "Deployment",
12
+ "DaemonSet",
13
+ "StatefulSet",
14
+ "ReplicaSet",
15
+ "Job",
16
+ "CronJob"
17
+ ]);
18
+ var marker = "data-power-logs-target";
19
+ function enabled() {
20
+ const clusterId = require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid;
21
+ return Boolean(clusterId && window.location.protocol === "https:" && window.location.hostname === `${clusterId}.renderer.freelens.app` && require_logs_preferences_store.LogsPreferencesStore.getInstanceOrCreate().enabled && require_power_preferences_store.PowerPreferencesStore.getInstanceOrCreate().enabled);
22
+ }
23
+ function parsePowerLogsTarget(value) {
24
+ if (!value || typeof value !== "object") return;
25
+ const target = value;
26
+ if (!kinds.has(target.kind) || ![
27
+ target.name,
28
+ target.namespace,
29
+ target.uid
30
+ ].every((part) => typeof part === "string" && part.length > 0 && part.length <= 253 && /^[a-zA-Z0-9_.-]+$/.test(part))) return;
31
+ return {
32
+ kind: target.kind,
33
+ namespace: target.namespace,
34
+ name: target.name,
35
+ uid: target.uid
36
+ };
37
+ }
38
+ function openPowerLogs(target, container) {
39
+ const valid = parsePowerLogsTarget(target);
40
+ if (!valid || !enabled()) return;
41
+ if (container !== void 0 && !/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(container)) return;
42
+ if (container && container.length > 63) return;
43
+ require_extensions.Renderer.Navigation.navigate(`/extension/${require_extension_info.EXTENSION_ID}/power-logs?target=${encodeURIComponent(JSON.stringify(valid))}${container ? `&container=${encodeURIComponent(container)}` : ""}`);
44
+ window.dispatchEvent(new CustomEvent("power-logs-target", { detail: {
45
+ ...valid,
46
+ container
47
+ } }));
48
+ require_extensions.Renderer.Navigation.hideDetails();
49
+ }
50
+ function cachedWorkloadPods(target) {
51
+ const owners = /* @__PURE__ */ new Set([target.uid]);
52
+ const intermediates = target.kind === "Deployment" ? require_extensions.Renderer.K8sApi.replicaSetStore?.items : target.kind === "CronJob" ? require_extensions.Renderer.K8sApi.jobStore?.items : [];
53
+ for (const object of intermediates ?? []) if (object.metadata.namespace === target.namespace && object.metadata.uid && object.metadata.ownerReferences?.some((owner) => owner.controller === true && owner.uid === target.uid)) owners.add(object.metadata.uid);
54
+ return require_extensions.Renderer.K8sApi.podsStore.items.filter((pod) => pod.metadata.namespace === target.namespace && pod.metadata.ownerReferences?.some((owner) => owner.controller === true && owners.has(owner.uid)));
55
+ }
56
+ function containerStatusClass(container, status) {
57
+ const state = Object.keys(status.state ?? {})[0] ?? "";
58
+ const lastState = Object.keys(status.lastState ?? {})[0];
59
+ if (state === "terminated" || container.type === "ephemeralContainers" && lastState === "terminated") return "terminated";
60
+ if (container.type === "ephemeralContainers") return "container-ephemeral";
61
+ if (status.ready) return status.restartCount > 0 ? "restarted" : "running";
62
+ return state === "running" ? "waiting" : state;
63
+ }
64
+ var PowerLogsMenu = require__global_external_mobx_react.observer(({ object, toolbar }) => {
65
+ if (!enabled()) return null;
66
+ const target = parsePowerLogsTarget({
67
+ kind: object.kind,
68
+ name: object.metadata.name,
69
+ namespace: object.metadata.namespace,
70
+ uid: object.metadata.uid
71
+ });
72
+ if (!target) return null;
73
+ const containers = target.kind === "Pod" ? object.getAllContainersWithType() : [];
74
+ const statuses = target.kind === "Pod" ? object.getContainerStatuses?.() ?? [] : [];
75
+ const pods = target.kind === "Pod" ? [] : cachedWorkloadPods(target);
76
+ const open = (event, container) => {
77
+ event.stopPropagation();
78
+ openPowerLogs(target, container);
79
+ };
80
+ return /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.MenuItem, {
81
+ onClick: (event) => open(event),
82
+ children: [
83
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
84
+ material: "subject",
85
+ interactive: toolbar,
86
+ tooltip: "Power Logs"
87
+ }),
88
+ /* @__PURE__ */ require_jsx_runtime.jsx("span", {
89
+ className: "title",
90
+ [marker]: JSON.stringify(target),
91
+ children: "Logs"
92
+ }),
93
+ (containers.length > 0 || pods.length > 0) && /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
94
+ className: "arrow",
95
+ material: "keyboard_arrow_right"
96
+ }), /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.SubMenu, { children: [
97
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.MenuItem, {
98
+ onClick: (event) => open(event),
99
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: target.kind === "Pod" ? "All containers" : "All pods" })
100
+ }),
101
+ containers.map((container) => /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.MenuItem, {
102
+ onClick: (event) => open(event, container.name),
103
+ children: [statuses.filter((status) => status.name === container.name).map((status) => /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.StatusBrick, { className: containerStatusClass(container, status) }, status.name)), /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: container.name })]
104
+ }, container.name)),
105
+ pods.map((pod) => {
106
+ const status = pod.getStatus();
107
+ return /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.MenuItem, {
108
+ onClick: (event) => {
109
+ event.stopPropagation();
110
+ openPowerLogs({
111
+ kind: "Pod",
112
+ name: pod.getName(),
113
+ namespace: pod.getNs(),
114
+ uid: pod.metadata.uid ?? ""
115
+ });
116
+ },
117
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.StatusBrick, {
118
+ className: status.toLowerCase().replaceAll(" ", "-"),
119
+ title: status
120
+ }), /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: pod.getName() })]
121
+ }, pod.metadata.uid);
122
+ })
123
+ ] })] })
124
+ ]
125
+ });
126
+ });
127
+ function startPowerLogsEntrypoints() {
128
+ const hidden = /* @__PURE__ */ new Map();
129
+ let stopped = false;
130
+ const restore = (element) => {
131
+ const original = hidden.get(element);
132
+ if (!original) return;
133
+ element.style.setProperty("display", original.value, original.priority);
134
+ if (!original.value) element.style.removeProperty("display");
135
+ hidden.delete(element);
136
+ };
137
+ const synchronize = () => {
138
+ const active = !stopped && enabled();
139
+ for (const [element, state] of hidden) if (!active || !state.replacement.isConnected || !element.isConnected) restore(element);
140
+ if (!active) return;
141
+ for (const label of document.querySelectorAll(`[${marker}]`)) {
142
+ const replacement = label.closest(".MenuItem");
143
+ if (!replacement?.parentElement) continue;
144
+ for (const sibling of replacement.parentElement.children) {
145
+ if (!(sibling instanceof HTMLElement) || sibling === replacement || !sibling.matches(".MenuItem") || sibling.querySelector(`[${marker}]`)) continue;
146
+ const title = sibling.querySelector(":scope > .title");
147
+ const icon = sibling.querySelector(":scope > .Icon");
148
+ if (title?.textContent?.trim() !== "Logs" || icon?.textContent?.trim() !== "subject") continue;
149
+ if (!hidden.has(sibling)) hidden.set(sibling, {
150
+ value: sibling.style.getPropertyValue("display"),
151
+ priority: sibling.style.getPropertyPriority("display"),
152
+ replacement
153
+ });
154
+ if (sibling.style.display !== "none") sibling.style.setProperty("display", "none");
155
+ }
156
+ }
157
+ };
158
+ const click = (event) => {
159
+ if (!enabled() || !(event.target instanceof Element)) return;
160
+ const icon = event.target.closest(".Icon");
161
+ if (!icon || icon.textContent?.trim() !== "subject" || !icon.closest(".TableCell.logs")) return;
162
+ const row = icon.closest(".TableRow");
163
+ if (!row || !/^\/pods\/?$/.test(window.location.pathname)) return;
164
+ const name = row.querySelector(".TableCell.name")?.textContent?.trim();
165
+ const namespace = row.querySelector(".TableCell.namespace")?.textContent?.trim();
166
+ if (!name || !namespace) return;
167
+ const matches = require_extensions.Renderer.K8sApi.podsStore.items.filter((pod) => pod.getName() === name && pod.getNs() === namespace);
168
+ if (matches.length !== 1 || !matches[0].getAllContainers().length) return;
169
+ const target = parsePowerLogsTarget({
170
+ kind: "Pod",
171
+ name,
172
+ namespace,
173
+ uid: matches[0].metadata.uid
174
+ });
175
+ if (!target) return;
176
+ event.preventDefault();
177
+ event.stopImmediatePropagation();
178
+ openPowerLogs(target);
179
+ };
180
+ const observer = new MutationObserver(synchronize);
181
+ observer.observe(document.body, {
182
+ childList: true,
183
+ subtree: true
184
+ });
185
+ document.addEventListener("click", click, true);
186
+ const stopReaction = require__global_external_mobx.reaction(enabled, synchronize, { fireImmediately: true });
187
+ return () => {
188
+ stopped = true;
189
+ observer.disconnect();
190
+ stopReaction();
191
+ document.removeEventListener("click", click, true);
192
+ for (const element of hidden.keys()) restore(element);
193
+ };
194
+ }
195
+ //#endregion
196
+ exports.PowerLogsMenu = PowerLogsMenu;
197
+ exports.openPowerLogs = openPowerLogs;
198
+ exports.parsePowerLogsTarget = parsePowerLogsTarget;
199
+ exports.startPowerLogsEntrypoints = startPowerLogsEntrypoints;
200
+
201
+ //# sourceMappingURL=power-logs-entrypoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-logs-entrypoints.js","names":[],"sources":["../../src/renderer/power-logs-entrypoints.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { reaction } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { EXTENSION_ID } from \"../common/extension-info\";\nimport { LogsPreferencesStore } from \"../common/store/logs-preferences-store\";\nimport { PowerPreferencesStore } from \"../common/store/power-preferences-store\";\n\nimport type { LogTarget, LogWorkloadKind } from \"../common/power-logs\";\n\nconst kinds = new Set<string>([\"Pod\", \"Deployment\", \"DaemonSet\", \"StatefulSet\", \"ReplicaSet\", \"Job\", \"CronJob\"]);\nconst marker = \"data-power-logs-target\";\n\nfunction enabled(): boolean {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n return Boolean(\n clusterId &&\n window.location.protocol === \"https:\" &&\n window.location.hostname === `${clusterId}.renderer.freelens.app` &&\n LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>().enabled &&\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled,\n );\n}\n\nexport function parsePowerLogsTarget(value: unknown): LogTarget | undefined {\n if (!value || typeof value !== \"object\") return;\n const target = value as LogTarget;\n if (\n !kinds.has(target.kind) ||\n ![target.name, target.namespace, target.uid].every(\n (part) => typeof part === \"string\" && part.length > 0 && part.length <= 253 && /^[a-zA-Z0-9_.-]+$/.test(part),\n )\n )\n return;\n return { kind: target.kind, namespace: target.namespace, name: target.name, uid: target.uid };\n}\n\nexport function openPowerLogs(target: LogTarget, container?: string): void {\n const valid = parsePowerLogsTarget(target);\n if (!valid || !enabled()) return;\n if (container !== undefined && !/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(container)) return;\n if (container && container.length > 63) return;\n Renderer.Navigation.navigate(\n `/extension/${EXTENSION_ID}/power-logs?target=${encodeURIComponent(JSON.stringify(valid))}${container ? `&container=${encodeURIComponent(container)}` : \"\"}`,\n );\n window.dispatchEvent(new CustomEvent(\"power-logs-target\", { detail: { ...valid, container } }));\n Renderer.Navigation.hideDetails();\n}\n\nfunction cachedWorkloadPods(target: LogTarget): Renderer.K8sApi.Pod[] {\n const owners = new Set([target.uid]);\n const intermediates =\n target.kind === \"Deployment\"\n ? Renderer.K8sApi.replicaSetStore?.items\n : target.kind === \"CronJob\"\n ? Renderer.K8sApi.jobStore?.items\n : [];\n for (const object of intermediates ?? []) {\n if (\n object.metadata.namespace === target.namespace &&\n object.metadata.uid &&\n object.metadata.ownerReferences?.some((owner) => owner.controller === true && owner.uid === target.uid)\n )\n owners.add(object.metadata.uid);\n }\n return Renderer.K8sApi.podsStore.items.filter(\n (pod) =>\n pod.metadata.namespace === target.namespace &&\n pod.metadata.ownerReferences?.some((owner) => owner.controller === true && owners.has(owner.uid)),\n );\n}\n\nfunction containerStatusClass(\n container: { type?: string },\n status: ReturnType<Renderer.K8sApi.Pod[\"getContainerStatuses\"]>[number],\n): string {\n const state = Object.keys(status.state ?? {})[0] ?? \"\";\n const lastState = Object.keys(status.lastState ?? {})[0];\n if (state === \"terminated\" || (container.type === \"ephemeralContainers\" && lastState === \"terminated\"))\n return \"terminated\";\n if (container.type === \"ephemeralContainers\") return \"container-ephemeral\";\n if (status.ready) return status.restartCount > 0 ? \"restarted\" : \"running\";\n return state === \"running\" ? \"waiting\" : state;\n}\n\nexport const PowerLogsMenu = observer(\n ({ object, toolbar }: Renderer.Component.KubeObjectMenuProps<Renderer.K8sApi.KubeObject>) => {\n if (!enabled()) return null;\n const target = parsePowerLogsTarget({\n kind: object.kind as LogWorkloadKind,\n name: object.metadata.name,\n namespace: object.metadata.namespace,\n uid: object.metadata.uid,\n });\n if (!target) return null;\n const containers = target.kind === \"Pod\" ? (object as Renderer.K8sApi.Pod).getAllContainersWithType() : [];\n const statuses = target.kind === \"Pod\" ? ((object as Renderer.K8sApi.Pod).getContainerStatuses?.() ?? []) : [];\n const pods = target.kind === \"Pod\" ? [] : cachedWorkloadPods(target);\n const open = (event: React.MouseEvent, container?: string) => {\n event.stopPropagation();\n openPowerLogs(target, container);\n };\n return (\n <Renderer.Component.MenuItem onClick={(event) => open(event)}>\n <Renderer.Component.Icon material=\"subject\" interactive={toolbar} tooltip=\"Power Logs\" />\n <span className=\"title\" {...{ [marker]: JSON.stringify(target) }}>\n Logs\n </span>\n {(containers.length > 0 || pods.length > 0) && (\n <>\n <Renderer.Component.Icon className=\"arrow\" material=\"keyboard_arrow_right\" />\n <Renderer.Component.SubMenu>\n <Renderer.Component.MenuItem onClick={(event) => open(event)}>\n <span>{target.kind === \"Pod\" ? \"All containers\" : \"All pods\"}</span>\n </Renderer.Component.MenuItem>\n {containers.map((container) => (\n <Renderer.Component.MenuItem key={container.name} onClick={(event) => open(event, container.name)}>\n {statuses\n .filter((status) => status.name === container.name)\n .map((status) => (\n <Renderer.Component.StatusBrick\n key={status.name}\n className={containerStatusClass(container, status)}\n />\n ))}\n <span>{container.name}</span>\n </Renderer.Component.MenuItem>\n ))}\n {pods.map((pod) => {\n const status = pod.getStatus();\n return (\n <Renderer.Component.MenuItem\n key={pod.metadata.uid}\n onClick={(event) => {\n event.stopPropagation();\n openPowerLogs({\n kind: \"Pod\",\n name: pod.getName(),\n namespace: pod.getNs(),\n uid: pod.metadata.uid ?? \"\",\n });\n }}\n >\n <Renderer.Component.StatusBrick\n className={status.toLowerCase().replaceAll(\" \", \"-\")}\n title={status}\n />\n <span>{pod.getName()}</span>\n </Renderer.Component.MenuItem>\n );\n })}\n </Renderer.Component.SubMenu>\n </>\n )}\n </Renderer.Component.MenuItem>\n );\n },\n);\n\nexport function startPowerLogsEntrypoints(): () => void {\n const hidden = new Map<HTMLElement, { value: string; priority: string; replacement: HTMLElement }>();\n let stopped = false;\n const restore = (element: HTMLElement) => {\n const original = hidden.get(element);\n if (!original) return;\n element.style.setProperty(\"display\", original.value, original.priority);\n if (!original.value) element.style.removeProperty(\"display\");\n hidden.delete(element);\n };\n const synchronize = () => {\n const active = !stopped && enabled();\n for (const [element, state] of hidden) {\n if (!active || !state.replacement.isConnected || !element.isConnected) restore(element);\n }\n if (!active) return;\n for (const label of document.querySelectorAll<HTMLElement>(`[${marker}]`)) {\n const replacement = label.closest<HTMLElement>(\".MenuItem\");\n if (!replacement?.parentElement) continue;\n for (const sibling of replacement.parentElement.children) {\n if (\n !(sibling instanceof HTMLElement) ||\n sibling === replacement ||\n !sibling.matches(\".MenuItem\") ||\n sibling.querySelector(`[${marker}]`)\n )\n continue;\n const title = sibling.querySelector(\":scope > .title\");\n const icon = sibling.querySelector(\":scope > .Icon\");\n if (title?.textContent?.trim() !== \"Logs\" || icon?.textContent?.trim() !== \"subject\") continue;\n if (!hidden.has(sibling))\n hidden.set(sibling, {\n value: sibling.style.getPropertyValue(\"display\"),\n priority: sibling.style.getPropertyPriority(\"display\"),\n replacement,\n });\n if (sibling.style.display !== \"none\") sibling.style.setProperty(\"display\", \"none\");\n }\n }\n };\n const click = (event: MouseEvent) => {\n if (!enabled() || !(event.target instanceof Element)) return;\n const icon = event.target.closest(\".Icon\");\n if (!icon || icon.textContent?.trim() !== \"subject\" || !icon.closest(\".TableCell.logs\")) return;\n const row = icon.closest(\".TableRow\");\n if (!row || !/^\\/pods\\/?$/.test(window.location.pathname)) return;\n const name = row.querySelector(\".TableCell.name\")?.textContent?.trim();\n const namespace = row.querySelector(\".TableCell.namespace\")?.textContent?.trim();\n if (!name || !namespace) return;\n const matches = Renderer.K8sApi.podsStore.items.filter(\n (pod) => pod.getName() === name && pod.getNs() === namespace,\n );\n if (matches.length !== 1 || !matches[0].getAllContainers().length) return;\n const target = parsePowerLogsTarget({ kind: \"Pod\", name, namespace, uid: matches[0].metadata.uid });\n if (!target) return;\n event.preventDefault();\n event.stopImmediatePropagation();\n openPowerLogs(target);\n };\n const observer = new MutationObserver(synchronize);\n observer.observe(document.body, { childList: true, subtree: true });\n document.addEventListener(\"click\", click, true);\n const stopReaction = reaction(enabled, synchronize, { fireImmediately: true });\n return () => {\n stopped = true;\n observer.disconnect();\n stopReaction();\n document.removeEventListener(\"click\", click, true);\n for (const element of hidden.keys()) restore(element);\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ //#region src/renderer/power-logs-sql-row.ts
2
+ var levels = /* @__PURE__ */ new Set([
3
+ "trace",
4
+ "debug",
5
+ "info",
6
+ "warn",
7
+ "error",
8
+ "fatal",
9
+ "unknown"
10
+ ]);
11
+ function sqlRowDetails(columns, row) {
12
+ const cells = new Map(columns.map((column, index) => [column, row[index]]));
13
+ const stringCell = (name) => typeof cells.get(name) === "string" ? cells.get(name) : "";
14
+ let fieldsJson = null;
15
+ let jsonColumn;
16
+ let largestBytes = -1;
17
+ const encoder = new TextEncoder();
18
+ columns.forEach((column, index) => {
19
+ const value = row[index];
20
+ if (typeof value !== "string") return;
21
+ try {
22
+ const parsed = JSON.parse(value);
23
+ if (parsed === null || typeof parsed !== "object") return;
24
+ const bytes = encoder.encode(value).byteLength;
25
+ if (bytes > largestBytes) {
26
+ largestBytes = bytes;
27
+ fieldsJson = value;
28
+ jsonColumn = column;
29
+ }
30
+ } catch {}
31
+ });
32
+ const timestamp = cells.get("timestamp");
33
+ const level = stringCell("level");
34
+ const previous = cells.get("previous");
35
+ return {
36
+ record: {
37
+ timestamp: typeof timestamp === "number" && Number.isFinite(timestamp) ? timestamp : null,
38
+ pod: stringCell("pod"),
39
+ podUid: stringCell("podUid"),
40
+ container: stringCell("container"),
41
+ level: levels.has(level) ? level : "unknown",
42
+ message: fieldsJson === null ? JSON.stringify(Object.fromEntries(columns.map((column, index) => [column, row[index] ?? null])), null, 2) : stringCell("message"),
43
+ fieldsJson,
44
+ previous: previous === true || previous === 1
45
+ },
46
+ ...jsonColumn === void 0 ? {} : { jsonColumn }
47
+ };
48
+ }
49
+ //#endregion
50
+ exports.sqlRowDetails = sqlRowDetails;
51
+
52
+ //# sourceMappingURL=power-logs-sql-row.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-logs-sql-row.js","names":[],"sources":["../../src/renderer/power-logs-sql-row.ts"],"sourcesContent":["import type { LogCell, LogLevel, LogRecord } from \"../common/power-logs\";\n\nconst levels = new Set<LogLevel>([\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"unknown\"]);\n\nexport function sqlRowDetails(columns: string[], row: LogCell[]): { record: LogRecord; jsonColumn?: string } {\n const cells = new Map(columns.map((column, index) => [column, row[index]]));\n const stringCell = (name: string) => (typeof cells.get(name) === \"string\" ? (cells.get(name) as string) : \"\");\n let fieldsJson: string | null = null;\n let jsonColumn: string | undefined;\n let largestBytes = -1;\n const encoder = new TextEncoder();\n columns.forEach((column, index) => {\n const value = row[index];\n if (typeof value !== \"string\") return;\n try {\n const parsed: unknown = JSON.parse(value);\n if (parsed === null || typeof parsed !== \"object\") return;\n const bytes = encoder.encode(value).byteLength;\n if (bytes > largestBytes) {\n largestBytes = bytes;\n fieldsJson = value;\n jsonColumn = column;\n }\n } catch {\n // malformed JSON remains available in the row fallback\n }\n });\n const timestamp = cells.get(\"timestamp\");\n const level = stringCell(\"level\");\n const previous = cells.get(\"previous\");\n return {\n record: {\n timestamp: typeof timestamp === \"number\" && Number.isFinite(timestamp) ? timestamp : null,\n pod: stringCell(\"pod\"),\n podUid: stringCell(\"podUid\"),\n container: stringCell(\"container\"),\n level: levels.has(level as LogLevel) ? (level as LogLevel) : \"unknown\",\n message:\n fieldsJson === null\n ? JSON.stringify(Object.fromEntries(columns.map((column, index) => [column, row[index] ?? null])), null, 2)\n : stringCell(\"message\"),\n fieldsJson,\n previous: previous === true || previous === 1,\n },\n ...(jsonColumn === undefined ? {} : { jsonColumn }),\n };\n}\n"],"mappings":";AAEA,IAAM,yBAAS,IAAI,IAAc;CAAC;CAAS;CAAS;CAAQ;CAAQ;CAAS;CAAS;AAAS,CAAC;AAEhG,SAAgB,cAAc,SAAmB,KAA4D;CAC3G,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAK,QAAQ,UAAU,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC;CAC1E,MAAM,cAAc,SAAkB,OAAO,MAAM,IAAI,IAAI,MAAM,WAAY,MAAM,IAAI,IAAI,IAAe;CAC1G,IAAI,aAA4B;CAChC,IAAI;CACJ,IAAI,eAAe;CACnB,MAAM,UAAU,IAAI,YAAY;CAChC,QAAQ,SAAS,QAAQ,UAAU;EACjC,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,UAAU;EAC/B,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,KAAK;GACxC,IAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;GACnD,MAAM,QAAQ,QAAQ,OAAO,KAAK,CAAC,CAAC;GACpC,IAAI,QAAQ,cAAc;IACxB,eAAe;IACf,aAAa;IACb,aAAa;GACf;EACF,QAAQ,CAER;CACF,CAAC;CACD,MAAM,YAAY,MAAM,IAAI,WAAW;CACvC,MAAM,QAAQ,WAAW,OAAO;CAChC,MAAM,WAAW,MAAM,IAAI,UAAU;CACrC,OAAO;EACL,QAAQ;GACN,WAAW,OAAO,cAAc,YAAY,OAAO,SAAS,SAAS,IAAI,YAAY;GACrF,KAAK,WAAW,KAAK;GACrB,QAAQ,WAAW,QAAQ;GAC3B,WAAW,WAAW,WAAW;GACjC,OAAO,OAAO,IAAI,KAAiB,IAAK,QAAqB;GAC7D,SACE,eAAe,OACX,KAAK,UAAU,OAAO,YAAY,QAAQ,KAAK,QAAQ,UAAU,CAAC,QAAQ,IAAI,UAAU,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IACxG,WAAW,SAAS;GAC1B;GACA,UAAU,aAAa,QAAQ,aAAa;EAC9C;EACA,GAAI,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW;CACnD;AACF"}
@@ -0,0 +1,122 @@
1
+ const require_extensions = require("./_virtual/_global-external_@freelensapp/extensions.js");
2
+ const require_power_logs = require("./src/common/power-logs.js");
3
+ const require_resource_search_client = require("./resource-search-client.js");
4
+ let electron = require("electron");
5
+ let node_crypto = require("node:crypto");
6
+ //#region src/renderer/power-logs-transport.ts
7
+ function createPowerLogsTransport(clusterId) {
8
+ const host = window.location.host;
9
+ if (window.location.protocol !== "https:" || window.location.hostname !== `${clusterId}.renderer.freelens.app` || require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid !== clusterId) throw new Error("Log requests require the active cluster frame");
10
+ const api = require_extensions.Renderer.K8sApi.KubeJsonApi.forCluster.call(void 0, clusterId);
11
+ const contextId = require_resource_search_client.searchContextId();
12
+ const invoke = (fields) => electron.ipcRenderer.invoke(require_power_logs.POWER_LOGS_CHANNEL, {
13
+ ...fields,
14
+ clusterId,
15
+ contextId
16
+ });
17
+ const controlled = async (fields, signal) => {
18
+ if (signal.aborted) throw new Error("Log request canceled");
19
+ let abort;
20
+ const canceled = new Promise((_resolve, reject) => {
21
+ abort = () => reject(/* @__PURE__ */ new Error("Log request canceled"));
22
+ signal.addEventListener("abort", abort, { once: true });
23
+ });
24
+ try {
25
+ await Promise.race([invoke(fields), canceled]);
26
+ } finally {
27
+ signal.removeEventListener("abort", abort);
28
+ }
29
+ };
30
+ const stream = async function* (path, query, signal, onOpen) {
31
+ if (signal?.aborted) throw new Error("Log request canceled");
32
+ const controller = new AbortController();
33
+ const streamId = path.endsWith("/log") ? (0, node_crypto.randomUUID)() : void 0;
34
+ let renewal;
35
+ let body;
36
+ const abort = () => {
37
+ controller.abort();
38
+ body?.destroy();
39
+ };
40
+ signal?.addEventListener("abort", abort, { once: true });
41
+ const timeout = setTimeout(abort, query.follow ? 3600 * 1e3 : 3e4);
42
+ try {
43
+ if (streamId) {
44
+ await controlled({
45
+ operation: "stream-open",
46
+ streamId,
47
+ follow: query.follow === true
48
+ }, controller.signal);
49
+ renewal = setInterval(() => {
50
+ invoke({
51
+ operation: "stream-renew",
52
+ streamId
53
+ }).catch(abort);
54
+ }, 1e4);
55
+ }
56
+ await controlled({
57
+ operation: "permit",
58
+ lane: "start"
59
+ }, controller.signal);
60
+ if (controller.signal.aborted || require_resource_search_client.searchContextId() !== contextId || require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid !== clusterId) throw new Error("Log context changed");
61
+ const response = await api.getResponse(path, { query }, {
62
+ signal: controller.signal,
63
+ headers: { Host: host },
64
+ size: 8 * 1048576
65
+ });
66
+ body = response.body;
67
+ if (signal?.aborted) {
68
+ abort();
69
+ throw new Error("Log request canceled");
70
+ }
71
+ if (!response.ok) throw Object.assign(/* @__PURE__ */ new Error("Log API request failed"), {
72
+ status: response.status,
73
+ retryAfter: response.headers.get("retry-after")
74
+ });
75
+ onOpen?.();
76
+ if (response.body) for await (const chunk of response.body) {
77
+ if (signal?.aborted) throw new Error("Log request canceled");
78
+ for (let offset = 0; offset < chunk.byteLength; offset += require_power_logs.POWER_LOGS_LIMITS.batchBytes) {
79
+ const part = chunk.subarray(offset, offset + require_power_logs.POWER_LOGS_LIMITS.batchBytes);
80
+ await controlled({
81
+ operation: "permit",
82
+ lane: "bytes",
83
+ bytes: part.byteLength
84
+ }, controller.signal);
85
+ if (controller.signal.aborted || require_resource_search_client.searchContextId() !== contextId || require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid !== clusterId) throw new Error("Log context changed");
86
+ yield part;
87
+ }
88
+ }
89
+ } finally {
90
+ clearTimeout(timeout);
91
+ clearInterval(renewal);
92
+ if (streamId) invoke({
93
+ operation: "stream-close",
94
+ streamId
95
+ }).catch(() => {});
96
+ body?.destroy();
97
+ signal?.removeEventListener("abort", abort);
98
+ }
99
+ };
100
+ return {
101
+ stream,
102
+ async get(path, query, signal) {
103
+ const chunks = [];
104
+ let size = 0;
105
+ for await (const chunk of stream(path, query ?? {}, signal)) {
106
+ const buffer = Buffer.from(chunk);
107
+ size += buffer.length;
108
+ if (size > 8 * 1048576) throw new Error("Resource page exceeded the response budget");
109
+ chunks.push(buffer);
110
+ }
111
+ try {
112
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
113
+ } catch {
114
+ throw new Error("Resource response could not be parsed");
115
+ }
116
+ }
117
+ };
118
+ }
119
+ //#endregion
120
+ exports.createPowerLogsTransport = createPowerLogsTransport;
121
+
122
+ //# sourceMappingURL=power-logs-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-logs-transport.js","names":[],"sources":["../../src/renderer/power-logs-transport.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { POWER_LOGS_CHANNEL, POWER_LOGS_LIMITS } from \"../common/power-logs\";\nimport { searchContextId } from \"./resource-search-client\";\n\nimport type { PowerLogsTransport } from \"./power-logs-collector\";\nexport function createPowerLogsTransport(clusterId: string): PowerLogsTransport {\n const host = window.location.host;\n if (\n window.location.protocol !== \"https:\" ||\n window.location.hostname !== `${clusterId}.renderer.freelens.app` ||\n Renderer.Catalog.activeCluster.get()?.metadata.uid !== clusterId\n )\n throw new Error(\"Log requests require the active cluster frame\");\n const api = Renderer.K8sApi.KubeJsonApi.forCluster.call(undefined, clusterId);\n const contextId = searchContextId();\n const invoke = (fields: object) => ipcRenderer.invoke(POWER_LOGS_CHANNEL, { ...fields, clusterId, contextId });\n const controlled = async (fields: object, signal: AbortSignal) => {\n if (signal.aborted) throw new Error(\"Log request canceled\");\n let abort!: () => void;\n const canceled = new Promise<never>((_resolve, reject) => {\n abort = () => reject(new Error(\"Log request canceled\"));\n signal.addEventListener(\"abort\", abort, { once: true });\n });\n try {\n await Promise.race([invoke(fields), canceled]);\n } finally {\n signal.removeEventListener(\"abort\", abort);\n }\n };\n const stream: PowerLogsTransport[\"stream\"] = async function* (path, query, signal, onOpen) {\n if (signal?.aborted) throw new Error(\"Log request canceled\");\n const controller = new AbortController();\n const streamId = path.endsWith(\"/log\") ? randomUUID() : undefined;\n let renewal: ReturnType<typeof setInterval> | undefined;\n let body: { destroy(): void } | null | undefined;\n const abort = () => {\n controller.abort();\n body?.destroy();\n };\n signal?.addEventListener(\"abort\", abort, { once: true });\n const timeout = setTimeout(abort, query.follow ? 60 * 60 * 1000 : 30000);\n try {\n if (streamId) {\n await controlled({ operation: \"stream-open\", streamId, follow: query.follow === true }, controller.signal);\n renewal = setInterval(() => {\n void invoke({ operation: \"stream-renew\", streamId }).catch(abort);\n }, 10000);\n }\n await controlled({ operation: \"permit\", lane: \"start\" }, controller.signal);\n if (\n controller.signal.aborted ||\n searchContextId() !== contextId ||\n Renderer.Catalog.activeCluster.get()?.metadata.uid !== clusterId\n )\n throw new Error(\"Log context changed\");\n const response = await api.getResponse(\n path,\n { query },\n { signal: controller.signal, headers: { Host: host }, size: 8 * 1048576 },\n );\n body = response.body;\n if (signal?.aborted) {\n abort();\n throw new Error(\"Log request canceled\");\n }\n if (!response.ok)\n throw Object.assign(new Error(\"Log API request failed\"), {\n status: response.status,\n retryAfter: response.headers.get(\"retry-after\"),\n });\n onOpen?.();\n if (response.body)\n for await (const chunk of response.body as unknown as AsyncIterable<Uint8Array>) {\n if (signal?.aborted) throw new Error(\"Log request canceled\");\n for (let offset = 0; offset < chunk.byteLength; offset += POWER_LOGS_LIMITS.batchBytes) {\n const part = chunk.subarray(offset, offset + POWER_LOGS_LIMITS.batchBytes);\n await controlled({ operation: \"permit\", lane: \"bytes\", bytes: part.byteLength }, controller.signal);\n if (\n controller.signal.aborted ||\n searchContextId() !== contextId ||\n Renderer.Catalog.activeCluster.get()?.metadata.uid !== clusterId\n )\n throw new Error(\"Log context changed\");\n yield part;\n }\n }\n } finally {\n clearTimeout(timeout);\n clearInterval(renewal);\n if (streamId) void invoke({ operation: \"stream-close\", streamId }).catch(() => {});\n body?.destroy();\n signal?.removeEventListener(\"abort\", abort);\n }\n };\n return {\n stream,\n async get<T>(path, query, signal): Promise<T> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of stream(path, query ?? {}, signal)) {\n const buffer = Buffer.from(chunk);\n size += buffer.length;\n if (size > 8 * 1048576) throw new Error(\"Resource page exceeded the response budget\");\n chunks.push(buffer);\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString(\"utf8\")) as T;\n } catch {\n throw new Error(\"Resource response could not be parsed\");\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ //#region src/renderer/power-logs.css.ts
2
+ var powerLogsStyles = `
3
+ body:has(.power-logs[data-testid="power-logs-page"]) .power-ai-launcher { display:none; }
4
+ .power-logs { display:flex; flex-direction:column; height:100%; min-height:0; min-width:0; box-sizing:border-box; overflow:hidden; padding:12px; gap:6px; color:var(--textColorPrimary); container-type:inline-size; }
5
+ .power-logs header, .power-logs-toolbar, .power-logs-filters, .power-logs-source { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
6
+ .power-logs header h1 { margin:0; font-size:16px; display:flex; align-items:center; gap:10px; }
7
+ .power-logs header .power-logs-actions { margin-left:auto; display:flex; gap:8px; flex-wrap:wrap; }
8
+ .power-logs :is(button,input,select,textarea), .power-logs .power-logs-options > summary { font:inherit; color:inherit; }
9
+ .power-logs :is(.power-logs-filters > input,textarea) { background:var(--contentColor); border:1px solid var(--borderColor); border-radius:5px; padding:4px 8px; min-width:0; }
10
+ .power-logs-filters > input { flex:1; min-width:180px; }
11
+ .power-logs label { display:flex; align-items:center; gap:8px; }
12
+ .power-logs button, .power-logs .power-logs-options > summary { display:inline-flex; align-items:center; justify-content:center; gap:6px; min-height:28px; padding:3px 8px; border:1px solid var(--borderColor); border-radius:5px; background:var(--contentColor); cursor:pointer; box-shadow:none; }
13
+ .power-logs button::before { content:none; }
14
+ .power-logs :is(button:not(:disabled),.power-logs-options > summary):hover { color:var(--primary); border-color:var(--primary); }
15
+ .power-logs button[aria-pressed=true], .power-logs button[aria-selected=true] { color:var(--primary); background:color-mix(in srgb,var(--primary) 12%,var(--contentColor)); border-color:var(--primary); }
16
+ .power-logs button:disabled { opacity:.45; cursor:default; }
17
+ .power-logs :is(button,input,select,textarea):focus-visible, .power-logs .power-logs-options > summary:focus-visible { outline:2px solid var(--primary); outline-offset:2px; }
18
+ .power-logs .power-logs-filters > input:focus-visible, .power-logs textarea:focus-visible { outline:none; border-color:var(--primary); box-shadow:inset 0 0 0 1px var(--primary); }
19
+ .power-logs .power-logs-muted { color:var(--textColorSecondary); font-size:12px; line-height:1.5; }
20
+ .power-logs .power-logs-notice { padding:3px 8px; border:1px solid var(--borderColor); border-radius:4px; line-height:1.5; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; flex-shrink:0; }
21
+ .power-logs .power-logs-error { color:var(--colorError,#e68b80); }
22
+ .power-logs-tabs { display:flex; gap:4px; flex-shrink:0; }
23
+ .power-logs header .power-logs-page-title { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
24
+ .power-logs-snapshot-option { display:flex; align-items:center; justify-content:space-between; gap:12px; min-width:0; }
25
+ .power-logs-option-text { display:flex; flex-direction:column; gap:3px; min-width:0; white-space:normal; overflow-wrap:anywhere; }
26
+ .power-logs-option-text strong { font-weight:500; }
27
+ .power-logs-option-text small { opacity:.85; font-size:11px; }
28
+ .power-logs-source-option { display:flex; align-items:center; gap:10px; width:100%; min-width:0; white-space:normal; line-height:1.4; }
29
+ .power-logs-source-option > :first-child { flex-shrink:0; opacity:.75; }
30
+ .power-logs-source-option .power-logs-option-text { flex:1; }
31
+ .power-logs-source-option strong, .power-logs-source-option small { white-space:normal; overflow:visible; overflow-wrap:anywhere; }
32
+ .power-logs-source-check { display:inline-flex; width:16px; flex-shrink:0; }
33
+ .power-logs-snapshot-option > button { display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; min-width:28px; min-height:28px; padding:0; border:0; border-radius:4px; background:transparent; color:inherit; cursor:pointer; }
34
+ .power-logs-snapshot-option > button:not(:disabled):hover { color:var(--colorError); background:color-mix(in srgb,var(--colorError) 12%,transparent); }
35
+ .power-logs-snapshot-option > button:focus-visible { outline:2px solid var(--primary); outline-offset:-2px; }
36
+ .power-logs-snapshot-option > button:disabled { opacity:.45; cursor:default; }
37
+ .power-logs-level-label { color:var(--textColorSecondary); }
38
+ .power-logs-level-label[data-level=debug] { color:var(--colorInfo); }
39
+ .power-logs-level-label[data-level=info] { color:var(--primary); }
40
+ .power-logs-level-label[data-level=warn] { color:var(--colorWarning); }
41
+ .power-logs-level-label[data-level=error],.power-logs-level-label[data-level=fatal] { color:var(--colorError); }
42
+ .Select__option--is-selected .power-logs-level-label { color:inherit; }
43
+ .power-logs-workspace { position:relative; display:flex; flex:1; min-height:0; }
44
+ .power-logs-viewer { display:flex; flex-direction:column; flex:1; min-width:0; min-height:0; gap:4px; }
45
+ .power-logs-stream { position:relative; flex:1; min-height:0; min-width:0; overflow:auto; border:1px solid var(--borderColor); border-radius:6px; background:var(--contentColor); }
46
+ .power-log-row { min-height:0!important; position:absolute; left:0; right:0; width:100%; display:grid!important; grid-template-columns:95px 48px minmax(100px,180px) minmax(0,1fr); align-items:center; gap:10px!important; padding:0 12px!important; border:0!important; border-left:3px solid var(--textColorSecondary)!important; border-bottom:1px solid var(--borderFaintColor)!important; border-radius:0!important; text-align:left; background:transparent!important; font-family:var(--font-monospace,monospace)!important; font-size:12px!important; }
47
+ .power-logs[data-compact=true] .power-log-row { padding-inline:8px!important; gap:6px!important; }
48
+ .power-logs[data-compact=true] td,.power-logs[data-compact=true] th { padding:3px 8px; }
49
+ .power-log-row > span { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
50
+ .power-log-row .power-log-level { font-size:10px; font-weight:600; text-transform:uppercase; }
51
+ .power-log-row[data-level=warn] { border-left-color:var(--colorWarning,#d9a441)!important; }
52
+ .power-log-row[data-level=error],.power-log-row[data-level=fatal] { border-left-color:var(--colorError,#d26860)!important; }
53
+ .power-log-row[data-level=info] { border-left-color:var(--primary)!important; }
54
+ .power-logs-detail { position:absolute; z-index:5; top:0; bottom:0; right:0; box-sizing:border-box; box-shadow:-4px 0 18px #0004; display:flex; flex-direction:column; align-items:stretch; gap:12px; width:460px; max-width:95%; padding:16px; background:var(--contentColor); border:1px solid var(--borderColor); border-radius:6px; overflow:auto; }
55
+ .power-logs-detail header { justify-content:flex-end; }
56
+ .power-logs-detail header > strong { margin-right:auto; }
57
+ .power-logs .power-logs-detail-close { flex-shrink:0; width:28px; padding:0; border-color:transparent; background:transparent; }
58
+ .power-logs .power-logs-detail-close:not(:disabled):hover { border-color:transparent; background:color-mix(in srgb,var(--primary) 10%,transparent); }
59
+ .power-log-json { --json-key:#9cdcfe; --json-string:#ce9178; --json-number:#b5cea8; --json-literal:#c586c0; }
60
+ .theme-light .power-log-json { --json-key:#005a9e; --json-string:#9e2b1a; --json-number:#17642d; --json-literal:#7a288c; }
61
+ .power-log-json [data-token=key] { color:var(--json-key); }
62
+ .power-log-json [data-token=string] { color:var(--json-string); }
63
+ .power-log-json [data-token=number] { color:var(--json-number); }
64
+ .power-log-json [data-token=literal] { color:var(--json-literal); }
65
+ .power-logs pre { white-space:pre-wrap; overflow-wrap:anywhere; font-size:12px; line-height:1.6; }
66
+ .power-logs textarea { box-sizing:border-box; width:100%; height:56px; min-height:48px; max-height:120px; flex-shrink:0; resize:vertical; font-family:var(--font-monospace,monospace); }
67
+ .power-logs-results { flex:1; min-height:0; overflow:auto; border:1px solid var(--borderColor); border-radius:6px; }
68
+ .power-logs table { border-collapse:collapse; table-layout:fixed; font-size:12px; width:100%; min-width:0; }
69
+
70
+ .power-logs th,.power-logs td { padding:6px 10px; text-align:left; border-bottom:1px solid var(--borderColor); max-width:400px; white-space:nowrap; vertical-align:top; }
71
+ .power-logs .power-logs-cell { display:block; overflow:hidden; text-overflow:ellipsis; max-height:4.8em; }
72
+ .power-logs tbody tr { cursor:pointer; }
73
+ .power-logs tbody tr:hover, .power-logs tbody tr:focus-visible { background:color-mix(in srgb,var(--primary) 10%,var(--contentColor)); outline:none; }
74
+ .power-logs td[data-column=message] { font-family:var(--font-monospace,monospace); font-size:12px; white-space:pre-wrap; overflow-wrap:anywhere; }
75
+ .power-logs td[data-level=error], .power-logs td[data-level=fatal] { color:var(--colorError,#d26860); }
76
+ .power-logs td[data-level=warn] { color:var(--colorWarning,#d9a441); }
77
+ .power-logs th { position:sticky; top:0; background:var(--contentColor); }
78
+ .power-logs dialog { position:fixed; inset:0; margin:auto; background:var(--mainBackground); color:var(--textColorPrimary); border:1px solid var(--borderColor); border-radius:8px; padding:24px; width:min(640px,85vw); max-height:80vh; overflow:auto; }
79
+ .power-logs dialog::backdrop { background:#0007; }
80
+ .power-logs-empty { padding:32px; text-align:center; color:var(--textColorSecondary); }
81
+
82
+ .power-logs > :not(.power-logs-workspace):not(.power-logs-results) { flex-shrink:0; }
83
+ .power-logs-target, .power-logs-caption { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
84
+ .power-logs-select { display:inline-block; min-width:0; max-width:360px; flex:1; }
85
+ .power-logs-source .power-logs-select { flex:1; max-width:none; }
86
+ .power-logs-select > div { width:100%; min-width:0; }
87
+ .power-logs-filters .power-logs-select { flex:0 1 180px; }
88
+ .power-logs-filters .power-logs-select[data-source-select] { flex:1 1 260px; max-width:420px; }
89
+
90
+ .power-logs-capture { display:flex; }
91
+ .power-logs-capture > button { color:var(--primary); }
92
+ .power-logs-options { position:relative; }
93
+ .power-logs-options > summary { list-style:none; }
94
+ .power-logs-options > summary::-webkit-details-marker { display:none; }
95
+ .power-logs .power-logs-options[open] > summary { color:var(--primary); border-color:var(--primary); background:color-mix(in srgb,var(--primary) 12%,var(--contentColor)); }
96
+ .power-logs-options > div { position:absolute; z-index:10; top:100%; right:0; box-sizing:border-box; width:280px; max-width:calc(100vw - 32px); border-radius:6px; padding:12px; display:flex; flex-direction:column; gap:12px; background:var(--mainBackground); border:1px solid var(--borderColor); box-shadow:0 4px 18px #0005; }
97
+ .power-logs-options label { white-space:nowrap; justify-content:space-between; gap:12px; }
98
+ .power-logs-options .power-logs-select { min-width:130px; }
99
+ .power-logs-select .Select__single-value { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
100
+ .power-logs-sql-tools button { min-height:24px; font-size:12px; }
101
+ .power-logs-pagination { justify-content:flex-end; gap:8px; }
102
+ .power-logs-pagination button { width:28px; padding:3px; }
103
+ .power-logs-footer { display:flex; align-items:center; justify-content:space-between; gap:12px; min-width:0; }
104
+ .power-logs-caption { flex:1; min-width:0; font-size:11px!important; }
105
+ .power-logs .power-logs-collection-note { display:flex; align-items:center; gap:5px; min-width:0; max-width:55%; padding:1px 6px; font-size:10px; }
106
+ .power-logs-collection-note > :first-child { color:var(--colorWarning,#d9a441); flex-shrink:0; }
107
+ .power-logs-collection-note > :last-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
108
+ .power-logs-status { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
109
+ .power-logs .power-logs-error { white-space:normal; overflow:visible; overflow-wrap:anywhere; }
110
+ .power-logs-snapshot-notes { max-height:100px; overflow:auto; }
111
+ @container(max-width:760px) { .power-logs-detail { width:min(420px,86%); padding:12px; gap:10px; } .power-logs-filters .power-logs-select { flex:1 1 130px; } .power-logs-filters > input { flex-basis:100%; } .power-log-row { grid-template-columns:80px 42px minmax(0,1fr); } .power-log-row .power-log-origin { display:none; } .power-logs header .power-logs-actions { gap:4px; } }
112
+ `;
113
+ //#endregion
114
+ exports.powerLogsStyles = powerLogsStyles;
115
+
116
+ //# sourceMappingURL=power-logs.css.js.map