Skip to content

Sync with upstream @hyperdx/app@2.44.0 - #5

Closed
mfroembgen wants to merge 11 commits into
mainfrom
fork-sync/app-2.44.0
Closed

mfroembgen wants to merge 11 commits into
mainfrom
fork-sync/app-2.44.0

Conversation

@mfroembgen

@mfroembgen mfroembgen commented Nov 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

Merges upstream @hyperdx/app@2.44.0 (f172a489c) into the fork with a real merge commit. It is the same commit as @hyperdx/api@2.44.0, @hyperdx/otel-collector@2.44.0, @hyperdx/common-utils@0.34.0, @hyperdx/cli@0.9.0 and upstream's GitHub "Latest" release, cli-v0.9.0.

main (b6bdb1aaa, 2.43.1 squash-synced)
  └─ Merge upstream @hyperdx/app@2.44.0          3183562f3  conflict resolutions only
       ├─ test: run upstream 2.44.0 tests on Vitest
       ├─ fix: adapt upstream 2.44.0 code to the fork stack
       ├─ fix: keep webhook DNS checks on Bun
       ├─ feat: run ClickStack self-telemetry on Bun
       ├─ ci: prove recorder fixes with the ClickStack browser SDK
       └─ test: keep a member when WorkOS tests remove teammates

