Skip to content

Commit 3f295a0

Browse files
feat: add universal IDs to client nodes
1 parent e86ad84 commit 3f295a0

File tree

21 files changed

+277
-235
lines changed

21 files changed

+277
-235
lines changed

packages/kit/src/core/config/index.spec.js

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const get_defaults = (prefix = '') => ({
101101
serviceWorker: {
102102
register: true
103103
},
104-
tracing: false,
104+
tracing: undefined,
105105
typescript: {},
106106
paths: {
107107
base: '',
@@ -407,58 +407,59 @@ test('errors on loading config with incorrect default export', async () => {
407407
});
408408

409409
test('accepts valid tracing values', () => {
410-
// Test boolean values
411410
assert.doesNotThrow(() => {
412411
validate_config({
413412
kit: {
414-
tracing: true
413+
tracing: 'server'
415414
}
416415
});
417416
});
418417

419418
assert.doesNotThrow(() => {
420419
validate_config({
421420
kit: {
422-
tracing: false
421+
tracing: undefined
423422
}
424423
});
425424
});
425+
});
426426

427-
// Test string values
428-
assert.doesNotThrow(() => {
427+
test('errors on invalid tracing values', () => {
428+
assert.throws(() => {
429429
validate_config({
430430
kit: {
431-
tracing: 'server'
431+
// @ts-expect-error - given value expected to throw
432+
tracing: true
432433
}
433434
});
434-
});
435+
}, /^config\.kit\.tracing should be undefined or "server"$/);
435436

436-
assert.doesNotThrow(() => {
437+
assert.throws(() => {
437438
validate_config({
438439
kit: {
439-
tracing: 'client'
440+
// @ts-expect-error - given value expected to throw
441+
tracing: false
440442
}
441443
});
442-
});
444+
}, /^config\.kit\.tracing should be undefined or "server"$/);
443445

444-
assert.doesNotThrow(() => {
446+
assert.throws(() => {
445447
validate_config({
446448
kit: {
447-
tracing: undefined
449+
// @ts-expect-error - given value expected to throw
450+
tracing: 'client'
448451
}
449452
});
450-
});
451-
});
453+
}, /^config\.kit\.tracing should be undefined or "server"$/);
452454

453-
test('errors on invalid tracing values', () => {
454455
assert.throws(() => {
455456
validate_config({
456457
kit: {
457458
// @ts-expect-error - given value expected to throw
458459
tracing: 'invalid'
459460
}
460461
});
461-
}, /^config\.kit\.tracing should be true, false, "server", or "client"$/);
462+
}, /^config\.kit\.tracing should be undefined or "server"$/);
462463

463464
assert.throws(() => {
464465
validate_config({
@@ -467,7 +468,7 @@ test('errors on invalid tracing values', () => {
467468
tracing: 42
468469
}
469470
});
470-
}, /^config\.kit\.tracing should be true, false, "server", or "client"$/);
471+
}, /^config\.kit\.tracing should be undefined or "server"$/);
471472

472473
assert.throws(() => {
473474
validate_config({
@@ -476,5 +477,5 @@ test('errors on invalid tracing values', () => {
476477
tracing: null
477478
}
478479
});
479-
}, /^config\.kit\.tracing should be true, false, "server", or "client"$/);
480+
}, /^config\.kit\.tracing should be undefined or "server"$/);
480481
});

packages/kit/src/core/config/options.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,11 @@ const options = object(
270270
files: fun((filename) => !/\.DS_Store/.test(filename))
271271
}),
272272

