Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/olive-donkeys-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: keep one request event identity across `handle`, `load` and `handleFetch`
16 changes: 5 additions & 11 deletions packages/kit/src/exports/hooks/sequence.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
/** @import { Handle, RequestEvent, ResolveOptions } from '@sveltejs/kit' */
import {
merge_tracing,
get_request_store,
with_request_store
} from '@sveltejs/kit/internal/server';
import { get_request_store, with_request_store } from '@sveltejs/kit/internal/server';

/**
* A helper function for sequencing multiple `handle` calls in a middleware-like manner.
Expand Down Expand Up @@ -98,11 +94,10 @@ export function sequence(...handlers) {
return state.tracing.record_span({
name: `sveltekit.handle.sequenced.${handle.name ? handle.name : i}`,
attributes: {},
fn: async (current) => {
const traced_event = merge_tracing(event, current);
return await with_request_store({ event: traced_event, state }, () =>
fn: async () =>
with_request_store({ event, state }, () =>
handle({
event: traced_event,
event,
resolve: (event, options) => {
/** @type {ResolveOptions['transformPageChunk']} */
const transformPageChunk = async ({ html, done }) => {
Expand Down Expand Up @@ -138,8 +133,7 @@ export function sequence(...handlers) {
});
}
})
);
}
)
});
}
};
Expand Down
17 changes: 0 additions & 17 deletions packages/kit/src/exports/internal/server/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/** @import { Span } from '@opentelemetry/api' */
import { try_get_request_store } from './event.js';

