@ogygia/devtools 0.11.4 → 0.13.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/README.md +1 -1
- package/dist/app.d.ts +3 -0
- package/dist/app.js +9 -0
- package/dist/devtools/BoundaryOverlay.svelte +10 -6
- package/dist/devtools/Devtools.svelte +24 -18
- package/dist/devtools/IslandDetail.svelte +7 -5
- package/dist/devtools/PageTab.svelte +4 -2
- package/dist/devtools/ProfilerTab.svelte +8 -2
- package/dist/devtools/SessionTab.svelte +21 -8
- package/dist/devtools/highlight.js +14 -7
- package/dist/devtools/ledger-dom.js +6 -9
- package/dist/devtools/names.js +18 -17
- package/dist/devtools/page.d.ts +2 -0
- package/dist/devtools/page.js +37 -17
- package/dist/devtools/profile-store.d.ts +4 -9
- package/dist/devtools/profile-store.js +26 -21
- package/dist/devtools/session.d.ts +2 -0
- package/dist/devtools/session.js +48 -42
- package/dist/devtools/testing-engine.js +10 -1
- package/dist/devtools/ui-app.d.ts +3 -1
- package/dist/devtools/ui-app.js +9 -3
- package/dist/devtools/ui.js +83 -40
- package/dist/messages/build.d.ts +21 -0
- package/dist/messages/build.js +56 -0
- package/dist/messages/index.d.ts +3 -0
- package/dist/messages/index.js +3 -0
- package/dist/messages/runtime.d.ts +63 -0
- package/dist/messages/runtime.js +122 -0
- package/dist/profiler/async-io.d.ts +12 -7
- package/dist/profiler/async-io.js +94 -82
- package/dist/profiler/beacon-standalone.js +15 -6
- package/dist/profiler/busy.d.ts +13 -0
- package/dist/profiler/busy.js +45 -0
- package/dist/profiler/client.js +5 -24
- package/dist/profiler/embedded-maps.js +9 -5
- package/dist/profiler/gc.d.ts +5 -0
- package/dist/profiler/gc.js +75 -11
- package/dist/profiler/index.d.ts +23 -2
- package/dist/profiler/index.js +648 -373
- package/dist/profiler/net.d.ts +14 -6
- package/dist/profiler/net.js +61 -45
- package/dist/profiler/patterns.js +29 -1
- package/dist/profiler/source-scan.js +24 -12
- package/dist/profiler/standalone.js +12 -4
- package/dist/profiler/storage/index.d.ts +14 -3
- package/dist/profiler/storage/index.js +41 -41
- package/dist/profiler/storage/postgres.d.ts +18 -5
- package/dist/profiler/storage/postgres.js +124 -85
- package/dist/profiler/storage/redis.d.ts +18 -5
- package/dist/profiler/storage/redis.js +160 -131
- package/dist/profiler/storage/sqlite.d.ts +15 -2
- package/dist/profiler/storage/sqlite.js +54 -48
- package/dist/profiler/ui/ComponentsTable.svelte +2 -2
- package/dist/profiler/ui/Dashboard.svelte +2 -3
- package/dist/profiler/ui/DownloadHtml.svelte +1 -0
- package/dist/profiler/ui/ExportButton.svelte +1 -0
- package/dist/profiler/ui/Flame.svelte +10 -4
- package/dist/profiler/ui/Flame.svelte.d.ts +0 -5
- package/dist/profiler/ui/FrameDetails.svelte +13 -2
- package/dist/profiler/ui/FrameDetails.svelte.d.ts +0 -6
- package/dist/profiler/ui/FunctionsTable.svelte +2 -2
- package/dist/profiler/ui/IslandsTable.svelte +2 -2
- package/dist/profiler/ui/OnThisPage.svelte +12 -4
- package/dist/profiler/ui/RunView.svelte +31 -27
- package/dist/profiler/ui/ShareLink.svelte +6 -1
- package/dist/profiler/ui/Sidebar.svelte +14 -9
- package/dist/profiler/ui/Treemap.svelte +11 -4
- package/dist/profiler/ui/Treemap.svelte.d.ts +0 -6
- package/dist/profiler/ui/WaitingTable.svelte +2 -2
- package/dist/profiler/ui/fake-progress.svelte.d.ts +7 -12
- package/dist/profiler/ui/fake-progress.svelte.js +57 -36
- package/dist/profiler/ui/press.js +4 -2
- package/dist/profiler/ui/row-anchor.svelte.d.ts +0 -6
- package/dist/profiler/ui/row-anchor.svelte.js +13 -8
- package/dist/profiler/ui/sort.svelte.d.ts +9 -6
- package/dist/profiler/ui/sort.svelte.js +34 -28
- package/dist/profiler/visit.d.ts +0 -1
- package/dist/profiler/visit.js +1 -2
- package/dist/server.js +27 -10
- package/dist/vite.js +3 -2
- package/package.json +18 -9
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { scope } from "@ogygia/machine";
|
|
1
2
|
// src/profiler/ui/press.ts
|
|
2
3
|
/** The keys alone, as an `onkeydown` handler: for an element whose markup already gives it its
|
|
3
4
|
* role and `tabindex="0"`, so the compiler sees the keyboard path next to the click. */
|
|
@@ -13,7 +14,8 @@ const press_key = (e) => {
|
|
|
13
14
|
};
|
|
14
15
|
const pressable = (node) => {
|
|
15
16
|
if (node.tabIndex < 0) node.tabIndex = 0;
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const s = scope();
|
|
18
|
+
s.on(node, "keydown", press_key);
|
|
19
|
+
return () => s.close();
|
|
18
20
|
};
|
|
19
21
|
export { press_key, pressable };
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ROW ANCHORS — a finding links to the row it is about (`#comp=<name>`, `#fn=<key>`); the table
|
|
3
|
-
* island opens that row and scrolls to it, on load and on every hash change. Shared by the two
|
|
4
|
-
* tables: give it the anchor kind and a getter for the open state, get back the row id maker and
|
|
5
|
-
* the effect to install.
|
|
6
|
-
*/
|
|
7
1
|
export type RowKind = "comp" | "fn" | "island" | "seed";
|
|
8
2
|
export declare function row_id(kind: RowKind, key: string): string;
|
|
9
3
|
/** The `href` a finding uses to reach a row. */
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { scope } from "@ogygia/machine";
|
|
1
2
|
// src/profiler/ui/row-anchor.svelte.ts
|
|
3
|
+
/**
|
|
4
|
+
* ROW ANCHORS — a finding links to the row it is about (`#comp=<name>`, `#fn=<key>`); the table
|
|
5
|
+
* island opens that row and scrolls to it, on load and on every hash change. Shared by the two
|
|
6
|
+
* tables: give it the anchor kind and a getter for the open state, get back the row id maker and
|
|
7
|
+
* the effect to install.
|
|
8
|
+
*/
|
|
2
9
|
function row_id(kind, key) {
|
|
3
10
|
let h = 5381;
|
|
4
11
|
for (let i = 0; i < key.length; i++) h = (Math.imul(h, 33) ^ key.charCodeAt(i)) >>> 0;
|
|
@@ -11,6 +18,7 @@ function row_href(anchor) {
|
|
|
11
18
|
}
|
|
12
19
|
/** Install in a table island: opens the row named by the URL hash (if it is one of `keys`). */
|
|
13
20
|
function follow_hash(kind, keys, open) {
|
|
21
|
+
const s = scope();
|
|
14
22
|
const apply = () => {
|
|
15
23
|
const m = /^#(comp|fn|island|seed)=(.*)$/.exec(location.hash);
|
|
16
24
|
if (!m || m[1] !== kind) return;
|
|
@@ -22,7 +30,7 @@ function follow_hash(kind, keys, open) {
|
|
|
22
30
|
}
|
|
23
31
|
if (!keys().includes(key)) return;
|
|
24
32
|
open(key);
|
|
25
|
-
|
|
33
|
+
s.timeout(() => {
|
|
26
34
|
document.getElementById(row_id(kind, key))?.scrollIntoView({
|
|
27
35
|
block: "center",
|
|
28
36
|
behavior: "smooth"
|
|
@@ -30,15 +38,12 @@ function follow_hash(kind, keys, open) {
|
|
|
30
38
|
}, 30);
|
|
31
39
|
};
|
|
32
40
|
apply();
|
|
33
|
-
|
|
41
|
+
s.on(window, "hashchange", apply);
|
|
34
42
|
const again = (e) => {
|
|
35
43
|
const href = (e.target?.closest?.("a"))?.getAttribute("href");
|
|
36
|
-
if (href && href === location.hash)
|
|
37
|
-
};
|
|
38
|
-
document.addEventListener("click", again);
|
|
39
|
-
return () => {
|
|
40
|
-
window.removeEventListener("hashchange", apply);
|
|
41
|
-
document.removeEventListener("click", again);
|
|
44
|
+
if (href && href === location.hash) s.timeout(apply, 0);
|
|
42
45
|
};
|
|
46
|
+
s.on(document, "click", again);
|
|
47
|
+
return () => s.close();
|
|
43
48
|
}
|
|
44
49
|
export { follow_hash, row_href, row_id };
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reactive column sort shared by the profiler's tables (was report.ts's TABLE_SORT_JS DOM hack).
|
|
3
|
-
* Give it a getter for the rows and the initial numeric key; it owns the sort state and
|
|
3
|
+
* Give it a getter for the rows and the initial numeric key; it owns the sort state and holds the
|
|
4
4
|
* sorted view + a click handler. Svelte runes in a `.svelte.ts` module — imported by the table
|
|
5
5
|
* islands, one instance each.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export declare class Sortable<T> {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(rows: () => T[], initial_key: string);
|
|
10
|
+
get key(): string;
|
|
11
|
+
get sorted(): T[];
|
|
10
12
|
click(k: string): void;
|
|
13
|
+
/** The little arrow for a header: ▲/▼ when it's the active column, else empty. */
|
|
11
14
|
arrow(k: string): string;
|
|
15
|
+
/** The header's `aria-sort`: what a screen reader says the arrow means. */
|
|
12
16
|
aria(k: string): "ascending" | "descending" | "none";
|
|
13
|
-
}
|
|
14
|
-
export declare function sortable<T>(rows: () => T[], initial_key: string): Sortable<T>;
|
|
17
|
+
}
|
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
// src/profiler/ui/sort.svelte.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Reactive column sort shared by the profiler's tables (was report.ts's TABLE_SORT_JS DOM hack).
|
|
4
|
+
* Give it a getter for the rows and the initial numeric key; it owns the sort state and holds the
|
|
5
|
+
* sorted view + a click handler. Svelte runes in a `.svelte.ts` module — imported by the table
|
|
6
|
+
* islands, one instance each.
|
|
7
|
+
*/
|
|
8
|
+
var Sortable = class {
|
|
9
|
+
#rows;
|
|
10
|
+
#key = $state("");
|
|
11
|
+
#dir = $state("desc");
|
|
12
|
+
#sorted = $derived.by(() => [...this.#rows()].sort((a, b) => {
|
|
13
|
+
const x = Number(a[this.#key]) || 0;
|
|
14
|
+
const y = Number(b[this.#key]) || 0;
|
|
15
|
+
return this.#dir === "asc" ? x - y : y - x;
|
|
9
16
|
}));
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
constructor(rows, initial_key) {
|
|
18
|
+
this.#rows = rows;
|
|
19
|
+
this.#key = initial_key;
|
|
20
|
+
}
|
|
21
|
+
get key() {
|
|
22
|
+
return this.#key;
|
|
23
|
+
}
|
|
24
|
+
get sorted() {
|
|
25
|
+
return this.#sorted;
|
|
26
|
+
}
|
|
27
|
+
click(k) {
|
|
28
|
+
if (this.#key === k) this.#dir = this.#dir === "asc" ? "desc" : "asc";
|
|
12
29
|
else {
|
|
13
|
-
key = k;
|
|
14
|
-
dir = "desc";
|
|
30
|
+
this.#key = k;
|
|
31
|
+
this.#dir = "desc";
|
|
15
32
|
}
|
|
16
33
|
}
|
|
17
34
|
/** The little arrow for a header: ▲/▼ when it's the active column, else empty. */
|
|
18
|
-
|
|
19
|
-
return key === k ? dir === "asc" ? " ▲" : " ▼" : "";
|
|
35
|
+
arrow(k) {
|
|
36
|
+
return this.#key === k ? this.#dir === "asc" ? " ▲" : " ▼" : "";
|
|
20
37
|
}
|
|
21
38
|
/** The header's `aria-sort`: what a screen reader says the arrow means. */
|
|
22
|
-
|
|
23
|
-
return key === k ? dir === "asc" ? "ascending" : "descending" : "none";
|
|
39
|
+
aria(k) {
|
|
40
|
+
return this.#key === k ? this.#dir === "asc" ? "ascending" : "descending" : "none";
|
|
24
41
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return key;
|
|
28
|
-
},
|
|
29
|
-
get sorted() {
|
|
30
|
-
return sorted;
|
|
31
|
-
},
|
|
32
|
-
click,
|
|
33
|
-
arrow,
|
|
34
|
-
aria
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export { sortable };
|
|
42
|
+
};
|
|
43
|
+
export { Sortable };
|
package/dist/profiler/visit.d.ts
CHANGED
package/dist/profiler/visit.js
CHANGED
|
@@ -311,8 +311,7 @@ function parse_visit(page, raw) {
|
|
|
311
311
|
type,
|
|
312
312
|
bytes,
|
|
313
313
|
as: str(m.as, 20) ?? "",
|
|
314
|
-
crossorigin: typeof m.crossorigin === "string" ? m.crossorigin.slice(0, 20) : null
|
|
315
|
-
...m.hole === true ? { hole: true } : {}
|
|
314
|
+
crossorigin: typeof m.crossorigin === "string" ? m.crossorigin.slice(0, 20) : null
|
|
316
315
|
});
|
|
317
316
|
}
|
|
318
317
|
if (preload_misses.length) visit.preload_misses = preload_misses;
|
package/dist/server.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { set_devtools_app } from "./app.js";
|
|
1
2
|
import { profiler_demand_skip } from "./profiler/on-demand.js";
|
|
3
|
+
import { OgygiaError } from "./messages/runtime.js";
|
|
4
|
+
import { STALE, flights } from "@ogygia/machine";
|
|
2
5
|
import { defineServer } from "@ogygia/core/plugin";
|
|
3
6
|
import { want_request_stats } from "@ogygia/core/internal/server";
|
|
4
7
|
// src/server.ts
|
|
@@ -9,31 +12,45 @@ import { want_request_stats } from "@ogygia/core/internal/server";
|
|
|
9
12
|
* path — loads on the first request through a dynamic import, so an app pays for it only when it is
|
|
10
13
|
* on; with `onDemand`, only once someone opens the profiler.
|
|
11
14
|
*/
|
|
12
|
-
/** the mounted profiler
|
|
13
|
-
let mounted;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/** the mounted profiler, once a mount succeeded */
|
|
16
|
+
let mounted = null;
|
|
17
|
+
/** The process's one profiler mount: the first requests that arrive together share it. A mount
|
|
18
|
+
* that fails (an edge runtime without node:inspector, a dev server mid-edit) is not kept, so the
|
|
19
|
+
* next request tries again. */
|
|
20
|
+
const mounting = flights.keyed()({
|
|
21
|
+
name: "profiler mount",
|
|
22
|
+
key: [],
|
|
23
|
+
ignore: { options: "one mount for the process: the first request's options are the ones it mounts with" },
|
|
24
|
+
run: async ({ options }) => {
|
|
17
25
|
const { profiler } = await import("./profiler/index.js");
|
|
18
26
|
const { getProfilerStore } = await import("./profiler/storage/index.js").catch(() => ({ getProfilerStore: () => void 0 }));
|
|
19
27
|
const store = getProfilerStore();
|
|
20
|
-
mounted = profiler({
|
|
28
|
+
return mounted = profiler({
|
|
21
29
|
...options,
|
|
22
30
|
...store ? { store } : {}
|
|
23
31
|
});
|
|
24
|
-
} catch {
|
|
25
|
-
mounted = null;
|
|
26
32
|
}
|
|
27
|
-
|
|
33
|
+
});
|
|
34
|
+
/** a failed mount was said (once for the process: an edge runtime fails every request the same way) */
|
|
35
|
+
let mount_failure_said = false;
|
|
36
|
+
async function mount(options) {
|
|
37
|
+
return mounting.get({ options }).then((m) => m === STALE ? null : m, (error) => {
|
|
38
|
+
if (!mount_failure_said) {
|
|
39
|
+
mount_failure_said = true;
|
|
40
|
+
console.error(new OgygiaError("devtools_profiler_mount_failed"), error);
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
});
|
|
28
44
|
}
|
|
29
45
|
const server = defineServer({
|
|
30
46
|
setup(app) {
|
|
47
|
+
set_devtools_app(app);
|
|
31
48
|
if (app.options.profiler) want_request_stats();
|
|
32
49
|
},
|
|
33
50
|
async handle({ event, options }, next) {
|
|
34
51
|
const config = options.profiler;
|
|
35
52
|
if (!config) return next();
|
|
36
|
-
if (profiler_demand_skip(!!config.onDemand, mounted !==
|
|
53
|
+
if (profiler_demand_skip(!!config.onDemand, mounted !== null, event.url.pathname, config.path || "/__profiler")) return next();
|
|
37
54
|
const prof = await mount(config);
|
|
38
55
|
if (!prof) return next();
|
|
39
56
|
return prof({
|
package/dist/vite.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { warn } from "./messages/build.js";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -58,8 +59,8 @@ function devtools_vite(dock, profiler) {
|
|
|
58
59
|
config(_config, env) {
|
|
59
60
|
dev = env.command === "serve";
|
|
60
61
|
if (env.command === "build" && isMainThread) {
|
|
61
|
-
if (dock)
|
|
62
|
-
if (profiler && "secret" in profiler && !profiler.secret)
|
|
62
|
+
if (dock) warn("devtools_on_in_build");
|
|
63
|
+
if (profiler && "secret" in profiler && !profiler.secret) warn("devtools_profiler_secret_empty");
|
|
63
64
|
}
|
|
64
65
|
const out = {};
|
|
65
66
|
if (dock && env.command === "serve") out.optimizeDeps = { include: ["@ogygia/devtools > @neodrag/svelte", "@ogygia/devtools > @neodrag/svelte/resize"] };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ogygia/devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Devtools for ogygia: the in-page dock, and the SSR profiler with its report, client marks and storage adapters",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"devtools",
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"type": "module",
|
|
25
|
+
"sideEffects": [
|
|
26
|
+
"**/*.css"
|
|
27
|
+
],
|
|
25
28
|
"exports": {
|
|
26
29
|
".": {
|
|
27
30
|
"types": "./dist/devtools/index.d.ts",
|
|
@@ -59,6 +62,10 @@
|
|
|
59
62
|
"./profiler/storage/postgres": {
|
|
60
63
|
"types": "./dist/profiler/storage/postgres.d.ts",
|
|
61
64
|
"default": "./dist/profiler/storage/postgres.js"
|
|
65
|
+
},
|
|
66
|
+
"./internal/messages": {
|
|
67
|
+
"types": "./dist/messages/index.d.ts",
|
|
68
|
+
"default": "./dist/messages/index.js"
|
|
62
69
|
}
|
|
63
70
|
},
|
|
64
71
|
"publishConfig": {
|
|
@@ -66,10 +73,15 @@
|
|
|
66
73
|
},
|
|
67
74
|
"dependencies": {
|
|
68
75
|
"@neodrag/svelte": "3.0.0-next.12",
|
|
69
|
-
"
|
|
70
|
-
"@ogygia/router": "^0.
|
|
76
|
+
"@ogygia/machine": "^0.13.0",
|
|
77
|
+
"@ogygia/router": "^0.13.0",
|
|
78
|
+
"devalue": "^5.9.3"
|
|
71
79
|
},
|
|
72
80
|
"devDependencies": {
|
|
81
|
+
"@ogygia/config": "0.0.0",
|
|
82
|
+
"@ogygia/core": "0.13.0",
|
|
83
|
+
"@ogygia/tooling": "0.0.0",
|
|
84
|
+
"@ogygia/tsdown-plugin-svelte": "1.1.1",
|
|
73
85
|
"@playwright/test": "1.62.1",
|
|
74
86
|
"@sveltejs/kit": "^2.70.2",
|
|
75
87
|
"@sveltejs/vite-plugin-svelte": "^7.2.0",
|
|
@@ -80,16 +92,13 @@
|
|
|
80
92
|
"tsdown": "^0.23.4",
|
|
81
93
|
"typescript": "^6.0.3",
|
|
82
94
|
"vite": "^8.3.5",
|
|
83
|
-
"vitest": "^4.1.12"
|
|
84
|
-
"@ogygia/core": "0.11.4",
|
|
85
|
-
"@ogygia/tooling": "0.0.0",
|
|
86
|
-
"@ogygia/tsdown-plugin-svelte": "1.1.0"
|
|
95
|
+
"vitest": "^4.1.12"
|
|
87
96
|
},
|
|
88
97
|
"peerDependencies": {
|
|
98
|
+
"@ogygia/core": "^0.13.0",
|
|
89
99
|
"@sveltejs/kit": ">=2.70.2 <4",
|
|
90
100
|
"svelte": "^5.56.8",
|
|
91
|
-
"vite": "^8.2.4"
|
|
92
|
-
"@ogygia/core": "^0.11.4"
|
|
101
|
+
"vite": "^8.2.4"
|
|
93
102
|
},
|
|
94
103
|
"scripts": {
|
|
95
104
|
"build": "tsdown",
|