273-
tracing: validate(false, (input, keypath) => {
274-
if (typeof input === 'boolean') return input;
275-
if (input === 'server' || input === 'client') return input;
276-
throw new Error(`${keypath} should be true, false, "server", or "client"`);
273+
tracing: validate(undefined, (input, keypath) => {
274+
if (input !== 'server') {
275+
throw new Error(`${keypath} should be undefined or "server"`);
276+
}
277+
return input;
277278
}),
278279

279280
typescript: object({

packages/kit/src/core/sync/write_client_manifest.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,6 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
174174
175175
export const hash = ${s(kit.router.type === 'hash')};
176176
177-
export const tracing = ${s(kit.tracing === true || kit.tracing === 'client')};
178-
179177
export const decode = (type, value) => decoders[type](value);
180178
181179
export { default as root } from '../root.${isSvelte5Plus() ? 'js' : 'svelte'}';

packages/kit/src/core/sync/write_server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { set_building, set_prerendering } from '__sveltekit/environment';
3333
import { set_assets } from '__sveltekit/paths';
3434
import { set_manifest, set_read_implementation } from '__sveltekit/server';
3535
import { set_private_env, set_public_env, set_safe_public_env } from '${runtime_directory}/shared-server.js';
36+
import { get_tracer } from '${runtime_directory}/telemetry/get_tracer.js';
3637
3738
export const options = {
3839
app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')},
@@ -60,7 +61,7 @@ export const options = {
6061
.replace(/%sveltekit\.status%/g, '" + status + "')
6162
.replace(/%sveltekit\.error\.message%/g, '" + message + "')}
6263
},
63-
tracing: ${config.kit.tracing === true || config.kit.tracing === 'server'},
64+
tracer: get_tracer({ is_enabled: ${s(config.kit.tracing === 'server')} }),
6465
version_hash: ${s(hash(config.kit.version.name))}
6566
};
6667

packages/kit/src/exports/hooks/sequence.js

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { get_tracer } from '../../runtime/telemetry/get_tracer.js';
2+
import { record_span } from '../../runtime/telemetry/record_span.js';
3+
14
/**
25
* A helper function for sequencing multiple `handle` calls in a middleware-like manner.
36
* The behavior for the `handle` options is as follows:
@@ -73,7 +76,8 @@ export function sequence(...handlers) {
7376
const length = handlers.length;
7477
if (!length) return ({ event, resolve }) => resolve(event);
7578

76-
return ({ event, resolve }) => {
79+
return async ({ event, resolve }) => {
80+
const tracer = await get_tracer();
7781
return apply_handle(0, event, {});
7882

7983
/**
@@ -85,38 +89,46 @@ export function sequence(...handlers) {
8589
function apply_handle(i, event, parent_options) {
8690
const handle = handlers[i];
8791

88-
return handle({
89-
event,
90-
resolve: (event, options) => {
91-
/** @type {import('@sveltejs/kit').ResolveOptions['transformPageChunk']} */
92-
const transformPageChunk = async ({ html, done }) => {
93-
if (options?.transformPageChunk) {
94-
html = (await options.transformPageChunk({ html, done })) ?? '';
95-
}
92+
return record_span({
93+
name: 'sveltekit.handle.child',
94+
tracer,
95+
attributes: {
96+
'sveltekit.handle.child.index': i
97+
},
98+
fn: async (span) =>
99+
handle({
100+
event: { ...event, span },
101+
resolve: (event, options) => {
102+
/** @type {import('@sveltejs/kit').ResolveOptions['transformPageChunk']} */
103+
const transformPageChunk = async ({ html, done }) => {
104+
if (options?.transformPageChunk) {
105+
html = (await options.transformPageChunk({ html, done })) ?? '';
106+
}
96107

97-
if (parent_options?.transformPageChunk) {
98-
html = (await parent_options.transformPageChunk({ html, done })) ?? '';
99-
}
108+
if (parent_options?.transformPageChunk) {
109+
html = (await parent_options.transformPageChunk({ html, done })) ?? '';
110+
}
100111

101-
return html;
102-
};
112+
return html;
113+
};
103114

104-
/** @type {import('@sveltejs/kit').ResolveOptions['filterSerializedResponseHeaders']} */
105-
const filterSerializedResponseHeaders =
106-
parent_options?.filterSerializedResponseHeaders ??
107-
options?.filterSerializedResponseHeaders;
115+
/** @type {import('@sveltejs/kit').ResolveOptions['filterSerializedResponseHeaders']} */
116+
const filterSerializedResponseHeaders =
117+
parent_options?.filterSerializedResponseHeaders ??
118+
options?.filterSerializedResponseHeaders;
108119

109-
/** @type {import('@sveltejs/kit').ResolveOptions['preload']} */
110-
const preload = parent_options?.preload ?? options?.preload;
120+
/** @type {import('@sveltejs/kit').ResolveOptions['preload']} */
121+
const preload = parent_options?.preload ?? options?.preload;
111122

112-
return i < length - 1
113-
? apply_handle(i + 1, event, {
114-
transformPageChunk,
115-
filterSerializedResponseHeaders,
116-
preload
117-
})
118-
: resolve(event, { transformPageChunk, filterSerializedResponseHeaders, preload });
119-
}
123+
return i < length - 1
124+
? apply_handle(i + 1, event, {
125+
transformPageChunk,
126+
filterSerializedResponseHeaders,
127+
preload
128+
})
129+
: resolve(event, { transformPageChunk, filterSerializedResponseHeaders, preload });
130+
}
131+
})
120132
});
121133
}
122134
};

packages/kit/src/exports/hooks/sequence.spec.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import { installPolyfills } from '../node/polyfills.js';
44

55
installPolyfills();
66

