Skip to content

Commit cea0011

Browse files
authored
Merge branch 'develop' into claude/gifted-johnson-6ymldh
2 parents 23ed271 + beca211 commit cea0011

219 files changed

Lines changed: 5642 additions & 1470 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/build.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,10 +1040,7 @@ jobs:
10401040
use-installer: true
10411041
token: ${{ secrets.GITHUB_TOKEN }}
10421042
- name: Set up Deno
1043-
if:
1044-
matrix.test-application == 'deno' || matrix.test-application == 'deno-static' || matrix.test-application ==
1045-
'deno-redis' || matrix.test-application == 'hono-4' || matrix.test-application == 'deno-mysql' ||
1046-
matrix.test-application == 'deno-pg'
1043+
if: matrix.test-application == 'deno' || matrix.test-application == 'hono-4'
10471044
uses: denoland/setup-deno@v2.0.5
10481045
with:
10491046
deno-version: ${{ matrix.deno-version || 'v2.8.3' }}
@@ -1150,6 +1147,9 @@ jobs:
11501147
E2E_TEST_SENTRY_ORG_SLUG: 'sentry-javascript-sdks'
11511148
E2E_TEST_SENTRY_PROJECT: 'sentry-javascript-e2e-tests'
11521149
E2E_OPENROUTER_API_KEY: ${{ secrets.E2E_OPENROUTER_API_KEY }}
1150+
# Used by test apps that deploy a real Cloudflare Worker, e.g. cloudflare-workers-send-to-sentry
1151+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
1152+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
11531153
strategy:
11541154
fail-fast: false
11551155
matrix: ${{ fromJson(needs.job_build.outputs.e2e-matrix-optional) }}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: 'Automation: Cleanup E2E workers'
2+
on:
3+
pull_request:
4+
types:
5+
- closed
6+
7+
jobs:
8+
cleanup:
9+
# The optional E2E job deploys only for PRs from this repository, so forks never have a worker to delete.
10+
if: github.event.pull_request.head.repo.full_name == github.repository
11+
runs-on: ubuntu-latest
12+
permissions: {}
13+
timeout-minutes: 5
14+
env:
15+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
16+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
17+
strategy:
18+
matrix:
19+
# Name prefix of every E2E app that deploys a real worker, see the app's global-setup.mjs
20+
worker-prefix:
21+
- e2e-send-to-sentry
22+
steps:
23+
- name: Set up Node
24+
uses: actions/setup-node@v7
25+
with:
26+
node-version: 24
27+
28+
- name: Delete worker
29+
run: |
30+
WORKER="${{ matrix.worker-prefix }}-pr-${{ github.event.pull_request.number }}"
31+
32+
if ! output=$(npx --yes wrangler@4 delete --name "$WORKER" --force 2>&1); then
33+
echo "$output"
34+
# 10007 means the worker does not exist, i.e. the PR never ran the optional E2E job.
35+
echo "$output" | grep -q 'code: 10007' || exit 1
36+
fi

‎CHANGELOG.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7-
Work in this release was contributed by @psh4607, @thijsw, @trinitiwowka, @nehaprasad-dev, @JealousGx, @Jxxunnn, @eddie333016, @davidmurdoch, @yashschandra, @atharv-sys32, @AG0708, @birkskyum, @mkly, @mcbbugu, @suhailopensource, @zkasuran, @mohd-akram, @RealBhupesh, @halillusion, @psang39, @hafzism, @JosephDoUrden, @Tyagiquamar, @Andarist, and @msnelling. Thank you for your contributions!
7+
Work in this release was contributed by @psh4607, @thijsw, @trinitiwowka, @nehaprasad-dev, @JealousGx, @Jxxunnn, @eddie333016, @davidmurdoch, @yashschandra, @atharv-sys32, @AG0708, @birkskyum, @mkly, @mcbbugu, @suhailopensource, @zkasuran, @mohd-akram, @RealBhupesh, @halillusion, @psang39, @hafzism, @JosephDoUrden, @Tyagiquamar, @Andarist, @msnelling, and @oesnuj. Thank you for your contributions!
88