export function get_origin() {
Expand All @@ -7,22 +6,6 @@ export function get_origin() {
return request && new URL(request.url).origin;
}

/**
* @template {{ tracing: { enabled: boolean, root: Span, current: Span } }} T
* @param {T} event_like
* @param {Span} current
* @returns {T}
*/
export function merge_tracing(event_like, current) {
return {
...event_like,
tracing: {
...event_like.tracing,
current
}
};
}

export {
with_request_store,
getRequestEvent,
Expand Down
12 changes: 2 additions & 10 deletions packages/kit/src/runtime/server/data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { once } from '../../../utils/functions.js';
import { server_data_serializer_json } from '../page/data_serializer.js';
import { load_server_data } from '../page/load_data.js';
import { handle_error_and_jsonify } from '../errors.js';
import { normalize_path } from '../../../utils/url.js';
import { text_encoder } from '../../utils.js';
import { with_version_header } from '../utils.js';

Expand All @@ -17,7 +16,6 @@ import { with_version_header } from '../utils.js';
* @param {import('@sveltejs/kit').SSRManifest} manifest
* @param {import('types').SSRState} state
* @param {boolean[] | undefined} invalidated_data_nodes
* @param {import('types').TrailingSlash} trailing_slash
* @returns {Promise<Response>}
*/
export async function render_data(
Expand All @@ -27,8 +25,7 @@ export async function render_data(
options,
manifest,
state,
invalidated_data_nodes,
trailing_slash
invalidated_data_nodes
) {
if (!route.page) {
// requesting /__data.json should fail for a +server.js
Expand All @@ -41,11 +38,6 @@ export async function render_data(

let aborted = false;

const url = new URL(event.url);
url.pathname = normalize_path(url.pathname, trailing_slash);

const new_event = { ...event, url };

const functions = node_ids.map((n, i) => {
return once(async () => {
try {
Expand All @@ -59,7 +51,7 @@ export async function render_data(
const node = n == undefined ? n : await manifest._.nodes[n]();
// load this. for the child, return as is. for the final result, stream things
return load_server_data({
event: new_event,
event,
event_state,
state,
node,
Expand Down
8 changes: 2 additions & 6 deletions packages/kit/src/runtime/server/page/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as devalue from 'devalue';
import { DEV } from 'esm-env';
import { json } from '@sveltejs/kit';
import { HttpError, Redirect, ActionFailure, SvelteKitError } from '@sveltejs/kit/internal';
import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
import { with_request_store } from '@sveltejs/kit/internal/server';
import { normalize_error } from '../../../utils/error.js';
import { is_form_content_type, negotiate } from '../../../utils/http.js';
import { create_replacer, with_version_header } from '../utils.js';
Expand Down Expand Up @@ -281,11 +281,7 @@ async function call_action(event, event_state, actions) {
'http.route': event.route.id || 'unknown'
},
fn: async (current) => {
const traced_event = merge_tracing(event, current);

const result = await with_request_store({ event: traced_event, state: event_state }, () =>
action(traced_event)
);
const result = await with_request_store({ event, state: event_state }, () => action(event));

if (result instanceof ActionFailure) {
current.setAttributes({
Expand Down
21 changes: 8 additions & 13 deletions packages/kit/src/runtime/server/page/load_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DEV } from 'esm-env';
import { noop } from '../../../utils/functions.js';
import { disable_search, make_trackable } from '../../../utils/url.js';
import { validate_depends, validate_load_response } from '../../shared.js';
import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
import { with_request_store } from '@sveltejs/kit/internal/server';
import { record_span } from '../../telemetry/record_span.js';
import { base64_encode } from '../../utils.js';
import { NULL_BODY_STATUS } from '../constants.js';
Expand Down Expand Up @@ -81,11 +81,10 @@ export async function load_server_data({ event, event_state, state, node, parent
'sveltekit.load.environment': 'server',
'http.route': event.route.id || 'unknown'
},
fn: async (current) => {
const traced_event = merge_tracing(event, current);
const result = await with_request_store({ event: traced_event, state: event_state }, () =>
fn: async () =>
with_request_store({ event, state: event_state }, () =>
load.call(null, {
...traced_event,
...event,
fetch: (info, init) => {
const url = new URL(info instanceof Request ? info.url : info, event.url);

Expand Down Expand Up @@ -170,10 +169,7 @@ export async function load_server_data({ event, event_state, state, node, parent
}
}
})
);

return result;
}
)
});

if (DEV) {
Expand Down Expand Up @@ -232,11 +228,10 @@ export async function load_data({
'sveltekit.load.environment': 'server',
'http.route': event.route.id || 'unknown'
},
fn: async (current) => {
const traced_event = merge_tracing(event, current);
fn: async () => {
const child_state = { ...event_state, is_in_universal_load: true };

return await with_request_store({ event: traced_event, state: child_state }, () =>
return await with_request_store({ event, state: child_state }, () =>
load.call(null, {
url: event.url,
params: event.params,
Expand All @@ -247,7 +242,7 @@ export async function load_data({
depends: noop,
parent,
untrack: (fn) => fn(),
tracing: traced_event.tracing
tracing: event.tracing
})
);
}
Expand Down
19 changes: 8 additions & 11 deletions packages/kit/src/runtime/server/remote-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { json, error } from '@sveltejs/kit';
import { Redirect, SvelteKitError } from '@sveltejs/kit/internal';
import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
import { with_request_store } from '@sveltejs/kit/internal/server';
import { app_dir, base } from '$app/paths/internal/server';
import { is_form_content_type } from '../../utils/http.js';
import { create_remote_key, parse_remote_arg, split_remote_key, stringify } from '../shared.js';
Expand All @@ -29,10 +29,9 @@ export async function handle_remote_call(event, state, options, manifest, id) {
attributes: {
'sveltekit.remote.call.id': id
},
fn: async (current) => {
const traced_event = merge_tracing(event, current);
const response = await with_request_store({ event: traced_event, state }, () =>
handle_remote_call_internal(traced_event, state, options, manifest, id)
fn: async () => {
const response = await with_request_store({ event, state }, () =>
handle_remote_call_internal(event, state, options, manifest, id)
);
return with_version_header(response);
}
Expand Down Expand Up @@ -520,12 +519,10 @@ export async function handle_remote_form_post(event, state, manifest, id) {
attributes: {
'sveltekit.remote.form.post.id': id
},
fn: (current) => {
const traced_event = merge_tracing(event, current);
return with_request_store({ event: traced_event, state }, () =>
handle_remote_form_post_internal(traced_event, state, manifest, id)
);
}
fn: () =>
with_request_store({ event, state }, () =>
handle_remote_form_post_internal(event, state, manifest, id)
)
});
}

Expand Down
71 changes: 36 additions & 35 deletions packages/kit/src/runtime/server/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { DEV } from 'esm-env';
import { json, text } from '@sveltejs/kit';
import { Redirect, SvelteKitError } from '@sveltejs/kit/internal';
import { merge_tracing, with_request_store } from '@sveltejs/kit/internal/server';
import { with_request_store } from '@sveltejs/kit/internal/server';
import { base, app_dir } from '$app/paths/internal/server';
import { is_endpoint_request, render_endpoint } from './endpoint.js';
import { render_page } from './page/index.js';
Expand Down Expand Up @@ -39,7 +39,7 @@ import {
import { server_data_serializer } from './page/data_serializer.js';
import { get_remote_id, handle_remote_call } from './remote-functions.js';
import { record_span } from '../telemetry/record_span.js';
import { otel } from '../telemetry/otel.js';
import { otel, trace } from '../telemetry/otel.js';

/** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
const default_transform = ({ html }) => html;
Expand Down Expand Up @@ -204,6 +204,8 @@ export async function internal_respond(request, options, manifest, state) {
cookies,
// @ts-expect-error `fetch` needs to be created after the `event` itself
fetch: null,
// @ts-expect-error `tracing` needs the root span, which is created during `handle`
tracing: null,
getClientAddress:
state.getClientAddress ||
(() => {
Expand Down Expand Up @@ -421,6 +423,9 @@ export async function internal_respond(request, options, manifest, state) {
}
});
}
} else {
// a data request can't follow a redirect, so normalize the path in place
url.pathname = normalize_path(url.pathname, trailing_slash);
}

if (state.before_handle || state.emulator?.platform) {
Expand Down Expand Up @@ -484,18 +489,17 @@ export async function internal_respond(request, options, manifest, state) {
'sveltekit.is_sub_request': event.isSubRequest
},
fn: async (root_span) => {
const traced_event = {
...event,
tracing: {
enabled: __SVELTEKIT_SERVER_TRACING_ENABLED__,
root: root_span,
current: root_span
event.tracing = {
enabled: __SVELTEKIT_SERVER_TRACING_ENABLED__,
root: root_span,
get current() {
return trace?.getActiveSpan() ?? root_span;
}
};

return await with_request_store({ event: traced_event, state: event_state }, () =>
return await with_request_store({ event, state: event_state }, () =>
options.hooks.handle({
event: traced_event,
event,
resolve: (event, opts) => {
return record_span({
name: 'sveltekit.resolve',
Expand All @@ -506,30 +510,28 @@ export async function internal_respond(request, options, manifest, state) {
// counter-intuitively, we need to clear the event, so that it's not
// e.g. accessible when loading modules needed to handle the request
return with_request_store(null, () =>
resolve(merge_tracing(event, resolve_span), page_nodes, opts).then(
(response) => {
// add headers/cookies here, rather than inside `resolve`, so that we
// can do it once for all responses instead of once per `return`
for (const key in headers) {
const value = headers[key];
response.headers.set(key, /** @type {string} */ (value));
}

add_cookies_to_headers(response.headers, new_cookies.values());

if (state.prerendering && event.route.id !== null) {
response.headers.set('x-sveltekit-routeid', encodeURI(event.route.id));
}

resolve_span.setAttributes({
'http.response.status_code': response.status,
'http.response.body.size':
response.headers.get('content-length') || 'unknown'
});

return response;
resolve(event, page_nodes, opts).then((response) => {
// add headers/cookies here, rather than inside `resolve`, so that we
// can do it once for all responses instead of once per `return`
for (const key in headers) {
const value = headers[key];
response.headers.set(key, /** @type {string} */ (value));
}

add_cookies_to_headers(response.headers, new_cookies.values());

if (state.prerendering && event.route.id !== null) {
response.headers.set('x-sveltekit-routeid', encodeURI(event.route.id));
}
)

resolve_span.setAttributes({
'http.response.status_code': response.status,
'http.response.body.size':
response.headers.get('content-length') || 'unknown'
});

return response;
})
);
}
});
Expand Down Expand Up @@ -655,8 +657,7 @@ export async function internal_respond(request, options, manifest, state) {
options,
manifest,
state,
invalidated_data_nodes,
trailing_slash
invalidated_data_nodes
);
} else {
let endpoint;
Expand Down
10 changes: 9 additions & 1 deletion packages/kit/src/runtime/telemetry/otel.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
/** @import { Tracer, SpanStatusCode, PropagationAPI, ContextAPI } from '@opentelemetry/api' */
/** @import { Tracer, SpanStatusCode, PropagationAPI, ContextAPI, TraceAPI } from '@opentelemetry/api' */

/** @type {Promise<{ tracer: Tracer, SpanStatusCode: typeof SpanStatusCode, propagation: PropagationAPI, context: ContextAPI }> | null} */
export let otel = null;

/**
* Synchronously readable once `otel` has resolved, which is guaranteed
* before any span exists — `record_span` awaits `otel` first.
* @type {TraceAPI | null}
*/
export let trace = null;

if (__SVELTEKIT_SERVER_TRACING_ENABLED__) {
otel = import('@opentelemetry/api')
.then((module) => {
trace = module.trace;
return {
tracer: module.trace.getTracer('sveltekit'),
propagation: module.propagation,
Expand Down
Loading
Loading