7+
const dummy_event = /** @type {import('@sveltejs/kit').RequestEvent} */ ({
8+
route: { id: 'test' },
9+
request: { method: 'GET' },
10+
url: new URL('https://example.com'),
11+
isDataRequest: false,
12+
isSubRequest: false
13+
});
14+
715
test('applies handlers in sequence', async () => {
816
/** @type {string[]} */
917
const order = [];
@@ -29,10 +37,9 @@ test('applies handlers in sequence', async () => {
2937
}
3038
);
3139

32-
const event = /** @type {import('@sveltejs/kit').RequestEvent} */ ({});
3340
const response = new Response();
3441

35-
assert.equal(await handler({ event, resolve: () => response }), response);
42+
assert.equal(await handler({ event: dummy_event, resolve: () => response }), response);
3643
expect(order).toEqual(['1a', '2a', '3a', '3b', '2b', '1b']);
3744
});
3845

@@ -47,9 +54,8 @@ test('uses transformPageChunk option passed to non-terminal handle function', as
4754
async ({ event, resolve }) => resolve(event)
4855
);
4956

50-
const event = /** @type {import('@sveltejs/kit').RequestEvent} */ ({});
5157
const response = await handler({
52-
event,
58+
event: dummy_event,
5359
resolve: async (_event, opts = {}) => {
5460
let html = '';
5561

@@ -84,9 +90,8 @@ test('merges transformPageChunk option', async () => {
8490
}
8591
);
8692

87-
const event = /** @type {import('@sveltejs/kit').RequestEvent} */ ({});
8893
const response = await handler({
89-
event,
94+
event: dummy_event,
9095
resolve: async (_event, opts = {}) => {
9196
let html = '';
9297

@@ -117,9 +122,8 @@ test('uses first defined preload option', async () => {
117122
}
118123
);
119124

120-
const event = /** @type {import('@sveltejs/kit').RequestEvent} */ ({});
121125
const response = await handler({
122-
event,
126+
event: dummy_event,
123127
resolve: (_event, opts = {}) => {
124128
let html = '';
125129

@@ -150,9 +154,8 @@ test('uses first defined filterSerializedResponseHeaders option', async () => {
150154
}
151155
);
152156

153-
const event = /** @type {import('@sveltejs/kit').RequestEvent} */ ({});
154157
const response = await handler({
155-
event,
158+
event: dummy_event,
156159
resolve: (_event, opts = {}) => {
157160
let html = '';
158161

packages/kit/src/exports/public.d.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from '../types/private.js';
1919
import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types';
2020
import type { SvelteConfig } from '@sveltejs/vite-plugin-svelte';
21+
import { Span } from '@opentelemetry/api';
2122

2223
export { PrerenderOption } from '../types/private.js';
2324

@@ -687,15 +688,11 @@ export interface KitConfig {
687688
files?(filepath: string): boolean;
688689
};
689690
/**
690-
* Whether to enable OpenTelemetry tracing for SvelteKit operations including handle hooks, load functions, and form actions.
691-
* - `true` - Enable tracing for both server and client
692-
* - `false` - Disable tracing
693-
* - `'server'` - Enable tracing only on the server side
694-
* - `'client'` - Enable tracing only on the client side
695-
* @default false
691+
* Whether to enable serverside OpenTelemetry tracing for SvelteKit operations including handle hooks, load functions, and form actions.
692+
* @default undefined
696693
* @since 2.22.0
697694
*/
698-
tracing?: boolean | 'server' | 'client';
695+
tracing?: 'server';
699696
typescript?: {
700697
/**
701698
* A function that allows you to edit the generated `tsconfig.json`. You can mutate the config (recommended) or return a new one.
@@ -977,6 +974,11 @@ export interface LoadEvent<
977974
* ```
978975
*/
979976
untrack: <T>(fn: () => T) => T;
977+
978+
/**
979+
* If tracing is enabled, the current span.
980+
*/
981+
span?: Span;
980982
}
981983

982984
export interface NavigationEvent<
@@ -1252,6 +1254,11 @@ export interface RequestEvent<
12521254
* `true` for `+server.js` calls coming from SvelteKit without the overhead of actually making an HTTP request. This happens when you make same-origin `fetch` requests on the server.
12531255
*/
12541256
isSubRequest: boolean;
1257+
1258+
/**
1259+
* If tracing is enabled, the current span.
1260+
*/
1261+
span?: Span;
12551262
}
12561263

12571264
/**
@@ -1408,6 +1415,11 @@ export interface ServerLoadEvent<
14081415
* ```
14091416
*/
14101417
untrack: <T>(fn: () => T) => T;
1418+
1419+
/**
1420+
* If tracing is enabled, the current span.
1421+
*/
1422+
span?: Span;
14111423
}
14121424

14131425
/**

0 commit comments

Comments
 (0)