9+
- feat(browser)!: `browser.navigation.type` on web vital and bfcache navigation spans now carries the navigation type exactly as web-vitals reports it. `bfcache` is now `back-forward-cache`, and a back/forward navigation that missed the bfcache (`back-forward`) or a discarded-tab restore (`restore`) is no longer folded into `navigate`. Update any dashboards or alerts filtering on `bfcache`.
910
- feat(core): Add `createFetchIntegration`, the shared implementation behind the global-`fetch` integrations in `@sentry/bun`, `@sentry/cloudflare`, `@sentry/deno` and `@sentry/vercel-edge`. Those four packages carried four copies of it; they now share one. Two changes come out of that:
1011
- All four gain a `tracePropagation` option (default `true`). Turn it off to stop injecting `sentry-trace` and `baggage` without also turning off spans. To scope propagation to specific URLs, keep using `tracePropagationTargets` in the client options.
1112
- Integration options now follow the client. Previously a second `Sentry.init()` in the same process silently reused the options of the first one.

‎MIGRATION.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,8 @@ Affected SDKs: `@sentry/remix`.
14291429
14301430
The plugin now also applies the build-time instrumentation transform. If you added `sentryOrchestrionPlugin()` from `@sentry/server-utils/orchestrion/vite` to your Vite config manually, remove it. Opt out with `sentryRemixVitePlugin({ buildTimeInstrumentation: false })`.
14311431
1432+
It also injects debug IDs and uploads source maps once you pass `org`, `project` and `authToken` — opt out with `sentryRemixVitePlugin({ sourcemaps: { disable: true } })`.
1433+
14321434
### React: Simpler React Router setup via `@sentry/react/react-router`
14331435
14341436
Affected SDKs: `@sentry/react`.

‎dev-packages/browser-integration-tests/utils/helpers.ts‎

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -549,18 +549,61 @@ export async function getFirstSentryEnvelopeRequest<T>(
549549
}
550550

551551
export async function hidePage(page: Page): Promise<void> {
552-
// web-vitals defers processing an interaction's event entries into
553-
// `requestIdleCallback(..., { timeout: 1000 })`, and Chromium only reaches idle here once that
554-
// timeout elapses. Hiding the page first forces a report while the metric is still unset, so no
555-
// vital is emitted at all. Idle callbacks run in scheduling order, so waiting for one queued now
556-
// means web-vitals' earlier callback has already run.
552+
// web-vitals processes an interaction's event entries in `requestIdleCallback(..., { timeout:
553+
// 1000 })`, and Chromium only reaches idle here once that timeout elapses. Hiding before that
554+
// callback runs loses the interaction: the forced report web-vitals does on `visibilitychange`
555+
// runs ahead of it, while the callback itself reports unforced, so INP is never emitted at all.
556+
//
557+
// Idle callbacks run in scheduling order, but web-vitals only schedules its callback once the
558+
// Event Timing entry reaches its observer, which is after the click. Queuing one right away
559+
// therefore queues it first and hides the page too early. Waiting for the entry and queuing from
560+
// a task after it keeps web-vitals ahead: its observer is registered first, so it is notified
561+
// first, and the `setTimeout` lands after the microtask it defers that work into.
557562
await page.evaluate(() => {
558563
return new Promise<void>(resolve => {
559-
if (typeof requestIdleCallback !== 'function') {
560-
resolve();
564+
const scheduleIdle = (): void => {
565+
if (typeof requestIdleCallback !== 'function') {
566+
resolve();
567+
return;
568+
}
569+
requestIdleCallback(() => resolve(), { timeout: 1000 });
570+
};
571+
572+
// Callers that never interacted have no Event Timing entry coming, so there is nothing to
573+
// order against and nothing to wait for.
574+
const interactionCount = (performance as Performance & { interactionCount?: number }).interactionCount ?? 0;
575+
if (!interactionCount && !performance.getEntriesByType('first-input').length) {
576+
scheduleIdle();
561577
return;
562578
}
563-
requestIdleCallback(() => resolve(), { timeout: 1000 });
579+
580+
let observer: PerformanceObserver | undefined;
581+
let fallback: ReturnType<typeof setTimeout>;
582+
583+
// An interaction the Event Timing buffer no longer reports would otherwise wait here forever,
584+
// so cap the wait rather than require an entry.
585+
const done = (): void => {
586+
clearTimeout(fallback);
587+
observer?.disconnect();
588+
setTimeout(scheduleIdle, 0);
589+
};
590+
591+
fallback = setTimeout(done, 1000);
592+
593+
try {
594+
// `durationThreshold` is missing from the DOM types, as it is in the SDK's own observer.
595+
const eventOptions: PerformanceObserverInit & { durationThreshold?: number } = {
596+
type: 'event',
597+
buffered: true,
598+
durationThreshold: 0,
599+
};
600+
601+
observer = new PerformanceObserver(done);
602+
observer.observe(eventOptions);
603+
observer.observe({ type: 'first-input', buffered: true });
604+
} catch {
605+
done();
606+
}
564607
});
565608
});
566609

@@ -572,7 +615,6 @@ export async function hidePage(page: Page): Promise<void> {
572615
},
573616
});
574617

575-
// Dispatch the visibilitychange event to notify listeners
576618
document.dispatchEvent(new Event('visibilitychange'));
577619
});
578620
}

‎dev-packages/bundler-plugin-integration-tests/fixtures/esbuild/telemetry.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ test(import.meta.url, ({ runBundler, readOutputFiles, runFileInNode }) => {
66
expect(readOutputFiles()).toMatchInlineSnapshot(`
77
{
88
"sentry-telemetry.json": "[{"sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"}},[[{"type":"session"},{"sid":"UUID","init":true,"started":"TIMESTAMP","timestamp":"TIMESTAMP","status":"ok","errors":0,"duration":DURATION,"attrs":{"release":"PLUGIN_VERSION","environment":"production"}}]]],
9-
[{"event_id":"UUID","sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"},"trace":{"environment":"production","release":"PLUGIN_VERSION","public_key":"UUID","trace_id":"UUID","org_id":"1","transaction":"Sentry Bundler Plugin execution","sampled":"true","sample_rand":"SAMPLE_RAND","sample_rate":"1"}},[[{"type":"transaction"},{"contexts":{"trace":{"span_id":"SHORT_UUID","trace_id":"UUID","data":{"sentry.origin":"manual","sentry.segment.name.source":"custom","sentry.sample_rate":1},"status":"ok","origin":"manual"},"runtime":{"name":"node","version":"NODE_VERSION"}},"spans":[],"start_timestamp":START_TIMESTAMP,"timestamp":TIMESTAMP,"transaction":"Sentry Bundler Plugin execution","type":"transaction","transaction_info":{"source":"custom"},"platform":"PLATFORM","event_id":"UUID","environment":"production","release":"PLUGIN_VERSION","tags":{"upload-legacy-sourcemaps":false,"module-metadata":false,"inject-build-information":false,"set-commits":"auto","finalize-release":true,"deploy-options":false,"custom-error-handler":false,"sourcemaps-assets":false,"delete-after-upload":false,"sourcemaps-disabled":false,"react-annotate":false,"node":"NODE_VERSION","platform":"PLATFORM","meta-framework":"none","application-key-set":false,"ci":true,"project":"undefined","bundler":"esbuild","bundler-major-version":"28"},"user":{},"sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION","integrations":[],"packages":[{"name":"npm:@sentry/node","version":"SDK_VERSION"}]}}]]],
9+
[{"event_id":"UUID","sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"},"trace":{"environment":"production","release":"PLUGIN_VERSION","public_key":"UUID","trace_id":"UUID","org_id":"1","transaction":"Sentry Bundler Plugin execution","sampled":"true","sample_rand":"SAMPLE_RAND","sample_rate":"0.3"}},[[{"type":"transaction"},{"contexts":{"trace":{"span_id":"SHORT_UUID","trace_id":"UUID","data":{"sentry.origin":"manual","sentry.segment.name.source":"custom","sentry.sample_rate":0.3},"status":"ok","origin":"manual"},"runtime":{"name":"node","version":"NODE_VERSION"}},"spans":[],"start_timestamp":START_TIMESTAMP,"timestamp":TIMESTAMP,"transaction":"Sentry Bundler Plugin execution","type":"transaction","transaction_info":{"source":"custom"},"platform":"PLATFORM","event_id":"UUID","environment":"production","release":"PLUGIN_VERSION","tags":{"upload-legacy-sourcemaps":false,"module-metadata":false,"inject-build-information":false,"set-commits":"auto","finalize-release":true,"deploy-options":false,"custom-error-handler":false,"sourcemaps-assets":false,"delete-after-upload":false,"sourcemaps-disabled":false,"react-annotate":false,"node":"NODE_VERSION","platform":"PLATFORM","meta-framework":"none","application-key-set":false,"ci":true,"project":"undefined","bundler":"esbuild","bundler-major-version":"28"},"user":{},"sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION","integrations":[],"packages":[{"name":"npm:@sentry/node","version":"SDK_VERSION"}]}}]]],
1010
[{"sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"}},[[{"type":"session"},{"sid":"UUID","init":false,"started":"TIMESTAMP","timestamp":"TIMESTAMP","status":"exited","errors":0,"duration":DURATION,"attrs":{"release":"PLUGIN_VERSION","environment":"production"}}]]],
1111
",
1212
"telemetry.js": "(() => {

‎dev-packages/bundler-plugin-integration-tests/fixtures/rolldown/telemetry.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ test(import.meta.url, ({ runBundler, readOutputFiles, runFileInNode }) => {
1818
//#endregion
1919
",
2020
"sentry-telemetry.json": "[{"sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"}},[[{"type":"session"},{"sid":"UUID","init":true,"started":"TIMESTAMP","timestamp":"TIMESTAMP","status":"ok","errors":0,"duration":DURATION,"attrs":{"release":"PLUGIN_VERSION","environment":"production"}}]]],
21-
[{"event_id":"UUID","sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"},"trace":{"environment":"production","release":"PLUGIN_VERSION","public_key":"UUID","trace_id":"UUID","org_id":"1","transaction":"Sentry Bundler Plugin execution","sampled":"true","sample_rand":"SAMPLE_RAND","sample_rate":"1"}},[[{"type":"transaction"},{"contexts":{"trace":{"span_id":"SHORT_UUID","trace_id":"UUID","data":{"sentry.origin":"manual","sentry.segment.name.source":"custom","sentry.sample_rate":1},"status":"ok","origin":"manual"},"runtime":{"name":"node","version":"NODE_VERSION"}},"spans":[],"start_timestamp":START_TIMESTAMP,"timestamp":TIMESTAMP,"transaction":"Sentry Bundler Plugin execution","type":"transaction","transaction_info":{"source":"custom"},"platform":"PLATFORM","event_id":"UUID","environment":"production","release":"PLUGIN_VERSION","tags":{"upload-legacy-sourcemaps":false,"module-metadata":false,"inject-build-information":false,"set-commits":"auto","finalize-release":true,"deploy-options":false,"custom-error-handler":false,"sourcemaps-assets":false,"delete-after-upload":false,"sourcemaps-disabled":false,"react-annotate":false,"node":"NODE_VERSION","platform":"PLATFORM","meta-framework":"none","application-key-set":false,"ci":true,"project":"undefined","bundler":"rollup","bundler-major-version":"4"},"user":{},"sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION","integrations":[],"packages":[{"name":"npm:@sentry/node","version":"SDK_VERSION"}]}}]]],
21+
[{"event_id":"UUID","sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"},"trace":{"environment":"production","release":"PLUGIN_VERSION","public_key":"UUID","trace_id":"UUID","org_id":"1","transaction":"Sentry Bundler Plugin execution","sampled":"true","sample_rand":"SAMPLE_RAND","sample_rate":"0.3"}},[[{"type":"transaction"},{"contexts":{"trace":{"span_id":"SHORT_UUID","trace_id":"UUID","data":{"sentry.origin":"manual","sentry.segment.name.source":"custom","sentry.sample_rate":0.3},"status":"ok","origin":"manual"},"runtime":{"name":"node","version":"NODE_VERSION"}},"spans":[],"start_timestamp":START_TIMESTAMP,"timestamp":TIMESTAMP,"transaction":"Sentry Bundler Plugin execution","type":"transaction","transaction_info":{"source":"custom"},"platform":"PLATFORM","event_id":"UUID","environment":"production","release":"PLUGIN_VERSION","tags":{"upload-legacy-sourcemaps":false,"module-metadata":false,"inject-build-information":false,"set-commits":"auto","finalize-release":true,"deploy-options":false,"custom-error-handler":false,"sourcemaps-assets":false,"delete-after-upload":false,"sourcemaps-disabled":false,"react-annotate":false,"node":"NODE_VERSION","platform":"PLATFORM","meta-framework":"none","application-key-set":false,"ci":true,"project":"undefined","bundler":"rollup","bundler-major-version":"4"},"user":{},"sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION","integrations":[],"packages":[{"name":"npm:@sentry/node","version":"SDK_VERSION"}]}}]]],
2222
[{"sent_at":"TIMESTAMP","sdk":{"name":"sentry.javascript.node","version":"SDK_VERSION"}},[[{"type":"session"},{"sid":"UUID","init":false,"started":"TIMESTAMP","timestamp":"TIMESTAMP","status":"exited","errors":0,"duration":DURATION,"attrs":{"release":"PLUGIN_VERSION","environment":"production"}}]]],
2323
",
2424
}

0 commit comments

Comments
 (0)