Overview
Privacy-first, on-demand browser diagnostics for AbsoluteJS applications.
@absolutejs/diagnosticsv0.2.1betaObservabilityPrivacy-first AbsoluteJS Support Mode: bounded browser diagnostics, redacted HAR capture, correlated support bundles, secure lifecycle storage, native UI, and operator tooling.
bun add @absolutejs/diagnosticsPrivacy-first, on-demand browser diagnostics for AbsoluteJS applications.
It records a bounded network and console timeline only after an explicit support/operator action, exports a redacted HAR 1.2 document, and provides a Playwright/CDP path when a vendor needs a complete DevTools capture. Request and response bodies are off by default. Redaction happens before in-page entries are retained and again at export or server ingest.
@absolutejs/beacon stays tiny and always-on. It records redacted request
breadcrumbs and actionable failures, not complete protocol archives.
@absolutejs/errors groups and persists issues. It should link a diagnostic
id, not own large support artifacts.
@absolutejs/replay records privacy-masked DOM state. A DOM recording is not
an HTTP archive.
@absolutejs/observability can compose all four capabilities and correlate
the diagnostic id with Beacon session, Replay, Errors, and traces.
Creating a controller does not start recording:
The recorder wraps the current fetch, XHR, and console functions, so it can coexist with Beacon. It also consumes Resource Timing entries for static and third-party resources visible to the page. stop() restores only wrappers it still owns.
The in-page manifest always declares completeness: "in-page-partial" and cacheDisabled: false. Application JavaScript cannot truthfully claim a full HAR.
Body capture is deliberately difficult to enable
There is no captureBodies: true switch. Supply a per-request allow function and select request and/or response explicitly:
Strings and URL-encoded/JSON bodies are redacted immediately. Blob, stream, multipart, and other binary request bodies are never inspected by the in-page recorder.
Use the Playwright entry point when a payment processor, identity provider, or other vendor requests a real HAR with Preserve Log and Disable Cache:
Playwright first records to a uniquely named raw temporary file. stop() closes the context so Playwright flushes the HAR, creates the redacted output, runs the sharing audit, and removes the raw temporary file in a finally block. Call stop() rather than closing the browser window at the OS level.
The metadata declares completeness: "devtools-complete", whether cache was disabled, exact UTC start/end times, and any operator markers.
createSupportModeController provides a consent-shaped state machine: idle → recording → reviewing → sending → sent. Creating it never starts a recording. A host can use the headless controller directly or connect the framework-neutral native element.
The element explains what will be recorded, requires an explicit Start click, shows a persistent recording state, supports named markers, and exposes the privacy-audit result before send.
createSupportBundle() produces one audited JSON artifact containing the redacted in-page archive and HAR plus marker, replay, release, environment, issue-fingerprint, and W3C trace correlations. It does not embed Replay data, server logs, or issue records; those remain in their purpose-built stores and are joined by id.
Request-level trace correlation recognizes valid traceparent headers and records exposed Server-Timing metrics. Diagnostic-id propagation is same-origin, opt-in, and off by default because mutating requests can affect caches or signed requests.
The optional Elysia correlation plugin makes the bounded correlation available to handlers and appends server timing:
Defaults remove or mask:
Authorization, Cookie, Set-Cookie, proxy credentials, and API-key
headers
every URL query value and every fragment
bearer values and JWT-shaped strings
tokens, sessions, credentials, passwords, signatures, wallet payloads,
payment fields, card fields, and common personal-contact fields
request and response bodies in DevTools HAR captures
body content beyond the configured byte limit
The sharing audit reports finding codes and locations, never the suspected secret value.
The relay defaults closed. A host must provide authorization and storage:
The relay enforces a byte limit, validates the archive shape, redacts again, audits the serialized HAR, and only then calls the store. Wire storage to @absolutejs/blob or another private store with an explicit retention policy.
Secure lifecycle storage
createDiagnosticBlobCaptureStore() adapts any @absolutejs/blob store. The relay can enforce retention, atomic download limits, short-lived HMAC-signed download URLs, explicit deletion, and mandatory lifecycle audit hooks.
maxDownloads is accepted only when the store implements atomic consume(); the plugin refuses unsafe configuration rather than pretending a normal get() is sufficient. The Blob adapter exposes serialized consume() only with singleWriter: true. Clustered applications must supply a transactional store implementation instead of relying on an object-store read/modify/write race.
@absolutejs/diagnostics/viewer builds a chronological network, console, and marker timeline. compareSupportBundles(left, right) reports request-set, status, failure-count, timing, console, and marker differences—useful for comparing a successful card attempt with a failed wallet attempt.
A normal webpage cannot observe:
protected cookies and browser-owned authorization data
most cross-origin response headers or bodies
native Apple Pay or browser-wallet network traffic
browser cache, connection, and service-worker protocol details with DevTools
fidelity
requests made by another device during a QR handoff
Therefore an in-page export is useful but partial. Use Playwright/CDP for a complete desktop-browser HAR. Capturing native iPhone Safari with Web Inspector still requires Apple's supported Mac-connected workflow; this package cannot bypass platform security boundaries.
Outcomes
Privacy-first, on-demand browser diagnostics for AbsoluteJS applications.
@absolutejs/beacon stays tiny and always-on. It records redacted request
Install only the optional capability you use:
Hardening checklist
Follow in order
Install only the optional capability you use:
bun add playwright # complete Chromium HAR capture
bun add elysia # upload/retrieval relayCreating a controller does not start recording:
import { createBrowserDiagnostics } from "@absolutejs/diagnostics/browser";
const diagnostics = createBrowserDiagnostics({
project: "web",
release: APP_RELEASE,
replayId: () => replay.getReplayId(),
traceId: () => currentTraceId(),
ignoredUrlSubstrings: ["/api/diagnostics"],
});
// Call only after an explicit support/operator action.
const session = diagnostics.start({ reason: "payment provider reproduction" });
// Reproduce the problem, then stop and download a redacted HAR.
const archive = await session.stop();
session.downloadHar("payment-provider.redacted.har");There is no captureBodies: true switch. Supply a per-request allow function and select request and/or response explicitly:
const diagnostics = createBrowserDiagnostics({
project: "web",
bodyCapture: {
request: true,
response: true,
maxBodyBytes: 16_384,
allow: ({ sameOrigin, url }) =>
sameOrigin && new URL(url).pathname.startsWith("/api/support-safe/"),
},
});Supported entry points declared by this project’s package manifest. Internal dist paths are not part of the package contract.
Public package entry point declared in package.json.
Scripts declared by this project’s package manifest.
Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.
type BrowserDiagnosticsOptions = {
bodyCapture?: DiagnosticBodyCapturePolicy;
environment?: string;
ignoredUrlSubstrings?: string[];
maxBytes?: number;
maxConsoleEntries?: number;
maxNetworkEntries?: number;
preserveQueryValues?: string[];
project: string;
/** Add the diagnostic id to same-origin requests. Off by default because
* request mutation can affect caches, signatures, and CORS behavior. */
propagateDiagnosticId?: boolean;
release?: string;
replayId?: () => string | undefined;
traceId?: () => string | undefined;
};@absolutejs/diagnostics