@tracepanel/js 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +224 -12
- package/dist/agent.d.ts +5 -1
- package/dist/agent.js +12 -3
- package/dist/agent.js.map +1 -1
- package/dist/aws.d.ts +27 -0
- package/dist/aws.js +368 -0
- package/dist/aws.js.map +1 -0
- package/dist/bun.js +6 -82
- package/dist/bun.js.map +1 -1
- package/dist/calls.d.ts +5 -0
- package/dist/calls.js +7 -0
- package/dist/calls.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/explain.d.ts +5 -0
- package/dist/explain.js +56 -7
- package/dist/explain.js.map +1 -1
- package/dist/fastify.d.ts +2 -0
- package/dist/fastify.js +100 -0
- package/dist/fastify.js.map +1 -0
- package/dist/frameworks.js +3 -0
- package/dist/frameworks.js.map +1 -1
- package/dist/hono.d.ts +2 -0
- package/dist/hono.js +63 -0
- package/dist/hono.js.map +1 -0
- package/dist/koa.d.ts +2 -0
- package/dist/koa.js +119 -0
- package/dist/koa.js.map +1 -0
- package/dist/llm.d.ts +20 -0
- package/dist/llm.js +632 -0
- package/dist/llm.js.map +1 -0
- package/dist/memory.d.ts +69 -0
- package/dist/memory.js +203 -0
- package/dist/memory.js.map +1 -0
- package/dist/model.d.ts +22 -1
- package/dist/model.js.map +1 -1
- package/dist/next.js +4 -4
- package/dist/next.js.map +1 -1
- package/dist/processor.d.ts +40 -4
- package/dist/processor.js +156 -29
- package/dist/processor.js.map +1 -1
- package/dist/profile.d.ts +34 -8
- package/dist/profile.js +98 -13
- package/dist/profile.js.map +1 -1
- package/dist/queries.d.ts +20 -0
- package/dist/queries.js +75 -0
- package/dist/queries.js.map +1 -0
- package/dist/respond.d.ts +12 -0
- package/dist/respond.js +85 -0
- package/dist/respond.js.map +1 -0
- package/dist/setup.js +22 -5
- package/dist/setup.js.map +1 -1
- package/dist/sql.d.ts +1 -0
- package/dist/sql.js +11 -2
- package/dist/sql.js.map +1 -1
- package/dist/sqlite.d.ts +13 -0
- package/dist/sqlite.js +291 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/stack.d.ts +3 -1
- package/dist/stack.js +30 -6
- package/dist/stack.js.map +1 -1
- package/dist/testing.d.ts +128 -0
- package/dist/testing.js +362 -0
- package/dist/testing.js.map +1 -0
- package/dist/transactions.d.ts +11 -1
- package/dist/transactions.js +70 -34
- package/dist/transactions.js.map +1 -1
- package/dist/view.d.ts +17 -0
- package/dist/view.js +71 -0
- package/dist/view.js.map +1 -0
- package/dist/vitest-setup.d.ts +1 -0
- package/dist/vitest-setup.js +63 -0
- package/dist/vitest-setup.js.map +1 -0
- package/dist/vitest.d.ts +57 -0
- package/dist/vitest.js +130 -0
- package/dist/vitest.js.map +1 -0
- package/dist/widget.d.ts +16 -0
- package/dist/widget.js +33 -1
- package/dist/widget.js.map +1 -1
- package/package.json +69 -4
package/dist/view.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// The route's handler as a span of its own, for frameworks no OpenTelemetry instrumentation of ours traces (Fastify,
|
|
2
|
+
// Koa, Hono): the processor draws it as Express's route handler, the request's handler named by its route
|
|
3
|
+
// (`/books/:id`), with what it runs under it. An error it throws is the request's, unless the framework answers it
|
|
4
|
+
// below 500 (a 404 the app threw): that is an answer.
|
|
5
|
+
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
6
|
+
/** What tells the processor a span is a route's handler. */
|
|
7
|
+
export const VIEW = "view";
|
|
8
|
+
const tracer = trace.getTracer("tracepanel-view");
|
|
9
|
+
// The errors recorded on a handler's span already: the framework's error hook leaves them be.
|
|
10
|
+
const recorded = new WeakSet();
|
|
11
|
+
/** The status a framework answers an error with: its own statusCode or status (http-errors, Hono's), else 500. */
|
|
12
|
+
export function statusOf(error) {
|
|
13
|
+
if (error === null || typeof error !== "object")
|
|
14
|
+
return 500;
|
|
15
|
+
const { statusCode, status } = error;
|
|
16
|
+
const code = typeof statusCode === "number" ? statusCode : typeof status === "number" ? status : 500;
|
|
17
|
+
return code >= 400 && code < 600 ? code : 500;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* An error the request ends with, on a span: once, and only when the framework answers it with 500 or above.
|
|
21
|
+
* `status`: what it answered, where the app's error handler decides (Hono's onError).
|
|
22
|
+
*/
|
|
23
|
+
export function recordError(span, error, status = statusOf(error)) {
|
|
24
|
+
if (status < 500)
|
|
25
|
+
return;
|
|
26
|
+
const thrown = error instanceof Error ? error : new Error(String(error));
|
|
27
|
+
if (recorded.has(thrown))
|
|
28
|
+
return;
|
|
29
|
+
recorded.add(thrown);
|
|
30
|
+
span.recordException(thrown);
|
|
31
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
32
|
+
}
|
|
33
|
+
/** Whether a handler's span recorded this error already. */
|
|
34
|
+
export function wasRecorded(error) {
|
|
35
|
+
return error !== null && typeof error === "object" && recorded.has(error);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* `run` in a span for the route's handler, named by its route. `origin`: the app's line that added the route, when
|
|
39
|
+
* it is known. An error `run` throws is recorded and thrown on.
|
|
40
|
+
*/
|
|
41
|
+
export function inView(route, origin, run) {
|
|
42
|
+
const attributes = {
|
|
43
|
+
"tracepanel.span_kind": VIEW,
|
|
44
|
+
"code.view": route,
|
|
45
|
+
...(origin ? { "code.origin": origin } : {}),
|
|
46
|
+
};
|
|
47
|
+
return tracer.startActiveSpan(`handler - ${route}`, { attributes }, (span) => {
|
|
48
|
+
let result;
|
|
49
|
+
try {
|
|
50
|
+
result = run(span);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
recordError(span, error);
|
|
54
|
+
span.end();
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
if (result instanceof Promise) {
|
|
58
|
+
return result.then((value) => {
|
|
59
|
+
span.end();
|
|
60
|
+
return value;
|
|
61
|
+
}, (error) => {
|
|
62
|
+
recordError(span, error);
|
|
63
|
+
span.end();
|
|
64
|
+
throw error;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
span.end();
|
|
68
|
+
return result;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=view.js.map
|
package/dist/view.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Each test file's setup under Tracepanel's Vitest plugin (vitest.ts): Tracepanel on in the test's process, and each
|
|
2
|
+
// test a trace, failed by what the agent finds in it. Vitest runs it before the file's own imports, so the database
|
|
3
|
+
// drivers the tests load are instrumented.
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { aroundEach, inject } from "vitest";
|
|
6
|
+
import { start } from "./setup.js";
|
|
7
|
+
import { Console, DEFAULT_FAIL_ON, failure, problems, TestSink, TracedTest, UsageError, } from "./testing.js";
|
|
8
|
+
import { rules } from "./vitest.js";
|
|
9
|
+
// On as `tracepanel run` turns it on, a TRACEPANEL_* variable still over it; the widget would change the pages the
|
|
10
|
+
// tests read.
|
|
11
|
+
if (!process.env.TRACEPANEL_ENABLED)
|
|
12
|
+
process.env.TRACEPANEL_ENABLED = "1";
|
|
13
|
+
if (!process.env.TRACEPANEL_WIDGET)
|
|
14
|
+
process.env.TRACEPANEL_WIDGET = "0";
|
|
15
|
+
const WRAPPED = Symbol.for("tracepanel.testSink");
|
|
16
|
+
/** What the test failed with: not a skip, nor an expected failure. */
|
|
17
|
+
function errorsOf(task) {
|
|
18
|
+
return task.fails ? [] : (task.result?.errors ?? []);
|
|
19
|
+
}
|
|
20
|
+
const tracepanel = start();
|
|
21
|
+
if (tracepanel) {
|
|
22
|
+
// Vitest loaded node:http before the instrumentation went in: required now, it is patched for the servers the tests
|
|
23
|
+
// start (their requests' traces) and the calls they make.
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
for (const name of ["node:http", "node:https"])
|
|
26
|
+
require(name);
|
|
27
|
+
const { processor } = tracepanel;
|
|
28
|
+
// Without the plugin (the setup file named by hand): its defaults, and no agent.
|
|
29
|
+
const provided = inject("tracepanel") ?? { failOn: [...DEFAULT_FAIL_ON], console: "" };
|
|
30
|
+
const sink = processor.sink;
|
|
31
|
+
if (!sink[WRAPPED])
|
|
32
|
+
processor.sink = Object.assign(new TestSink(sink, provided.console !== ""), { [WRAPPED]: true });
|
|
33
|
+
const failOn = new Set(provided.failOn);
|
|
34
|
+
aroundEach(async (runTest, { task }) => {
|
|
35
|
+
let found;
|
|
36
|
+
try {
|
|
37
|
+
found = rules(task, failOn);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
// The test's own rules: its failure, not the run's.
|
|
41
|
+
if (error instanceof UsageError)
|
|
42
|
+
throw failure(error.message, error.name);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
const name = `${task.file.name} > ${task.fullTestName}`;
|
|
46
|
+
const attrs = {
|
|
47
|
+
"test.case.name": name,
|
|
48
|
+
"code.filepath": task.file.name,
|
|
49
|
+
"code.lineno": task.location?.line ?? 0,
|
|
50
|
+
"code.function": task.name,
|
|
51
|
+
};
|
|
52
|
+
// The agent's console as it is now: an agent started anew listens on a new port.
|
|
53
|
+
const url = provided.console ? tracepanel.console.get(true) : "";
|
|
54
|
+
const run = new TracedTest(name, attrs, processor, url ? new Console(url) : undefined);
|
|
55
|
+
await run.record(runTest, () => errorsOf(task));
|
|
56
|
+
if (errorsOf(task).length > 0 || task.result?.state === "skip")
|
|
57
|
+
return;
|
|
58
|
+
const failed = await problems(run, found, (allow) => `Allowed here with the test's option { meta: { tracepanel: { allow: [${allow}] } } }.`);
|
|
59
|
+
if (failed.length > 0)
|
|
60
|
+
throw failure(failed.join("\n\n"));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=vitest-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-setup.js","sourceRoot":"","sources":["../src/vitest-setup.ts"],"names":[],"mappings":"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"}
|
package/dist/vitest.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Plugin } from "vitest/config";
|
|
2
|
+
import { type Finding, type Kind, type Rules, type TracedTest } from "./testing.js";
|
|
3
|
+
export type { Finding, Kind } from "./testing.js";
|
|
4
|
+
export { KINDS, maxQueries } from "./testing.js";
|
|
5
|
+
/** A test's own rules, nearest first: the test's `meta.tracepanel`, then its suites'. */
|
|
6
|
+
export interface TestRules {
|
|
7
|
+
/** Fail the test when it and its requests make more queries than this. */
|
|
8
|
+
maxQueries?: number;
|
|
9
|
+
/** The kinds of issues that fail the test, instead of the plugin's `failOn`. */
|
|
10
|
+
failOn?: Kind | Kind[];
|
|
11
|
+
/** Kinds of issues taken out of those that fail the test. */
|
|
12
|
+
allow?: Kind | Kind[];
|
|
13
|
+
}
|
|
14
|
+
export interface TracepanelOptions {
|
|
15
|
+
/** The kinds of issues that fail a test: n+1 and duplicates by default (the kinds: KINDS). */
|
|
16
|
+
failOn?: Kind | Kind[];
|
|
17
|
+
}
|
|
18
|
+
/** What the plugin hands each test file's setup. */
|
|
19
|
+
export interface Provided {
|
|
20
|
+
failOn: Kind[];
|
|
21
|
+
/** The console the agent serves, or "" without one. */
|
|
22
|
+
console: string;
|
|
23
|
+
}
|
|
24
|
+
declare module "vitest" {
|
|
25
|
+
interface TaskMeta {
|
|
26
|
+
tracepanel?: TestRules;
|
|
27
|
+
}
|
|
28
|
+
interface ProvidedContext {
|
|
29
|
+
tracepanel: Provided;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** The project's agent's console, the agent started now unless one answers: "" when there is none. */
|
|
33
|
+
export declare function agentConsole(): Promise<string>;
|
|
34
|
+
/** Runs each test as a trace, and fails one with an N+1 or duplicate queries (`failOn`: the kinds that fail it). */
|
|
35
|
+
export declare function tracepanel(options?: TracepanelOptions): Plugin;
|
|
36
|
+
/** A test or a suite, as far as its rules go. */
|
|
37
|
+
interface Node {
|
|
38
|
+
meta?: {
|
|
39
|
+
tracepanel?: unknown;
|
|
40
|
+
};
|
|
41
|
+
suite?: Node | undefined;
|
|
42
|
+
}
|
|
43
|
+
/** The test's rules: its `meta.tracepanel`, then its suites', the nearest first, over the plugin's `failOn`. */
|
|
44
|
+
export declare function rules(task: Node, failOn: ReadonlySet<Kind>): Rules;
|
|
45
|
+
/** The test's trace, as testTrace() gives it: its queries so far, what the agent found, its link in the console. */
|
|
46
|
+
export interface TestTrace {
|
|
47
|
+
/** How many queries the test made so far, its requests' included. */
|
|
48
|
+
readonly queries: number;
|
|
49
|
+
/** Those queries, in the order they ended. */
|
|
50
|
+
readonly sql: TracedTest["sql"];
|
|
51
|
+
/** What the agent found so far: in the requests the test made. Empty without an agent. */
|
|
52
|
+
issues(): Promise<Finding[]>;
|
|
53
|
+
/** The test's trace in the agent's console, or undefined without an agent. */
|
|
54
|
+
readonly url: string | undefined;
|
|
55
|
+
}
|
|
56
|
+
/** The current test's trace: needs tracepanel() in the plugins of the Vitest config. */
|
|
57
|
+
export declare function testTrace(): TestTrace;
|
package/dist/vitest.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Tracepanel's Vitest plugin: each test a trace, and what the agent finds in it (an N+1, duplicate queries) a failure.
|
|
2
|
+
//
|
|
3
|
+
// // vitest.config.ts
|
|
4
|
+
// import { tracepanel } from "@tracepanel/js/vitest";
|
|
5
|
+
// export default defineConfig({ plugins: [tracepanel()] }); // tracepanel({ failOn: ["n+1", "slow-sql"] })
|
|
6
|
+
//
|
|
7
|
+
// test("feed", { meta: { tracepanel: { maxQueries: 10, allow: ["n+1"] } } }, async () => {
|
|
8
|
+
// await request(app).get("/feed");
|
|
9
|
+
// expect(testTrace().queries).toBeLessThanOrEqual(10);
|
|
10
|
+
// await maxQueries(2, () => request(app).get("/feed?page=2"));
|
|
11
|
+
// });
|
|
12
|
+
//
|
|
13
|
+
// The plugin adds a setup file to each test file (vitest-setup.ts): it turns Tracepanel on in the test's process as
|
|
14
|
+
// `node --import @tracepanel/js/register` does, with the widget off, and runs each test as a trace. The plugin starts
|
|
15
|
+
// the project's agent once, as Vitest starts, unless one answers. Once a test has passed, the agent is asked what it
|
|
16
|
+
// found in the test's trace and in its requests': a finding of a kind it fails on fails the test, with the finding,
|
|
17
|
+
// its query, where the code made it and a link to the trace in the console. Without an agent the tests run as usual,
|
|
18
|
+
// and a single warning says that findings are not checked: counting queries needs no agent.
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import { ConsoleUrl, Starter } from "./agent.js";
|
|
21
|
+
import { loadConfig } from "./config.js";
|
|
22
|
+
import { currentTest, DEFAULT_FAIL_ON, kinds, UsageError, } from "./testing.js";
|
|
23
|
+
export { KINDS, maxQueries } from "./testing.js";
|
|
24
|
+
// This file's own setup file: the built one next to it, or the source in this repository's tests.
|
|
25
|
+
const SETUP = fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? "./vitest-setup.ts" : "./vitest-setup.js", import.meta.url));
|
|
26
|
+
/** Whether the agent's console answers: what the tests read the findings from. */
|
|
27
|
+
async function answers(url) {
|
|
28
|
+
if (!url)
|
|
29
|
+
return false;
|
|
30
|
+
try {
|
|
31
|
+
const answer = await fetch(`${url.replace(/\/+$/, "")}/api/traces?limit=1`, { signal: AbortSignal.timeout(2000) });
|
|
32
|
+
return answer.ok;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** The project's agent's console, the agent started now unless one answers: "" when there is none. */
|
|
39
|
+
export async function agentConsole() {
|
|
40
|
+
if (process.env.TRACEPANEL_AGENT === "off")
|
|
41
|
+
return "";
|
|
42
|
+
const config = loadConfig();
|
|
43
|
+
const consoleUrl = new ConsoleUrl(config.storeDir);
|
|
44
|
+
if (await answers(consoleUrl.get(true)))
|
|
45
|
+
return consoleUrl.get(true);
|
|
46
|
+
// None answers at the address the project's agent left (it exited, or was killed): a new one starts.
|
|
47
|
+
if (!new Starter(config.storeDir).ensure(true))
|
|
48
|
+
return "";
|
|
49
|
+
for (let tries = 0; tries < 20; tries++) {
|
|
50
|
+
if (await answers(consoleUrl.get(true)))
|
|
51
|
+
return consoleUrl.get(true);
|
|
52
|
+
await new Promise((done) => setTimeout(done, 50));
|
|
53
|
+
}
|
|
54
|
+
return "";
|
|
55
|
+
}
|
|
56
|
+
function why() {
|
|
57
|
+
const named = process.env.TRACEPANEL_AGENT;
|
|
58
|
+
if (named === "off")
|
|
59
|
+
return "the agent is off (TRACEPANEL_AGENT=off).";
|
|
60
|
+
if (named && named !== "auto")
|
|
61
|
+
return `no agent's console answers for ${named}.`;
|
|
62
|
+
return "the agent didn't start.";
|
|
63
|
+
}
|
|
64
|
+
/** Runs each test as a trace, and fails one with an N+1 or duplicate queries (`failOn`: the kinds that fail it). */
|
|
65
|
+
export function tracepanel(options = {}) {
|
|
66
|
+
const failOn = [...kinds(options.failOn ?? [...DEFAULT_FAIL_ON], "tracepanel({ failOn })")];
|
|
67
|
+
let consoleUrl;
|
|
68
|
+
return {
|
|
69
|
+
name: "tracepanel",
|
|
70
|
+
async config(config) {
|
|
71
|
+
consoleUrl ??= agentConsole();
|
|
72
|
+
const provided = { failOn, console: await consoleUrl };
|
|
73
|
+
// First of the setup files: the instrumentation goes in before another's imports load a database driver.
|
|
74
|
+
config.test ??= {};
|
|
75
|
+
const { test } = config;
|
|
76
|
+
const setupFiles = test.setupFiles === undefined ? [] : [test.setupFiles].flat();
|
|
77
|
+
test.setupFiles = [SETUP, ...setupFiles.filter((file) => file !== SETUP)];
|
|
78
|
+
test.includeTaskLocation = true;
|
|
79
|
+
test.provide = { ...test.provide, tracepanel: provided };
|
|
80
|
+
},
|
|
81
|
+
configureVitest({ vitest }) {
|
|
82
|
+
void consoleUrl?.then((url) => {
|
|
83
|
+
const fails = failOn.length > 0 ? [...failOn].sort().join(", ") : "nothing";
|
|
84
|
+
vitest.logger.log(`tracepanel: each test a trace · fails on ${fails} · ${url ? `console ${url}` : "no agent: findings not checked"}`);
|
|
85
|
+
if (!url)
|
|
86
|
+
vitest.logger.warn(`tracepanel: ${why()} The tests run without the agent's findings.`);
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const RULES = ["allow", "failOn", "maxQueries"];
|
|
92
|
+
/** The test's rules: its `meta.tracepanel`, then its suites', the nearest first, over the plugin's `failOn`. */
|
|
93
|
+
export function rules(task, failOn) {
|
|
94
|
+
const values = {};
|
|
95
|
+
for (let node = task; node; node = node.suite) {
|
|
96
|
+
const own = node.meta?.tracepanel;
|
|
97
|
+
if (own === undefined)
|
|
98
|
+
continue;
|
|
99
|
+
if (typeof own !== "object" || own === null || Array.isArray(own)) {
|
|
100
|
+
throw new UsageError(`meta.tracepanel takes an object (${RULES.join(", ")}), got ${JSON.stringify(own)}`);
|
|
101
|
+
}
|
|
102
|
+
for (const [key, value] of Object.entries(own))
|
|
103
|
+
if (!(key in values))
|
|
104
|
+
values[key] = value;
|
|
105
|
+
}
|
|
106
|
+
const unknown = Object.keys(values)
|
|
107
|
+
.filter((key) => !RULES.includes(key))
|
|
108
|
+
.sort();
|
|
109
|
+
if (unknown.length > 0)
|
|
110
|
+
throw new UsageError(`meta.tracepanel has no ${unknown.join(", ")} (${RULES.join(", ")})`);
|
|
111
|
+
const limit = values.maxQueries;
|
|
112
|
+
if (limit !== undefined && !(Number.isInteger(limit) && limit >= 0)) {
|
|
113
|
+
throw new UsageError(`maxQueries must be a whole number, got ${JSON.stringify(limit)}`);
|
|
114
|
+
}
|
|
115
|
+
const failing = "failOn" in values ? kinds(values.failOn, "failOn") : new Set(failOn);
|
|
116
|
+
const allowed = kinds(values.allow ?? [], "allow");
|
|
117
|
+
return {
|
|
118
|
+
failOn: new Set([...failing].filter((kind) => !allowed.has(kind))),
|
|
119
|
+
maxQueries: limit,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** The current test's trace: needs tracepanel() in the plugins of the Vitest config. */
|
|
123
|
+
export function testTrace() {
|
|
124
|
+
const test = currentTest();
|
|
125
|
+
if (!test) {
|
|
126
|
+
throw new UsageError("testTrace() needs a test's trace, and none is running: add tracepanel() to the plugins of the Vitest config");
|
|
127
|
+
}
|
|
128
|
+
return test;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"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"}
|
package/dist/widget.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type Readable, Transform } from "node:stream";
|
|
2
|
+
import { type RequestHeaders } from "./request.js";
|
|
1
3
|
import type { Runtime } from "./runtime.js";
|
|
2
4
|
export interface Badge {
|
|
3
5
|
headers: Record<string, string>;
|
|
@@ -22,6 +24,18 @@ export declare function badge(tracepanel: Runtime, request: BadgeRequest): Badge
|
|
|
22
24
|
* a page on another origin, an SPA on Vite's dev server, can read the trace's id then. Undefined for other responses.
|
|
23
25
|
*/
|
|
24
26
|
export declare function exposedHeaders(allowOrigin: unknown, existing: unknown): string | undefined;
|
|
27
|
+
export interface ResponseMarks {
|
|
28
|
+
/** The badge's headers, Access-Control-Expose-Headers with them on a CORS response. */
|
|
29
|
+
headers: Record<string, string>;
|
|
30
|
+
/** The Set-Cookie that names a redirect answering a page's navigation, for the next page's panel. */
|
|
31
|
+
cookie: string | undefined;
|
|
32
|
+
script: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* What a framework's response gets (Fastify's, Koa's): the badge's headers, the redirect's cookie, and the script for
|
|
36
|
+
* a page. `header` reads the response's headers so far.
|
|
37
|
+
*/
|
|
38
|
+
export declare function responseMarks(tracepanel: Runtime, request: BadgeRequest, requested: RequestHeaders, header: (name: string) => unknown): ResponseMarks | undefined;
|
|
25
39
|
/** The tag first in <head>, so the widget wraps fetch before the page's scripts keep a reference to it. */
|
|
26
40
|
export declare function inject(page: string, tag: string): string;
|
|
27
41
|
/**
|
|
@@ -48,3 +62,5 @@ export declare class Stream {
|
|
|
48
62
|
/** What was held, once the body ends. */
|
|
49
63
|
end(): Buffer;
|
|
50
64
|
}
|
|
65
|
+
/** A Node stream with the script put into the page as it passes (a Fastify or Koa page streamed). */
|
|
66
|
+
export declare function streamWith(source: Readable, tag: string): Transform;
|
package/dist/widget.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// What a response gives the widget: the trace's id and timing in headers, and widget.min.js in an HTML page.
|
|
2
|
+
import { pipeline, Transform } from "node:stream";
|
|
2
3
|
import { runtimeLabel } from "./processor.js";
|
|
4
|
+
import { redirectCookie } from "./request.js";
|
|
3
5
|
function escapeHtml(text) {
|
|
4
6
|
return text.replace(/[&<>"]/g, (char) => `&#${char.charCodeAt(0)};`);
|
|
5
7
|
}
|
|
@@ -26,7 +28,7 @@ export function badge(tracepanel, request) {
|
|
|
26
28
|
headers["Tracepanel-Url"] = `${consoleUrl}#/t/${timing.id}`;
|
|
27
29
|
// The console on the page's own origin, where the app serves it: the widget and the page's recording share it.
|
|
28
30
|
const api = tracepanel.onOrigin?.prefix ?? consoleUrl;
|
|
29
|
-
const scriptAttrs = page && consoleUrl
|
|
31
|
+
const scriptAttrs = page && consoleUrl && tracepanel.config.widget
|
|
30
32
|
? {
|
|
31
33
|
src: `${api}widget.min.js`,
|
|
32
34
|
"data-tracepanel-api": api,
|
|
@@ -61,6 +63,21 @@ export function exposedHeaders(allowOrigin, existing) {
|
|
|
61
63
|
.filter(Boolean);
|
|
62
64
|
return [...new Set([...names, ...EXPOSED])].join(", ");
|
|
63
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* What a framework's response gets (Fastify's, Koa's): the badge's headers, the redirect's cookie, and the script for
|
|
68
|
+
* a page. `header` reads the response's headers so far.
|
|
69
|
+
*/
|
|
70
|
+
export function responseMarks(tracepanel, request, requested, header) {
|
|
71
|
+
const marks = tracepanel.badge(request);
|
|
72
|
+
if (!marks)
|
|
73
|
+
return undefined;
|
|
74
|
+
const headers = { ...marks.headers };
|
|
75
|
+
const expose = exposedHeaders(header("access-control-allow-origin"), header("access-control-expose-headers"));
|
|
76
|
+
if (expose)
|
|
77
|
+
headers["Access-Control-Expose-Headers"] = expose;
|
|
78
|
+
const cookie = redirectCookie(marks.headers["Tracepanel-Id"] ?? "", request.status, requested);
|
|
79
|
+
return { headers, cookie, script: marks.script };
|
|
80
|
+
}
|
|
64
81
|
/** The tag first in <head>, so the widget wraps fetch before the page's scripts keep a reference to it. */
|
|
65
82
|
export function inject(page, tag) {
|
|
66
83
|
const head = /<head(?:\s[^>]*)?>/i.exec(page);
|
|
@@ -130,4 +147,19 @@ export class Stream {
|
|
|
130
147
|
return rest;
|
|
131
148
|
}
|
|
132
149
|
}
|
|
150
|
+
/** A Node stream with the script put into the page as it passes (a Fastify or Koa page streamed). */
|
|
151
|
+
export function streamWith(source, tag) {
|
|
152
|
+
const script = new Stream(tag);
|
|
153
|
+
const piped = new Transform({
|
|
154
|
+
transform(chunk, _encoding, done) {
|
|
155
|
+
done(null, script.feed(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
|
|
156
|
+
},
|
|
157
|
+
flush(done) {
|
|
158
|
+
const rest = script.end();
|
|
159
|
+
done(null, rest.length > 0 ? rest : undefined);
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
// An error of the page's stream ends this one with it.
|
|
163
|
+
return pipeline(source, piped, () => { });
|
|
164
|
+
}
|
|
133
165
|
//# sourceMappingURL=widget.js.map
|
package/dist/widget.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAE7G,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tracepanel/js",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Traces and logs for Node.js and Bun apps (Express, NestJS, Next.js, Nuxt, Bun.serve): every request with its SQL, logs and errors, N+1 queries found",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Traces and logs for Node.js and Bun apps (Express, Fastify, Koa, Hono, NestJS, Next.js, Nuxt, Bun.serve): every request with its SQL, logs and errors, N+1 queries found",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "pnpm@12.11.0",
|
|
@@ -21,6 +21,18 @@
|
|
|
21
21
|
"types": "./dist/express.d.ts",
|
|
22
22
|
"default": "./dist/express.js"
|
|
23
23
|
},
|
|
24
|
+
"./fastify": {
|
|
25
|
+
"types": "./dist/fastify.d.ts",
|
|
26
|
+
"default": "./dist/fastify.js"
|
|
27
|
+
},
|
|
28
|
+
"./koa": {
|
|
29
|
+
"types": "./dist/koa.d.ts",
|
|
30
|
+
"default": "./dist/koa.js"
|
|
31
|
+
},
|
|
32
|
+
"./hono": {
|
|
33
|
+
"types": "./dist/hono.d.ts",
|
|
34
|
+
"default": "./dist/hono.js"
|
|
35
|
+
},
|
|
24
36
|
"./next": {
|
|
25
37
|
"types": "./dist/next.d.ts",
|
|
26
38
|
"default": "./dist/next.js"
|
|
@@ -44,6 +56,10 @@
|
|
|
44
56
|
"./browser": {
|
|
45
57
|
"types": "./dist/browser.d.ts",
|
|
46
58
|
"default": "./dist/browser.js"
|
|
59
|
+
},
|
|
60
|
+
"./vitest": {
|
|
61
|
+
"types": "./dist/vitest.d.ts",
|
|
62
|
+
"default": "./dist/vitest.js"
|
|
47
63
|
}
|
|
48
64
|
},
|
|
49
65
|
"bin": {
|
|
@@ -64,6 +80,7 @@
|
|
|
64
80
|
"dependencies": {
|
|
65
81
|
"@opentelemetry/api": "^1.9.1",
|
|
66
82
|
"@opentelemetry/instrumentation": "^0.223.0",
|
|
83
|
+
"@opentelemetry/instrumentation-aws-sdk": "^0.78.0",
|
|
67
84
|
"@opentelemetry/instrumentation-express": "^0.71.0",
|
|
68
85
|
"@opentelemetry/instrumentation-http": "^0.223.0",
|
|
69
86
|
"@opentelemetry/instrumentation-ioredis": "^0.71.0",
|
|
@@ -76,42 +93,81 @@
|
|
|
76
93
|
"@opentelemetry/sdk-trace-base": "^2.12.0",
|
|
77
94
|
"@opentelemetry/sdk-trace-node": "^2.12.0",
|
|
78
95
|
"@prisma/instrumentation": "^7.10.0",
|
|
79
|
-
"@tracepanel/agent": "~0.
|
|
96
|
+
"@tracepanel/agent": "~0.6.0",
|
|
80
97
|
"import-in-the-middle": "^3.5.2"
|
|
81
98
|
},
|
|
82
99
|
"peerDependencies": {
|
|
100
|
+
"@types/express": ">=4.17",
|
|
101
|
+
"@types/koa": ">=3",
|
|
83
102
|
"express": ">=4.18",
|
|
103
|
+
"fastify": ">=5",
|
|
104
|
+
"hono": ">=4.8",
|
|
105
|
+
"koa": ">=3",
|
|
84
106
|
"react": ">=18",
|
|
85
|
-
"
|
|
107
|
+
"vitest": ">=4.1"
|
|
86
108
|
},
|
|
87
109
|
"peerDependenciesMeta": {
|
|
88
110
|
"express": {
|
|
89
111
|
"optional": true
|
|
90
112
|
},
|
|
113
|
+
"fastify": {
|
|
114
|
+
"optional": true
|
|
115
|
+
},
|
|
116
|
+
"hono": {
|
|
117
|
+
"optional": true
|
|
118
|
+
},
|
|
119
|
+
"koa": {
|
|
120
|
+
"optional": true
|
|
121
|
+
},
|
|
91
122
|
"react": {
|
|
92
123
|
"optional": true
|
|
93
124
|
},
|
|
125
|
+
"vitest": {
|
|
126
|
+
"optional": true
|
|
127
|
+
},
|
|
94
128
|
"@types/express": {
|
|
95
129
|
"optional": true
|
|
130
|
+
},
|
|
131
|
+
"@types/koa": {
|
|
132
|
+
"optional": true
|
|
96
133
|
}
|
|
97
134
|
},
|
|
98
135
|
"devDependencies": {
|
|
136
|
+
"@ai-sdk/anthropic": "^4.0.88",
|
|
137
|
+
"@ai-sdk/openai": "^4.0.102",
|
|
138
|
+
"@anthropic-ai/sdk": "^1.3.0",
|
|
139
|
+
"@aws-sdk/client-dynamodb": "^3.1156.0",
|
|
140
|
+
"@aws-sdk/client-s3": "^3.1156.0",
|
|
141
|
+
"@aws-sdk/client-secrets-manager": "^3.1156.0",
|
|
142
|
+
"@aws-sdk/client-sqs": "^3.1156.0",
|
|
143
|
+
"@aws-sdk/lib-dynamodb": "^3.1156.0",
|
|
99
144
|
"@biomejs/biome": "2.5.15",
|
|
145
|
+
"@fastify/formbody": "^9.0.1",
|
|
146
|
+
"@hono/node-server": "^2.1.5",
|
|
147
|
+
"@koa/router": "^15.7.0",
|
|
100
148
|
"@opentelemetry/context-async-hooks": "^2.12.0",
|
|
149
|
+
"@types/better-sqlite3": "^9.6.0",
|
|
101
150
|
"@types/cookie-session": "^2.0.49",
|
|
102
151
|
"@types/express": "^5.0.6",
|
|
103
152
|
"@types/express-session": "^1.19.0",
|
|
153
|
+
"@types/koa": "^3.0.3",
|
|
104
154
|
"@types/node": "^26.6.5",
|
|
105
155
|
"@types/pg": "^8.23.1",
|
|
106
156
|
"@types/react": "^19.3.0",
|
|
157
|
+
"ai": "^7.0.153",
|
|
158
|
+
"better-sqlite3": "^12.11.1",
|
|
107
159
|
"bullmq": "^6.3.17",
|
|
108
160
|
"cookie-session": "^2.1.1",
|
|
109
161
|
"express": "^5.3.0",
|
|
110
162
|
"express-session": "^1.19.0",
|
|
163
|
+
"fastify": "^5.12.7",
|
|
111
164
|
"h3": "^1.15.11",
|
|
112
165
|
"happy-dom": "^21.0.1",
|
|
113
166
|
"hono": "^4.13.13",
|
|
114
167
|
"ioredis": "^6.0.0",
|
|
168
|
+
"koa": "^3.2.1",
|
|
169
|
+
"libsql": "^0.5.29",
|
|
170
|
+
"openai": "^7.43.0",
|
|
115
171
|
"pg": "^8.23.1",
|
|
116
172
|
"pino": "^10.4.0",
|
|
117
173
|
"typescript": "^7.0.2",
|
|
@@ -119,16 +175,25 @@
|
|
|
119
175
|
"winston": "^3.19.0"
|
|
120
176
|
},
|
|
121
177
|
"keywords": [
|
|
178
|
+
"anthropic",
|
|
179
|
+
"aws",
|
|
122
180
|
"bun",
|
|
123
181
|
"express",
|
|
182
|
+
"fastify",
|
|
183
|
+
"hono",
|
|
184
|
+
"koa",
|
|
185
|
+
"llm",
|
|
124
186
|
"n+1",
|
|
125
187
|
"nestjs",
|
|
126
188
|
"nextjs",
|
|
127
189
|
"nuxt",
|
|
190
|
+
"openai",
|
|
128
191
|
"opentelemetry",
|
|
129
192
|
"pino",
|
|
130
193
|
"sql",
|
|
194
|
+
"sqlite",
|
|
131
195
|
"tracing",
|
|
196
|
+
"vitest",
|
|
132
197
|
"winston"
|
|
133
198
|
],
|
|
134
199
|
"repository": {
|