The previous sync (#4) squash-merged 2.43.1, so main has 2.43.0 but not 2.43.1 as an ancestor. Conflicts were therefore resolved against 2.43.1 as the base. Files that main already had at 2.43.1 content take the upstream version.

Upstream replaced its self-instrumentation SDKs (@hyperdx/node-opentelemetry → @clickhouse/clickstack-node, @hyperdx/browser → @clickhouse/clickstack-browser). That drove most of the follow-up work:

  • Self-telemetry on Bun. The fork's tracing.ts preload is replaced by upstream's telemetry.ts, run with bun --preload. On Bun, instrumenting HTTPS after HTTP unwraps the HTTP server instrumentation, so the preload gives the HTTPS server its own emit first. OAuth code/state and token parameters are scrubbed from HTTP span URLs, as the old WorkOS-mode config did. The SDK prints one warning at startup that its ESM loader hook is unavailable on Bun; the compiled API is CommonJS, so nothing is lost.
  • @opentelemetry/api pinned to 1.9.1 in the app and API (was 1.10.0). Both ClickStack SDKs require <1.10, and a newer API copy cannot read the globals the SDK registers, so custom spans and metrics would go to no-op providers.
  • Webhook DNS check on Bun (security). Upstream 2.44.0 hardens webhook delivery with an undici Agent whose DNS lookup rejects private addresses. Bun maps the bare undici specifier to a built-in fetch that ignores dispatcher, so on the fork the check never ran: a test that resolves a public host to 127.0.0.1 reached the network. The fork now imports undici/index.js (the real package), and that test passes.
  • Browser recorder fix. The new browser SDK imports @rrweb/record 2.2 from node_modules, so the fork's @hyperdx/browser patch is dropped. The CI memory proof (fork-image.yml › sdk-memory) now targets the new SDK. It no longer asserts request/response body capture, because @clickhouse/clickstack-browser cannot capture bodies (upstream notes this in its release notes).
  • Zod 4 schema behaviour. One new upstream schema relied on Zod 3 treating a z.unknown() key as optional. Under Zod 4 the field is required, so every Prometheus error lost its message and category. It is now .optional().

Fork patches

All fork patches are carried forward:

  • b1a4d7b3f fix: preserve JSON and Map search filter expressions. Merged with upstream's new @-prefixed JSON key fixture in tests/e2e/seed-clickhouse.ts.
  • 122b942c6 feat: add WorkOS browser login and MCP OAuth. Adapted to upstream's org API keys and last-member guard; see Conflicts.
  • 9f108460f refactor: align fork runtime, tooling and dependencies (Bun, Vinext, Vitest, tsrs, dependency majors, fork image workflow). Upstream's new code and tests are adapted in the follow-up commits.
  • b6bdb1aaa (the 2.43.1 squash sync) carries no fork-specific change beyond these patches: its diff equals upstream 2.43.0..2.43.1.

Dropped or replaced:

  • The @hyperdx/browser@0.26.0 Bun patch, which upstream superseded with @clickhouse/clickstack-browser.
  • The @hyperdx/node-opentelemetry tracing preload, replaced by upstream's ClickStack preload with the fork's Bun and WorkOS behaviour carried over.
  • @hyperdx/cli is versioned 0.9.0-fork.1, following the fork's existing -fork.1 convention.

Conflicts

Resolved in the merge commit (base 2.43.1 for the 3-way resolution):

File Resolution
CHANGELOG.md, packages/{api,app,otel-collector}/CHANGELOG.md, packages/otel-collector/package.json, .github/CODEOWNERS Upstream (spurious: main already had 2.43.1 content)
.env Upstream 2.44.0 version, plus the fork's collector 0.164 versions
yarn.lock, packages/app/jest.config.js, packages/api/jest.setup.ts Kept deleted (fork uses Bun/Vitest); the upstream additions (clickstack-browser mock alias, undici fetch mock) moved to vitest.config.mts / vitest.setup.ts
packages/app/src/theme/{index.ts,__tests__/*} Upstream deletion (single ClickStack brand); the fork's edits there were mechanical. Fork-only pages now import @/brand
.yarn/patches/uplot-npm-1.6.32-*.patch Moved to patches/uplot-1.6.32.patch as a Bun patchedDependencies entry
package.json, packages/{api,app,cli}/package.json Fork scripts and pins kept. Upstream's new dependencies added at exact versions; @hyperdx/browser and @hyperdx/node-opentelemetry dropped; cli version 0.9.0-fork.1; build:clickhouse drops NEXT_PUBLIC_THEME like upstream
packages/api/bin/hyperdx, packages/app/playwright.config.ts Bun --preload of upstream's telemetry.js; e2e keeps Vinext commands with upstream's HDX_EXPORTER_ENABLED=false and 6-minute startup timeout
packages/api/src/controllers/user.ts Upstream org API keys, NOT_VIRTUAL and last-member guard, combined with the fork's WorkOS behaviour: removal unsets the team and rotates the key, and the restore path re-sets them instead of reinserting; hasPasswordAuth aggregate excludes virtual users. The last-member guard applies with WorkOS too, so the fork's WorkOS removal tests now keep a second member in the team
packages/api/src/middleware/auth.ts, mcp/app.ts Upstream org-key auth plus the fork's user?.team check (removed WorkOS members cannot authenticate) and validateMcpUser
packages/api/src/mcp/tools/dashboards/schemas.ts, mcp/utils/registerTool.ts Upstream PromQL tile schema and annotations.title, with the fork's Zod 4 union error map and ZodObject types
packages/api/src/fixtures.ts Upstream (TimeSeries version 7/8 handling supersedes the fork's version 3 pin)
packages/api/src/controllers/alertsPage.ts Upstream params type with Mongoose 9 QueryFilter
packages/app/pages/_app.tsx Upstream (browser telemetry moved to instrumentation-client.ts, theme provider removed), keeping the fork's Buffer/randomUUID polyfills and NuqsAdapter
packages/app/pages/_document.tsx Upstream favicons, prefixed with the fork's BASE_PATH like __ENV.js
packages/app/src/components/AppNav/AppNav.components.tsx Fork POST logout form, plus upstream's RUM session reset on click
packages/app/src/AuthPage.tsx Fork (password UI lives in PasswordAuthPage.tsx, now importing @/brand)
packages/app/src/DBSearchPageAlertModal.tsx Upstream (prefill removed) with the fork's passthroughFormResolver and SavedSearchAlertRead type
packages/app/src/{DBDashboardPage,DBChartPage}.tsx, components/{DBRowTable,ExceptionSubpanel,DBTraceWaterfallChart}.tsx, utils.ts, McpServerSection.tsx Both sides' imports/state (fork filter parser, react-table v9 types, lazy state init, OAuth setup)
packages/app/tests/e2e/seed-clickhouse.ts Both: fork JSON integer/mixed/boolean fields and upstream @request_id key
packages/cli/src/cli.tsx Both imports (fork #package version, upstream mcp install)
.github/workflows/release.yml, release-nightly.yml Upstream (no GHCR login, RUNNER_* variables) with the fork's pinned action SHAs and ubuntu-24.04-arm default
.github/workflows/e2e-tests.yml Fork runner and worker selection kept; upstream's longer timeout applied to the hosted runner. Upstream's step-level E2E_WORKERS was dropped because on this repo it would override the fork's value with an empty one
CONTRIBUTING.md, agent_docs/architecture.md, packages/app/AGENTS.md Fork runtime (Bun/Vinext) with upstream's ClickStack naming
33 test files and renderAlertTemplate.int.test.ts.snap Upstream content converted to Vitest (snapshot keys use Vitest's > separator)

How to reproduce

Starting point: this worktree with Bun from mise.toml.

On main:

  1. App/API/collector manifests are 2.43.1.

On this branch:

  1. Manifests are 2.44.0 (@hyperdx/cli 0.9.0-fork.1), and git merge-base --is-ancestor f172a489c HEAD succeeds.
  2. Run bun ci, make ci-build, make ci-lint, make ci-unit.

How to test on Vercel preview

N/A. This is an upstream sync; upstream's UI changes are described in its release notes below.

Evidence

Local checks (macOS, Bun 1.4.4 via Mise):

Check Result
bun ci (frozen lockfile) pass
nx run-many -t ci:build pass
tsrs --noEmit in api, app, common-utils, cli, hdx-eval pass, 0 errors
bun run lint in api (301/302 warnings), app, common-utils, cli, hdx-eval; lint:styles pass
bun scripts/ci/ratchet.mjs, scripts/ci/check-openapi-sync.sh, knip pass
ci:unit api 87 files, 1,561 tests pass
ci:unit app 358 files, 5,564 tests pass
ci:unit common-utils / cli 3,134 / 134 tests pass
Bun preload fixture (telemetry.test.ts): HTTP server span, Express span, http.server.request.duration, OAuth code absent from span attributes pass with the preload, fails without it
bun test scripts/ci/__tests__/browser-sdk-memory.test.mjs; bun scripts/ci/browser-sdk-memory.mjs pass: 4 full snapshots, 1 probe mutation, 100 shadow observers created and disconnected, 0 detached

Not run locally: integration tests (ClickHouse/MongoDB), E2E, collector smoke tests and the image build. They need the Docker-based CI stack; this PR's CI runs them.

Merge Danger

Door: two-way

The source can be reverted; nothing is published by this PR.

Blast Radius: application

Upstream's own telemetry now uses the stable HTTP semantic convention names (http.server.request.duration, url.full) and different browser attributes (see the app release notes). Dashboards built on the fork's self-telemetry may need updating.

This repository only allows squash merges, which would flatten the upstream ancestry this merge preserves; a merge commit is needed to keep upstream history.

References

Upstream changes

Release notes for every upstream release after 2.43.1, up to and including @hyperdx/app@2.44.0 / cli-v0.9.0.

@hyperdx/app@2.44.0

Release notes
Minor Changes
  • 142c9cc: feat: narrow ad hoc dashboard filter suggestions with a condition

    An ad hoc filter on SQL sources can now carry a SQL or Lucene "Keys and values
    filter", like a queried filter's dropdown values filter, that limits the rows
    its keys and values are suggested from. It can reference the dashboard's other
    variables. While it references a required filter with nothing selected, the ad
    hoc filter can't add or edit conditions and names the filter it is waiting on.
    Failed suggestions now show the database's error message.

  • cd0e9ed: feat: add optional titleEmoji webhook option; false removes the emoji prefix from notification titles sent through that webhook

  • 5b0d074: feat: self-instrument with @clickhouse/clickstack-node and
    @clickhouse/clickstack-browser instead of @hyperdx/node-opentelemetry and
    @hyperdx/browser

    HyperDX's own telemetry changes shape. HTTP spans use the stable semantic
    convention keys (http.request.method, http.response.status_code,
    url.full). pino records come from the @opentelemetry/instrumentation-pino
    scope with real severity numbers instead of the node-logger scope with
    severity number 0. Console capture covers every console call in the API, and
    browser console output is recorded as log records instead of spans. Uncaught
    exceptions are recorded as FATAL log records, and API errors as an exception
    event on the Express span instead of a separate error span.

    Browser telemetry records the user as user.id, user.email and user.name
    instead of userEmail and userName, keeps the team name as teamName, and no
    longer records a user navigated action. Browser fetch and XHR spans no longer
    record request and response headers or bodies. Browser sessions restart once
    after the upgrade. The per-signal browser endpoints and
    NEXT_PUBLIC_OTEL_RESOURCE_ATTRIBUTES work as before. Browser traces and logs
    are now sent gzip-compressed every 5 seconds. If the browser sends to a
    collector other than ClickStack's, its CORS allowed_headers must be "*" or
    include content-type and content-encoding (and authorization), and a proxy
    in front of it must forward Content-Encoding unchanged.

    The Next.js server now sends its own telemetry in production builds too, not
    only under next dev, when HYPERDX_API_KEY or OTEL_EXPORTER_OTLP_HEADERS is
    set. HDX_EXPORTER_ENABLED=false turns it off along with browser telemetry. It
    reports under its own service name, the configured one plus -next
    (hdx-oss-app-next in the docker-compose app service and when no name is
    set), so its spans stay apart from the API's and the browser's. The HyperDX
    images now default OTEL_SERVICE_NAME to hdx-oss-app. Each /api request
    adds Next.js server spans for the proxy hop. Requests for build and public/
    assets, such as /_next/static/*, /__ENV.js and /pyodide/*, are not traced.

    HYPERDX_API_KEY still enables self-instrumentation. Without
    OTEL_EXPORTER_OTLP_ENDPOINT, server-side self-telemetry now goes to
    http://localhost:4318 instead of https://in-otel.hyperdx.io, so set the
    endpoint explicitly. HDX_NODE_* variables are no longer read. For request
    headers and bodies set OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_* and
    CLICKSTACK_CAPTURE_HTTP_BODY.

  • 0b7926d: feat: Team members can create team-owned API keys with a description and expiry that keep working after their creator leaves.

  • af17e8f: The app always uses ClickStack branding. Brand selection, the HyperDX palette, and the font picker are removed. Light, dark, and system color mode stay in Preferences.

  • dd8c2e4: feat: Pick a time zone for the search and dashboard pages from the time picker, overriding the time zone in User Preferences. The picker shows the zone it uses, and the choice is kept in the URL and in links from charts and tables

Patch Changes
  • 7de661b: feat: Row side panel summarizes clicks, navigations and console messages from OpenTelemetry browser SDKs, and navigation rows no longer show an HTTP Request section

  • df737d8: refactor: use the click-ui Separator instead of the Mantine Divider in the
    chart display, heatmap, number format, and on-click drawers, and in the ad hoc
    and query expression dashboard filter forms.

  • 4b8df6d: fix: show a neutral spinner while charts load

    Chart tiles now show a spinner with "Loading Chart Data..." while a query is in
    flight, including when the previous result was empty. Before, they kept showing
    "No data found within time range." until the new query finished. Loaders now
    default to a neutral gray instead of yellow.

  • ab36d4e: feat: publish the HyperDX image as clickhouse/clickstack alongside
    hyperdx/hyperdx, matching the other clickhouse/clickstack-* images. Release
    workflows no longer log into ghcr.io, which received no pushes.

  • f56d4ad: fix(app): use the ClickStack hexagon and bolt mark in the logo, the collapsed nav, and the favicon.

  • d7df729: chore: GitHub links (changelog, support, package metadata) now point at ClickHouse/ClickStack, and docker-compose.yml pulls the app image as clickhouse/clickstack

  • f56d4ad: fix(app): open the full nav over the page on compact viewports. On narrow screens the sidebar toggle now opens the full nav as an overlay instead of doing nothing.

  • 513b237: fix: start the trace waterfall higher in the side panel

    Trace spans no longer repeat their name in a box under the panel title, or the
    service as a chip next to the metadata row that already shows it. The
    "⌘/Ctrl + scroll to zoom" hint moves into the timeline's top-left corner
    instead of taking its own row. Long span names that the title truncates keep
    the box. Log panels keep their body box and service chip.

  • 9269f77: fix: "Denoise results" now removes noise on typical data. A pattern now counts as noisy above 5% of sampled events instead of 10%, which often matched nothing. Patterns that include error or warning lines are never hidden. The MCP denoise option uses the same 5% threshold. Denoise also mines the source's body column instead of the last table column, removes ANSI-colored rows that match a noisy pattern, says when results can't be denoised, and shows hidden patterns as a short summary with a shortened, expandable list.

  • e2754d2: fix: use SHA256 instead of MD5 for JSON row lookup WHERE clauses so row
    details and drill-down work on FIPS-enabled ClickHouse deployments

  • 5abf27e: Saving a search no longer reloads the page: the new saved search is opened with
    a client-side navigation, which also fixes the 404 this caused on the static
    ClickStack build.

  • ba7d006: fix: heatmap hover tooltip no longer adds scrollbars or shifts the tile; it now
    sits above the chart instead of inside it

  • 04f55d1: feat: Exception panel parses JavaScript stack traces from OpenTelemetry SDKs into frames, with a section per Caused by: error

  • d0dd06f: fix: count legacy STATUS_CODE_ERROR spans as errors on the service map and trace
    waterfall

  • 7935c64: feat: add hdx mcp install to connect AI agents without pasting a key

    npx @hyperdx/cli mcp install asks for a personal access key or an
    organization API key with hidden input, checks it, and adds the ClickStack MCP
    server to Claude Code, Codex, Cursor, and VS Code. Team Settings now leads with
    this command, so the key no longer has to go into a copied command or an agent
    chat. The per-agent snippets remain for setting up one agent by hand.

  • 41b2b74: feat: fall back to server MergeTree settings to detect persisted _block_number and _block_offset columns when the table's CREATE query omits them

  • 442d6df: fix: refresh cached table columns after 5 minutes

    The shared metadata cache kept each table's DESCRIBE result for the life of
    the process, so the API did not see columns added with ALTER TABLE, such as
    new MATERIALIZED columns, until it restarted. Cached columns now expire after 5
    minutes. Other cached metadata is unchanged.

  • eb2439e: fix: leave metric points with no recorded value out of charts and alerts

    When a scraped series goes away or a scrape fails, the collector's prometheus
    receiver sends a point flagged "no recorded value" (a Prometheus staleness
    marker), and the ClickHouse exporter stores it as zeros. Metric charts and
    alerts read it as a real value: a gauge's min and avg dropped and count
    included the series that went away, and a counter or histogram that came back
    after the marker counted its whole total again. Metric queries now skip points
    with this flag.

  • 81b6b60: refactor: use the click-ui Separator instead of the Mantine Divider in the
    keyboard shortcuts modal, What's new drawer, filter settings popover, metric
    explorer, chart explorer, time picker, and Service Map tooltip.

  • 9df8b8d: fix: bump next to 16.4.3 so builds no longer fail intermittently when Google Fonts returns extensionless font URLs

  • ec0db7a: fix: Creating an alert from the search page asks for one name, not two. An unsaved search is named once in the alert modal's header and the alert inherits that name and its tags; on a saved search the alert's own name field is labelled "Alert name" and shows the inherited name as its placeholder instead of pre-filling a duplicate.

  • 467c167: feat: A pinned filter collapsed in the search sidebar stays collapsed the next
    time the source loads, instead of always opening

  • 6468dad: fix: keep session replay events from different page loads apart

    Browser SDKs up to @clickhouse/clickstack-browser 1.2.0 number replay events
    from 1 again on every page load. When a page closed before all chunks of a large
    event were sent, its leftover chunk could be joined with a later page's event of
    the same number. That page's snapshot then failed to parse and did not render.
    Chunks are now grouped by event number and full-precision timestamp, and replay
    rows are ordered by the full-precision timestamp, so rows of two page loads in
    the same second no longer interleave.

    The app's own browser telemetry now uses @clickhouse/clickstack-browser 1.2.1,
    whose replay event numbers no longer repeat across page loads.

  • 86cd38b: fix: only use the key-only row details lookup when the table persists both _block_number and _block_offset. A lone block column (e.g. a server-wide enable_block_offset_column) is not unique with a second-precision primary key and could open the wrong row; it is now only added as a tiebreaker to the full-row lookup.

  • 82b2104: fix: show a loader while row details load

    Expanded search rows and the trace viewer's span details showed "Empty" or "No
    body for this event." while the row was still loading. They now show a loader
    until the row arrives.

  • 3a412e4: fix: run the row details query once when opening a row

    The side panel ran the same SELECT * row query twice: once for the panel, and
    again when its Overview or Column Values tab mounted. A row that was found is
    now reused from the cache, so the tab and later tab switches do not query it
    again. A different row or source still runs the query, and a row that was not
    found is looked up again.

  • 78143c8: feat: on ClickHouse Cloud, read system.shared_merge_tree_settings when detecting _block_number and _block_offset columns, falling back to system.merge_tree_settings per key

  • 4e93ae5: fix(app): render the ClickStack name as text in the expanded sidebar, 8px from the logo symbol.

  • 38f58cf: refactor: use the click-ui Separator instead of the Mantine Divider in the
    source form and the sources list.

  • 2bad9af: refactor: use the click-ui Separator instead of the Mantine Divider in the
    Team Settings sections.

  • af75b2b: feat: Trace waterfall shows OpenTelemetry browser SDK request timings as dots on fetch and XHR spans, and the click that triggered a browser trace

  • 4e93ae5: fix(app): use the new favicon set, including an SVG, in the browser tab, bookmarks, and touch icon.

  • dc58efd: fix: The app no longer crashes on load in browsers that report a POSIX-style language such as en-US@posix

  • Updated dependencies [142c9cc]

  • Updated dependencies [30b1494]

  • Updated dependencies [0453aa1]

  • Updated dependencies [cd0e9ed]

  • Updated dependencies [5b0d074]

  • Updated dependencies [5b0d074]

  • Updated dependencies [769c0de]

  • Updated dependencies [9269f77]

  • Updated dependencies [48c8379]

  • Updated dependencies [e2754d2]

  • Updated dependencies [22f824c]

  • Updated dependencies [6425332]

  • Updated dependencies [d0dd06f]

  • Updated dependencies [349fc21]

  • Updated dependencies [6310023]

  • Updated dependencies [5584f84]

  • Updated dependencies [253a690]

  • Updated dependencies [66e3941]

  • Updated dependencies [7e85229]

  • Updated dependencies [9093282]

  • Updated dependencies [53bf540]

  • Updated dependencies [0eec5e1]

  • Updated dependencies [917c9ca]

  • Updated dependencies [95fa364]

  • Updated dependencies [d08b2fa]

  • Updated dependencies [a13c80e]

  • Updated dependencies [0262822]

  • Updated dependencies [41b2b74]

  • Updated dependencies [442d6df]

  • Updated dependencies [eb2439e]

  • Updated dependencies [0b7926d]

  • Updated dependencies [0eec5e1]

  • Updated dependencies [0a5237e]

  • Updated dependencies [78143c8]

  • Updated dependencies [b7b4d95]

  • Updated dependencies [b1d4e60]

  • Updated dependencies [ef56bd7]

  • Updated dependencies [c792850]

  • Updated dependencies [90302c7]

    • @hyperdx/common-utils@0.34.0
    • @hyperdx/api@2.44.0

@hyperdx/api@2.44.0

Release notes
Minor Changes
  • cd0e9ed: feat: add optional titleEmoji webhook option; false removes the emoji prefix from notification titles sent through that webhook

  • 5b0d074: feat: self-instrument with @clickhouse/clickstack-node and
    @clickhouse/clickstack-browser instead of @hyperdx/node-opentelemetry and
    @hyperdx/browser

    HyperDX's own telemetry changes shape. HTTP spans use the stable semantic
    convention keys (http.request.method, http.response.status_code,
    url.full). pino records come from the @opentelemetry/instrumentation-pino
    scope with real severity numbers instead of the node-logger scope with
    severity number 0. Console capture covers every console call in the API, and
    browser console output is recorded as log records instead of spans. Uncaught
    exceptions are recorded as FATAL log records, and API errors as an exception
    event on the Express span instead of a separate error span.

    Browser telemetry records the user as user.id, user.email and user.name
    instead of userEmail and userName, keeps the team name as teamName, and no
    longer records a user navigated action. Browser fetch and XHR spans no longer
    record request and response headers or bodies. Browser sessions restart once
    after the upgrade. The per-signal browser endpoints and
    NEXT_PUBLIC_OTEL_RESOURCE_ATTRIBUTES work as before. Browser traces and logs
    are now sent gzip-compressed every 5 seconds. If the browser sends to a
    collector other than ClickStack's, its CORS allowed_headers must be "*" or
    include content-type and content-encoding (and authorization), and a proxy
    in front of it must forward Content-Encoding unchanged.

    The Next.js server now sends its own telemetry in production builds too, not
    only under next dev, when HYPERDX_API_KEY or OTEL_EXPORTER_OTLP_HEADERS is
    set. HDX_EXPORTER_ENABLED=false turns it off along with browser telemetry. It
    reports under its own service name, the configured one plus -next
    (hdx-oss-app-next in the docker-compose app service and when no name is
    set), so its spans stay apart from the API's and the browser's. The HyperDX
    images now default OTEL_SERVICE_NAME to hdx-oss-app. Each /api request
    adds Next.js server spans for the proxy hop. Requests for build and public/
    assets, such as /_next/static/*, /__ENV.js and /pyodide/*, are not traced.

    HYPERDX_API_KEY still enables self-instrumentation. Without
    OTEL_EXPORTER_OTLP_ENDPOINT, server-side self-telemetry now goes to
    http://localhost:4318 instead of https://in-otel.hyperdx.io, so set the
    endpoint explicitly. HDX_NODE_* variables are no longer read. For request
    headers and bodies set OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_* and
    CLICKSTACK_CAPTURE_HTTP_BODY.

  • 349fc21: feat(mcp): add clickstack_describe_table to list the tables in a database and describe a table that is not a registered source (columns, keys, engine, skipping indices, approximate size, optional row sample)

  • 0eec5e1: feat: Describe PromQL sources in MCP and hide them when PromQL is disabled

    clickstack_describe_source now returns the label names and metric names of a PromQL source, from either a ClickHouse TimeSeries table or a Prometheus-compatible endpoint, instead of a column schema. clickstack_list_sources and clickstack_describe_source show which backend a PromQL source uses, and for TimeSeries tables explain how to read them with clickstack_sql. Prometheus endpoint sources no longer show their placeholder table. When ENABLE_PROMQL is off, MCP hides PromQL sources from listing, describing and deleting, and clickstack_save_source no longer accepts kind: "promql".

  • 95fa364: feat(mcp): support setting a dashboard's savedFilterValues via the MCP dashboard tools

  • 0b7926d: feat: Team members can create team-owned API keys with a description and expiry that keep working after their creator leaves.

  • c792850: feat: filter the v2 list alerts endpoint by tag, search, source and state

Patch Changes
  • 30b1494: feat: add an internal extension point for alert detection strategies; threshold alerts are evaluated as before, and the alerts.evaluate metric now carries an alert_evaluator attribute

  • 0453aa1: fix: A grouped alert whose group vanishes from the data now resolves with the group's values in {{attributes.*}} (alert title and message) and {{var.*}} (webhook body)

  • 5b0d074: fix: let browsers cache the collector's CORS preflights for 10 minutes

    The OTLP receiver now answers preflights with Access-Control-Max-Age: 600.
    Without it, browsers cached a preflight for only 5 seconds, which is how often
    the browser SDK exports, so about half of its requests were preflights.

  • 769c0de: fix: ignore team and createdBy in dashboard and saved search PATCH bodies so they can't be moved to another team or have their owner rewritten

  • 9269f77: fix: "Denoise results" now removes noise on typical data. A pattern now counts as noisy above 5% of sampled events instead of 10%, which often matched nothing. Patterns that include error or warning lines are never hidden. The MCP denoise option uses the same 5% threshold. Denoise also mines the source's body column instead of the last table column, removes ANSI-colored rows that match a noisy pattern, says when results can't be denoised, and shows hidden patterns as a short summary with a shortened, expandable list.

  • 48c8379: docs: Document minAutoGranularity on metric and PromQL sources in the external
    API

    GET, POST and PUT /api/v2/sources already accepted and returned
    minAutoGranularity, but the OpenAPI spec omitted it, so clients generated from
    the spec dropped or rejected the field.

  • 6425332: perf: PromQL label lookups with match[] read only the matched metrics' tags
    rows when every selector names its metric

  • 6310023: fix: give clickstack_save_source's highlightedRowAttributeExpressions parameter a real type in the MCP tool schema (it rendered as an untyped $ref), and set annotations.title on every MCP tool

  • 5584f84: fix: make clickstack_event_patterns drill-down snippets executable

    Each pattern's whereSnippet is now a SQL predicate (whereLanguage: "sql") that keeps the template's token order and variable positions and includes the caller's filter and the source table filter, so passing it to clickstack_search returns the pattern's events. Before, a template like Sending <*> rows produced Body:"Sending rows", which matched nothing, and map fields produced Lucene that failed to parse. bodyExpression now also accepts JSONExtractString(<column>, '<key>', ...) to mine a field inside JSON bodies, and the tool reports sample coverage and the actual trend bucket interval and boundaries.

    clickstack_event_patterns, clickstack_emerging_signals and dashboard event-pattern tiles now apply the log source's tableFilterExpression, so their counts can drop for sources that set one. minePatterns now reports each cluster's own template; before, it could report the template of a different same-length cluster that some members did not fit.

  • 253a690: docs: MCP tool descriptions and the query guide now recommend the quoted Lucene
    form field:"value" for exact matches, and bare terms or phrases for log body
    text, so agents keep the primary key and the text index

  • 66e3941: feat: MCP query_tile and query_tiles run PromQL tiles against Prometheus endpoints and ClickHouse TimeSeries tables

  • 7e85229: feat: MCP clickstack_promql tool runs PromQL against a PromQL source, and the MCP prompts and instructions cover PromQL sources, tiles and label filters while PromQL is enabled

  • 9093282: fix: Refuse Prometheus endpoint responses over 8 MB in MCP PromQL label lookups and queries, instead of buffering them whole

  • 53bf540: fix: MCP query_tile returns PromQL table and histogram heatmap tiles in the rows the dashboard draws

  • 917c9ca: feat: MCP dashboard tools read and write PromQL tiles and PROMETHEUS_LABEL filters when PromQL is enabled, and hide but keep them when it is disabled

  • d08b2fa: feat(mcp): clickstack_sql accepts a queries array to run up to 10
    independent queries in parallel under a shared 60s deadline. Each query reports
    its own ok/error/timeout status, so one failing query does not fail the
    others. Single-query calls with sql behave as before.

  • a13c80e: feat(mcp): clickstack_table takes optional limit and having, and orders grouped results by the first select item, descending, when no orderBy is given

  • 0262822: fix: MCP tool responses that are over the size budget now shorten long strings with a …(+N chars) suffix instead of replacing them, say what was trimmed in trimNotes, and clickstack_event_patterns / clickstack_emerging_signals drop samples and shorten long patterns before cutting whole patterns, so the requested topN survives when it can

  • 442d6df: fix: refresh cached table columns after 5 minutes

    The shared metadata cache kept each table's DESCRIBE result for the life of
    the process, so the API did not see columns added with ALTER TABLE, such as
    new MATERIALIZED columns, until it restarted. Cached columns now expire after 5
    minutes. Other cached metadata is unchanged.

  • eb2439e: fix: leave metric points with no recorded value out of charts and alerts

    When a scraped series goes away or a scrape fails, the collector's prometheus
    receiver sends a point flagged "no recorded value" (a Prometheus staleness
    marker), and the ClickHouse exporter stores it as zeros. Metric charts and
    alerts read it as a real value: a gauge's min and avg dropped and count
    included the series that went away, and a counter or histogram that came back
    after the marker counted its whole total again. Metric queries now skip points
    with this flag.

  • 0eec5e1: fix: Authenticate to Prometheus connections whose host includes credentials

    A Prometheus connection host such as http://user:pass@prometheus:9090 made every PromQL query fail with "Failed to reach Prometheus", because fetch rejects URLs that carry credentials. The credentials are now sent as a Basic auth header.

  • 0a5237e: fix: reject alerts on dashboard tiles the alert checker never evaluates (PromQL
    tiles, and builder tiles with unsupported display types), and drop them when a
    dashboard is saved

  • b7b4d95: fix: update systeminformation to 5.33.19

    The root resolutions pin let the lockfile keep systeminformation 5.30.7, which
    has known command injection advisories, including two high-severity ones in
    networkInterfaces() on Linux (GHSA-5xpp-75jx-m839, GHSA-hvx9-hwr7-wjj9). The
    API installs it through @opentelemetry/instrumentation-host-metrics, which
    asks for ^5.31.6, but the old pin held it at 5.30.7. The pin now starts at
    5.33.19, the newest 5.x release, which fixes all of them.

  • b1d4e60: fix: PromQL label lookups (dashboard variables, label autocomplete) now work on TimeSeries tables of schema version 8, the default from ClickHouse 26.10. These keep each series' time range in a separate time ranges table instead of the tags table's min_time/max_time, so match[] failed with "requires store_min_time_and_max_time = 1" and time-bounded lookups read the whole tags table.

  • ef56bd7: fix: usage stats job no longer fails ClickHouse auth on password-protected
    connections

  • 90302c7: fix: Block generic and incident.io webhooks whose hostname resolves to a private or reserved address. The check runs on the address actually dialed, so it also covers DNS rebinding. Self-hosted setups that send webhooks to internal hostnames must add them to WEBHOOK_HOSTNAME_ALLOWLIST.

  • Updated dependencies [142c9cc]

  • Updated dependencies [cd0e9ed]

  • Updated dependencies [9269f77]

  • Updated dependencies [e2754d2]

  • Updated dependencies [22f824c]

  • Updated dependencies [6425332]

  • Updated dependencies [d0dd06f]

  • Updated dependencies [5584f84]

  • Updated dependencies [41b2b74]

  • Updated dependencies [442d6df]

  • Updated dependencies [eb2439e]

  • Updated dependencies [0b7926d]

  • Updated dependencies [0a5237e]

  • Updated dependencies [78143c8]

  • Updated dependencies [b1d4e60]

    • @hyperdx/common-utils@0.34.0

@hyperdx/common-utils@0.34.0

Release notes
Minor Changes
  • 142c9cc: feat: narrow ad hoc dashboard filter suggestions with a condition

    An ad hoc filter on SQL sources can now carry a SQL or Lucene "Keys and values
    filter", like a queried filter's dropdown values filter, that limits the rows
    its keys and values are suggested from. It can reference the dashboard's other
    variables. While it references a required filter with nothing selected, the ad
    hoc filter can't add or edit conditions and names the filter it is waiting on.
    Failed suggestions now show the database's error message.

  • cd0e9ed: feat: add optional titleEmoji webhook option; false removes the emoji prefix from notification titles sent through that webhook

  • 0b7926d: feat: Team members can create team-owned API keys with a description and expiry that keep working after their creator leaves.

Patch Changes
  • 9269f77: fix: "Denoise results" now removes noise on typical data. A pattern now counts as noisy above 5% of sampled events instead of 10%, which often matched nothing. Patterns that include error or warning lines are never hidden. The MCP denoise option uses the same 5% threshold. Denoise also mines the source's body column instead of the last table column, removes ANSI-colored rows that match a noisy pattern, says when results can't be denoised, and shows hidden patterns as a short summary with a shortened, expandable list.

  • e2754d2: fix: use SHA256 instead of MD5 for JSON row lookup WHERE clauses so row
    details and drill-down work on FIPS-enabled ClickHouse deployments

  • 22f824c: fix: keep JSON path segments with special characters quoted in row detail lookups

  • 6425332: perf: PromQL label lookups with match[] read only the matched metrics' tags
    rows when every selector names its metric

  • d0dd06f: fix: count legacy STATUS_CODE_ERROR spans as errors on the service map and trace
    waterfall

  • 5584f84: fix: make clickstack_event_patterns drill-down snippets executable

    Each pattern's whereSnippet is now a SQL predicate (whereLanguage: "sql") that keeps the template's token order and variable positions and includes the caller's filter and the source table filter, so passing it to clickstack_search returns the pattern's events. Before, a template like Sending <*> rows produced Body:"Sending rows", which matched nothing, and map fields produced Lucene that failed to parse. bodyExpression now also accepts JSONExtractString(<column>, '<key>', ...) to mine a field inside JSON bodies, and the tool reports sample coverage and the actual trend bucket interval and boundaries.

    clickstack_event_patterns, clickstack_emerging_signals and dashboard event-pattern tiles now apply the log source's tableFilterExpression, so their counts can drop for sources that set one. minePatterns now reports each cluster's own template; before, it could report the template of a different same-length cluster that some members did not fit.

  • 41b2b74: feat: fall back to server MergeTree settings to detect persisted _block_number and _block_offset columns when the table's CREATE query omits them

  • 442d6df: fix: refresh cached table columns after 5 minutes

    The shared metadata cache kept each table's DESCRIBE result for the life of
    the process, so the API did not see columns added with ALTER TABLE, such as
    new MATERIALIZED columns, until it restarted. Cached columns now expire after 5
    minutes. Other cached metadata is unchanged.

  • eb2439e: fix: leave metric points with no recorded value out of charts and alerts

    When a scraped series goes away or a scrape fails, the collector's prometheus
    receiver sends a point flagged "no recorded value" (a Prometheus staleness
    marker), and the ClickHouse exporter stores it as zeros. Metric charts and
    alerts read it as a real value: a gauge's min and avg dropped and count
    included the series that went away, and a counter or histogram that came back
    after the marker counted its whole total again. Metric queries now skip points
    with this flag.

  • 0a5237e: fix: reject alerts on dashboard tiles the alert checker never evaluates (PromQL
    tiles, and builder tiles with unsupported display types), and drop them when a
    dashboard is saved

  • 78143c8: feat: on ClickHouse Cloud, read system.shared_merge_tree_settings when detecting _block_number and _block_offset columns, falling back to system.merge_tree_settings per key

  • b1d4e60: fix: PromQL label lookups (dashboard variables, label autocomplete) now work on TimeSeries tables of schema version 8, the default from ClickHouse 26.10. These keep each series' time range in a separate time ranges table instead of the tags table's min_time/max_time, so match[] failed with "requires store_min_time_and_max_time = 1" and time-bounded lookups read the whole tags table.

@hyperdx/otel-collector@2.44.0

Release notes
Patch Changes
  • 5b0d074: fix: let browsers cache the collector's CORS preflights for 10 minutes

    The OTLP receiver now answers preflights with Access-Control-Max-Age: 600.
    Without it, browsers cached a preflight for only 5 seconds, which is how often
    the browser SDK exports, so about half of its requests were preflights.

  • 8384fe6: perf: compress the seed schemas with ZSTD(3) instead of ZSTD(1)

    The seed schemas pinned ZSTD(1) on almost every column. Level 3 gives a better
    compression ratio at a small insert-time CPU cost, without affecting reads, and
    it is the default codec of ClickHouse since 26.9. It is pinned explicitly so
    that older ClickHouse versions, whose default is LZ4, get it too. Delta
    codecs drop their byte-size argument, which ClickHouse infers from the column
    type. Only newly created tables are affected; existing tables keep their codecs.

  • 7021810: feat: session ID columns, session.id from rum.sessionId, severity text

    The hyperdx_sessions seed adds materialized rum.sessionId and session.id
    columns with skip indexes, and the otel_logs seed adds a materialized
    session.id column with a skip index, so session queries no longer read the
    attribute maps. Only newly created tables get them; existing tables need an
    ALTER TABLE ... ADD COLUMN to benefit.

    Spans, logs and session replay events from older @hyperdx/browser SDKs, which
    carry the session id only in the rum.sessionId resource attribute, now also
    get the OpenTelemetry session.id attribute. An existing session.id is never
    overwritten and rum.sessionId is kept. If you override pipeline processors:
    lists in CUSTOM_OTELCOL_CONFIG_FILE, add transform/session_id to keep this.

    Logs that carry a severity number but no severity text, such as those from the
    new browser SDK, now get the matching level text (info, error, ...) instead
    of an empty level. Severity text set by the producer is never overwritten.

@hyperdx/cli@0.9.0

Release notes
Minor Changes
  • 7935c64: feat: add hdx mcp install to connect AI agents without pasting a key

    npx @hyperdx/cli mcp install asks for a personal access key or an
    organization API key with hidden input, checks it, and adds the ClickStack MCP
    server to Claude Code, Codex, Cursor, and VS Code. Team Settings now leads with
    this command, so the key no longer has to go into a copied command or an agent
    chat. The per-agent snippets remain for setting up one agent by hand.

Patch Changes
  • d7df729: chore: GitHub links (changelog, support, package metadata) now point at ClickHouse/ClickStack, and docker-compose.yml pulls the app image as clickhouse/clickstack
  • e2754d2: fix: use SHA256 instead of MD5 for JSON row lookup WHERE clauses so row
    details and drill-down work on FIPS-enabled ClickHouse deployments

cli-v0.9.0

Release notes
@hyperdx/cli v0.9.0
Minor Changes
  • 7935c64: feat: add hdx mcp install to connect AI agents without pasting a key

    npx @hyperdx/cli mcp install asks for a personal access key or an
    organization API key with hidden input, checks it, and adds the ClickStack MCP
    server to Claude Code, Codex, Cursor, and VS Code. Team Settings now leads with
    this command, so the key no longer has to go into a copied command or an agent
    chat. The per-agent snippets remain for setting up one agent by hand.

Patch Changes
  • d7df729: chore: GitHub links (changelog, support, package metadata) now point at ClickHouse/ClickStack, and docker-compose.yml pulls the app image as clickhouse/clickstack
  • e2754d2: fix: use SHA256 instead of MD5 for JSON row lookup WHERE clauses so row
    details and drill-down work on FIPS-enabled ClickHouse deployments

Installation

npm (recommended):

npm install -g @hyperdx/cli

Or run directly with npx:

npx @hyperdx/cli tui -s <your-hyperdx-api-url>

Manual download (standalone binary, no Node.js required):

# macOS Apple Silicon
curl -L https://github.com/ClickHouse/ClickStack/releases/download/cli-v0.9.0/hdx-darwin-arm64 -o hdx
# macOS Intel
curl -L https://github.com/ClickHouse/ClickStack/releases/download/cli-v0.9.0/hdx-darwin-x64 -o hdx
# Linux x64
curl -L https://github.com/ClickHouse/ClickStack/releases/download/cli-v0.9.0/hdx-linux-x64 -o hdx

chmod +x hdx && sudo mv hdx /usr/local/bin/
Usage
hdx auth login -s <your-hyperdx-api-url>
hdx tui

Convert the Jest APIs in upstream's new and changed tests, mock the
ClickStack browser SDK through the Vitest config, and update assertions
that depend on the fork's newer libraries.
- Use Mongoose 9 QueryFilter, Zod 4 record and optional-unknown schemas,
  the fork validation middleware, @clickhouse/client types and the runtime
  env helper in upstream code added since 2.43.1.
- Pin @opentelemetry/api 1.9.1 in the app and API: the ClickStack SDKs
  accept only <1.10, and a newer API copy cannot read the SDK globals.
- Lock the new upstream dependencies and format the merged sources.
Bun resolves the bare undici specifier to a built-in fetch that ignores
the dispatcher, so the private-address DNS check that upstream added for
webhook delivery never ran. Import the undici package entry instead and
route it to the test fetch mock.
Replace the fork's HyperDX SDK tracing preload with upstream's
ClickStack telemetry preload and carry its Bun and WorkOS behavior over:
give Bun's HTTPS server its own emit so HTTP server spans survive, and
scrub OAuth credentials from HTTP span URLs. The Bun fixture now also
checks that a callback code never reaches span attributes.
Upstream replaced @hyperdx/browser with @clickhouse/clickstack-browser,
whose ESM entry imports the installed @rrweb/record, so drop the fork's
@hyperdx/browser patch. Point the memory proof at the new SDK: its
OTLP/JSON exports, resumeReplay checkouts and @rrweb/record module. It no
longer asserts body capture, which the new SDK does not offer.

Document the Bun specifics of the telemetry preload and webhook fetch.
Upstream 2.44.0 never removes the last person in a team, so it can always
sign in to revoke org API keys. The WorkOS removal tests emptied the team
and got last_member back, leaving the member in place. Keep a second
member so the removals run, and assert the deleted result.
@mfroembgen

Copy link
Copy Markdown
Owner Author

Superseded by #6. main was force-pushed to the rebased branch fork-sync/app-2.44.0-rebase (4f1ffe94f28b): upstream @hyperdx/app@2.44.0 with the fork patch commits on top. The previous main head was b6bdb1aaa138. Closing this merge-based sync without merging.

@mfroembgen mfroembgen closed this Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant