Skip to content

Commit d5dc9e2

Browse files
committed
Merge remote-tracking branch 'origin/develop' into ab/channel-based-default
# Conflicts: # dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json # dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json # dev-packages/e2e-tests/test-applications/node-otel/tests/transactions.test.ts
2 parents e33fc84 + 671d333 commit d5dc9e2

452 files changed

Lines changed: 696 additions & 5140 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.

dev-packages/browser-integration-tests/suites/tracing/request/xhr-streamed/test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ sentryTest('creates spans for XHR requests', async ({ getLocalTestUrl, page }) =
1919

2020
const allSpans = await spansPromise;
2121
const pageloadSpan = allSpans.find(s => getSpanOp(s) === 'pageload');
22-
const requestSpans = allSpans.filter(s => getSpanOp(s) === 'http.client');
22+
const requestSpans = allSpans
23+
.filter(s => getSpanOp(s) === 'http.client')
24+
.sort((a, b) =>
25+
(a.attributes!['http.url']!.value as string).localeCompare(b.attributes!['http.url']!.value as string),
26+
);
2327

2428
expect(requestSpans).toHaveLength(3);
2529

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { streamText } from 'ai';
2+
3+
// The browser bundle also pulls in an orchestrion-instrumented module (`ai`).
4+
// Injected `node:diagnostics_channel` calls only exist server-side, so the
5+
// client bundle must stay free of them (they throw `X is not a function` in
6+
// the browser otherwise).
7+
document.title = `streamText: ${typeof streamText}`;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>orchestrion client build</title>
5+
</head>
6+
<body>
7+
<script type="module" src="/client/main.ts"></script>
8+
</body>
9+
</html>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { streamText } from 'ai';
2+
3+
// The worker imports an orchestrion-instrumented module (`ai`), so the server
4+
// bundle is expected to contain `diagnostics_channel` injections.
5+
export default {
6+
async fetch(request: Request): Promise<Response> {
7+
if (new URL(request.url).pathname === '/worker') {
8+
return new Response(`streamText: ${typeof streamText}`);
9+
}
10+
return new Response('not found', { status: 404 });
11+
},
12+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { readdirSync, readFileSync } from 'fs';
2+
import { join } from 'path';
3+
import { expect, it } from 'vitest';
4+
import { createRunner } from '../../../../runner';
5+
6+
function readBundles(dir: string): string {
7+
return readdirSync(dir, { withFileTypes: true, recursive: true })
8+
.filter(entry => entry.isFile() && /\.m?js$/.test(entry.name))
9+
.map(entry => readFileSync(join(entry.parentPath, entry.name), 'utf8'))
10+
.join('\n');
11+
}
12+
13+
// Regression test: orchestrion splices `node:diagnostics_channel` calls into
14+
// instrumented modules, which only exist server-side. When a worker ships
15+
// browser assets, Vite produces a `client` bundle next to the server (worker)
16+
// bundle — and the injected `tracingChannel` calls used to land in the client
17+
// bundle too, where they throw `X is not a function` in the browser.
18+
it('injects diagnostics_channel calls into the server bundle only, not the client bundle', async ({ signal }) => {
19+
const runner = createRunner(__dirname).start(signal);
20+
21+
// Waits for `vite build` + wrangler boot and proves the instrumented worker
22+
// still runs.
23+
const response = await runner.makeRequest<string>('get', '/worker');
24+
expect(response).toBe('streamText: function');
25+
26+
// The worker imports `ai`, so the server bundle must actually be
27+
// instrumented — otherwise a plugin that never runs would also pass.
28+
const workerBundle = readBundles(join(__dirname, 'dist', 'cloudflare_vite_dc_client_build'));
29+
expect(workerBundle).toContain('orchestrion:ai:streamText');
30+
31+
const clientBundle = readBundles(join(__dirname, 'dist', 'client'));
32+
expect(clientBundle).not.toContain('orchestrion:ai');
33+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { cloudflare } from '@cloudflare/vite-plugin';
2+
import { sentryCloudflareVitePlugin } from '@sentry/cloudflare/vite';
3+
import { defineConfig } from 'vite';
4+
5+
export default defineConfig({
6+
plugins: [
7+
cloudflare(),
8+
sentryCloudflareVitePlugin({
9+
_experimental: {
10+
useDiagnosticsChannelInjection: true,
11+
},
12+
}),
13+
],
14+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "../../../node_modules/wrangler/config-schema.json",
3+
"name": "cloudflare-vite-dc-client-build",
4+
// `main` points at the source entry; the runner detects `vite.config.mts`, runs
5+
// `vite build`, and serves the built output (so the orchestrion transform runs).
6+
"main": "index.ts",
7+
"compatibility_date": "2026-04-26",
8+
"compatibility_flags": ["nodejs_compat"],
9+
// Giving the worker assets makes the Cloudflare Vite plugin produce a browser
10+
// (`client`) bundle next to the server (worker) bundle — the setup where the
11+
// orchestrion plugin must not touch the client output.
12+
"assets": {
13+
"directory": "./dist/client",
14+
},
15+
}

dev-packages/e2e-tests/run.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ async function run(): Promise<void> {
183183
const env = {
184184
...process.env,
185185
...envVarsToInject,
186+
// Volta applies a project's node pin only to commands it manages, and it
187+
// manages pnpm only when this is set. Without it, the `volta run pnpm`
188+
// calls below build each app on whatever node is already on PATH rather
189+
// than the version its package.json pins. CI reads that pin directly
190+
// (see `node-version-file` in .github/workflows/build.yml), so leaving
191+
// this unset makes local runs fail on apps CI passes.
192+
VOLTA_FEATURE_PNPM: '1',
186193
};
187194

188195
console.log('Syncing packed tarball symlinks...');

dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { expect, test } from '@playwright/test';
22
import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
33

4-
const packageJson = require('../package.json');
5-
64
test('Should record exceptions for faulty edge server components', async ({ page }) => {
75
const errorEventPromise = waitForError('nextjs-app-dir', errorEvent => {
86
return errorEvent?.exception?.values?.[0]?.value === 'Edge Server Component Error';
@@ -27,9 +25,6 @@ test('Should record exceptions for faulty edge server components', async ({ page
2725
});
2826

2927
test('Should record transaction for edge server components', async ({ page }) => {
30-
const nextjsVersion = packageJson.dependencies.next;
31-
const nextjsMajor = Number(nextjsVersion.split('.')[0]);
32-
3328
const serverComponentTransactionPromise = waitForTransaction('nextjs-app-dir', async transactionEvent => {
3429
return (
3530
transactionEvent?.transaction === 'GET /edge-server-components' &&
@@ -44,12 +39,9 @@ test('Should record transaction for edge server components', async ({ page }) =>
4439
expect(serverComponentTransaction).toBeDefined();
4540
expect(serverComponentTransaction.contexts?.trace?.op).toBe('http.server');
4641

47-
// For some reason headers aren't picked up on Next.js 13 - also causing scope isolation to be broken
48-
if (nextjsMajor >= 14) {
49-
expect(serverComponentTransaction.request?.headers).toBeDefined();
42+
expect(serverComponentTransaction.request?.headers).toBeDefined();
5043

51-
// Assert that isolation scope works properly
52-
expect(serverComponentTransaction.tags?.['my-isolated-tag']).toBe(true);
53-
expect(serverComponentTransaction.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
54-
}
44+
// Assert that isolation scope works properly
45+
expect(serverComponentTransaction.tags?.['my-isolated-tag']).toBe(true);
46+
expect(serverComponentTransaction.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
5547
});

dev-packages/e2e-tests/test-applications/node-exports-test-app/scripts/consistentExports.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ const NODE_EXPORTS_IGNORE = [
1919
'getDefaultIntegrationsWithoutPerformance',
2020
'initWithoutDefaultIntegrations',
2121
'SentryContextManager',
22-
'validateOpenTelemetrySetup',
2322
'preloadOpenTelemetry',
2423
// Internal helper only needed within integrations (e.g. bunRuntimeMetricsIntegration)
2524
'_INTERNAL_normalizeCollectionInterval',

0 commit comments

Comments
 (0)