Skip to content

Deploy May 26, 2026#6061

Merged
canova merged 62 commits into
productionfrom
main
May 26, 2026
Merged

Deploy May 26, 2026#6061
canova merged 62 commits into
productionfrom
main

Conversation

@canova
Copy link
Copy Markdown
Member

@canova canova commented May 26, 2026

Changes:

[fatadel] Remove unused dependencies from package.json (#6010)
[Nazım Can Altınova] Make profiler-cli work in sandboxed environments (#6003)
[Markus Stange] Make profiler-edit run profile compacting before writing out the file (#6015)
[Markus Stange] Migrate from prettier to oxfmt (#5986)
[Markus Stange] Add a --symbolicate-wasm arg to profiler-edit. (#6008)
[Markus Stange] Build and upload the cli artifact in PRs (#6020)
[Markus Stange] Use @streamparser/json if the input is too large to fit in a V8 string (#6016)
[Nazım Can Altınova] Print also the status output right after cli load command (#6019)
[Nicolas Chevobbe] Update devtools-reps to 0.27.7 (#6030)
[Nazım Can Altınova] Include --search option in pq filter push (#6026)
[Nazım Can Altınova] Update all Yarn dependencies (2026-05-20) (#6033)
[fatadel] Translate URL track-index state through profile sanitization (#6000)
[Markus Stange] Make withSize use a wrapper element so that it can stop calling findDOMNode (#5988)
[Markus Stange] Fix dhat importer (#6036)
[Nazım Can Altınova] Annotate inlined frames in CLI call trees and stacks (#6041)
[Nazım Can Altınova] Use proper types in cli tests instead of custom inline types (#6038)
[Nazım Can Altınova] Fix text truncation for frames named after Object.prototype methods (#6044)
[Nazım Can Altınova] Add missing key props to CodeErrorOverlay error list items (#6047)
[depfu[bot]] ⬆️ Update oxfmt to version 0.51.0 (#6054)
[Nazım Can Altınova] 🔃 Sync: l10n -> main (May 26, 2026) (#6058)
[Nazım Can Altınova] Use URL-state symbol server for profiler-cli function annotate (#6051)
[Nazım Can Altınova] Bump profiler-cli version to 0.2.0 (#6059)

And special thanks to our localizers:

fr: YD
sr: Марко Костић (Marko Kostić)
tr: Ali Demirtaş
zh-CN: Olvcpr423
zh-CN: wxie

Firefox Profiler [bot] and others added 30 commits May 8, 2026 08:41
Drops dependencies and devDependencies with no remaining importers, plus
the now-orphaned @types/react-splitter-layout resolution.

- url, weaktuplemap (no imports anywhere in src/scripts/profiler-cli)
- @babel/cli (build pipeline is esbuild, not babel CLI)
- @babel/plugin-proposal-class-properties (superseded by
  @babel/plugin-transform-class-properties referenced in babel.config.json)
- @types/react-splitter-layout (the runtime package is no longer a
  dependency and SplitterLayout is not used in src/)
- mkdirp (no references in scripts or configs)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.0.6 to 3.1.2.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](fastify/fast-uri@v3.0.6...v3.1.2)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…6014)

Bumps [@babel/plugin-transform-modules-systemjs](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-modules-systemjs) from 7.29.0 to 7.29.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.4/packages/babel-plugin-transform-modules-systemjs)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-modules-systemjs"
  dependency-version: 7.29.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Daemon process is the one that does all the network requests, and it
looks like all the sandboxed environments use an environment proxy for
allowed/disallowed domains using `HTTP_PROXY/HTTPS_PROXY`.

I was a bit suspicious at first thinking that maybe this is not great
security-wise, but then learned that this is the deafult behavior pretty
much everywhere except for node, and node is considering about turning
it on by default. For example, this is the default in curl, python, go,
and in popular rust packages like reqwest. The rationale is that, if
they have access to your machine, setting this env vars is the least of
your concern.

For example, see the curl documentation:
https://curl.se/docs/tutorial.html#:~:text=SPNEGO%29%2E-,Environment%20Variables
Previously, isProcessRunning used `kill(pid, 0)`, to check daemon is
still alive, which returns EPERM in sandboxed environments regardless of
whether the process actually exists. This commit replaces this check
with a socket connection attempt. A connection failure (either ENOENT or
ECONNREFUSED) successfully indicates a dead daemon on all platforms
without requiring any signal permission.


Also it replaces waitForProcessExit with waitForSocketClose, which polls
the same connect probe. Updates validateSession to be async and use the
new check, collapsing the separate PID and socket-file-existence checks
into a single socket connect attempt.
There were two things that prevented us from having a working cli in the
sandboxed environments:
1. HTTP(S) proxy needs to be used
- All network request must go through some proxy, so the sandboxed
environment can choose to allow or block the requests per domain. If it
doesn't use this proxy, the requests are usually blocked automatically
without a way to allow. It seemed a bit sketchy to me at first but then
I realized that this is the default behavior on many places like curl,
python, go, and node is considering enabling this by default.
2. Signaling a process is not allowed
- `process.kill(pid, 0);` isn't allowed in sandboxed environments, so
this can't be used to check if the process is still alive. Instead, I
converted that `isProcessRunning` to `isDaemonReachable` and used the
existing sockets to check if the daemon is still listening that socket
(for example with ECONNREFUSED).

Also please see the individual commit messages.

I tested both on macOS and Linux, and they seem to work (with some
additional config depending on what you use for sandboxing)
…#6015)

`profiler-edit` was just writing out the profile with `JSON.stringify`,
which is different from what the front-end does when you download the
profile - the front-end goes through profile sanitization, which also
runs compacting.

You can see in the snapshot tests that running compacting removes some
unused strings from the stringArray.
Numbers from my machine:
`yarn prettier-fix` before: 6.5 seconds
`yarn fmt` after: 1.3 seconds

`yarn lint-fix` is still slow (9 seconds), I think that's bottlenecked on eslint.
Numbers from my machine:
`yarn prettier-fix` before: 6.5 seconds
`yarn fmt` after: 1.3 seconds

`yarn lint-fix` is still slow (9 seconds), I think that's bottlenecked
on eslint.
This allows applying wasm symbols to existing profiles that were captured
with a stripped wasm bundle.

The script looks for functions with names of the shape `wasm-function[123]`,
which is what Firefox uses when the wasm file doesn't have a names section.

Usage:

```
yarn build-node-tools && \
node node-tools-dist/profiler-edit.js -i input.json.gz \
--symbolicate-wasm http://host/a.wasm=./a-unstripped.wasm \
--symbolicate-wasm http://host/b.wasm=./b-unstripped.wasm \
-o out.json.gz
```
This allows applying wasm symbols to existing profiles that were
captured with a stripped wasm bundle.

The script looks for functions with names of the shape
`wasm-function[123]`, which is what Firefox uses when the wasm file
doesn't have a names section.

Usage:

```
yarn build-node-tools && \
node node-tools-dist/profiler-edit.js -i input.json.gz \
--symbolicate-wasm http://host/a.wasm=./a-unstripped.wasm \
--symbolicate-wasm http://host/b.wasm=./b-unstripped.wasm \
-o out.json.gz
```

---

I've successfully used it to turn https://share.firefox.dev/4f9O7oh into
https://share.firefox.dev/4nd6GKk .
This PR does similarly to what we did for the node tools artifact. It
would be nice to have profiler-cli uploaded as an artifact for PRs etc
so people can try it out easily for manual testing.
#6016)

Here's a file which decompresses to a 605.8MB JSON string:
[etw-speedometer3.json.gz](https://firefox-ci-tc.services.mozilla.com/api/queue/v1/task/FplSekLmRsm6lmh_2fKu7A/runs/0/artifacts/public/test_info/etw-speedometer3.json.gz)

Loading this file in Chrome, or in node via profiler-edit, fails due to
the string size.

As a workaround we can use a streaming JSON parser which doesn't
materialize a string for the entire thing.
Previously, we didn't show any info about the profile that's being
loaded to after `pq load xyz`. This status output at least shows some
basic information like, selected thread, time range and filters.
Co-authored-by: Марко Костић (Marko Kostić) <marko.m.kostic@gmail.com> (sr)
Co-authored-by: YD <ygda+fx@free.fr> (fr)
Firefox Profiler [bot] and others added 27 commits May 20, 2026 09:19
Bumps [protobufjs](https://github.com/protobufjs/protobuf.js) from 8.0.3 to 8.2.0.
- [Release notes](https://github.com/protobufjs/protobuf.js/releases)
- [Changelog](https://github.com/protobufjs/protobuf.js/blob/master/CHANGELOG.md)
- [Commits](protobufjs/protobuf.js@protobufjs-v8.0.3...protobufjs-v8.2.0)

---
updated-dependencies:
- dependency-name: protobufjs
  dependency-version: 8.2.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
workbox-window 7.4.1 ships a UMD build without `__esModule: true` (a
side effect of the package's Rollup 2 -> 4 migration, since Rollup's
`output.esModule` default changed from `true` to `"if-default-prop"` and
workbox-window has no default export). Without the marker, Babel's
`_interopRequireWildcard` copies the module's exports for `import * as
WorkboxModule from 'workbox-window'`, so `jest.spyOn(WorkboxModule,
'Workbox')` mutated a copy while the source file's `import { Workbox }`
kept resolving to the real constructor.

Replace the namespace-spy with `jest.mock('workbox-window', ...)` so
both sides share the same mocked `Workbox`, and switch the per-test
implementation to `(Workbox as jest.Mock).mockImplementation(...)`.
Previously, hidden non-thread tracks (screenshots, network, IPC, marker)
reappeared after publishing a sanitized profile when sanitization also
removed a thread: the URL state's hidden-track sets and track-order were
reset whenever threads were re-indexed, even though the non-thread tracks
still existed in the sanitized profile. When a tab filter was active, the
bug also affected tracks in surviving processes because the
`tabToThreadIndexesMap` used to filter the new global track list still
referenced pre-sanitization thread indexes.

`attemptToPublish` now builds an old-to-new `TrackIndex` map by matching
tracks on stable identity (pid, screenshot id, threadIndex, counterIndex,
visual-progress singleton, or marker schema name plus marker name string)
and translates `hiddenGlobalTracks`, `globalTrackOrder`,
`hiddenLocalTracksByPid`, and `localTrackOrderByPid` through it on
`SANITIZED_PROFILE_PUBLISHED`. Old-side thread, counter, and string-table
indexes are normalized through the maps in `ProfileIndexTranslationMaps`
before comparison. The `tabToThreadIndexesMap` is rebuilt from the
sanitized profile's threads and pages so its `ThreadIndex` values are
valid in the new track-index space; the `innerWindowID → tabID`
computation is extracted into a shared `computeInnerWindowIDToTabMap`
helper that the existing `getInnerWindowIDToTabMap` selector also uses.

Fixes #2947
Fixes #6035.

I broke this in the move to the shared tables. We were mutating
the frameTable + funcTable + stackTable from an empty profile,
and then throwing out our mutated tables by replacing them with
the empty tables from the globalDataCollector.
…OMNode (#5988)

findDOMNode is deprecated in React 18 and removed in React 19 strict mode,
and withSize was the last in-tree caller.

withSize now renders a `<div style="display: contents">` around the wrapped
component and observes `wrapper.firstElementChild` via the existing
ResizeObserver wrapper, and is converted to a function component.

EmptyThreadIndicator and Timeline tests mocked findDOMNode to inject sizes;
those mocks silently became no-ops once findDOMNode was gone and are
replaced with autoMockElementSize.

---------

Co-authored-by: fatadel <afatkhutdinov@mozilla.com>
Co-authored-by: Ali Demirtaş <alidemirtas94@gmail.com> (tr)
[Production](https://profiler.firefox.com/from-url/https%3A%2F%2Fraw.githubusercontent.com%2Ffirefox-devtools%2Fprofiler%2Frefs%2Fheads%2Fmain%2Fsrc%2Ftest%2Ffixtures%2Fupgrades%2Fdhat.json.gz/)
| [Deploy
preview](https://deploy-preview-6036--perf-html.netlify.app/from-url/https%3A%2F%2Fraw.githubusercontent.com%2Ffirefox-devtools%2Fprofiler%2Frefs%2Fheads%2Fmain%2Fsrc%2Ftest%2Ffixtures%2Fupgrades%2Fdhat.json.gz/)

Fixes #6035.

I broke this in the move to the shared tables. We were mutating the
frameTable + funcTable + stackTable from an empty profile, and then
throwing out our mutated tables by replacing them with the empty tables
from the globalDataCollector.
Some frames in a profile are inlined into their caller's machine code by
the compiler. The profiler frontend marks these with a small "inl" badge
and a tooltip naming the outer function, but the CLI previously gave no
hint, so consumers could not tell that an inlined frame's body actually
executes inside another function and would treat it as an independent
call site.

Each call tree node and heaviest-stack frame now carries an
`inlineStatus` of `'inlined'` or `'divergent'`, derived from
`CallNodeInfo.sourceFramesInlinedIntoSymbolForNode` The CLI formatter
appends `(inl)` or `(inl?)` after the function name and, when at least
one frame in the output is inlined, prints a one-line legend above the
tree / heaviest stack explaining the markers.
Bumps [@tootallnate/once](https://github.com/TooTallNate/once) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/TooTallNate/once/releases)
- [Changelog](https://github.com/TooTallNate/once/blob/v2.0.1/CHANGELOG.md)
- [Commits](TooTallNate/once@2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: "@tootallnate/once"
  dependency-version: 2.0.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ali Demirtaş <alidemirtas94@gmail.com> (tr)
I think we wrote these tests when we didn't have proper types, and they
were never added here. This patch adds proper types also to make sure
that we will catch any type errors in the future.
…6044)

TextMeasurement's width cache was a plain object, so looking up
`_cache["toString"]` returned Object.prototype.toString instead of
undefined. getFittedText treated that function as a cached width,
which collapsed the truncation algorithm and produced just "…".

This affected JS frames whose names collide with Object.prototype:
toString, hasOwnProperty, valueOf, constructor, isPrototypeOf,
propertyIsEnumerable, toLocaleString, __proto__. Visible in the
flame graph, stack chart, marker chart, and js-tracer canvases.

Switching the cache to a Map solves this problem.
Seven of the ten error cases in the errors.map() were missing a key prop
on their Localized wrapper, and that was causing a React dev warning
about non-unique keys in a list.
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Bumps [qs](https://github.com/ljharb/qs) from 6.14.2 to 6.15.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](ljharb/qs@v6.14.2...v6.15.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.15.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updated locales: fr, sr, tr, zh-CN.
`function annotate --mode asm` always fell back to the hardcoded
`http://localhost:3000` when `--symbol-server` wasn't passed to the
annotate command, and ignored both `?symbolServer=` from a loaded
profiler.firefox.com URL and `--symbol-server` passed to `pq load`.

This commit changes the cli to resolve the symbol server inside
`ProfileQuerier.functionAnnotate` via `getSymbolServerUrl` when no
explicit URL is provided, so the value set by either source on the URL
state is taken into account. An explicit `--symbol-server` on `function
annotate` still overrides.
@canova canova requested a review from fatadel as a code owner May 26, 2026 15:45
@canova canova removed the request for review from fatadel May 26, 2026 15:45
@canova canova merged commit 92cd06c into production May 26, 2026
38 of 39 checks passed
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.

5 participants