@64mb/freelens-power 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/main/common/power-logs.js.map +1 -1
- package/out/main/common/store/logs-preferences-store.js +5 -0
- package/out/main/common/store/logs-preferences-store.js.map +1 -1
- package/out/main/dashboard-views.js +26 -0
- package/out/main/dashboard-views.js.map +1 -1
- package/out/main/power-logs-database.js +5 -0
- package/out/main/power-logs-database.js.map +1 -1
- package/out/main/power-logs-ipc.js +8 -0
- package/out/main/power-logs-ipc.js.map +1 -1
- package/out/renderer/ai-diagnostic-handoff.js +1 -0
- package/out/renderer/ai-diagnostic-handoff.js.map +1 -1
- package/out/renderer/ai-extras.js +7 -2
- package/out/renderer/ai-extras.js.map +1 -1
- package/out/renderer/ai.js +1 -1
- package/out/renderer/ai.js.map +1 -1
- package/out/renderer/appearance.js +2 -0
- package/out/renderer/appearance.js.map +1 -1
- package/out/renderer/dashboard.js +35 -8
- package/out/renderer/dashboard.js.map +1 -1
- package/out/renderer/index.js +2 -1
- package/out/renderer/index.js.map +1 -1
- package/out/renderer/power-log-json-cell.js +14 -6
- package/out/renderer/power-log-json-cell.js.map +1 -1
- package/out/renderer/power-log-json.js +100 -16
- package/out/renderer/power-log-json.js.map +1 -1
- package/out/renderer/power-log-sql-editor.js +91 -0
- package/out/renderer/power-log-sql-editor.js.map +1 -0
- package/out/renderer/power-logs-client.js +4 -0
- package/out/renderer/power-logs-client.js.map +1 -1
- package/out/renderer/power-logs-sql-drafts.js +76 -0
- package/out/renderer/power-logs-sql-drafts.js.map +1 -0
- package/out/renderer/power-logs-sql-row.js +3 -11
- package/out/renderer/power-logs-sql-row.js.map +1 -1
- package/out/renderer/power-logs.css.js +8 -4
- package/out/renderer/power-logs.css.js.map +1 -1
- package/out/renderer/power-logs.js +190 -141
- package/out/renderer/power-logs.js.map +1 -1
- package/out/renderer/preferences/preferences.js +2 -9
- package/out/renderer/preferences/preferences.js.map +1 -1
- package/out/renderer/preferences/section-navigation.js +44 -0
- package/out/renderer/preferences/section-navigation.js.map +1 -0
- package/out/renderer/src/common/power-log-json-preset.js +23 -25
- package/out/renderer/src/common/power-log-json-preset.js.map +1 -1
- package/out/renderer/src/common/power-log-sql-level.js +25 -0
- package/out/renderer/src/common/power-log-sql-level.js.map +1 -0
- package/out/renderer/src/common/power-logs-ai.js +4 -0
- package/out/renderer/src/common/power-logs-ai.js.map +1 -1
- package/out/renderer/src/common/power-logs.js.map +1 -1
- package/out/renderer/src/common/store/logs-preferences-store.js +5 -0
- package/out/renderer/src/common/store/logs-preferences-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"power-logs.js","names":[],"sources":["../../../src/common/power-logs.ts"],"sourcesContent":["export const POWER_LOGS_CHANNEL = \"freelens-power:logs\";\nexport const POWER_LOGS_DEFAULT_LIMITS = {\n liveRows: 10000,\n liveBytes: 16 * 1024 * 1024,\n batchRows: 1000,\n batchBytes: 2 * 1024 * 1024,\n recordBytes: 64 * 1024,\n captureBytes: 256 * 1024 * 1024,\n captureRows: 1000000,\n captures: 3,\n sources: 200,\n resultRows: 1000,\n resultBytes: 2 * 1024 * 1024,\n queryMs: 15000,\n ttlMs: 60 * 60 * 1000,\n historyLines: 1000,\n historyBytes: 1024 * 1024,\n captureSourceLines: 10000,\n captureSourceBytes: 8 * 1024 * 1024,\n requestsPerSecond: 2,\n bytesPerSecond: 1024 * 1024,\n historyConcurrency: 2,\n liveConcurrency: 4,\n} as const;\n\nexport type PowerLogsLimitKey = keyof typeof POWER_LOGS_DEFAULT_LIMITS;\nexport type PowerLogsLimits = { [Key in PowerLogsLimitKey]: number };\nexport const POWER_LOGS_LIMITS: PowerLogsLimits = { ...POWER_LOGS_DEFAULT_LIMITS };\n\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"fatal\" | \"unknown\";\nexport type LogWorkloadKind = \"Pod\" | \"Deployment\" | \"DaemonSet\" | \"StatefulSet\" | \"ReplicaSet\" | \"Job\" | \"CronJob\";\nexport interface LogTarget {\n kind: LogWorkloadKind;\n namespace: string;\n name: string;\n uid: string;\n}\nexport interface LogSource {\n namespace: string;\n pod: string;\n podUid: string;\n container: string;\n previous?: boolean;\n}\nexport interface LogRecord {\n timestamp: number | null;\n pod: string;\n podUid: string;\n container: string;\n level: LogLevel;\n message: string;\n fieldsJson: string | null;\n previous?: boolean;\n}\nexport interface LogCapture {\n id: string;\n target: LogTarget;\n createdAt: number;\n expiresAt: number;\n state: \"collecting\" | \"ready\" | \"partial\";\n rows: number;\n bytes: number;\n notes: string[];\n}\nexport type LogCell = string | number | boolean | null;\nexport interface LogQueryResult {\n error?: string;\n columns: string[];\n rows: LogCell[][];\n truncated: boolean;\n elapsedMs: number;\n}\nexport interface LogPartition {\n clusterId: string;\n contextId: string;\n}\nexport type LogRequest = LogPartition &\n (\n | { operation: \"permit\"; lane: \"start\" | \"bytes\"; bytes?: number }\n | { operation: \"stream-open\"; streamId: string; follow: boolean }\n | { operation: \"stream-close\" | \"stream-renew\"; streamId: string }\n | { operation: \"create\"; target: LogTarget }\n | { operation: \"append\"; captureId: string; records: LogRecord[] }\n | { operation: \"finish\"; captureId: string; partial: boolean; notes: string[] }\n | { operation: \"list\" }\n | { operation: \"delete\"; captureId: string }\n | { operation: \"query\"; captureId: string; queryId: string; sql: string }\n | { operation: \"cancel\"; queryId: string }\n | { operation: \"export\"; captureId: string }\n );\n"],"mappings":";AAAA,IAAa,qBAAqB;AAClC,IAAa,4BAA4B;CACvC,UAAU;CACV,WAAW,KAAK,OAAO;CACvB,WAAW;CACX,YAAY,IAAI,OAAO;CACvB,aAAa,KAAK;CAClB,cAAc,MAAM,OAAO;CAC3B,aAAa;CACb,UAAU;CACV,SAAS;CACT,YAAY;CACZ,aAAa,IAAI,OAAO;CACxB,SAAS;CACT,OAAO,OAAU;CACjB,cAAc;CACd,cAAc,OAAO;CACrB,oBAAoB;CACpB,oBAAoB,IAAI,OAAO;CAC/B,mBAAmB;CACnB,gBAAgB,OAAO;CACvB,oBAAoB;CACpB,iBAAiB;AACnB;AAIA,IAAa,oBAAqC,EAAE,GAAG,0BAA0B"}
|
|
1
|
+
{"version":3,"file":"power-logs.js","names":[],"sources":["../../../src/common/power-logs.ts"],"sourcesContent":["export const POWER_LOGS_CHANNEL = \"freelens-power:logs\";\nexport const POWER_LOGS_DEFAULT_LIMITS = {\n liveRows: 10000,\n liveBytes: 16 * 1024 * 1024,\n batchRows: 1000,\n batchBytes: 2 * 1024 * 1024,\n recordBytes: 64 * 1024,\n captureBytes: 256 * 1024 * 1024,\n captureRows: 1000000,\n captures: 3,\n sources: 200,\n resultRows: 1000,\n resultBytes: 2 * 1024 * 1024,\n queryMs: 15000,\n ttlMs: 60 * 60 * 1000,\n historyLines: 1000,\n historyBytes: 1024 * 1024,\n captureSourceLines: 10000,\n captureSourceBytes: 8 * 1024 * 1024,\n requestsPerSecond: 2,\n bytesPerSecond: 1024 * 1024,\n historyConcurrency: 2,\n liveConcurrency: 4,\n} as const;\n\nexport type PowerLogsLimitKey = keyof typeof POWER_LOGS_DEFAULT_LIMITS;\nexport type PowerLogsLimits = { [Key in PowerLogsLimitKey]: number };\nexport const POWER_LOGS_LIMITS: PowerLogsLimits = { ...POWER_LOGS_DEFAULT_LIMITS };\n\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"fatal\" | \"unknown\";\nexport type LogWorkloadKind = \"Pod\" | \"Deployment\" | \"DaemonSet\" | \"StatefulSet\" | \"ReplicaSet\" | \"Job\" | \"CronJob\";\nexport interface LogTarget {\n kind: LogWorkloadKind;\n namespace: string;\n name: string;\n uid: string;\n}\nexport interface LogSource {\n namespace: string;\n pod: string;\n podUid: string;\n container: string;\n previous?: boolean;\n}\nexport interface LogRecord {\n timestamp: number | null;\n pod: string;\n podUid: string;\n container: string;\n level: LogLevel;\n message: string;\n fieldsJson: string | null;\n previous?: boolean;\n}\nexport interface LogCapture {\n id: string;\n target: LogTarget;\n createdAt: number;\n expiresAt: number;\n state: \"collecting\" | \"ready\" | \"partial\";\n rows: number;\n bytes: number;\n notes: string[];\n lastSql?: string;\n}\nexport type LogCell = string | number | boolean | null;\nexport interface LogQueryResult {\n error?: string;\n columns: string[];\n rows: LogCell[][];\n truncated: boolean;\n elapsedMs: number;\n}\nexport interface LogPartition {\n clusterId: string;\n contextId: string;\n}\nexport type LogRequest = LogPartition &\n (\n | { operation: \"permit\"; lane: \"start\" | \"bytes\"; bytes?: number }\n | { operation: \"stream-open\"; streamId: string; follow: boolean }\n | { operation: \"stream-close\" | \"stream-renew\"; streamId: string }\n | { operation: \"create\"; target: LogTarget }\n | { operation: \"append\"; captureId: string; records: LogRecord[] }\n | { operation: \"finish\"; captureId: string; partial: boolean; notes: string[] }\n | { operation: \"list\" }\n | { operation: \"delete\"; captureId: string }\n | { operation: \"save-sql\"; captureId: string; sql: string }\n | { operation: \"query\"; captureId: string; queryId: string; sql: string }\n | { operation: \"cancel\"; queryId: string }\n | { operation: \"export\"; captureId: string }\n );\n"],"mappings":";AAAA,IAAa,qBAAqB;AAClC,IAAa,4BAA4B;CACvC,UAAU;CACV,WAAW,KAAK,OAAO;CACvB,WAAW;CACX,YAAY,IAAI,OAAO;CACvB,aAAa,KAAK;CAClB,cAAc,MAAM,OAAO;CAC3B,aAAa;CACb,UAAU;CACV,SAAS;CACT,YAAY;CACZ,aAAa,IAAI,OAAO;CACxB,SAAS;CACT,OAAO,OAAU;CACjB,cAAc;CACd,cAAc,OAAO;CACrB,oBAAoB;CACpB,oBAAoB,IAAI,OAAO;CAC/B,mBAAmB;CACnB,gBAAgB,OAAO;CACvB,oBAAoB;CACpB,iBAAiB;AACnB;AAIA,IAAa,oBAAqC,EAAE,GAAG,0BAA0B"}
|
|
@@ -6,6 +6,7 @@ var LogsPreferencesStore = class extends require_extensions.Common.Store.Extensi
|
|
|
6
6
|
enabled = false;
|
|
7
7
|
gentle = true;
|
|
8
8
|
compactRows = false;
|
|
9
|
+
hideResourceNameColumn = false;
|
|
9
10
|
limits = require_power_logs_limits.normalizePowerLogsLimits(void 0);
|
|
10
11
|
constructor() {
|
|
11
12
|
super({
|
|
@@ -14,6 +15,7 @@ var LogsPreferencesStore = class extends require_extensions.Common.Store.Extensi
|
|
|
14
15
|
enabled: false,
|
|
15
16
|
gentle: true,
|
|
16
17
|
compactRows: false,
|
|
18
|
+
hideResourceNameColumn: false,
|
|
17
19
|
limits: require_power_logs_limits.normalizePowerLogsLimits(void 0)
|
|
18
20
|
}
|
|
19
21
|
});
|
|
@@ -21,6 +23,7 @@ var LogsPreferencesStore = class extends require_extensions.Common.Store.Extensi
|
|
|
21
23
|
enabled: require__global_external_mobx.observable,
|
|
22
24
|
gentle: require__global_external_mobx.observable,
|
|
23
25
|
compactRows: require__global_external_mobx.observable,
|
|
26
|
+
hideResourceNameColumn: require__global_external_mobx.observable,
|
|
24
27
|
limits: require__global_external_mobx.observable
|
|
25
28
|
});
|
|
26
29
|
}
|
|
@@ -28,6 +31,7 @@ var LogsPreferencesStore = class extends require_extensions.Common.Store.Extensi
|
|
|
28
31
|
this.enabled = data?.enabled === true;
|
|
29
32
|
this.gentle = data?.gentle !== false;
|
|
30
33
|
this.compactRows = data?.compactRows === true;
|
|
34
|
+
this.hideResourceNameColumn = data?.hideResourceNameColumn === true;
|
|
31
35
|
this.limits = require_power_logs_limits.normalizePowerLogsLimits(data?.limits);
|
|
32
36
|
}
|
|
33
37
|
toJSON() {
|
|
@@ -35,6 +39,7 @@ var LogsPreferencesStore = class extends require_extensions.Common.Store.Extensi
|
|
|
35
39
|
enabled: this.enabled,
|
|
36
40
|
gentle: this.gentle,
|
|
37
41
|
compactRows: this.compactRows,
|
|
42
|
+
hideResourceNameColumn: this.hideResourceNameColumn,
|
|
38
43
|
limits: require_power_logs_limits.normalizePowerLogsLimits(this.limits)
|
|
39
44
|
};
|
|
40
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs-preferences-store.js","names":[],"sources":["../../../../src/common/store/logs-preferences-store.ts"],"sourcesContent":["import { Common } from \"@freelensapp/extensions\";\nimport { makeObservable, observable } from \"mobx\";\nimport { normalizePowerLogsLimits } from \"../power-logs-limits\";\n\nimport type { PowerLogsLimits } from \"../power-logs\";\n\nexport class LogsPreferencesStore extends Common.Store.ExtensionStore<{\n enabled: boolean;\n gentle: boolean;\n compactRows: boolean;\n limits: PowerLogsLimits;\n}> {\n enabled = false;\n gentle = true;\n compactRows = false;\n limits = normalizePowerLogsLimits(undefined);\n\n constructor() {\n super({\n configName: \"logs-preferences\",\n defaults: {
|
|
1
|
+
{"version":3,"file":"logs-preferences-store.js","names":[],"sources":["../../../../src/common/store/logs-preferences-store.ts"],"sourcesContent":["import { Common } from \"@freelensapp/extensions\";\nimport { makeObservable, observable } from \"mobx\";\nimport { normalizePowerLogsLimits } from \"../power-logs-limits\";\n\nimport type { PowerLogsLimits } from \"../power-logs\";\n\nexport class LogsPreferencesStore extends Common.Store.ExtensionStore<{\n enabled: boolean;\n gentle: boolean;\n compactRows: boolean;\n hideResourceNameColumn: boolean;\n limits: PowerLogsLimits;\n}> {\n enabled = false;\n gentle = true;\n compactRows = false;\n hideResourceNameColumn = false;\n limits = normalizePowerLogsLimits(undefined);\n\n constructor() {\n super({\n configName: \"logs-preferences\",\n defaults: {\n enabled: false,\n gentle: true,\n compactRows: false,\n hideResourceNameColumn: false,\n limits: normalizePowerLogsLimits(undefined),\n },\n });\n makeObservable(this, {\n enabled: observable,\n gentle: observable,\n compactRows: observable,\n hideResourceNameColumn: observable,\n limits: observable,\n });\n }\n\n fromStore(data: {\n enabled?: boolean;\n gentle?: boolean;\n compactRows?: boolean;\n hideResourceNameColumn?: boolean;\n limits?: unknown;\n }): void {\n this.enabled = data?.enabled === true;\n this.gentle = data?.gentle !== false;\n this.compactRows = data?.compactRows === true;\n this.hideResourceNameColumn = data?.hideResourceNameColumn === true;\n this.limits = normalizePowerLogsLimits(data?.limits);\n }\n\n toJSON() {\n return {\n enabled: this.enabled,\n gentle: this.gentle,\n compactRows: this.compactRows,\n hideResourceNameColumn: this.hideResourceNameColumn,\n limits: normalizePowerLogsLimits(this.limits),\n };\n }\n}\n"],"mappings":";;;;AAMA,IAAa,uBAAb,cAA0C,mBAAA,OAAO,MAAM,eAMpD;CACD,UAAU;CACV,SAAS;CACT,cAAc;CACd,yBAAyB;CACzB,SAAS,0BAAA,yBAAyB,KAAA,CAAS;CAE3C,cAAc;EACZ,MAAM;GACJ,YAAY;GACZ,UAAU;IACR,SAAS;IACT,QAAQ;IACR,aAAa;IACb,wBAAwB;IACxB,QAAQ,0BAAA,yBAAyB,KAAA,CAAS;GAC5C;EACF,CAAC;EACD,8BAAA,eAAe,MAAM;GACnB,SAAS,8BAAA;GACT,QAAQ,8BAAA;GACR,aAAa,8BAAA;GACb,wBAAwB,8BAAA;GACxB,QAAQ,8BAAA;EACV,CAAC;CACH;CAEA,UAAU,MAMD;EACP,KAAK,UAAU,MAAM,YAAY;EACjC,KAAK,SAAS,MAAM,WAAW;EAC/B,KAAK,cAAc,MAAM,gBAAgB;EACzC,KAAK,yBAAyB,MAAM,2BAA2B;EAC/D,KAAK,SAAS,0BAAA,yBAAyB,MAAM,MAAM;CACrD;CAEA,SAAS;EACP,OAAO;GACL,SAAS,KAAK;GACd,QAAQ,KAAK;GACb,aAAa,KAAK;GAClB,wBAAwB,KAAK;GAC7B,QAAQ,0BAAA,yBAAyB,KAAK,MAAM;EAC9C;CACF;AACF"}
|
|
@@ -372,6 +372,31 @@ function startDashboardViews() {
|
|
|
372
372
|
}
|
|
373
373
|
};
|
|
374
374
|
owners.set(sender, owner);
|
|
375
|
+
const activeOwner = owner;
|
|
376
|
+
let backgrounded = false;
|
|
377
|
+
const blur = () => {
|
|
378
|
+
backgrounded = true;
|
|
379
|
+
};
|
|
380
|
+
const focus = () => {
|
|
381
|
+
if (!backgrounded) return;
|
|
382
|
+
backgrounded = false;
|
|
383
|
+
if (!dashboardUrl(sender.getURL())) return;
|
|
384
|
+
for (const [id, card] of activeOwner.cards) {
|
|
385
|
+
const configured = configuredCards().find((item) => item.id === id);
|
|
386
|
+
if (!card.visible || card.floating || !configured) continue;
|
|
387
|
+
card.skeleton.view.setVisible(card.loading);
|
|
388
|
+
card.container.setVisible(!card.failed || card.loading);
|
|
389
|
+
if ((configured.refreshEvery10Seconds || configured.autoRefresh) && !card.loading) reload(card, configured.url);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
window.on("blur", blur);
|
|
393
|
+
window.on("focus", focus);
|
|
394
|
+
const cleanup = owner.cleanup;
|
|
395
|
+
owner.cleanup = () => {
|
|
396
|
+
window.removeListener("blur", blur);
|
|
397
|
+
window.removeListener("focus", focus);
|
|
398
|
+
cleanup();
|
|
399
|
+
};
|
|
375
400
|
}
|
|
376
401
|
if (payload && typeof payload === "object" && "hidden" in payload && payload.hidden === true) {
|
|
377
402
|
hide(event.sender);
|
|
@@ -558,6 +583,7 @@ function startDashboardViews() {
|
|
|
558
583
|
applyWebsiteStyles(card);
|
|
559
584
|
}
|
|
560
585
|
card.visible = true;
|
|
586
|
+
card.skeleton.view.setVisible(card.loading);
|
|
561
587
|
card.container.setVisible(!card.failed && (card.loading || card.url === configured.url));
|
|
562
588
|
const zoom = event.sender.getZoomFactor();
|
|
563
589
|
card.container.setBorderRadius(Math.round(12 * zoom));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-views.js","names":[],"sources":["../../src/main/dashboard-views.ts"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\nimport { join } from \"node:path\";\nimport {\n app,\n BrowserWindow,\n type IpcMainInvokeEvent,\n ipcMain,\n nativeTheme,\n type Rectangle,\n session,\n shell,\n View,\n type WebContents,\n WebContentsView,\n} from \"electron\";\nimport { reaction } from \"mobx\";\nimport { sanitizeDashboardCards } from \"../common/dashboard\";\nimport { dashboardReadinessScript } from \"../common/dashboard-readiness\";\nimport { dashboardSelectorScript } from \"../common/dashboard-selector\";\nimport {\n DASHBOARD_SITE_ICONS,\n DASHBOARD_VIEWS_LOADING,\n DASHBOARD_VIEWS_PIN,\n DASHBOARD_VIEWS_PINNED,\n type DashboardSiteIcon,\n} from \"../common/dashboard-views\";\nimport { DashboardPreferencesStore } from \"../common/store/dashboard-preferences-store\";\nimport { boundedDashboardIcons, loadDashboardIcons, saveDashboardIcons } from \"./dashboard-icon-cache\";\nimport { observeDashboardNetwork } from \"./dashboard-network\";\n\nconst syncChannel = \"freelens-power:dashboard-views:sync\";\nconst reloadChannel = \"freelens-power:dashboard-views:reload\";\nconst clearChannel = \"freelens-power:dashboard-views:clear\";\nconst dashboardPath = \"/extension/freelens-power/dashboard\";\nconst websiteStyles =\n \"* { scrollbar-width: none !important; } *::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }\";\n\nconst expandedWebsiteStyles =\n \"* { scrollbar-width: auto !important; } *::-webkit-scrollbar { display: revert !important; width: revert !important; height: revert !important; }\";\n\nfunction rendererUrl(value: string, dashboardOnly = false): boolean {\n try {\n const url = new URL(value);\n return (\n url.protocol === \"https:\" &&\n (url.hostname === \"renderer.freelens.app\" || url.hostname.endsWith(\".renderer.freelens.app\")) &&\n (!dashboardOnly || url.pathname === dashboardPath)\n );\n } catch {\n return false;\n }\n}\nfunction dashboardUrl(value: string): boolean {\n return rendererUrl(value, true);\n}\nfunction webUrl(value: string): boolean {\n try {\n return [\"https:\", \"http:\"].includes(new URL(value).protocol);\n } catch {\n return false;\n }\n}\nfunction rectangle(value: unknown): Rectangle | undefined {\n if (!value || typeof value !== \"object\") return;\n const rect = value as Rectangle;\n if (\n ![rect.x, rect.y, rect.width, rect.height].every(\n (n) => Number.isFinite(n) && Number.isInteger(n) && Math.abs(n) <= 32768,\n ) ||\n rect.width <= 0 ||\n rect.height <= 0\n )\n return;\n return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };\n}\n\nfunction createDashboardSkeleton() {\n const view = new View();\n view.setBackgroundColor(nativeTheme.shouldUseDarkColors ? \"#202124\" : \"#ffffff\");\n const bars = Array.from({ length: 4 }, () => {\n const bar = new View();\n bar.setBackgroundColor(nativeTheme.shouldUseDarkColors ? \"#393b40\" : \"#e8e9eb\");\n bar.setBorderRadius(6);\n view.addChildView(bar);\n return bar;\n });\n return {\n view,\n layout: (width: number, height: number) => {\n view.setBounds({ x: 0, y: 0, width, height });\n bars.forEach((bar, index) => {\n bar.setBounds({\n x: 20,\n y: index === 0 ? 20 : 60 + (index - 1) * 24,\n width: Math.max(1, Math.round((width - 40) * (index === 0 ? 0.45 : 1))),\n height: index === 0 ? 20 : index === 3 ? Math.max(30, height - 128) : 12,\n });\n });\n },\n };\n}\n\ntype WebsiteStyleState = {\n view: { webContents: WebContents };\n scrollbars?: boolean;\n websiteStylesKey?: string;\n websiteStylesGeneration?: number;\n};\n\ntype CardView = {\n container: View;\n skeleton: ReturnType<typeof createDashboardSkeleton>;\n view: WebContentsView;\n url: string;\n failed: boolean;\n loading: boolean;\n visible: boolean;\n generation: number;\n stopPreparation?: () => void;\n selector?: string;\n scrollbars?: boolean;\n websiteStylesKey?: string;\n websiteStylesGeneration?: number;\n pending?: Promise<void>;\n requestedNavigation?: boolean;\n nativeNavigation?: { finish: () => void; fail: () => void };\n favicon?: string;\n faviconRequest?: AbortController;\n refreshTimer?: ReturnType<typeof setTimeout>;\n refreshInterval?: number;\n refreshGeneration?: number;\n floating?: BrowserWindow;\n floatingStyles?: WebsiteStyleState;\n floatingPreparation?: {\n refresh: () => Promise<boolean>;\n selectorChanged: () => void;\n stop: () => void;\n isPreparing: () => boolean;\n };\n};\ntype Owner = { window: BrowserWindow; cards: Map<string, CardView>; cleanup: () => void };\n\nasync function applyWebsiteStyles(card: WebsiteStyleState): Promise<void> {\n const contents = card.view.webContents;\n const generation = (card.websiteStylesGeneration ?? 0) + 1;\n card.websiteStylesGeneration = generation;\n const previous = card.websiteStylesKey;\n card.websiteStylesKey = undefined;\n if (contents.isDestroyed()) return;\n if (previous) await contents.removeInsertedCSS(previous).catch(() => {});\n if (card.websiteStylesGeneration !== generation || contents.isDestroyed()) return;\n const key = await contents\n .insertCSS(card.scrollbars ? expandedWebsiteStyles : websiteStyles, { cssOrigin: \"user\" })\n .catch(() => undefined);\n if (!key) return;\n if (card.websiteStylesGeneration === generation && !contents.isDestroyed()) card.websiteStylesKey = key;\n else if (!contents.isDestroyed()) await contents.removeInsertedCSS(key).catch(() => {});\n}\n\nasync function waitForReadiness(\n contents: WebContents,\n _network: ReturnType<typeof observeDashboardNetwork>,\n selector: () => string | undefined,\n current: () => boolean,\n): Promise<void> {\n let deadline: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n (async () => {\n if (!current()) return;\n await contents.mainFrame.executeJavaScript(dashboardSelectorScript(selector())).catch(() => {});\n if (!current()) return;\n await contents.mainFrame.executeJavaScript(dashboardReadinessScript(selector()));\n })().catch(() => new Promise<void>((resolve) => setTimeout(resolve, 200))),\n new Promise<void>((resolve) => {\n deadline = setTimeout(resolve, 8500);\n }),\n ]);\n } finally {\n clearTimeout(deadline);\n }\n}\n\nasync function prepareDashboardPage(contents: WebContents): Promise<void> {\n if (contents.isDestroyed()) return;\n let deadline: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n contents.mainFrame\n .executeJavaScript('document.dispatchEvent(new Event(\"freelens-power:dashboard:preparing\"))')\n .catch(() => {}),\n new Promise<void>((resolve) => {\n deadline = setTimeout(resolve, 250);\n }),\n ]);\n } finally {\n clearTimeout(deadline);\n }\n}\n\nfunction releaseDashboardPage(contents: WebContents): Promise<unknown> {\n if (contents.isDestroyed()) return Promise.resolve();\n return contents.mainFrame\n .executeJavaScript('document.dispatchEvent(new Event(\"freelens-power:dashboard:prepared\"))')\n .catch(() => {});\n}\n\nexport function startDashboardViews(): () => void {\n const websiteSession = session.fromPartition(\"persist:freelens-power-websites\");\n websiteSession.setPermissionRequestHandler((_contents, _permission, callback) => callback(false));\n websiteSession.setPermissionCheckHandler(() => false);\n const owners = new Map<WebContents, Owner>();\n const icons = new Map<string, DashboardSiteIcon>();\n const remove = (owner: Owner, id: string) => {\n const card = owner.cards.get(id);\n if (!card) return;\n owner.cards.delete(id);\n card.nativeNavigation?.fail();\n card.stopPreparation?.();\n card.websiteStylesGeneration = (card.websiteStylesGeneration ?? 0) + 1;\n card.faviconRequest?.abort();\n clearTimeout(card.refreshTimer);\n card.floatingPreparation?.stop();\n card.floating?.destroy();\n card.floating = undefined;\n if (!owner.window.isDestroyed()) owner.window.contentView.removeChildView(card.container);\n if (!card.view.webContents.isDestroyed()) card.view.webContents.close();\n };\n const clear = (sender: WebContents) => {\n const owner = owners.get(sender);\n if (!owner) return;\n owners.delete(sender);\n for (const id of owner.cards.keys()) remove(owner, id);\n owner.cleanup();\n };\n const hide = (sender: WebContents) => {\n for (const card of owners.get(sender)?.cards.values() ?? []) {\n card.visible = false;\n card.container.setVisible(false);\n }\n };\n const configuredCards = () =>\n sanitizeDashboardCards(DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>().cards);\n const cachePath = join(app.getPath(\"userData\"), \"freelens-power\", \"dashboard-icons.json\");\n const ready = loadDashboardIcons(cachePath).then((saved) => {\n const configured = configuredCards();\n for (const icon of saved) {\n if (!icons.has(icon.id) && configured.some((card) => card.id === icon.id && card.url === icon.pageUrl))\n icons.set(icon.id, icon);\n }\n });\n let writes = ready;\n const persistIcons = () => {\n writes = writes\n .then(async () => {\n const configured = configuredCards();\n const bounded = boundedDashboardIcons(\n [...icons.values()].filter((icon) =>\n configured.some((card) => card.id === icon.id && card.url === icon.pageUrl),\n ),\n );\n icons.clear();\n for (const icon of bounded) icons.set(icon.id, icon);\n await saveDashboardIcons(cachePath, bounded);\n })\n .catch(() => {});\n };\n persistIcons();\n const publishLoading = (card: CardView) => {\n for (const [sender, owner] of owners) {\n const id = [...owner.cards].find(([, candidate]) => candidate === card)?.[0];\n if (\n !id ||\n sender.isDestroyed() ||\n !dashboardUrl(sender.mainFrame.url) ||\n !dashboardUrl(sender.getURL()) ||\n !configuredCards().some((configured) => configured.id === id && configured.url === card.url)\n )\n continue;\n sender.send(DASHBOARD_VIEWS_LOADING, { id, url: card.url, loading: card.loading, failed: card.failed });\n }\n };\n const reload = (card: CardView, configuredUrl: string, initial = false, navigation?: Promise<void>) => {\n const current = card.view.webContents.getURL();\n const target = !initial && card.url === configuredUrl && webUrl(current) ? current : configuredUrl;\n const prepareExisting = !initial && !navigation && !card.loading && !card.failed && webUrl(current);\n card.faviconRequest?.abort();\n if (!navigation) card.nativeNavigation?.fail();\n card.url = configuredUrl;\n card.failed = false;\n card.loading = true;\n card.stopPreparation?.();\n const contents = card.view.webContents;\n const backgroundThrottling = contents.getBackgroundThrottling();\n if (backgroundThrottling) contents.setBackgroundThrottling(false);\n const network = observeDashboardNetwork(card.view.webContents);\n let stopped = false;\n let documentReady: (() => void) | undefined;\n const stopPreparation = () => {\n if (stopped) return;\n stopped = true;\n network.dispose();\n contents.removeListener(\"destroyed\", stopPreparation);\n if (documentReady) contents.removeListener(\"dom-ready\", documentReady);\n if (!contents.isDestroyed() && backgroundThrottling && !contents.getBackgroundThrottling())\n contents.setBackgroundThrottling(backgroundThrottling);\n if (card.stopPreparation === stopPreparation) card.stopPreparation = undefined;\n };\n card.stopPreparation = stopPreparation;\n contents.once(\"destroyed\", stopPreparation);\n const generation = ++card.generation;\n card.skeleton.view.setVisible(true);\n card.container.setVisible(card.visible && !card.floating);\n publishLoading(card);\n const settled = (failed: boolean) => {\n if (card.generation !== generation || card.view.webContents.isDestroyed()) return;\n card.failed = failed;\n card.loading = false;\n card.skeleton.view.setVisible(false);\n for (const [sender, owner] of owners) {\n if (![...owner.cards.values()].includes(card)) continue;\n card.container.setVisible(card.visible && !card.floating && !failed && dashboardUrl(sender.getURL()));\n }\n publishLoading(card);\n };\n const load = () => {\n if (\n card.generation !== generation ||\n card.view.webContents.isDestroyed() ||\n ![...owners.values()].some((owner) => [...owner.cards.values()].includes(card))\n )\n return Promise.resolve();\n if (navigation) return navigation;\n const navigate = () => {\n if (card.generation !== generation || contents.isDestroyed()) return Promise.resolve();\n card.requestedNavigation = true;\n return contents.loadURL(target).finally(() => {\n if (card.generation === generation) card.requestedNavigation = false;\n });\n };\n return prepareExisting ? prepareDashboardPage(contents).then(navigate) : navigate();\n };\n const ready = new Promise<void>((resolve) => {\n documentReady = resolve;\n contents.once(\"dom-ready\", documentReady);\n });\n card.pending = Promise.race([load(), ready]).then(\n async () => {\n let preparing = true;\n const current = () =>\n preparing &&\n card.generation === generation &&\n !card.view.webContents.isDestroyed() &&\n [...owners.values()].some((owner) => [...owner.cards.values()].includes(card));\n try {\n await waitForReadiness(contents, network, () => card.selector, current);\n if (current()) await releaseDashboardPage(contents);\n } finally {\n preparing = false;\n stopPreparation();\n }\n settled(false);\n },\n () => {\n if (card.generation === generation) void releaseDashboardPage(contents);\n stopPreparation();\n settled(true);\n },\n );\n return card.pending;\n };\n const applySelector = (card: { view: { webContents: WebContents }; selector?: string }) => {\n if (card.view.webContents.isDestroyed()) return Promise.resolve();\n return card.view.webContents.mainFrame.executeJavaScript(dashboardSelectorScript(card.selector)).catch(() => {});\n };\n const refreshTimers = () => {\n const configured = configuredCards();\n for (const [id, icon] of icons) {\n if (!configured.some((card) => card.id === id && card.url === icon.pageUrl)) {\n icons.delete(id);\n persistIcons();\n }\n }\n for (const [sender, owner] of owners) {\n for (const [id, card] of owner.cards) {\n const setting = configured.find((item) => item.id === id);\n if (!setting || setting.url !== card.url) {\n remove(owner, id);\n continue;\n }\n if (card.selector !== setting.selector) {\n card.selector = setting.selector;\n applySelector(card);\n card.floatingPreparation?.selectorChanged();\n }\n if (card.floating && !card.floating.isDestroyed()) card.floating.setTitle(setting.title);\n if (card.floatingStyles) {\n const scrollbars = setting.size === \"l\" || setting.size === \"xl\";\n if (card.floatingStyles.scrollbars !== scrollbars) {\n card.floatingStyles.scrollbars = scrollbars;\n void applyWebsiteStyles(card.floatingStyles);\n }\n }\n const interval = setting.refreshEvery10Seconds ? 10000 : setting.autoRefresh ? 600000 : undefined;\n if (card.refreshInterval === interval) continue;\n clearTimeout(card.refreshTimer);\n card.refreshTimer = undefined;\n card.refreshInterval = interval;\n const refreshGeneration = (card.refreshGeneration ?? 0) + 1;\n card.refreshGeneration = refreshGeneration;\n if (!interval) continue;\n const schedule = () => {\n if (\n owners.get(sender) !== owner ||\n owner.cards.get(id) !== card ||\n card.refreshGeneration !== refreshGeneration\n )\n return;\n if (card.loading && card.pending) {\n void card.pending.then(schedule);\n return;\n }\n card.refreshTimer = setTimeout(tick, interval);\n };\n const tick = async () => {\n try {\n const latest = configuredCards().find((item) => item.id === id);\n if (\n owners.get(sender) !== owner ||\n owner.cards.get(id) !== card ||\n !latest ||\n latest.url !== card.url ||\n (latest.refreshEvery10Seconds ? 10000 : latest.autoRefresh ? 600000 : undefined) !== interval ||\n card.view.webContents.isDestroyed()\n )\n return;\n if (card.loading) {\n await card.pending;\n return;\n }\n if (latest.refreshEvery10Seconds) {\n if (card.floating) {\n if (card.floating.isDestroyed() || card.floatingPreparation?.isPreparing()) return;\n await Promise.all([reload(card, latest.url), card.floatingPreparation?.refresh()]);\n } else if (card.visible && dashboardUrl(sender.getURL())) await reload(card, latest.url);\n } else if (!card.floating && !dashboardUrl(sender.getURL())) await reload(card, latest.url);\n } finally {\n schedule();\n }\n };\n schedule();\n }\n }\n };\n const stopSettingsReaction = reaction(\n () =>\n JSON.stringify(\n configuredCards().map(({ id, title, url, size, autoRefresh, refreshEvery10Seconds, selector }) => ({\n id,\n title,\n url,\n size,\n autoRefresh,\n refreshEvery10Seconds,\n selector,\n })),\n ),\n refreshTimers,\n );\n const trusted = (event: IpcMainInvokeEvent) =>\n event.senderFrame === event.sender.mainFrame &&\n dashboardUrl(event.senderFrame?.url ?? \"\") &&\n dashboardUrl(event.sender.getURL());\n ipcMain.handle(DASHBOARD_SITE_ICONS, async (event) => {\n if (\n event.senderFrame !== event.sender.mainFrame ||\n !rendererUrl(event.senderFrame?.url ?? \"\") ||\n !rendererUrl(event.sender.getURL()) ||\n !BrowserWindow.fromWebContents(event.sender)\n )\n return [];\n await ready;\n return configuredCards().flatMap((card) => {\n const icon = icons.get(card.id);\n return icon?.pageUrl === card.url ? [icon] : [];\n });\n });\n ipcMain.handle(syncChannel, async (event, payload: unknown) => {\n if (!trusted(event)) return;\n const window = BrowserWindow.fromWebContents(event.sender);\n if (!window || window.isDestroyed()) return;\n const requested =\n payload && typeof payload === \"object\" && \"cards\" in payload && Array.isArray(payload.cards) ? payload.cards : [];\n const cards = sanitizeDashboardCards(\n DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>().cards,\n );\n let owner = owners.get(event.sender);\n if (!owner) {\n const sender = event.sender;\n const navigation = (_event: unknown, url: string) => {\n if (!dashboardUrl(url)) hide(sender);\n };\n const destroyed = () => clear(sender);\n sender.on(\"did-navigate\", navigation);\n sender.on(\"did-navigate-in-page\", navigation);\n sender.on(\"destroyed\", destroyed);\n owner = {\n window,\n cards: new Map(),\n cleanup: () => {\n sender.removeListener(\"did-navigate\", navigation);\n sender.removeListener(\"did-navigate-in-page\", navigation);\n sender.removeListener(\"destroyed\", destroyed);\n },\n };\n owners.set(sender, owner);\n }\n if (payload && typeof payload === \"object\" && \"hidden\" in payload && payload.hidden === true) {\n hide(event.sender);\n return { failed: [], pinned: [...owner.cards].filter(([, card]) => card.floating).map(([id]) => id) };\n }\n const visible = new Set<string>();\n for (const item of requested.slice(0, cards.length)) {\n if (!item || typeof item !== \"object\" || typeof item.id !== \"string\" || visible.has(item.id)) continue;\n const configured = cards.find((card) => card.id === item.id);\n const bounds = rectangle(item.bounds);\n const clip = rectangle(item.clip);\n if (\n !configured ||\n !bounds ||\n !clip ||\n clip.x < bounds.x ||\n clip.y < bounds.y ||\n clip.x + clip.width > bounds.x + bounds.width ||\n clip.y + clip.height > bounds.y + bounds.height\n )\n continue;\n visible.add(item.id);\n let card = owner.cards.get(item.id);\n if (card?.floating) {\n card.visible = false;\n card.container.setVisible(false);\n continue;\n }\n if (!card) {\n const container = new View();\n container.setBackgroundColor(\"#00000000\");\n const view = new WebContentsView({\n webPreferences: {\n nodeIntegration: false,\n nodeIntegrationInSubFrames: false,\n contextIsolation: true,\n sandbox: true,\n webSecurity: true,\n partition: \"persist:freelens-power-websites\",\n preload: join(__dirname, \"dashboard-preload.js\"),\n },\n });\n view.setBackgroundColor(\"#00000000\");\n view.webContents.setWindowOpenHandler(({ url }) => {\n if (webUrl(url)) void shell.openExternal(url).catch(() => {});\n return { action: \"deny\" };\n });\n const navigation = (event: Electron.Event, url: string) => {\n if (!webUrl(url)) event.preventDefault();\n };\n view.webContents.on(\"will-navigate\", navigation);\n view.webContents.on(\"will-redirect\", navigation);\n view.webContents.on(\"will-frame-navigate\", (event) => {\n if (!webUrl(event.url)) event.preventDefault();\n });\n container.addChildView(view);\n const skeleton = createDashboardSkeleton();\n container.addChildView(skeleton.view);\n window.contentView.addChildView(container);\n card = { container, skeleton, view, url: \"\", failed: false, loading: false, visible: false, generation: 0 };\n owner.cards.set(item.id, card);\n const created = card;\n view.webContents.on(\"before-input-event\", (_event, input: Electron.Input) => {\n if (\n input.type !== \"keyDown\" ||\n input.key !== \"Escape\" ||\n owners.get(event.sender) !== owner ||\n owner.cards.get(item.id) !== created ||\n !trusted(event)\n )\n return;\n event.sender.send(\"freelens-power:dashboard-escape\");\n });\n created.selector = configured.selector;\n view.webContents.on(\"did-start-navigation\", (_event, _url, inPlace, mainFrame) => {\n if (!mainFrame) return;\n if (created.requestedNavigation) {\n created.requestedNavigation = false;\n return;\n }\n created.nativeNavigation?.fail();\n const navigation = new Promise<void>((resolve, reject) => {\n created.nativeNavigation = {\n finish: () => {\n created.nativeNavigation = undefined;\n resolve();\n },\n fail: () => {\n created.nativeNavigation = undefined;\n reject(new Error(\"dashboard navigation failed\"));\n },\n };\n });\n if (inPlace)\n void view.webContents.mainFrame\n .executeJavaScript('document.dispatchEvent(new Event(\"freelens-power:dashboard:preparing\"))')\n .catch(() => {});\n void reload(created, created.url, false, navigation);\n if (inPlace) created.nativeNavigation?.finish();\n });\n view.webContents.on(\"did-finish-load\", () => {\n void applyWebsiteStyles(created);\n void applySelector(created);\n created.nativeNavigation?.finish();\n });\n view.webContents.on(\"did-fail-load\", (_event, code, _description, _url, mainFrame) => {\n if (!mainFrame || (code === -3 && view.webContents.isLoading())) return;\n created.nativeNavigation?.fail();\n });\n view.webContents.on(\"page-favicon-updated\", (_event, favicons: string[]) => {\n const favicon = favicons.find((value) => {\n if (!webUrl(value)) return false;\n const parsed = new URL(value);\n return !parsed.username && !parsed.password;\n });\n if (!favicon || owners.get(event.sender) !== owner || owner.cards.get(item.id) !== created) return;\n created.faviconRequest?.abort();\n const request = new AbortController();\n created.faviconRequest = request;\n created.favicon = favicon;\n const publish = (url: string) => {\n if (\n request.signal.aborted ||\n owners.get(event.sender) !== owner ||\n owner.cards.get(item.id) !== created ||\n event.senderFrame !== event.sender.mainFrame\n )\n return;\n created.favicon = url;\n if (\n url.startsWith(\"data:\") &&\n configuredCards().some((card) => card.id === item.id && card.url === created.url)\n ) {\n icons.set(item.id, { id: item.id, pageUrl: created.url, dataUrl: url });\n persistIcons();\n if (rendererUrl(event.senderFrame?.url ?? \"\") && rendererUrl(event.sender.getURL()))\n event.sender.send(DASHBOARD_SITE_ICONS);\n }\n if (!trusted(event)) return;\n event.sender.send(\"freelens-power:dashboard-site-icon\", { id: item.id, url });\n };\n publish(favicon);\n const timeout = setTimeout(() => request.abort(), 5000);\n void (async () => {\n let current = favicon;\n for (let redirects = 0; redirects <= 5; redirects++) {\n const response = await websiteSession.fetch(current, {\n signal: request.signal,\n redirect: \"manual\",\n credentials: \"include\",\n });\n if (response.status >= 300 && response.status < 400) {\n await response.body?.cancel();\n const location = response.headers.get(\"location\");\n if (!location) return;\n const next = new URL(location, current);\n if (!webUrl(next.href) || next.username || next.password) return;\n current = next.href;\n continue;\n }\n const mime = response.headers.get(\"content-type\")?.split(\";\")[0].trim().toLowerCase();\n if (\n !response.ok ||\n !mime ||\n ![\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/x-icon\",\n \"image/vnd.microsoft.icon\",\n \"image/svg+xml\",\n ].includes(mime) ||\n Number(response.headers.get(\"content-length\")) > 524288\n ) {\n await response.body?.cancel();\n return;\n }\n const reader = response.body?.getReader();\n if (!reader) return;\n const chunks: Uint8Array[] = [];\n let size = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.length;\n if (size > 524288) {\n await reader.cancel();\n return;\n }\n chunks.push(value);\n }\n if (size) publish(`data:${mime};base64,${Buffer.concat(chunks).toString(\"base64\")}`);\n return;\n }\n })()\n .catch(() => {})\n .finally(() => clearTimeout(timeout));\n });\n }\n if (card.scrollbars !== (item.scrollbars === true)) {\n card.scrollbars = item.scrollbars === true;\n void applyWebsiteStyles(card);\n }\n card.visible = true;\n card.container.setVisible(!card.failed && (card.loading || card.url === configured.url));\n const zoom = event.sender.getZoomFactor();\n card.container.setBorderRadius(Math.round(12 * zoom));\n card.view.setBorderRadius(Math.round(12 * zoom));\n const scale = (rect: Rectangle): Rectangle => ({\n x: Math.round(rect.x * zoom),\n y: Math.round(rect.y * zoom),\n width: Math.round(rect.width * zoom),\n height: Math.round(rect.height * zoom),\n });\n card.container.setBounds(scale(clip));\n card.skeleton.layout(Math.round(clip.width * zoom), Math.round(clip.height * zoom));\n card.view.setBounds(\n scale({ x: bounds.x - clip.x, y: bounds.y - clip.y, width: bounds.width, height: bounds.height }),\n );\n if (card.url !== configured.url) {\n card.favicon = undefined;\n card.faviconRequest?.abort();\n void reload(card, configured.url, true);\n }\n publishLoading(card);\n if (card.favicon) event.sender.send(\"freelens-power:dashboard-site-icon\", { id: item.id, url: card.favicon });\n }\n for (const [id, card] of owner.cards) {\n if (!cards.some((configured) => configured.id === id)) remove(owner, id);\n else if (!visible.has(id)) {\n card.visible = false;\n card.container.setVisible(false);\n }\n }\n refreshTimers();\n await Promise.all([...owner.cards.values()].map((card) => card.pending));\n return {\n failed: [...owner.cards.entries()].filter(([, card]) => card.failed).map(([id]) => id),\n pinned: [...owner.cards].filter(([, card]) => card.floating).map(([id]) => id),\n };\n });\n const publishPinned = (sender: WebContents, owner: Owner) => {\n if (!sender.isDestroyed())\n sender.send(\n DASHBOARD_VIEWS_PINNED,\n [...owner.cards].filter(([, card]) => card.floating).map(([id]) => id),\n );\n };\n ipcMain.handle(DASHBOARD_VIEWS_PIN, (event, payload: unknown) => {\n if (\n !trusted(event) ||\n !payload ||\n typeof payload !== \"object\" ||\n !(\"id\" in payload) ||\n typeof payload.id !== \"string\" ||\n !((\"pinned\" in payload && typeof payload.pinned === \"boolean\") || (\"focus\" in payload && payload.focus === true))\n )\n return;\n const id = payload.id;\n const owner = owners.get(event.sender);\n const card = owner?.cards.get(payload.id);\n const configured = configuredCards().find((item) => item.id === payload.id);\n if (\n !owner ||\n !card ||\n !configured ||\n card.url !== configured.url ||\n owner.window.isDestroyed() ||\n BrowserWindow.fromWebContents(event.sender) !== owner.window ||\n card.view.webContents.isDestroyed()\n )\n return;\n if (\"focus\" in payload && payload.focus === true) {\n card.floating?.show();\n card.floating?.focus();\n } else if (!(\"pinned\" in payload) || !payload.pinned) {\n card.floating?.close();\n } else if (!card.floating) {\n const floating = new BrowserWindow({\n title: configured.title,\n width: 800,\n height: 600,\n minWidth: 240,\n minHeight: 160,\n resizable: true,\n alwaysOnTop: true,\n autoHideMenuBar: true,\n show: false,\n webPreferences: {\n nodeIntegration: false,\n nodeIntegrationInSubFrames: false,\n contextIsolation: true,\n sandbox: true,\n webSecurity: true,\n partition: \"persist:freelens-power-websites\",\n preload: join(__dirname, \"dashboard-preload.js\"),\n },\n });\n floating.setMenu(null);\n floating.setAlwaysOnTop(true, \"floating\");\n floating.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });\n card.floating = floating;\n card.container.setVisible(false);\n const contents = floating.webContents;\n const floatingStyles: WebsiteStyleState = {\n view: { webContents: contents },\n scrollbars: configured.size === \"l\" || configured.size === \"xl\",\n };\n card.floatingStyles = floatingStyles;\n contents.setWindowOpenHandler(({ url }) => {\n if (webUrl(url)) void shell.openExternal(url).catch(() => {});\n return { action: \"deny\" };\n });\n const navigation = (event: Electron.Event, url: string) => {\n if (!webUrl(url)) event.preventDefault();\n };\n contents.on(\"will-navigate\", navigation);\n contents.on(\"will-redirect\", navigation);\n contents.on(\"will-frame-navigate\", (event) => {\n if (!webUrl(event.url)) event.preventDefault();\n });\n contents.on(\"page-title-updated\", (event) => event.preventDefault());\n contents.on(\"will-prevent-unload\", (event) => event.preventDefault());\n const loadingSkeleton = createDashboardSkeleton();\n const skeleton = loadingSkeleton.view;\n const layoutSkeleton = () => {\n const { width, height } = floating.getContentBounds();\n loadingSkeleton.layout(width, height);\n };\n floating.contentView.addChildView(skeleton);\n floating.on(\"resize\", layoutSkeleton);\n layoutSkeleton();\n let generation = 0;\n let floatingPreparing = false;\n let stopPreparation = () => {};\n let finishLoad: (() => Promise<boolean>) | undefined;\n const begin = () => {\n stopPreparation();\n floatingPreparing = true;\n const token = ++generation;\n const backgroundThrottling = contents.getBackgroundThrottling();\n if (backgroundThrottling) contents.setBackgroundThrottling(false);\n const network = observeDashboardNetwork(contents);\n let active = true;\n let finishing: Promise<boolean> | undefined;\n const current = () => active && generation === token && card.floating === floating && !contents.isDestroyed();\n skeleton.setVisible(true);\n stopPreparation = () => {\n if (!active) return;\n active = false;\n floatingPreparing = false;\n network.dispose();\n if (!contents.isDestroyed() && backgroundThrottling) contents.setBackgroundThrottling(true);\n };\n const stop = stopPreparation;\n const finish = () => {\n finishing ??= (async () => {\n await waitForReadiness(contents, network, () => card.selector, current);\n if (!current()) return false;\n await releaseDashboardPage(contents);\n if (!current()) return false;\n skeleton.setVisible(false);\n stop();\n return false;\n })();\n return finishing;\n };\n finishLoad = finish;\n return {\n finish,\n fail: () => {\n if (current()) {\n void releaseDashboardPage(contents);\n skeleton.setVisible(false);\n stop();\n }\n },\n };\n };\n const refresh = () => {\n const preparation = begin();\n const current = contents.getURL();\n let documentReady: () => void;\n const ready = new Promise<boolean>((resolve) => {\n documentReady = () => {\n void (finishLoad?.() ?? Promise.resolve(false)).then(resolve);\n };\n contents.once(\"dom-ready\", documentReady);\n });\n const loading = prepareDashboardPage(contents)\n .then(() => contents.loadURL(webUrl(current) ? current : configured.url))\n .then(\n () => finishLoad?.() ?? false,\n () => {\n preparation.fail();\n return !contents.isDestroyed();\n },\n );\n return Promise.race([loading, ready]).finally(() => {\n contents.removeListener(\"dom-ready\", documentReady);\n });\n };\n card.floatingPreparation = {\n refresh,\n isPreparing: () => floatingPreparing,\n selectorChanged: () => {\n const preparation = begin();\n void preparation.finish();\n },\n stop: () => {\n ++generation;\n stopPreparation();\n },\n };\n contents.on(\"did-start-navigation\", (_event, _url, inPlace, mainFrame) => {\n if (!mainFrame) return;\n const preparation = begin();\n if (inPlace) void preparation.finish();\n });\n contents.on(\"dom-ready\", () => {\n void applyWebsiteStyles(floatingStyles);\n if (!contents.isDestroyed()) void finishLoad?.();\n });\n contents.on(\"did-finish-load\", () => {\n void applyWebsiteStyles(floatingStyles);\n if (!contents.isDestroyed()) void finishLoad?.();\n });\n contents.on(\"did-fail-load\", (_event, code, _description, _url, mainFrame) => {\n if (!mainFrame || code === -3) return;\n stopPreparation();\n void releaseDashboardPage(contents);\n skeleton.setVisible(false);\n });\n contents.once(\"destroyed\", () => {\n ++generation;\n stopPreparation();\n });\n floating.on(\"closed\", () => {\n if (card.floating !== floating) return;\n card.floatingPreparation?.stop();\n card.floatingPreparation = undefined;\n floatingStyles.websiteStylesGeneration = (floatingStyles.websiteStylesGeneration ?? 0) + 1;\n card.floatingStyles = undefined;\n card.floating = undefined;\n if (owner.cards.get(id) === card) publishPinned(event.sender, owner);\n });\n const initial = begin();\n void contents.loadURL(configured.url).then(() => finishLoad?.(), initial.fail);\n floating.show();\n }\n publishPinned(event.sender, owner);\n return { pinned: [...owner.cards].filter(([, item]) => item.floating).map(([id]) => id) };\n });\n ipcMain.handle(clearChannel, (event) => {\n if (\n event.senderFrame === event.sender.mainFrame &&\n rendererUrl(event.senderFrame?.url ?? \"\") &&\n rendererUrl(event.sender.getURL())\n )\n hide(event.sender);\n });\n ipcMain.handle(reloadChannel, async (event, payload: unknown) => {\n if (\n !trusted(event) ||\n !payload ||\n typeof payload !== \"object\" ||\n !(\"id\" in payload) ||\n typeof payload.id !== \"string\"\n )\n return;\n const owner = owners.get(event.sender);\n const card = owner?.cards.get(payload.id);\n const configured = sanitizeDashboardCards(\n DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>().cards,\n ).find((item) => item.id === payload.id);\n if (!card || !configured || card.view.webContents.isDestroyed()) return;\n const [, floatingFailed] = await Promise.all([\n reload(card, configured.url),\n card.floatingPreparation?.refresh() ?? Promise.resolve(false),\n ]);\n return { failed: card.failed || floatingFailed ? [payload.id] : [] };\n });\n return () => {\n stopSettingsReaction();\n ipcMain.removeHandler(DASHBOARD_VIEWS_PIN);\n ipcMain.removeHandler(DASHBOARD_SITE_ICONS);\n ipcMain.removeHandler(syncChannel);\n ipcMain.removeHandler(clearChannel);\n ipcMain.removeHandler(reloadChannel);\n for (const sender of owners.keys()) clear(sender);\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dashboard-views.js","names":[],"sources":["../../src/main/dashboard-views.ts"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\nimport { join } from \"node:path\";\nimport {\n app,\n BrowserWindow,\n type IpcMainInvokeEvent,\n ipcMain,\n nativeTheme,\n type Rectangle,\n session,\n shell,\n View,\n type WebContents,\n WebContentsView,\n} from \"electron\";\nimport { reaction } from \"mobx\";\nimport { sanitizeDashboardCards } from \"../common/dashboard\";\nimport { dashboardReadinessScript } from \"../common/dashboard-readiness\";\nimport { dashboardSelectorScript } from \"../common/dashboard-selector\";\nimport {\n DASHBOARD_SITE_ICONS,\n DASHBOARD_VIEWS_LOADING,\n DASHBOARD_VIEWS_PIN,\n DASHBOARD_VIEWS_PINNED,\n type DashboardSiteIcon,\n} from \"../common/dashboard-views\";\nimport { DashboardPreferencesStore } from \"../common/store/dashboard-preferences-store\";\nimport { boundedDashboardIcons, loadDashboardIcons, saveDashboardIcons } from \"./dashboard-icon-cache\";\nimport { observeDashboardNetwork } from \"./dashboard-network\";\n\nconst syncChannel = \"freelens-power:dashboard-views:sync\";\nconst reloadChannel = \"freelens-power:dashboard-views:reload\";\nconst clearChannel = \"freelens-power:dashboard-views:clear\";\nconst dashboardPath = \"/extension/freelens-power/dashboard\";\nconst websiteStyles =\n \"* { scrollbar-width: none !important; } *::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }\";\n\nconst expandedWebsiteStyles =\n \"* { scrollbar-width: auto !important; } *::-webkit-scrollbar { display: revert !important; width: revert !important; height: revert !important; }\";\n\nfunction rendererUrl(value: string, dashboardOnly = false): boolean {\n try {\n const url = new URL(value);\n return (\n url.protocol === \"https:\" &&\n (url.hostname === \"renderer.freelens.app\" || url.hostname.endsWith(\".renderer.freelens.app\")) &&\n (!dashboardOnly || url.pathname === dashboardPath)\n );\n } catch {\n return false;\n }\n}\nfunction dashboardUrl(value: string): boolean {\n return rendererUrl(value, true);\n}\nfunction webUrl(value: string): boolean {\n try {\n return [\"https:\", \"http:\"].includes(new URL(value).protocol);\n } catch {\n return false;\n }\n}\nfunction rectangle(value: unknown): Rectangle | undefined {\n if (!value || typeof value !== \"object\") return;\n const rect = value as Rectangle;\n if (\n ![rect.x, rect.y, rect.width, rect.height].every(\n (n) => Number.isFinite(n) && Number.isInteger(n) && Math.abs(n) <= 32768,\n ) ||\n rect.width <= 0 ||\n rect.height <= 0\n )\n return;\n return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };\n}\n\nfunction createDashboardSkeleton() {\n const view = new View();\n view.setBackgroundColor(nativeTheme.shouldUseDarkColors ? \"#202124\" : \"#ffffff\");\n const bars = Array.from({ length: 4 }, () => {\n const bar = new View();\n bar.setBackgroundColor(nativeTheme.shouldUseDarkColors ? \"#393b40\" : \"#e8e9eb\");\n bar.setBorderRadius(6);\n view.addChildView(bar);\n return bar;\n });\n return {\n view,\n layout: (width: number, height: number) => {\n view.setBounds({ x: 0, y: 0, width, height });\n bars.forEach((bar, index) => {\n bar.setBounds({\n x: 20,\n y: index === 0 ? 20 : 60 + (index - 1) * 24,\n width: Math.max(1, Math.round((width - 40) * (index === 0 ? 0.45 : 1))),\n height: index === 0 ? 20 : index === 3 ? Math.max(30, height - 128) : 12,\n });\n });\n },\n };\n}\n\ntype WebsiteStyleState = {\n view: { webContents: WebContents };\n scrollbars?: boolean;\n websiteStylesKey?: string;\n websiteStylesGeneration?: number;\n};\n\ntype CardView = {\n container: View;\n skeleton: ReturnType<typeof createDashboardSkeleton>;\n view: WebContentsView;\n url: string;\n failed: boolean;\n loading: boolean;\n visible: boolean;\n generation: number;\n stopPreparation?: () => void;\n selector?: string;\n scrollbars?: boolean;\n websiteStylesKey?: string;\n websiteStylesGeneration?: number;\n pending?: Promise<void>;\n requestedNavigation?: boolean;\n nativeNavigation?: { finish: () => void; fail: () => void };\n favicon?: string;\n faviconRequest?: AbortController;\n refreshTimer?: ReturnType<typeof setTimeout>;\n refreshInterval?: number;\n refreshGeneration?: number;\n floating?: BrowserWindow;\n floatingStyles?: WebsiteStyleState;\n floatingPreparation?: {\n refresh: () => Promise<boolean>;\n selectorChanged: () => void;\n stop: () => void;\n isPreparing: () => boolean;\n };\n};\ntype Owner = { window: BrowserWindow; cards: Map<string, CardView>; cleanup: () => void };\n\nasync function applyWebsiteStyles(card: WebsiteStyleState): Promise<void> {\n const contents = card.view.webContents;\n const generation = (card.websiteStylesGeneration ?? 0) + 1;\n card.websiteStylesGeneration = generation;\n const previous = card.websiteStylesKey;\n card.websiteStylesKey = undefined;\n if (contents.isDestroyed()) return;\n if (previous) await contents.removeInsertedCSS(previous).catch(() => {});\n if (card.websiteStylesGeneration !== generation || contents.isDestroyed()) return;\n const key = await contents\n .insertCSS(card.scrollbars ? expandedWebsiteStyles : websiteStyles, { cssOrigin: \"user\" })\n .catch(() => undefined);\n if (!key) return;\n if (card.websiteStylesGeneration === generation && !contents.isDestroyed()) card.websiteStylesKey = key;\n else if (!contents.isDestroyed()) await contents.removeInsertedCSS(key).catch(() => {});\n}\n\nasync function waitForReadiness(\n contents: WebContents,\n _network: ReturnType<typeof observeDashboardNetwork>,\n selector: () => string | undefined,\n current: () => boolean,\n): Promise<void> {\n let deadline: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n (async () => {\n if (!current()) return;\n await contents.mainFrame.executeJavaScript(dashboardSelectorScript(selector())).catch(() => {});\n if (!current()) return;\n await contents.mainFrame.executeJavaScript(dashboardReadinessScript(selector()));\n })().catch(() => new Promise<void>((resolve) => setTimeout(resolve, 200))),\n new Promise<void>((resolve) => {\n deadline = setTimeout(resolve, 8500);\n }),\n ]);\n } finally {\n clearTimeout(deadline);\n }\n}\n\nasync function prepareDashboardPage(contents: WebContents): Promise<void> {\n if (contents.isDestroyed()) return;\n let deadline: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n contents.mainFrame\n .executeJavaScript('document.dispatchEvent(new Event(\"freelens-power:dashboard:preparing\"))')\n .catch(() => {}),\n new Promise<void>((resolve) => {\n deadline = setTimeout(resolve, 250);\n }),\n ]);\n } finally {\n clearTimeout(deadline);\n }\n}\n\nfunction releaseDashboardPage(contents: WebContents): Promise<unknown> {\n if (contents.isDestroyed()) return Promise.resolve();\n return contents.mainFrame\n .executeJavaScript('document.dispatchEvent(new Event(\"freelens-power:dashboard:prepared\"))')\n .catch(() => {});\n}\n\nexport function startDashboardViews(): () => void {\n const websiteSession = session.fromPartition(\"persist:freelens-power-websites\");\n websiteSession.setPermissionRequestHandler((_contents, _permission, callback) => callback(false));\n websiteSession.setPermissionCheckHandler(() => false);\n const owners = new Map<WebContents, Owner>();\n const icons = new Map<string, DashboardSiteIcon>();\n const remove = (owner: Owner, id: string) => {\n const card = owner.cards.get(id);\n if (!card) return;\n owner.cards.delete(id);\n card.nativeNavigation?.fail();\n card.stopPreparation?.();\n card.websiteStylesGeneration = (card.websiteStylesGeneration ?? 0) + 1;\n card.faviconRequest?.abort();\n clearTimeout(card.refreshTimer);\n card.floatingPreparation?.stop();\n card.floating?.destroy();\n card.floating = undefined;\n if (!owner.window.isDestroyed()) owner.window.contentView.removeChildView(card.container);\n if (!card.view.webContents.isDestroyed()) card.view.webContents.close();\n };\n const clear = (sender: WebContents) => {\n const owner = owners.get(sender);\n if (!owner) return;\n owners.delete(sender);\n for (const id of owner.cards.keys()) remove(owner, id);\n owner.cleanup();\n };\n const hide = (sender: WebContents) => {\n for (const card of owners.get(sender)?.cards.values() ?? []) {\n card.visible = false;\n card.container.setVisible(false);\n }\n };\n const configuredCards = () =>\n sanitizeDashboardCards(DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>().cards);\n const cachePath = join(app.getPath(\"userData\"), \"freelens-power\", \"dashboard-icons.json\");\n const ready = loadDashboardIcons(cachePath).then((saved) => {\n const configured = configuredCards();\n for (const icon of saved) {\n if (!icons.has(icon.id) && configured.some((card) => card.id === icon.id && card.url === icon.pageUrl))\n icons.set(icon.id, icon);\n }\n });\n let writes = ready;\n const persistIcons = () => {\n writes = writes\n .then(async () => {\n const configured = configuredCards();\n const bounded = boundedDashboardIcons(\n [...icons.values()].filter((icon) =>\n configured.some((card) => card.id === icon.id && card.url === icon.pageUrl),\n ),\n );\n icons.clear();\n for (const icon of bounded) icons.set(icon.id, icon);\n await saveDashboardIcons(cachePath, bounded);\n })\n .catch(() => {});\n };\n persistIcons();\n const publishLoading = (card: CardView) => {\n for (const [sender, owner] of owners) {\n const id = [...owner.cards].find(([, candidate]) => candidate === card)?.[0];\n if (\n !id ||\n sender.isDestroyed() ||\n !dashboardUrl(sender.mainFrame.url) ||\n !dashboardUrl(sender.getURL()) ||\n !configuredCards().some((configured) => configured.id === id && configured.url === card.url)\n )\n continue;\n sender.send(DASHBOARD_VIEWS_LOADING, { id, url: card.url, loading: card.loading, failed: card.failed });\n }\n };\n const reload = (card: CardView, configuredUrl: string, initial = false, navigation?: Promise<void>) => {\n const current = card.view.webContents.getURL();\n const target = !initial && card.url === configuredUrl && webUrl(current) ? current : configuredUrl;\n const prepareExisting = !initial && !navigation && !card.loading && !card.failed && webUrl(current);\n card.faviconRequest?.abort();\n if (!navigation) card.nativeNavigation?.fail();\n card.url = configuredUrl;\n card.failed = false;\n card.loading = true;\n card.stopPreparation?.();\n const contents = card.view.webContents;\n const backgroundThrottling = contents.getBackgroundThrottling();\n if (backgroundThrottling) contents.setBackgroundThrottling(false);\n const network = observeDashboardNetwork(card.view.webContents);\n let stopped = false;\n let documentReady: (() => void) | undefined;\n const stopPreparation = () => {\n if (stopped) return;\n stopped = true;\n network.dispose();\n contents.removeListener(\"destroyed\", stopPreparation);\n if (documentReady) contents.removeListener(\"dom-ready\", documentReady);\n if (!contents.isDestroyed() && backgroundThrottling && !contents.getBackgroundThrottling())\n contents.setBackgroundThrottling(backgroundThrottling);\n if (card.stopPreparation === stopPreparation) card.stopPreparation = undefined;\n };\n card.stopPreparation = stopPreparation;\n contents.once(\"destroyed\", stopPreparation);\n const generation = ++card.generation;\n card.skeleton.view.setVisible(true);\n card.container.setVisible(card.visible && !card.floating);\n publishLoading(card);\n const settled = (failed: boolean) => {\n if (card.generation !== generation || card.view.webContents.isDestroyed()) return;\n card.failed = failed;\n card.loading = false;\n card.skeleton.view.setVisible(false);\n for (const [sender, owner] of owners) {\n if (![...owner.cards.values()].includes(card)) continue;\n card.container.setVisible(card.visible && !card.floating && !failed && dashboardUrl(sender.getURL()));\n }\n publishLoading(card);\n };\n const load = () => {\n if (\n card.generation !== generation ||\n card.view.webContents.isDestroyed() ||\n ![...owners.values()].some((owner) => [...owner.cards.values()].includes(card))\n )\n return Promise.resolve();\n if (navigation) return navigation;\n const navigate = () => {\n if (card.generation !== generation || contents.isDestroyed()) return Promise.resolve();\n card.requestedNavigation = true;\n return contents.loadURL(target).finally(() => {\n if (card.generation === generation) card.requestedNavigation = false;\n });\n };\n return prepareExisting ? prepareDashboardPage(contents).then(navigate) : navigate();\n };\n const ready = new Promise<void>((resolve) => {\n documentReady = resolve;\n contents.once(\"dom-ready\", documentReady);\n });\n card.pending = Promise.race([load(), ready]).then(\n async () => {\n let preparing = true;\n const current = () =>\n preparing &&\n card.generation === generation &&\n !card.view.webContents.isDestroyed() &&\n [...owners.values()].some((owner) => [...owner.cards.values()].includes(card));\n try {\n await waitForReadiness(contents, network, () => card.selector, current);\n if (current()) await releaseDashboardPage(contents);\n } finally {\n preparing = false;\n stopPreparation();\n }\n settled(false);\n },\n () => {\n if (card.generation === generation) void releaseDashboardPage(contents);\n stopPreparation();\n settled(true);\n },\n );\n return card.pending;\n };\n const applySelector = (card: { view: { webContents: WebContents }; selector?: string }) => {\n if (card.view.webContents.isDestroyed()) return Promise.resolve();\n return card.view.webContents.mainFrame.executeJavaScript(dashboardSelectorScript(card.selector)).catch(() => {});\n };\n const refreshTimers = () => {\n const configured = configuredCards();\n for (const [id, icon] of icons) {\n if (!configured.some((card) => card.id === id && card.url === icon.pageUrl)) {\n icons.delete(id);\n persistIcons();\n }\n }\n for (const [sender, owner] of owners) {\n for (const [id, card] of owner.cards) {\n const setting = configured.find((item) => item.id === id);\n if (!setting || setting.url !== card.url) {\n remove(owner, id);\n continue;\n }\n if (card.selector !== setting.selector) {\n card.selector = setting.selector;\n applySelector(card);\n card.floatingPreparation?.selectorChanged();\n }\n if (card.floating && !card.floating.isDestroyed()) card.floating.setTitle(setting.title);\n if (card.floatingStyles) {\n const scrollbars = setting.size === \"l\" || setting.size === \"xl\";\n if (card.floatingStyles.scrollbars !== scrollbars) {\n card.floatingStyles.scrollbars = scrollbars;\n void applyWebsiteStyles(card.floatingStyles);\n }\n }\n const interval = setting.refreshEvery10Seconds ? 10000 : setting.autoRefresh ? 600000 : undefined;\n if (card.refreshInterval === interval) continue;\n clearTimeout(card.refreshTimer);\n card.refreshTimer = undefined;\n card.refreshInterval = interval;\n const refreshGeneration = (card.refreshGeneration ?? 0) + 1;\n card.refreshGeneration = refreshGeneration;\n if (!interval) continue;\n const schedule = () => {\n if (\n owners.get(sender) !== owner ||\n owner.cards.get(id) !== card ||\n card.refreshGeneration !== refreshGeneration\n )\n return;\n if (card.loading && card.pending) {\n void card.pending.then(schedule);\n return;\n }\n card.refreshTimer = setTimeout(tick, interval);\n };\n const tick = async () => {\n try {\n const latest = configuredCards().find((item) => item.id === id);\n if (\n owners.get(sender) !== owner ||\n owner.cards.get(id) !== card ||\n !latest ||\n latest.url !== card.url ||\n (latest.refreshEvery10Seconds ? 10000 : latest.autoRefresh ? 600000 : undefined) !== interval ||\n card.view.webContents.isDestroyed()\n )\n return;\n if (card.loading) {\n await card.pending;\n return;\n }\n if (latest.refreshEvery10Seconds) {\n if (card.floating) {\n if (card.floating.isDestroyed() || card.floatingPreparation?.isPreparing()) return;\n await Promise.all([reload(card, latest.url), card.floatingPreparation?.refresh()]);\n } else if (card.visible && dashboardUrl(sender.getURL())) await reload(card, latest.url);\n } else if (!card.floating && !dashboardUrl(sender.getURL())) await reload(card, latest.url);\n } finally {\n schedule();\n }\n };\n schedule();\n }\n }\n };\n const stopSettingsReaction = reaction(\n () =>\n JSON.stringify(\n configuredCards().map(({ id, title, url, size, autoRefresh, refreshEvery10Seconds, selector }) => ({\n id,\n title,\n url,\n size,\n autoRefresh,\n refreshEvery10Seconds,\n selector,\n })),\n ),\n refreshTimers,\n );\n const trusted = (event: IpcMainInvokeEvent) =>\n event.senderFrame === event.sender.mainFrame &&\n dashboardUrl(event.senderFrame?.url ?? \"\") &&\n dashboardUrl(event.sender.getURL());\n ipcMain.handle(DASHBOARD_SITE_ICONS, async (event) => {\n if (\n event.senderFrame !== event.sender.mainFrame ||\n !rendererUrl(event.senderFrame?.url ?? \"\") ||\n !rendererUrl(event.sender.getURL()) ||\n !BrowserWindow.fromWebContents(event.sender)\n )\n return [];\n await ready;\n return configuredCards().flatMap((card) => {\n const icon = icons.get(card.id);\n return icon?.pageUrl === card.url ? [icon] : [];\n });\n });\n ipcMain.handle(syncChannel, async (event, payload: unknown) => {\n if (!trusted(event)) return;\n const window = BrowserWindow.fromWebContents(event.sender);\n if (!window || window.isDestroyed()) return;\n const requested =\n payload && typeof payload === \"object\" && \"cards\" in payload && Array.isArray(payload.cards) ? payload.cards : [];\n const cards = sanitizeDashboardCards(\n DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>().cards,\n );\n let owner = owners.get(event.sender);\n if (!owner) {\n const sender = event.sender;\n const navigation = (_event: unknown, url: string) => {\n if (!dashboardUrl(url)) hide(sender);\n };\n const destroyed = () => clear(sender);\n sender.on(\"did-navigate\", navigation);\n sender.on(\"did-navigate-in-page\", navigation);\n sender.on(\"destroyed\", destroyed);\n owner = {\n window,\n cards: new Map(),\n cleanup: () => {\n sender.removeListener(\"did-navigate\", navigation);\n sender.removeListener(\"did-navigate-in-page\", navigation);\n sender.removeListener(\"destroyed\", destroyed);\n },\n };\n owners.set(sender, owner);\n const activeOwner = owner;\n let backgrounded = false;\n const blur = () => {\n backgrounded = true;\n };\n const focus = () => {\n if (!backgrounded) return;\n backgrounded = false;\n if (!dashboardUrl(sender.getURL())) return;\n for (const [id, card] of activeOwner.cards) {\n const configured = configuredCards().find((item) => item.id === id);\n if (!card.visible || card.floating || !configured) continue;\n card.skeleton.view.setVisible(card.loading);\n card.container.setVisible(!card.failed || card.loading);\n if ((configured.refreshEvery10Seconds || configured.autoRefresh) && !card.loading)\n void reload(card, configured.url);\n }\n };\n window.on(\"blur\", blur);\n window.on(\"focus\", focus);\n const cleanup = owner.cleanup;\n owner.cleanup = () => {\n window.removeListener(\"blur\", blur);\n window.removeListener(\"focus\", focus);\n cleanup();\n };\n }\n if (payload && typeof payload === \"object\" && \"hidden\" in payload && payload.hidden === true) {\n hide(event.sender);\n return { failed: [], pinned: [...owner.cards].filter(([, card]) => card.floating).map(([id]) => id) };\n }\n const visible = new Set<string>();\n for (const item of requested.slice(0, cards.length)) {\n if (!item || typeof item !== \"object\" || typeof item.id !== \"string\" || visible.has(item.id)) continue;\n const configured = cards.find((card) => card.id === item.id);\n const bounds = rectangle(item.bounds);\n const clip = rectangle(item.clip);\n if (\n !configured ||\n !bounds ||\n !clip ||\n clip.x < bounds.x ||\n clip.y < bounds.y ||\n clip.x + clip.width > bounds.x + bounds.width ||\n clip.y + clip.height > bounds.y + bounds.height\n )\n continue;\n visible.add(item.id);\n let card = owner.cards.get(item.id);\n if (card?.floating) {\n card.visible = false;\n card.container.setVisible(false);\n continue;\n }\n if (!card) {\n const container = new View();\n container.setBackgroundColor(\"#00000000\");\n const view = new WebContentsView({\n webPreferences: {\n nodeIntegration: false,\n nodeIntegrationInSubFrames: false,\n contextIsolation: true,\n sandbox: true,\n webSecurity: true,\n partition: \"persist:freelens-power-websites\",\n preload: join(__dirname, \"dashboard-preload.js\"),\n },\n });\n view.setBackgroundColor(\"#00000000\");\n view.webContents.setWindowOpenHandler(({ url }) => {\n if (webUrl(url)) void shell.openExternal(url).catch(() => {});\n return { action: \"deny\" };\n });\n const navigation = (event: Electron.Event, url: string) => {\n if (!webUrl(url)) event.preventDefault();\n };\n view.webContents.on(\"will-navigate\", navigation);\n view.webContents.on(\"will-redirect\", navigation);\n view.webContents.on(\"will-frame-navigate\", (event) => {\n if (!webUrl(event.url)) event.preventDefault();\n });\n container.addChildView(view);\n const skeleton = createDashboardSkeleton();\n container.addChildView(skeleton.view);\n window.contentView.addChildView(container);\n card = { container, skeleton, view, url: \"\", failed: false, loading: false, visible: false, generation: 0 };\n owner.cards.set(item.id, card);\n const created = card;\n view.webContents.on(\"before-input-event\", (_event, input: Electron.Input) => {\n if (\n input.type !== \"keyDown\" ||\n input.key !== \"Escape\" ||\n owners.get(event.sender) !== owner ||\n owner.cards.get(item.id) !== created ||\n !trusted(event)\n )\n return;\n event.sender.send(\"freelens-power:dashboard-escape\");\n });\n created.selector = configured.selector;\n view.webContents.on(\"did-start-navigation\", (_event, _url, inPlace, mainFrame) => {\n if (!mainFrame) return;\n if (created.requestedNavigation) {\n created.requestedNavigation = false;\n return;\n }\n created.nativeNavigation?.fail();\n const navigation = new Promise<void>((resolve, reject) => {\n created.nativeNavigation = {\n finish: () => {\n created.nativeNavigation = undefined;\n resolve();\n },\n fail: () => {\n created.nativeNavigation = undefined;\n reject(new Error(\"dashboard navigation failed\"));\n },\n };\n });\n if (inPlace)\n void view.webContents.mainFrame\n .executeJavaScript('document.dispatchEvent(new Event(\"freelens-power:dashboard:preparing\"))')\n .catch(() => {});\n void reload(created, created.url, false, navigation);\n if (inPlace) created.nativeNavigation?.finish();\n });\n view.webContents.on(\"did-finish-load\", () => {\n void applyWebsiteStyles(created);\n void applySelector(created);\n created.nativeNavigation?.finish();\n });\n view.webContents.on(\"did-fail-load\", (_event, code, _description, _url, mainFrame) => {\n if (!mainFrame || (code === -3 && view.webContents.isLoading())) return;\n created.nativeNavigation?.fail();\n });\n view.webContents.on(\"page-favicon-updated\", (_event, favicons: string[]) => {\n const favicon = favicons.find((value) => {\n if (!webUrl(value)) return false;\n const parsed = new URL(value);\n return !parsed.username && !parsed.password;\n });\n if (!favicon || owners.get(event.sender) !== owner || owner.cards.get(item.id) !== created) return;\n created.faviconRequest?.abort();\n const request = new AbortController();\n created.faviconRequest = request;\n created.favicon = favicon;\n const publish = (url: string) => {\n if (\n request.signal.aborted ||\n owners.get(event.sender) !== owner ||\n owner.cards.get(item.id) !== created ||\n event.senderFrame !== event.sender.mainFrame\n )\n return;\n created.favicon = url;\n if (\n url.startsWith(\"data:\") &&\n configuredCards().some((card) => card.id === item.id && card.url === created.url)\n ) {\n icons.set(item.id, { id: item.id, pageUrl: created.url, dataUrl: url });\n persistIcons();\n if (rendererUrl(event.senderFrame?.url ?? \"\") && rendererUrl(event.sender.getURL()))\n event.sender.send(DASHBOARD_SITE_ICONS);\n }\n if (!trusted(event)) return;\n event.sender.send(\"freelens-power:dashboard-site-icon\", { id: item.id, url });\n };\n publish(favicon);\n const timeout = setTimeout(() => request.abort(), 5000);\n void (async () => {\n let current = favicon;\n for (let redirects = 0; redirects <= 5; redirects++) {\n const response = await websiteSession.fetch(current, {\n signal: request.signal,\n redirect: \"manual\",\n credentials: \"include\",\n });\n if (response.status >= 300 && response.status < 400) {\n await response.body?.cancel();\n const location = response.headers.get(\"location\");\n if (!location) return;\n const next = new URL(location, current);\n if (!webUrl(next.href) || next.username || next.password) return;\n current = next.href;\n continue;\n }\n const mime = response.headers.get(\"content-type\")?.split(\";\")[0].trim().toLowerCase();\n if (\n !response.ok ||\n !mime ||\n ![\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/x-icon\",\n \"image/vnd.microsoft.icon\",\n \"image/svg+xml\",\n ].includes(mime) ||\n Number(response.headers.get(\"content-length\")) > 524288\n ) {\n await response.body?.cancel();\n return;\n }\n const reader = response.body?.getReader();\n if (!reader) return;\n const chunks: Uint8Array[] = [];\n let size = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.length;\n if (size > 524288) {\n await reader.cancel();\n return;\n }\n chunks.push(value);\n }\n if (size) publish(`data:${mime};base64,${Buffer.concat(chunks).toString(\"base64\")}`);\n return;\n }\n })()\n .catch(() => {})\n .finally(() => clearTimeout(timeout));\n });\n }\n if (card.scrollbars !== (item.scrollbars === true)) {\n card.scrollbars = item.scrollbars === true;\n void applyWebsiteStyles(card);\n }\n card.visible = true;\n card.skeleton.view.setVisible(card.loading);\n card.container.setVisible(!card.failed && (card.loading || card.url === configured.url));\n const zoom = event.sender.getZoomFactor();\n card.container.setBorderRadius(Math.round(12 * zoom));\n card.view.setBorderRadius(Math.round(12 * zoom));\n const scale = (rect: Rectangle): Rectangle => ({\n x: Math.round(rect.x * zoom),\n y: Math.round(rect.y * zoom),\n width: Math.round(rect.width * zoom),\n height: Math.round(rect.height * zoom),\n });\n card.container.setBounds(scale(clip));\n card.skeleton.layout(Math.round(clip.width * zoom), Math.round(clip.height * zoom));\n card.view.setBounds(\n scale({ x: bounds.x - clip.x, y: bounds.y - clip.y, width: bounds.width, height: bounds.height }),\n );\n if (card.url !== configured.url) {\n card.favicon = undefined;\n card.faviconRequest?.abort();\n void reload(card, configured.url, true);\n }\n publishLoading(card);\n if (card.favicon) event.sender.send(\"freelens-power:dashboard-site-icon\", { id: item.id, url: card.favicon });\n }\n for (const [id, card] of owner.cards) {\n if (!cards.some((configured) => configured.id === id)) remove(owner, id);\n else if (!visible.has(id)) {\n card.visible = false;\n card.container.setVisible(false);\n }\n }\n refreshTimers();\n await Promise.all([...owner.cards.values()].map((card) => card.pending));\n return {\n failed: [...owner.cards.entries()].filter(([, card]) => card.failed).map(([id]) => id),\n pinned: [...owner.cards].filter(([, card]) => card.floating).map(([id]) => id),\n };\n });\n const publishPinned = (sender: WebContents, owner: Owner) => {\n if (!sender.isDestroyed())\n sender.send(\n DASHBOARD_VIEWS_PINNED,\n [...owner.cards].filter(([, card]) => card.floating).map(([id]) => id),\n );\n };\n ipcMain.handle(DASHBOARD_VIEWS_PIN, (event, payload: unknown) => {\n if (\n !trusted(event) ||\n !payload ||\n typeof payload !== \"object\" ||\n !(\"id\" in payload) ||\n typeof payload.id !== \"string\" ||\n !((\"pinned\" in payload && typeof payload.pinned === \"boolean\") || (\"focus\" in payload && payload.focus === true))\n )\n return;\n const id = payload.id;\n const owner = owners.get(event.sender);\n const card = owner?.cards.get(payload.id);\n const configured = configuredCards().find((item) => item.id === payload.id);\n if (\n !owner ||\n !card ||\n !configured ||\n card.url !== configured.url ||\n owner.window.isDestroyed() ||\n BrowserWindow.fromWebContents(event.sender) !== owner.window ||\n card.view.webContents.isDestroyed()\n )\n return;\n if (\"focus\" in payload && payload.focus === true) {\n card.floating?.show();\n card.floating?.focus();\n } else if (!(\"pinned\" in payload) || !payload.pinned) {\n card.floating?.close();\n } else if (!card.floating) {\n const floating = new BrowserWindow({\n title: configured.title,\n width: 800,\n height: 600,\n minWidth: 240,\n minHeight: 160,\n resizable: true,\n alwaysOnTop: true,\n autoHideMenuBar: true,\n show: false,\n webPreferences: {\n nodeIntegration: false,\n nodeIntegrationInSubFrames: false,\n contextIsolation: true,\n sandbox: true,\n webSecurity: true,\n partition: \"persist:freelens-power-websites\",\n preload: join(__dirname, \"dashboard-preload.js\"),\n },\n });\n floating.setMenu(null);\n floating.setAlwaysOnTop(true, \"floating\");\n floating.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });\n card.floating = floating;\n card.container.setVisible(false);\n const contents = floating.webContents;\n const floatingStyles: WebsiteStyleState = {\n view: { webContents: contents },\n scrollbars: configured.size === \"l\" || configured.size === \"xl\",\n };\n card.floatingStyles = floatingStyles;\n contents.setWindowOpenHandler(({ url }) => {\n if (webUrl(url)) void shell.openExternal(url).catch(() => {});\n return { action: \"deny\" };\n });\n const navigation = (event: Electron.Event, url: string) => {\n if (!webUrl(url)) event.preventDefault();\n };\n contents.on(\"will-navigate\", navigation);\n contents.on(\"will-redirect\", navigation);\n contents.on(\"will-frame-navigate\", (event) => {\n if (!webUrl(event.url)) event.preventDefault();\n });\n contents.on(\"page-title-updated\", (event) => event.preventDefault());\n contents.on(\"will-prevent-unload\", (event) => event.preventDefault());\n const loadingSkeleton = createDashboardSkeleton();\n const skeleton = loadingSkeleton.view;\n const layoutSkeleton = () => {\n const { width, height } = floating.getContentBounds();\n loadingSkeleton.layout(width, height);\n };\n floating.contentView.addChildView(skeleton);\n floating.on(\"resize\", layoutSkeleton);\n layoutSkeleton();\n let generation = 0;\n let floatingPreparing = false;\n let stopPreparation = () => {};\n let finishLoad: (() => Promise<boolean>) | undefined;\n const begin = () => {\n stopPreparation();\n floatingPreparing = true;\n const token = ++generation;\n const backgroundThrottling = contents.getBackgroundThrottling();\n if (backgroundThrottling) contents.setBackgroundThrottling(false);\n const network = observeDashboardNetwork(contents);\n let active = true;\n let finishing: Promise<boolean> | undefined;\n const current = () => active && generation === token && card.floating === floating && !contents.isDestroyed();\n skeleton.setVisible(true);\n stopPreparation = () => {\n if (!active) return;\n active = false;\n floatingPreparing = false;\n network.dispose();\n if (!contents.isDestroyed() && backgroundThrottling) contents.setBackgroundThrottling(true);\n };\n const stop = stopPreparation;\n const finish = () => {\n finishing ??= (async () => {\n await waitForReadiness(contents, network, () => card.selector, current);\n if (!current()) return false;\n await releaseDashboardPage(contents);\n if (!current()) return false;\n skeleton.setVisible(false);\n stop();\n return false;\n })();\n return finishing;\n };\n finishLoad = finish;\n return {\n finish,\n fail: () => {\n if (current()) {\n void releaseDashboardPage(contents);\n skeleton.setVisible(false);\n stop();\n }\n },\n };\n };\n const refresh = () => {\n const preparation = begin();\n const current = contents.getURL();\n let documentReady: () => void;\n const ready = new Promise<boolean>((resolve) => {\n documentReady = () => {\n void (finishLoad?.() ?? Promise.resolve(false)).then(resolve);\n };\n contents.once(\"dom-ready\", documentReady);\n });\n const loading = prepareDashboardPage(contents)\n .then(() => contents.loadURL(webUrl(current) ? current : configured.url))\n .then(\n () => finishLoad?.() ?? false,\n () => {\n preparation.fail();\n return !contents.isDestroyed();\n },\n );\n return Promise.race([loading, ready]).finally(() => {\n contents.removeListener(\"dom-ready\", documentReady);\n });\n };\n card.floatingPreparation = {\n refresh,\n isPreparing: () => floatingPreparing,\n selectorChanged: () => {\n const preparation = begin();\n void preparation.finish();\n },\n stop: () => {\n ++generation;\n stopPreparation();\n },\n };\n contents.on(\"did-start-navigation\", (_event, _url, inPlace, mainFrame) => {\n if (!mainFrame) return;\n const preparation = begin();\n if (inPlace) void preparation.finish();\n });\n contents.on(\"dom-ready\", () => {\n void applyWebsiteStyles(floatingStyles);\n if (!contents.isDestroyed()) void finishLoad?.();\n });\n contents.on(\"did-finish-load\", () => {\n void applyWebsiteStyles(floatingStyles);\n if (!contents.isDestroyed()) void finishLoad?.();\n });\n contents.on(\"did-fail-load\", (_event, code, _description, _url, mainFrame) => {\n if (!mainFrame || code === -3) return;\n stopPreparation();\n void releaseDashboardPage(contents);\n skeleton.setVisible(false);\n });\n contents.once(\"destroyed\", () => {\n ++generation;\n stopPreparation();\n });\n floating.on(\"closed\", () => {\n if (card.floating !== floating) return;\n card.floatingPreparation?.stop();\n card.floatingPreparation = undefined;\n floatingStyles.websiteStylesGeneration = (floatingStyles.websiteStylesGeneration ?? 0) + 1;\n card.floatingStyles = undefined;\n card.floating = undefined;\n if (owner.cards.get(id) === card) publishPinned(event.sender, owner);\n });\n const initial = begin();\n void contents.loadURL(configured.url).then(() => finishLoad?.(), initial.fail);\n floating.show();\n }\n publishPinned(event.sender, owner);\n return { pinned: [...owner.cards].filter(([, item]) => item.floating).map(([id]) => id) };\n });\n ipcMain.handle(clearChannel, (event) => {\n if (\n event.senderFrame === event.sender.mainFrame &&\n rendererUrl(event.senderFrame?.url ?? \"\") &&\n rendererUrl(event.sender.getURL())\n )\n hide(event.sender);\n });\n ipcMain.handle(reloadChannel, async (event, payload: unknown) => {\n if (\n !trusted(event) ||\n !payload ||\n typeof payload !== \"object\" ||\n !(\"id\" in payload) ||\n typeof payload.id !== \"string\"\n )\n return;\n const owner = owners.get(event.sender);\n const card = owner?.cards.get(payload.id);\n const configured = sanitizeDashboardCards(\n DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>().cards,\n ).find((item) => item.id === payload.id);\n if (!card || !configured || card.view.webContents.isDestroyed()) return;\n const [, floatingFailed] = await Promise.all([\n reload(card, configured.url),\n card.floatingPreparation?.refresh() ?? Promise.resolve(false),\n ]);\n return { failed: card.failed || floatingFailed ? [payload.id] : [] };\n });\n return () => {\n stopSettingsReaction();\n ipcMain.removeHandler(DASHBOARD_VIEWS_PIN);\n ipcMain.removeHandler(DASHBOARD_SITE_ICONS);\n ipcMain.removeHandler(syncChannel);\n ipcMain.removeHandler(clearChannel);\n ipcMain.removeHandler(reloadChannel);\n for (const sender of owners.keys()) clear(sender);\n };\n}\n"],"mappings":"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"}
|
|
@@ -93,6 +93,11 @@ var PowerLogsDatabase = class {
|
|
|
93
93
|
this.remove(request.captureId);
|
|
94
94
|
return true;
|
|
95
95
|
}
|
|
96
|
+
if (request.operation === "save-sql") {
|
|
97
|
+
if (typeof request.sql !== "string" || request.sql.length > 65536 || request.sql.includes("\0")) throw new Error("Invalid SQL draft");
|
|
98
|
+
capture.meta.lastSql = request.sql;
|
|
99
|
+
return { ...capture.meta };
|
|
100
|
+
}
|
|
96
101
|
if (request.operation === "export") throw new Error("Export requires trusted destination");
|
|
97
102
|
if (request.operation === "append") {
|
|
98
103
|
if (capture.meta.state !== "collecting") throw new Error("Capture is complete");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"power-logs-database.js","names":[],"sources":["../../src/main/power-logs-database.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { appendFileSync, chmodSync, createReadStream, mkdirSync, rmSync, truncateSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { POWER_LOGS_LIMITS as L, type LogCapture, type LogRequest } from \"../common/power-logs\";\n\nimport type { PowerLogsQuerySnapshot } from \"./power-logs-query\";\n\ntype Capture = {\n meta: LogCapture;\n partition: string;\n directory: string;\n spool: string;\n database: string;\n limits: { captureBytes: number; captureRows: number };\n};\nexport class PowerLogsDatabase {\n private captures = new Map<string, Capture>();\n private closed = false;\n private timer: ReturnType<typeof setInterval>;\n constructor(private directory: string) {\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n chmodSync(directory, 0o700);\n this.timer = setInterval(() => this.expire(), 30000);\n this.timer.unref();\n }\n private partition(request: LogRequest): string {\n return JSON.stringify([request.clusterId, request.contextId]);\n }\n private expire(): void {\n for (const [id, capture] of this.captures) {\n if (capture.meta.expiresAt > Date.now()) continue;\n try {\n this.remove(id);\n } catch {\n // retain expired entries within the capture limit until a later sweep can remove locked files\n }\n }\n }\n private remove(id: string): void {\n const capture = this.captures.get(id);\n if (!capture) return;\n try {\n rmSync(capture.directory, { recursive: true, force: true });\n } catch {\n throw new Error(\"Log capture storage is busy or unavailable\");\n }\n this.captures.delete(id);\n }\n exportPath(request: LogRequest & { captureId: string }): string {\n return this.capture(request).spool;\n }\n private capture(request: LogRequest & { captureId: string }): Capture {\n const capture = this.captures.get(request.captureId);\n if (!capture || capture.partition !== this.partition(request) || capture.meta.expiresAt <= Date.now())\n throw new Error(\"Capture unavailable\");\n return capture;\n }\n async run(request: LogRequest): Promise<unknown> {\n if (this.closed) throw new Error(\"Log storage unavailable\");\n this.expire();\n if (request.operation === \"permit\" || \"streamId\" in request) throw new Error(\"Log permits require main process\");\n const partition = this.partition(request);\n if (request.operation === \"cancel\") return true;\n if (request.operation === \"list\")\n return [...this.captures.values()]\n .filter((c) => c.partition === partition && c.meta.expiresAt > Date.now())\n .map((c) => ({ ...c.meta }));\n if (request.operation === \"create\") {\n if (this.captures.size >= L.captures) throw new Error(\"Capture limit reached\");\n const id = randomUUID(),\n directory = join(this.directory, id),\n now = Date.now();\n mkdirSync(directory, { mode: 0o700 });\n const spool = join(directory, \"logs.ndjson\");\n writeFileSync(spool, \"\", { mode: 0o600 });\n const meta: LogCapture = {\n id,\n target: request.target,\n createdAt: now,\n expiresAt: now + L.ttlMs,\n state: \"collecting\",\n rows: 0,\n bytes: 0,\n notes: [],\n };\n this.captures.set(id, {\n meta,\n partition,\n directory,\n spool,\n database: join(directory, \"logs.sqlite\"),\n limits: { captureBytes: L.captureBytes, captureRows: L.captureRows },\n });\n return { ...meta };\n }\n const capture = this.capture(request);\n if (request.operation === \"delete\") {\n this.remove(request.captureId);\n return true;\n }\n if (request.operation === \"export\") throw new Error(\"Export requires trusted destination\");\n if (request.operation === \"append\") {\n if (capture.meta.state !== \"collecting\") throw new Error(\"Capture is complete\");\n if (request.records.length > L.batchRows) throw new Error(\"Log batch exceeds limit\");\n const data = request.records\n .map((record) => JSON.stringify({ ...record, previous: record.previous === true }) + \"\\n\")\n .join(\"\");\n const bytes = Buffer.byteLength(data);\n if (\n bytes > L.batchBytes ||\n capture.meta.bytes + bytes > capture.limits.captureBytes ||\n capture.meta.rows + request.records.length > capture.limits.captureRows\n )\n throw new Error(\"Capture limit reached\");\n try {\n appendFileSync(capture.spool, data);\n } catch {\n truncateSync(capture.spool, capture.meta.bytes);\n throw new Error(\"Log capture storage unavailable\");\n }\n capture.meta.rows += request.records.length;\n capture.meta.bytes += bytes;\n return { ...capture.meta };\n }\n if (request.operation === \"finish\") {\n if (capture.meta.state !== \"collecting\") return { ...capture.meta };\n let database: DatabaseSync | undefined;\n try {\n writeFileSync(capture.database, \"\", { mode: 0o600 });\n database = new DatabaseSync(capture.database, { allowExtension: false });\n database.exec(\n \"PRAGMA journal_mode=OFF; PRAGMA synchronous=OFF; PRAGMA cache_size=-16384; PRAGMA temp_store=MEMORY\",\n );\n database.exec(\n \"CREATE TABLE logs(timestamp INTEGER, pod TEXT, podUid TEXT, container TEXT, level TEXT, message TEXT, fieldsJson TEXT, previous INTEGER CHECK(previous IN (0,1)))\",\n );\n const insert = database.prepare(\"INSERT INTO logs VALUES (?, ?, ?, ?, ?, ?, ?, ?)\");\n const input = createReadStream(capture.spool);\n const lines = createInterface({ input, crlfDelay: Infinity });\n let count = 0;\n database.exec(\"BEGIN\");\n try {\n for await (const line of lines) {\n const record = JSON.parse(line);\n insert.run(\n record.timestamp,\n record.pod,\n record.podUid,\n record.container,\n record.level,\n record.message,\n record.fieldsJson,\n record.previous ? 1 : 0,\n );\n if (++count % 5000 === 0) {\n database.exec(\"COMMIT; BEGIN\");\n await new Promise<void>((resolve) => setImmediate(resolve));\n }\n }\n database.exec(\"COMMIT\");\n } finally {\n lines.close();\n input.destroy();\n }\n database.exec(\"CREATE INDEX logs_timestamp ON logs(timestamp)\");\n } catch {\n database?.close();\n database = undefined;\n rmSync(capture.database, { force: true });\n throw new Error(\"Log capture storage unavailable\");\n } finally {\n database?.close();\n }\n capture.meta.state = request.partial ? \"partial\" : \"ready\";\n capture.meta.notes = request.notes;\n return { ...capture.meta };\n }\n if (capture.meta.state === \"collecting\") throw new Error(\"Finish capture before querying\");\n return {\n database: capture.database,\n captureId: capture.meta.id,\n expiresAt: capture.meta.expiresAt,\n } satisfies PowerLogsQuerySnapshot;\n }\n close(): void {\n this.closed = true;\n clearInterval(this.timer);\n this.captures.clear();\n rmSync(this.directory, { recursive: true, force: true });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"power-logs-database.js","names":[],"sources":["../../src/main/power-logs-database.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { appendFileSync, chmodSync, createReadStream, mkdirSync, rmSync, truncateSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { POWER_LOGS_LIMITS as L, type LogCapture, type LogRequest } from \"../common/power-logs\";\n\nimport type { PowerLogsQuerySnapshot } from \"./power-logs-query\";\n\ntype Capture = {\n meta: LogCapture;\n partition: string;\n directory: string;\n spool: string;\n database: string;\n limits: { captureBytes: number; captureRows: number };\n};\nexport class PowerLogsDatabase {\n private captures = new Map<string, Capture>();\n private closed = false;\n private timer: ReturnType<typeof setInterval>;\n constructor(private directory: string) {\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n chmodSync(directory, 0o700);\n this.timer = setInterval(() => this.expire(), 30000);\n this.timer.unref();\n }\n private partition(request: LogRequest): string {\n return JSON.stringify([request.clusterId, request.contextId]);\n }\n private expire(): void {\n for (const [id, capture] of this.captures) {\n if (capture.meta.expiresAt > Date.now()) continue;\n try {\n this.remove(id);\n } catch {\n // retain expired entries within the capture limit until a later sweep can remove locked files\n }\n }\n }\n private remove(id: string): void {\n const capture = this.captures.get(id);\n if (!capture) return;\n try {\n rmSync(capture.directory, { recursive: true, force: true });\n } catch {\n throw new Error(\"Log capture storage is busy or unavailable\");\n }\n this.captures.delete(id);\n }\n exportPath(request: LogRequest & { captureId: string }): string {\n return this.capture(request).spool;\n }\n private capture(request: LogRequest & { captureId: string }): Capture {\n const capture = this.captures.get(request.captureId);\n if (!capture || capture.partition !== this.partition(request) || capture.meta.expiresAt <= Date.now())\n throw new Error(\"Capture unavailable\");\n return capture;\n }\n async run(request: LogRequest): Promise<unknown> {\n if (this.closed) throw new Error(\"Log storage unavailable\");\n this.expire();\n if (request.operation === \"permit\" || \"streamId\" in request) throw new Error(\"Log permits require main process\");\n const partition = this.partition(request);\n if (request.operation === \"cancel\") return true;\n if (request.operation === \"list\")\n return [...this.captures.values()]\n .filter((c) => c.partition === partition && c.meta.expiresAt > Date.now())\n .map((c) => ({ ...c.meta }));\n if (request.operation === \"create\") {\n if (this.captures.size >= L.captures) throw new Error(\"Capture limit reached\");\n const id = randomUUID(),\n directory = join(this.directory, id),\n now = Date.now();\n mkdirSync(directory, { mode: 0o700 });\n const spool = join(directory, \"logs.ndjson\");\n writeFileSync(spool, \"\", { mode: 0o600 });\n const meta: LogCapture = {\n id,\n target: request.target,\n createdAt: now,\n expiresAt: now + L.ttlMs,\n state: \"collecting\",\n rows: 0,\n bytes: 0,\n notes: [],\n };\n this.captures.set(id, {\n meta,\n partition,\n directory,\n spool,\n database: join(directory, \"logs.sqlite\"),\n limits: { captureBytes: L.captureBytes, captureRows: L.captureRows },\n });\n return { ...meta };\n }\n const capture = this.capture(request);\n if (request.operation === \"delete\") {\n this.remove(request.captureId);\n return true;\n }\n if (request.operation === \"save-sql\") {\n if (typeof request.sql !== \"string\" || request.sql.length > 65536 || request.sql.includes(\"\\0\"))\n throw new Error(\"Invalid SQL draft\");\n capture.meta.lastSql = request.sql;\n return { ...capture.meta };\n }\n if (request.operation === \"export\") throw new Error(\"Export requires trusted destination\");\n if (request.operation === \"append\") {\n if (capture.meta.state !== \"collecting\") throw new Error(\"Capture is complete\");\n if (request.records.length > L.batchRows) throw new Error(\"Log batch exceeds limit\");\n const data = request.records\n .map((record) => JSON.stringify({ ...record, previous: record.previous === true }) + \"\\n\")\n .join(\"\");\n const bytes = Buffer.byteLength(data);\n if (\n bytes > L.batchBytes ||\n capture.meta.bytes + bytes > capture.limits.captureBytes ||\n capture.meta.rows + request.records.length > capture.limits.captureRows\n )\n throw new Error(\"Capture limit reached\");\n try {\n appendFileSync(capture.spool, data);\n } catch {\n truncateSync(capture.spool, capture.meta.bytes);\n throw new Error(\"Log capture storage unavailable\");\n }\n capture.meta.rows += request.records.length;\n capture.meta.bytes += bytes;\n return { ...capture.meta };\n }\n if (request.operation === \"finish\") {\n if (capture.meta.state !== \"collecting\") return { ...capture.meta };\n let database: DatabaseSync | undefined;\n try {\n writeFileSync(capture.database, \"\", { mode: 0o600 });\n database = new DatabaseSync(capture.database, { allowExtension: false });\n database.exec(\n \"PRAGMA journal_mode=OFF; PRAGMA synchronous=OFF; PRAGMA cache_size=-16384; PRAGMA temp_store=MEMORY\",\n );\n database.exec(\n \"CREATE TABLE logs(timestamp INTEGER, pod TEXT, podUid TEXT, container TEXT, level TEXT, message TEXT, fieldsJson TEXT, previous INTEGER CHECK(previous IN (0,1)))\",\n );\n const insert = database.prepare(\"INSERT INTO logs VALUES (?, ?, ?, ?, ?, ?, ?, ?)\");\n const input = createReadStream(capture.spool);\n const lines = createInterface({ input, crlfDelay: Infinity });\n let count = 0;\n database.exec(\"BEGIN\");\n try {\n for await (const line of lines) {\n const record = JSON.parse(line);\n insert.run(\n record.timestamp,\n record.pod,\n record.podUid,\n record.container,\n record.level,\n record.message,\n record.fieldsJson,\n record.previous ? 1 : 0,\n );\n if (++count % 5000 === 0) {\n database.exec(\"COMMIT; BEGIN\");\n await new Promise<void>((resolve) => setImmediate(resolve));\n }\n }\n database.exec(\"COMMIT\");\n } finally {\n lines.close();\n input.destroy();\n }\n database.exec(\"CREATE INDEX logs_timestamp ON logs(timestamp)\");\n } catch {\n database?.close();\n database = undefined;\n rmSync(capture.database, { force: true });\n throw new Error(\"Log capture storage unavailable\");\n } finally {\n database?.close();\n }\n capture.meta.state = request.partial ? \"partial\" : \"ready\";\n capture.meta.notes = request.notes;\n return { ...capture.meta };\n }\n if (capture.meta.state === \"collecting\") throw new Error(\"Finish capture before querying\");\n return {\n database: capture.database,\n captureId: capture.meta.id,\n expiresAt: capture.meta.expiresAt,\n } satisfies PowerLogsQuerySnapshot;\n }\n close(): void {\n this.closed = true;\n clearInterval(this.timer);\n this.captures.clear();\n rmSync(this.directory, { recursive: true, force: true });\n }\n}\n"],"mappings":"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"}
|
|
@@ -97,6 +97,14 @@ function validateLogRequest(input) {
|
|
|
97
97
|
...scoped,
|
|
98
98
|
operation: r.operation
|
|
99
99
|
};
|
|
100
|
+
if (r.operation === "save-sql") {
|
|
101
|
+
if (!text(r.sql, 65536)) return fail();
|
|
102
|
+
return {
|
|
103
|
+
...scoped,
|
|
104
|
+
operation: "save-sql",
|
|
105
|
+
sql: r.sql
|
|
106
|
+
};
|
|
107
|
+
}
|
|
100
108
|
if (r.operation === "query") {
|
|
101
109
|
if (!identifier(r.queryId) || !text(r.sql, 65536) || !r.sql.trim()) return fail();
|
|
102
110
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"power-logs-ipc.js","names":[],"sources":["../../src/main/power-logs-ipc.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { Main } from \"@freelensapp/extensions\";\nimport { BrowserWindow, dialog, ipcMain } from \"electron\";\nimport { reaction } from \"mobx\";\nimport {\n POWER_LOGS_LIMITS as L,\n type LogRecord,\n type LogRequest,\n type LogTarget,\n POWER_LOGS_CHANNEL,\n} from \"../common/power-logs\";\nimport { applyPowerLogsLimits, normalizePowerLogsLimits } from \"../common/power-logs-limits\";\nimport { LogsPreferencesStore } from \"../common/store/logs-preferences-store\";\nimport {\n acquirePowerLogStream,\n cancelPowerLogPermits,\n releasePowerLogStream,\n renewPowerLogStream,\n requestPowerLogPermit,\n startPowerLogBudget,\n} from \"./power-logs-budget\";\nimport { PowerLogsWorker, sweepPowerLogsStorage } from \"./power-logs-worker\";\nimport { trustedSearchSender } from \"./resource-search\";\n\nconst text = (value: unknown, limit: number): value is string =>\n typeof value === \"string\" && value.length <= limit && !/[\\x00]/.test(value);\nconst identifier = (value: unknown): value is string => text(value, 253) && /^[a-zA-Z0-9_.:-]+$/.test(value);\nconst fail = (): never => {\n throw new Error(\"Invalid log request\");\n};\nexport function validateLogRequest(input: unknown): LogRequest {\n if (!input || typeof input !== \"object\") return fail();\n const r = input as LogRequest;\n if (!identifier(r.clusterId) || !text(r.contextId, 512) || !r.contextId) return fail();\n const partition = { clusterId: r.clusterId, contextId: r.contextId };\n if (r.operation === \"stream-open\" || r.operation === \"stream-close\" || r.operation === \"stream-renew\") {\n if (!identifier(r.streamId)) return fail();\n if (r.operation === \"stream-open\") {\n if (typeof r.follow !== \"boolean\") return fail();\n return { ...partition, operation: \"stream-open\", streamId: r.streamId, follow: r.follow };\n }\n return { ...partition, operation: r.operation, streamId: r.streamId };\n }\n if (r.operation === \"permit\") {\n if (r.lane === \"start\" && r.bytes === undefined) return { ...partition, operation: \"permit\", lane: \"start\" };\n if (r.lane === \"bytes\" && Number.isSafeInteger(r.bytes) && r.bytes! > 0 && r.bytes! <= L.batchBytes)\n return { ...partition, operation: \"permit\", lane: \"bytes\", bytes: r.bytes };\n return fail();\n }\n if (r.operation === \"list\") return { ...partition, operation: \"list\" };\n if (r.operation === \"cancel\") {\n if (!identifier(r.queryId)) return fail();\n return { ...partition, operation: \"cancel\", queryId: r.queryId };\n }\n if (r.operation === \"create\") {\n const t = r.target as LogTarget | undefined;\n if (\n !t ||\n ![\"Pod\", \"Deployment\", \"DaemonSet\", \"StatefulSet\", \"ReplicaSet\", \"Job\", \"CronJob\"].includes(t.kind) ||\n !identifier(t.namespace) ||\n !identifier(t.name) ||\n !identifier(t.uid)\n )\n return fail();\n return {\n ...partition,\n operation: \"create\",\n target: { kind: t.kind, namespace: t.namespace, name: t.name, uid: t.uid },\n };\n }\n if (!(\"captureId\" in r) || !identifier(r.captureId)) return fail();\n const scoped = { ...partition, captureId: r.captureId };\n if (r.operation === \"delete\" || r.operation === \"export\") return { ...scoped, operation: r.operation };\n if (r.operation === \"query\") {\n if (!identifier(r.queryId) || !text(r.sql, 65536) || !r.sql.trim()) return fail();\n return { ...scoped, operation: \"query\", queryId: r.queryId, sql: r.sql };\n }\n if (r.operation === \"finish\") {\n if (\n typeof r.partial !== \"boolean\" ||\n !Array.isArray(r.notes) ||\n r.notes.length > 20 ||\n r.notes.some((n) => !text(n, 512))\n )\n return fail();\n return { ...scoped, operation: \"finish\", partial: r.partial, notes: [...r.notes] };\n }\n if (r.operation !== \"append\" || !Array.isArray(r.records) || r.records.length > L.batchRows) return fail();\n const records: LogRecord[] = r.records.map((record) => {\n if (\n !record ||\n typeof record !== \"object\" ||\n (record.timestamp !== null && (!Number.isSafeInteger(record.timestamp) || record.timestamp < 0)) ||\n !identifier(record.pod) ||\n !identifier(record.podUid) ||\n !identifier(record.container) ||\n (record.previous !== undefined && typeof record.previous !== \"boolean\") ||\n ![\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"unknown\"].includes(record.level) ||\n !text(record.message, L.recordBytes) ||\n (record.fieldsJson !== null && !text(record.fieldsJson, L.recordBytes))\n )\n return fail();\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 if (Buffer.byteLength(JSON.stringify(projected)) > L.recordBytes) return fail();\n return projected;\n });\n if (Buffer.byteLength(JSON.stringify(records)) > L.batchBytes) return fail();\n return { ...scoped, operation: \"append\", records };\n}\n\nexport function startPowerLogs(): () => void {\n let storageAvailable = true;\n try {\n sweepPowerLogsStorage();\n } catch {\n storageAvailable = false;\n }\n startPowerLogBudget();\n let active = true,\n worker: PowerLogsWorker | undefined;\n const streamOwners = new Map<\n string,\n { owner: string; contextId: string; clusterId: string; streamId: string; expiresAt: number }\n >();\n const dropExpiredOwners = () => {\n for (const [key, value] of streamOwners)\n if (value.expiresAt <= Date.now()) {\n releasePowerLogStream(value.clusterId, value.streamId);\n streamOwners.delete(key);\n }\n };\n const preferences = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>();\n const stop = reaction(\n () => ({ enabled: preferences.enabled, limits: normalizePowerLogsLimits(preferences.limits) }),\n ({ enabled, limits }) => {\n applyPowerLogsLimits(limits);\n if (!enabled) {\n cancelPowerLogPermits();\n streamOwners.clear();\n worker?.close();\n worker = undefined;\n }\n },\n { fireImmediately: true },\n );\n const fingerprint = (r: LogRequest): string => {\n const cluster = Main.Catalog.getClusterById(r.clusterId);\n if (!cluster) throw new Error(\"Log cluster unavailable\");\n return createHash(\"sha256\")\n .update(r.contextId)\n .update(\"\\0\")\n .update(cluster.contextName)\n .update(\"\\0\")\n .update(cluster.kubeConfigPath)\n .update(\"\\0\")\n .update(readFileSync(cluster.kubeConfigPath))\n .digest(\"hex\");\n };\n ipcMain.handle(POWER_LOGS_CHANNEL, async (event, input: unknown) => {\n try {\n const request = validateLogRequest(input);\n const allowed = () => active && preferences.enabled && trustedSearchSender(event, request.clusterId);\n if (!allowed()) throw new Error(\"Power Logs is disabled or unavailable\");\n const contextId = fingerprint(request);\n if (\n request.operation === \"stream-open\" ||\n request.operation === \"stream-close\" ||\n request.operation === \"stream-renew\"\n ) {\n dropExpiredOwners();\n const key = JSON.stringify([request.clusterId, request.streamId]);\n const owner = `${event.sender.id}:${event.senderFrame?.processId}:${event.senderFrame?.routingId}`;\n if (request.operation === \"stream-open\") {\n if (streamOwners.has(key)) throw new Error(\"Log stream already exists\");\n const entry = {\n owner,\n contextId,\n clusterId: request.clusterId,\n streamId: request.streamId,\n expiresAt: Date.now() + 35000,\n };\n streamOwners.set(key, entry);\n try {\n await acquirePowerLogStream(request.clusterId, request.streamId, request.follow);\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n entry.expiresAt = Date.now() + 35000;\n } catch (error) {\n if (streamOwners.get(key) === entry) {\n streamOwners.delete(key);\n releasePowerLogStream(request.clusterId, request.streamId);\n }\n throw error;\n }\n } else {\n const entry = streamOwners.get(key);\n if (!entry || entry.owner !== owner) throw new Error(\"Log stream owner changed\");\n if (request.operation === \"stream-close\") {\n streamOwners.delete(key);\n releasePowerLogStream(request.clusterId, request.streamId);\n } else {\n if (entry.contextId !== contextId) throw new Error(\"Log context changed\");\n renewPowerLogStream(request.clusterId, request.streamId);\n entry.expiresAt = Date.now() + 35000;\n }\n }\n return true;\n }\n if (request.operation === \"permit\") {\n await requestPowerLogPermit(request.clusterId, request.lane === \"bytes\" ? request.bytes : undefined);\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n return true;\n }\n if (!storageAvailable) throw new Error(\"Log storage unavailable\");\n let destination: string | undefined;\n if (request.operation === \"export\") {\n const window = BrowserWindow.fromWebContents(event.sender);\n if (!window) throw new Error(\"Log window unavailable\");\n const choice = await dialog.showSaveDialog(window, {\n title: \"Export captured logs\",\n defaultPath: \"logs.ndjson\",\n filters: [{ name: \"NDJSON\", extensions: [\"ndjson\"] }],\n });\n if (choice.canceled || !choice.filePath) return false;\n destination = choice.filePath;\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n }\n if (!worker || worker.isClosed) worker = new PowerLogsWorker();\n const result = await worker.call({ ...request, contextId }, destination);\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n return result;\n } catch {\n throw new Error(\"Power Logs operation failed or is unavailable\");\n }\n });\n return () => {\n active = false;\n cancelPowerLogPermits(true);\n streamOwners.clear();\n stop();\n ipcMain.removeHandler(POWER_LOGS_CHANNEL);\n worker?.close();\n worker = undefined;\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"power-logs-ipc.js","names":[],"sources":["../../src/main/power-logs-ipc.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { Main } from \"@freelensapp/extensions\";\nimport { BrowserWindow, dialog, ipcMain } from \"electron\";\nimport { reaction } from \"mobx\";\nimport {\n POWER_LOGS_LIMITS as L,\n type LogRecord,\n type LogRequest,\n type LogTarget,\n POWER_LOGS_CHANNEL,\n} from \"../common/power-logs\";\nimport { applyPowerLogsLimits, normalizePowerLogsLimits } from \"../common/power-logs-limits\";\nimport { LogsPreferencesStore } from \"../common/store/logs-preferences-store\";\nimport {\n acquirePowerLogStream,\n cancelPowerLogPermits,\n releasePowerLogStream,\n renewPowerLogStream,\n requestPowerLogPermit,\n startPowerLogBudget,\n} from \"./power-logs-budget\";\nimport { PowerLogsWorker, sweepPowerLogsStorage } from \"./power-logs-worker\";\nimport { trustedSearchSender } from \"./resource-search\";\n\nconst text = (value: unknown, limit: number): value is string =>\n typeof value === \"string\" && value.length <= limit && !/[\\x00]/.test(value);\nconst identifier = (value: unknown): value is string => text(value, 253) && /^[a-zA-Z0-9_.:-]+$/.test(value);\nconst fail = (): never => {\n throw new Error(\"Invalid log request\");\n};\nexport function validateLogRequest(input: unknown): LogRequest {\n if (!input || typeof input !== \"object\") return fail();\n const r = input as LogRequest;\n if (!identifier(r.clusterId) || !text(r.contextId, 512) || !r.contextId) return fail();\n const partition = { clusterId: r.clusterId, contextId: r.contextId };\n if (r.operation === \"stream-open\" || r.operation === \"stream-close\" || r.operation === \"stream-renew\") {\n if (!identifier(r.streamId)) return fail();\n if (r.operation === \"stream-open\") {\n if (typeof r.follow !== \"boolean\") return fail();\n return { ...partition, operation: \"stream-open\", streamId: r.streamId, follow: r.follow };\n }\n return { ...partition, operation: r.operation, streamId: r.streamId };\n }\n if (r.operation === \"permit\") {\n if (r.lane === \"start\" && r.bytes === undefined) return { ...partition, operation: \"permit\", lane: \"start\" };\n if (r.lane === \"bytes\" && Number.isSafeInteger(r.bytes) && r.bytes! > 0 && r.bytes! <= L.batchBytes)\n return { ...partition, operation: \"permit\", lane: \"bytes\", bytes: r.bytes };\n return fail();\n }\n if (r.operation === \"list\") return { ...partition, operation: \"list\" };\n if (r.operation === \"cancel\") {\n if (!identifier(r.queryId)) return fail();\n return { ...partition, operation: \"cancel\", queryId: r.queryId };\n }\n if (r.operation === \"create\") {\n const t = r.target as LogTarget | undefined;\n if (\n !t ||\n ![\"Pod\", \"Deployment\", \"DaemonSet\", \"StatefulSet\", \"ReplicaSet\", \"Job\", \"CronJob\"].includes(t.kind) ||\n !identifier(t.namespace) ||\n !identifier(t.name) ||\n !identifier(t.uid)\n )\n return fail();\n return {\n ...partition,\n operation: \"create\",\n target: { kind: t.kind, namespace: t.namespace, name: t.name, uid: t.uid },\n };\n }\n if (!(\"captureId\" in r) || !identifier(r.captureId)) return fail();\n const scoped = { ...partition, captureId: r.captureId };\n if (r.operation === \"delete\" || r.operation === \"export\") return { ...scoped, operation: r.operation };\n if (r.operation === \"save-sql\") {\n if (!text(r.sql, 65536)) return fail();\n return { ...scoped, operation: \"save-sql\", sql: r.sql };\n }\n if (r.operation === \"query\") {\n if (!identifier(r.queryId) || !text(r.sql, 65536) || !r.sql.trim()) return fail();\n return { ...scoped, operation: \"query\", queryId: r.queryId, sql: r.sql };\n }\n if (r.operation === \"finish\") {\n if (\n typeof r.partial !== \"boolean\" ||\n !Array.isArray(r.notes) ||\n r.notes.length > 20 ||\n r.notes.some((n) => !text(n, 512))\n )\n return fail();\n return { ...scoped, operation: \"finish\", partial: r.partial, notes: [...r.notes] };\n }\n if (r.operation !== \"append\" || !Array.isArray(r.records) || r.records.length > L.batchRows) return fail();\n const records: LogRecord[] = r.records.map((record) => {\n if (\n !record ||\n typeof record !== \"object\" ||\n (record.timestamp !== null && (!Number.isSafeInteger(record.timestamp) || record.timestamp < 0)) ||\n !identifier(record.pod) ||\n !identifier(record.podUid) ||\n !identifier(record.container) ||\n (record.previous !== undefined && typeof record.previous !== \"boolean\") ||\n ![\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"unknown\"].includes(record.level) ||\n !text(record.message, L.recordBytes) ||\n (record.fieldsJson !== null && !text(record.fieldsJson, L.recordBytes))\n )\n return fail();\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 if (Buffer.byteLength(JSON.stringify(projected)) > L.recordBytes) return fail();\n return projected;\n });\n if (Buffer.byteLength(JSON.stringify(records)) > L.batchBytes) return fail();\n return { ...scoped, operation: \"append\", records };\n}\n\nexport function startPowerLogs(): () => void {\n let storageAvailable = true;\n try {\n sweepPowerLogsStorage();\n } catch {\n storageAvailable = false;\n }\n startPowerLogBudget();\n let active = true,\n worker: PowerLogsWorker | undefined;\n const streamOwners = new Map<\n string,\n { owner: string; contextId: string; clusterId: string; streamId: string; expiresAt: number }\n >();\n const dropExpiredOwners = () => {\n for (const [key, value] of streamOwners)\n if (value.expiresAt <= Date.now()) {\n releasePowerLogStream(value.clusterId, value.streamId);\n streamOwners.delete(key);\n }\n };\n const preferences = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>();\n const stop = reaction(\n () => ({ enabled: preferences.enabled, limits: normalizePowerLogsLimits(preferences.limits) }),\n ({ enabled, limits }) => {\n applyPowerLogsLimits(limits);\n if (!enabled) {\n cancelPowerLogPermits();\n streamOwners.clear();\n worker?.close();\n worker = undefined;\n }\n },\n { fireImmediately: true },\n );\n const fingerprint = (r: LogRequest): string => {\n const cluster = Main.Catalog.getClusterById(r.clusterId);\n if (!cluster) throw new Error(\"Log cluster unavailable\");\n return createHash(\"sha256\")\n .update(r.contextId)\n .update(\"\\0\")\n .update(cluster.contextName)\n .update(\"\\0\")\n .update(cluster.kubeConfigPath)\n .update(\"\\0\")\n .update(readFileSync(cluster.kubeConfigPath))\n .digest(\"hex\");\n };\n ipcMain.handle(POWER_LOGS_CHANNEL, async (event, input: unknown) => {\n try {\n const request = validateLogRequest(input);\n const allowed = () => active && preferences.enabled && trustedSearchSender(event, request.clusterId);\n if (!allowed()) throw new Error(\"Power Logs is disabled or unavailable\");\n const contextId = fingerprint(request);\n if (\n request.operation === \"stream-open\" ||\n request.operation === \"stream-close\" ||\n request.operation === \"stream-renew\"\n ) {\n dropExpiredOwners();\n const key = JSON.stringify([request.clusterId, request.streamId]);\n const owner = `${event.sender.id}:${event.senderFrame?.processId}:${event.senderFrame?.routingId}`;\n if (request.operation === \"stream-open\") {\n if (streamOwners.has(key)) throw new Error(\"Log stream already exists\");\n const entry = {\n owner,\n contextId,\n clusterId: request.clusterId,\n streamId: request.streamId,\n expiresAt: Date.now() + 35000,\n };\n streamOwners.set(key, entry);\n try {\n await acquirePowerLogStream(request.clusterId, request.streamId, request.follow);\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n entry.expiresAt = Date.now() + 35000;\n } catch (error) {\n if (streamOwners.get(key) === entry) {\n streamOwners.delete(key);\n releasePowerLogStream(request.clusterId, request.streamId);\n }\n throw error;\n }\n } else {\n const entry = streamOwners.get(key);\n if (!entry || entry.owner !== owner) throw new Error(\"Log stream owner changed\");\n if (request.operation === \"stream-close\") {\n streamOwners.delete(key);\n releasePowerLogStream(request.clusterId, request.streamId);\n } else {\n if (entry.contextId !== contextId) throw new Error(\"Log context changed\");\n renewPowerLogStream(request.clusterId, request.streamId);\n entry.expiresAt = Date.now() + 35000;\n }\n }\n return true;\n }\n if (request.operation === \"permit\") {\n await requestPowerLogPermit(request.clusterId, request.lane === \"bytes\" ? request.bytes : undefined);\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n return true;\n }\n if (!storageAvailable) throw new Error(\"Log storage unavailable\");\n let destination: string | undefined;\n if (request.operation === \"export\") {\n const window = BrowserWindow.fromWebContents(event.sender);\n if (!window) throw new Error(\"Log window unavailable\");\n const choice = await dialog.showSaveDialog(window, {\n title: \"Export captured logs\",\n defaultPath: \"logs.ndjson\",\n filters: [{ name: \"NDJSON\", extensions: [\"ndjson\"] }],\n });\n if (choice.canceled || !choice.filePath) return false;\n destination = choice.filePath;\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n }\n if (!worker || worker.isClosed) worker = new PowerLogsWorker();\n const result = await worker.call({ ...request, contextId }, destination);\n if (!allowed() || fingerprint(request) !== contextId) throw new Error(\"Log context changed\");\n return result;\n } catch {\n throw new Error(\"Power Logs operation failed or is unavailable\");\n }\n });\n return () => {\n active = false;\n cancelPowerLogPermits(true);\n streamOwners.clear();\n stop();\n ipcMain.removeHandler(POWER_LOGS_CHANNEL);\n worker?.close();\n worker = undefined;\n };\n}\n"],"mappings":"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"}
|