diff --git a/packages/kit/src/exports/hooks/sequence.js b/packages/kit/src/exports/hooks/sequence.js index 8dd0b546c84e..1b3165e89d60 100644 --- a/packages/kit/src/exports/hooks/sequence.js +++ b/packages/kit/src/exports/hooks/sequence.js @@ -1,11 +1,6 @@ /** @import { RequestEvent } from '@sveltejs/kit' */ /** @import { Handle, ResolveOptions } from '@sveltejs/kit/hooks' */ -import { - merge_tracing, - get_request_store, - record_span, - with_request_store -} from '@sveltejs/kit/internal/server'; +import { merge_tracing, record_span, with_event } from '@sveltejs/kit/internal/server'; /** * A helper function for sequencing multiple `handle` calls in a middleware-like manner. @@ -85,7 +80,6 @@ export function sequence(...handlers) { if (!length) return ({ event, resolve }) => resolve(event); return ({ event, resolve }) => { - const { state } = get_request_store(); return apply_handle(0, event, {}); /** @@ -102,7 +96,7 @@ export function sequence(...handlers) { attributes: {}, fn: async (current) => { const traced_event = merge_tracing(event, current); - return await with_request_store({ event: traced_event, state }, () => + return await with_event(traced_event, () => handle({ event: traced_event, resolve: (event, options) => { diff --git a/packages/kit/src/exports/hooks/sequence.spec.js b/packages/kit/src/exports/hooks/sequence.spec.js index de46f009c93e..54c1cc7a25ff 100644 --- a/packages/kit/src/exports/hooks/sequence.spec.js +++ b/packages/kit/src/exports/hooks/sequence.spec.js @@ -1,5 +1,4 @@ /** @import { RequestEvent } from '@sveltejs/kit' */ -/** @import { RequestState } from 'types' */ import { assert, expect, test, vi } from 'vitest'; import { sequence } from './sequence.js'; @@ -13,10 +12,7 @@ vi.mock(import('@sveltejs/kit/internal/server'), async (actualPromise) => { const actual = await actualPromise(); return { ...actual, - get_request_store: () => ({ - event: /** @type {any} */ (dummy_event), - state: /** @type {RequestState} */ (/** @type {unknown} */ ({})) - }) + get_event: () => /** @type {any} */ (dummy_event) }; }); diff --git a/packages/kit/src/exports/internal/server/event.js b/packages/kit/src/exports/internal/server/event.js index 8d4979248092..e833323ef032 100644 --- a/packages/kit/src/exports/internal/server/event.js +++ b/packages/kit/src/exports/internal/server/event.js @@ -1,5 +1,5 @@ /** @import { Cookies, RequestEvent as Interface } from '@sveltejs/kit' */ -/** @import { RequestState, RequestStore } from 'types' */ +/** @import { RequestState } from 'types' */ /** @import { AsyncLocalStorage } from 'node:async_hooks' */ import { DEV } from 'esm-env'; import { IN_WEBCONTAINER } from '../../../constants.js'; @@ -15,6 +15,9 @@ export const RENDER = 16; /** The kinds on the stack, kept under a symbol so it is not part of the public shape */ export const CONTEXT = Symbol('sveltekit.context'); +/** The request state, shared by every view of the request */ +const STATE = Symbol('sveltekit.state'); + /** What a query view copies its page fields from */ const NO_PAGE = /** @type {Interface} */ ({}); @@ -135,11 +138,15 @@ export class RequestEvent { /** @type {number} */ [CONTEXT]; + /** @type {RequestState} */ + [STATE]; + /** * @param {Interface} source * @param {number} flags + * @param {RequestState} state */ - constructor(source, flags) { + constructor(source, flags, state) { this.cookies = source.cookies; this.fetch = source.fetch; this.getClientAddress = source.getClientAddress; @@ -159,6 +166,7 @@ export class RequestEvent { this.isRemoteRequest = source.isRemoteRequest; this.tracing = source.tracing; this[CONTEXT] = flags; + this[STATE] = state; } /** @@ -169,7 +177,7 @@ export class RequestEvent { * @returns {RequestEvent} */ static create(fields, state) { - const event = new RequestEvent(/** @type {Interface} */ (fields), 0); + const event = new RequestEvent(/** @type {Interface} */ (fields), 0, state); event.setHeaders = (new_headers) => set_headers(state, new_headers); @@ -182,9 +190,15 @@ export class RequestEvent { * @returns {RequestEvent} */ static from(event) { - return event instanceof RequestEvent - ? event - : new RequestEvent(event, /** @type {Partial} */ (event)[CONTEXT] ?? 0); + if (event instanceof RequestEvent) return event; + + const { [CONTEXT]: flags = 0, [STATE]: state } = /** @type {Partial} */ (event); + return new RequestEvent(event, flags, /** @type {RequestState} */ (state)); + } + + /** What the runtime knows about the request, shared by every view of it */ + get state() { + return this[STATE]; } /** Inside a `query` function, however deep */ @@ -221,7 +235,7 @@ export class RequestEvent { */ clone(kind, overrides) { const flags = this[CONTEXT] | kind; - const view = new (flags & QUERY ? QueryEvent : RequestEvent)(this, flags); + const view = new (flags & QUERY ? QueryEvent : RequestEvent)(this, flags, this[STATE]); if (kind & (QUERY | PRERENDER | FORM | COMMAND)) { view.cookies = new RemoteCookies(this.cookies, view.read_only); @@ -246,10 +260,10 @@ for (const property of /** @type {const} */ (['url', 'params', 'route'])) { }); } -/** @type {RequestStore | null} */ -let sync_store = null; +/** @type {RequestEvent | null} */ +let sync_event = null; -/** @type {AsyncLocalStorage | null} */ +/** @type {AsyncLocalStorage | null} */ let als; import('node:async_hooks') @@ -269,7 +283,7 @@ import('node:async_hooks') * @returns {Interface} */ export function getRequestEvent() { - const event = try_get_request_store()?.event; + const event = try_get_event(); if (!event) { let message = @@ -286,42 +300,42 @@ export function getRequestEvent() { return event; } -export function get_request_store() { - const result = try_get_request_store(); - if (!result) { - let message = 'Could not get the request store.'; +export function get_event() { + const event = try_get_event(); + if (!event) { + let message = 'Could not get the request event.'; if (als) { message += ' This is an internal error.'; } else { message += - ' In environments without `AsyncLocalStorage`, the request store (used by e.g. remote functions) must be accessed synchronously, not after an `await`.' + + ' In environments without `AsyncLocalStorage`, the request event (used by e.g. remote functions) must be accessed synchronously, not after an `await`.' + ' If it was accessed synchronously then this is an internal error.'; } throw new Error(message); } - return result; + return event; } -export function try_get_request_store() { - return sync_store ?? als?.getStore() ?? null; +export function try_get_event() { + return sync_event ?? als?.getStore() ?? null; } /** * @template T - * @param {RequestStore | null} store + * @param {RequestEvent | null} event * @param {() => T} fn */ -export function with_request_store(store, fn) { +export function with_event(event, fn) { try { - sync_store = store; - return als ? als.run(store, fn) : fn(); + sync_event = event; + return als ? als.run(event, fn) : fn(); } finally { - // Since AsyncLocalStorage is not working in webcontainers, we don't reset `sync_store` + // Since AsyncLocalStorage is not working in webcontainers, we don't reset `sync_event` // and handle only one request at a time in `src/runtime/server/index.js`. if (!IN_WEBCONTAINER) { - sync_store = null; + sync_event = null; } } } diff --git a/packages/kit/src/exports/internal/server/event.spec.js b/packages/kit/src/exports/internal/server/event.spec.js index 5c9892a1dff2..5c62e61dc9e3 100644 --- a/packages/kit/src/exports/internal/server/event.spec.js +++ b/packages/kit/src/exports/internal/server/event.spec.js @@ -1,7 +1,7 @@ /** @import { RequestEvent as Interface } from '@sveltejs/kit' */ /** @import { RequestState } from 'types' */ import { assert, expect, test } from 'vitest'; -import { RequestEvent, CONTEXT, QUERY, COMMAND, RENDER } from './event.js'; +import { RequestEvent, QUERY, COMMAND, RENDER } from './event.js'; function root() { return new RequestEvent( @@ -15,7 +15,8 @@ function root() { tracing: { enabled: false } }) ), - 0 + 0, + /** @type {any} */ ({ remote: {} }) ); } @@ -66,7 +67,8 @@ test('views share the request data and own nothing else', () => { const event = base.clone(QUERY); assert.strictEqual(event.locals, base.locals); - assert.deepEqual(Object.getOwnPropertySymbols(event), [CONTEXT]); + assert.equal(Object.getOwnPropertySymbols(event).length, 2); + assert.strictEqual(event.state, base.state); assert.isFalse(Object.hasOwn(event, 'url')); }); diff --git a/packages/kit/src/exports/internal/server/index.js b/packages/kit/src/exports/internal/server/index.js index ca7ea3e9e99a..480359e938ab 100644 --- a/packages/kit/src/exports/internal/server/index.js +++ b/packages/kit/src/exports/internal/server/index.js @@ -1,10 +1,10 @@ /** @import { Span } from '@opentelemetry/api' */ /** @import { RequestEvent as Interface } from '@sveltejs/kit' */ -import { RequestEvent, try_get_request_store } from './event.js'; +import { RequestEvent, try_get_event } from './event.js'; export function get_origin() { // `request.url` rather than `event.url`, which throws inside queries - const request = try_get_request_store()?.event.request; + const request = try_get_event()?.request; return request && new URL(request.url).origin; } @@ -18,10 +18,10 @@ export function merge_tracing(event, current) { } export { - with_request_store, + with_event, getRequestEvent, - get_request_store, - try_get_request_store, + get_event, + try_get_event, RequestEvent, CONTEXT, QUERY, diff --git a/packages/kit/src/runtime/app/paths/server.js b/packages/kit/src/runtime/app/paths/server.js index 3628b9b4440d..6705467bee7f 100644 --- a/packages/kit/src/runtime/app/paths/server.js +++ b/packages/kit/src/runtime/app/paths/server.js @@ -2,7 +2,7 @@ import { base, assets, relative } from './internal/server.js'; import { resolve_route, find_route } from '../../../utils/routing.js'; import { decode_pathname } from '../../../utils/url.js'; import { add_data_suffix } from '../../../pathname.js'; -import { try_get_request_store } from '@sveltejs/kit/internal/server'; +import { try_get_event } from '@sveltejs/kit/internal/server'; import { manifest } from '../../server/internal.js'; import { get_hooks } from '/server.js'; import { DEV } from 'esm-env'; @@ -39,14 +39,14 @@ export function resolve(id, params) { } if (relative) { - const store = try_get_request_store(); + const event = try_get_event(); - if (store && !store.state.prerendering?.fallback) { + if (event && !event.state.prerendering?.fallback) { // the relative path depth must reflect the URL the browser is actually at, which // for a data request includes the `__data.json` suffix that was stripped during routing - const pathname = store.event.isDataRequest - ? add_data_suffix(store.event.url.pathname) - : store.event.url.pathname; + const pathname = event.isDataRequest + ? add_data_suffix(event.url.pathname) + : event.url.pathname; const after_base = pathname.slice(base.length); const segments = after_base.split('/').slice(2); const prefix = segments.map(() => '..').join('/') || '.'; @@ -60,10 +60,10 @@ export function resolve(id, params) { /** @type {typeof import('./client.js').match} */ export async function match(url) { - const store = try_get_request_store(); + const event = try_get_event(); if (typeof url === 'string') { - const origin = store?.event.url.origin ?? 'a://a'; + const origin = event?.url.origin ?? 'a://a'; url = new URL(url, origin); } @@ -73,7 +73,7 @@ export async function match(url) { try { resolved_path = decode_pathname( - (await reroute?.({ url: new URL(url), fetch: store?.event.fetch ?? fetch })) ?? url.pathname + (await reroute?.({ url: new URL(url), fetch: event?.fetch ?? fetch })) ?? url.pathname ); } catch { return null; diff --git a/packages/kit/src/runtime/app/server/remote/command.js b/packages/kit/src/runtime/app/server/remote/command.js index 8afccf6cbf5d..9adbae75411e 100644 --- a/packages/kit/src/runtime/app/server/remote/command.js +++ b/packages/kit/src/runtime/app/server/remote/command.js @@ -1,7 +1,7 @@ /** @import { RemoteCommand } from '$app/server' */ /** @import { MaybePromise, RemoteCommandInternals } from 'types' */ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */ -import { get_request_store, COMMAND } from '@sveltejs/kit/internal/server'; +import { get_event, COMMAND } from '@sveltejs/kit/internal/server'; import { create_validator, run_remote_function } from './shared.js'; import { MUTATIVE_METHODS } from '../../../../constants.js'; @@ -63,7 +63,7 @@ export function command(validate_or_fn, maybe_fn) { /** @type {RemoteCommand & { __: RemoteCommandInternals }} */ const wrapper = (arg) => { - const { event, state } = get_request_store(); + const event = get_event(); const nested = event.read_only; if (nested || !MUTATIVE_METHODS.includes(event.request.method)) { @@ -78,9 +78,7 @@ export function command(validate_or_fn, maybe_fn) { throw new Error(`Cannot call a command (${__.name}) during server-side rendering`); } - const promise = Promise.resolve( - run_remote_function(event, state, COMMAND, () => validate(arg), fn) - ); + const promise = Promise.resolve(run_remote_function(event, COMMAND, () => validate(arg), fn)); // @ts-expect-error promise.updates = () => { diff --git a/packages/kit/src/runtime/app/server/remote/form.js b/packages/kit/src/runtime/app/server/remote/form.js index 5a2ed87f3cad..b7b566ddc16b 100644 --- a/packages/kit/src/runtime/app/server/remote/form.js +++ b/packages/kit/src/runtime/app/server/remote/form.js @@ -1,7 +1,7 @@ /** @import { RemoteFormInput, RemoteForm, RemoteFormInvalidField } from '$app/server' */ /** @import { InternalRemoteFormIssue, MaybePromise, HasNonOptionalBoolean, RemoteFormInternals } from 'types' */ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */ -import { FORM, get_request_store } from '@sveltejs/kit/internal/server'; +import { get_event, FORM } from '@sveltejs/kit/internal/server'; import { create_field_proxy, set_nested_value, @@ -98,7 +98,7 @@ export function form(validate_or_fn, maybe_fn) { // make it possible to differentiate between user submission and programmatic `field.set(...)` updates output.submission = true; - const { event, state } = get_request_store(); + const event = get_event(); const validated = await schema?.['~standard'].validate(data); if (meta.validate_only) { @@ -117,7 +117,6 @@ export function form(validate_or_fn, maybe_fn) { try { output.result = await run_remote_function( event, - state, FORM, () => data, (data) => (!maybe_fn ? fn() : fn(data, issue)) @@ -140,12 +139,12 @@ export function form(validate_or_fn, maybe_fn) { // We don't need to care about args or deduplicating calls, because uneval results are only relevant in full page reloads // where only one form submission is active at the same time if (!event.isRemoteRequest) { - const cache = get_cache(__, state); + const cache = get_cache(__, event); cache[''] ??= output; // register under the client-side action id so the output is serialized // into the page, allowing the hydrated client to restore `result`/`issues`/`input` - get_implicit_lookup(__, state)[__.key ? `${__.id}/${__.key}` : __.id] = () => cache['']; + get_implicit_lookup(__, event)[__.key ? `${__.id}/${__.key}` : __.id] = () => cache['']; } return output; @@ -156,7 +155,7 @@ export function form(validate_or_fn, maybe_fn) { Object.defineProperty(instance, 'action', { get: () => { - const search = new URLSearchParams(get_request_store().event.url.search); + const search = new URLSearchParams(get_event().url.search); search.delete('/remote'); const query = search.toString(); @@ -173,9 +172,9 @@ export function form(validate_or_fn, maybe_fn) { // so the current request's state has to be resolved at access time return create_field_proxy({ form_id: __.id, - get: () => get_cache(__, get_request_store().state)?.['']?.input ?? {}, + get: () => get_cache(__, get_event())?.['']?.input ?? {}, set: (path, value) => { - const cache = get_cache(__, get_request_store().state); + const cache = get_cache(__, get_event()); const entry = cache['']; if (entry?.submission) { @@ -192,8 +191,7 @@ export function form(validate_or_fn, maybe_fn) { deep_set(input, path.map(String), value); (cache[''] ??= {}).input = input; }, - get_issues: () => - flatten_issues(get_cache(__, get_request_store().state)?.['']?.issues ?? []), + get_issues: () => flatten_issues(get_cache(__, get_event())?.['']?.issues ?? []), get_touched: () => ({}), get_dirty: () => ({}) }); @@ -203,7 +201,7 @@ export function form(validate_or_fn, maybe_fn) { Object.defineProperty(instance, 'result', { get() { try { - return get_cache(__, get_request_store().state)?.['']?.result; + return get_cache(__, get_event())?.['']?.result; } catch { return undefined; } @@ -244,7 +242,7 @@ export function form(validate_or_fn, maybe_fn) { Object.defineProperty(instance, 'for', { /** @type {RemoteForm['for']} */ value: (key) => { - const { state } = get_request_store(); + const state = get_event().state; const cache_key = __.id + '|' + JSON.stringify(key); /** @type {RemoteForm & { __: RemoteFormInternals }} */ let instance = (state.remote.forms ??= new Map()).get(cache_key); diff --git a/packages/kit/src/runtime/app/server/remote/prerender.js b/packages/kit/src/runtime/app/server/remote/prerender.js index a8b5d07504e3..b2c0692c6f8e 100644 --- a/packages/kit/src/runtime/app/server/remote/prerender.js +++ b/packages/kit/src/runtime/app/server/remote/prerender.js @@ -2,7 +2,7 @@ /** @import { RemoteFunctionResponse, RemotePrerenderInputsGenerator, RemotePrerenderInternals, MaybePromise } from 'types' */ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */ import { HandledHttpError } from '@sveltejs/kit/internal'; -import { get_request_store, PRERENDER } from '@sveltejs/kit/internal/server'; +import { get_event, PRERENDER } from '@sveltejs/kit/internal/server'; import { stringify_remote_arg } from '../../../shared.js'; import { parse, stringify } from '#app/internal/transport'; import { noop } from '../../../../utils/functions.js'; @@ -83,14 +83,15 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) { /** @type {RemotePrerenderFunction & { __: RemotePrerenderInternals }} */ const wrapper = (arg) => { - const { event, state } = get_request_store(); + const event = get_event(); + const state = event.state; const payload = stringify_remote_arg(arg); // `get_response` (as opposed to bare `get_cache`) also registers the call in the // implicit lookup, so that the result is inlined into the page payload (`data.p`) // and the client doesn't need to fetch it again upon hydration /** @type {Promise & Partial>} */ - const promise = get_response(__, payload, event, state, async () => { + const promise = get_response(__, payload, event, async () => { const id = __.id; const url = `${base}/${app_dir}/remote/${id}${payload ? `/${payload}` : ''}`; @@ -126,7 +127,7 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) { return /** @type {Promise} */ (state.prerendering.remote_responses.get(url)); } - const promise = run_remote_function(event, state, PRERENDER, () => validate(arg), fn); + const promise = run_remote_function(event, PRERENDER, () => validate(arg), fn); if (state.prerendering) { state.prerendering.remote_responses.set(url, promise); diff --git a/packages/kit/src/runtime/app/server/remote/prerender.spec.js b/packages/kit/src/runtime/app/server/remote/prerender.spec.js index eeeca72eb077..05c5c59f1837 100644 --- a/packages/kit/src/runtime/app/server/remote/prerender.spec.js +++ b/packages/kit/src/runtime/app/server/remote/prerender.spec.js @@ -1,4 +1,3 @@ -/** @import { RequestState } from 'types' */ import { expect, test, vi } from 'vitest'; import { HandledHttpError, ValidationError } from '@sveltejs/kit/internal'; import { prerender } from './prerender.js'; @@ -13,7 +12,7 @@ vi.mock(import('@sveltejs/kit/internal/server'), async (actualPromise) => { const actual = await actualPromise(); return { ...actual, - get_request_store: () => store.current + get_event: () => store.current }; }); @@ -32,24 +31,15 @@ function setup(fetch_impl) { const wrapper = prerender(fn); /** @type {any} */ (wrapper).__.id = 'hash/fn'; - store.current = { - event: new RequestEvent( - /** @type {import('@sveltejs/kit').RequestEvent} */ ( - /** @type {unknown} */ ({ - request: { url: 'http://localhost/' }, - isRemoteRequest: false, - cookies: {} - }) - ), - 0 - ), - state: /** @type {RequestState} */ ( - /** @type {unknown} */ ({ - remote: {}, - prerendering: undefined - }) - ) - }; + store.current = new RequestEvent( + /** @type {any} */ ({ + request: { url: 'http://localhost/' }, + isRemoteRequest: false, + cookies: {} + }), + 0, + /** @type {any} */ ({ remote: {}, prerendering: undefined }) + ); vi.stubGlobal('fetch', vi.fn(fetch_impl)); @@ -74,11 +64,7 @@ test('propagates an error response instead of running the function', async () => const handleError = vi.fn(); set_hooks(/** @type {any} */ ({ handleError })); - const transformed = await handle_error_and_jsonify( - store.current.event, - store.current.state, - rejection - ); + const transformed = await handle_error_and_jsonify(store.current, rejection); expect(transformed).toBe(rejection.body); expect(handleError).not.toHaveBeenCalled(); @@ -90,17 +76,13 @@ test('passes validation errors to handleError without exposing issues by default const handleError = vi.fn(); set_hooks(/** @type {any} */ ({ handleError })); - const transformed = await handle_error_and_jsonify( - store.current.event, - store.current.state, - new ValidationError(issues) - ); + const transformed = await handle_error_and_jsonify(store.current, new ValidationError(issues)); expect(handleError).toHaveBeenCalledWith({ kind: 'validation', error: { status: 400, message: 'Bad Request' }, issues, - event: store.current.event + event: store.current }); expect(transformed).toEqual({ status: 400, message: 'Bad Request' }); }); diff --git a/packages/kit/src/runtime/app/server/remote/query.js b/packages/kit/src/runtime/app/server/remote/query.js index 06ee8525bec1..84435afbc1df 100644 --- a/packages/kit/src/runtime/app/server/remote/query.js +++ b/packages/kit/src/runtime/app/server/remote/query.js @@ -1,8 +1,8 @@ /** @import { RemoteLiveQuery, RemoteLiveQueryFunction, RemoteQuery, RemoteQueryFunction } from '$app/server' */ /** @import { RequestEvent } from '@sveltejs/kit/internal/server' */ -/** @import { RemoteInternals, MaybePromise, RequestState, RemoteQueryLiveInternals, RemoteQueryBatchInternals, RemoteQueryInternals, RemoteLiveQueryUserFunctionReturnType } from 'types' */ +/** @import { RemoteInternals, MaybePromise, RemoteQueryLiveInternals, RemoteQueryBatchInternals, RemoteQueryInternals, RemoteLiveQueryUserFunctionReturnType } from 'types' */ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */ -import { get_request_store, QUERY } from '@sveltejs/kit/internal/server'; +import { get_event, QUERY } from '@sveltejs/kit/internal/server'; import { create_remote_key, stringify_remote_arg } from '../../../shared.js'; import { prerendering } from '#app/env/server'; import { @@ -76,10 +76,10 @@ export function query(validate_or_fn, maybe_fn) { name: '', validate, bind(payload, validated_arg) { - const { event, state } = get_request_store(); + const event = get_event(); - return create_query_resource(__, payload, event, state, () => - run_remote_function(event, state, QUERY, () => validated_arg, fn) + return create_query_resource(__, payload, event, () => + run_remote_function(event, QUERY, () => validated_arg, fn) ); } }; @@ -92,11 +92,11 @@ export function query(validate_or_fn, maybe_fn) { ); } - const { event, state } = get_request_store(); + const event = get_event(); const payload = stringify_remote_arg(arg); - return create_query_resource(__, payload, event, state, () => - run_remote_function(event, state, QUERY, () => validate(arg), fn) + return create_query_resource(__, payload, event, () => + run_remote_function(event, QUERY, () => validate(arg), fn) ); }; @@ -147,26 +147,22 @@ function live(validate_or_fn, maybe_fn) { const validate = create_validator(validate_or_fn, maybe_fn); /** - * @param {any} event - * @param {any} state + * @param {RequestEvent} event * @param {any} get_input */ - const run = (event, state, get_input) => - run_remote_generator(event, state, QUERY, get_input, fn, __.name); + const run = (event, get_input) => run_remote_generator(event, QUERY, get_input, fn, __.name); /** @type {RemoteQueryLiveInternals} */ const __ = { type: 'query_live', id: '', name: '', - run: (event, state, arg) => run(event, state, () => validate(arg)), + run: (event, arg) => run(event, () => validate(arg)), validate, bind(payload, validated_arg) { - const { event, state } = get_request_store(); + const event = get_event(); - return create_live_query_resource(__, payload, event, state, () => - run(event, state, () => validated_arg) - ); + return create_live_query_resource(__, payload, event, () => run(event, () => validated_arg)); } }; @@ -178,12 +174,10 @@ function live(validate_or_fn, maybe_fn) { ); } - const { event, state } = get_request_store(); + const event = get_event(); const payload = stringify_remote_arg(arg); - return create_live_query_resource(__, payload, event, state, () => - run(event, state, () => validate(arg)) - ); + return create_live_query_resource(__, payload, event, () => run(event, () => validate(arg))); }; Object.defineProperty(wrapper, '__', { value: __ }); @@ -242,7 +236,8 @@ function batch(validate_or_fn, maybe_fn) { * @returns {Promise} */ const enqueue = (payload, get_validated) => { - const { event, state } = get_request_store(); + const event = get_event(); + const state = event.state; return new Promise((resolve, reject) => { const batches = (state.remote.batches ??= @@ -273,7 +268,6 @@ function batch(validate_or_fn, maybe_fn) { try { return await run_remote_function( event, - state, QUERY, async () => Promise.all(entries.map((entry) => entry.get_validated())), async (input) => { @@ -312,11 +306,10 @@ function batch(validate_or_fn, maybe_fn) { name: '', validate, run: async (args) => { - const { event, state } = get_request_store(); + const event = get_event(); return run_remote_function( event, - state, QUERY, async () => Promise.all(args.map(validate)), async (/** @type {any[]} */ input) => { @@ -328,7 +321,7 @@ function batch(validate_or_fn, maybe_fn) { const data = get_result(arg, i); return { type: 'result', data }; } catch (error) { - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); return { type: 'error', @@ -341,11 +334,9 @@ function batch(validate_or_fn, maybe_fn) { ); }, bind(payload, validated_arg) { - const { event, state } = get_request_store(); + const event = get_event(); - return create_query_resource(__, payload, event, state, () => - enqueue(payload, () => validated_arg) - ); + return create_query_resource(__, payload, event, () => enqueue(payload, () => validated_arg)); } }; @@ -357,10 +348,10 @@ function batch(validate_or_fn, maybe_fn) { ); } - const { event, state } = get_request_store(); + const event = get_event(); const payload = stringify_remote_arg(arg); - return create_query_resource(__, payload, event, state, () => + return create_query_resource(__, payload, event, () => // Collect all the calls to the same query in the same macrotask, // then execute them as one backend request. enqueue(payload, () => validate(arg)) @@ -375,12 +366,11 @@ function batch(validate_or_fn, maybe_fn) { /** * Include this value in the returned payload... * @param {RequestEvent} event - * @param {RequestState} state * @param {RemoteInternals} internals * @param {string} payload * @param {() => Promise} fn */ -export function refresh(event, state, internals, payload, fn) { +export function refresh(event, internals, payload, fn) { if (!internals.id) { // unless this is a non-exported (i.e. private) query... return; @@ -399,7 +389,7 @@ export function refresh(event, state, internals, payload, fn) { // mutations that happen after `refresh()` is called. If the developer re-awaits // the query before the request finishes, the cache entry created by that await // is reused instead of re-running the query. - (state.remote.explicit ??= new Map()).set(key, { + (event.state.remote.explicit ??= new Map()).set(key, { internals, fn }); @@ -409,16 +399,15 @@ export function refresh(event, state, internals, payload, fn) { * @param {RemoteInternals} __ * @param {string} payload — the stringified raw argument (i.e. the cache key the client will use) * @param {RequestEvent} event - * @param {RequestState} state * @param {() => Promise} fn * @returns {RemoteQuery} */ -function create_query_resource(__, payload, event, state, fn) { +function create_query_resource(__, payload, event, fn) { /** @type {Promise | null} */ let promise = null; const get_promise = () => { - return (promise ??= get_response(__, payload, event, state, fn)); + return (promise ??= get_response(__, payload, event, fn)); }; const populate_hydratable = () => { @@ -459,18 +448,18 @@ function create_query_resource(__, payload, event, state, fn) { }, refresh() { promise = null; - delete get_cache(__, state)[payload]; + delete get_cache(__, event)[payload]; - refresh(event, state, __, payload, get_promise); + refresh(event, __, payload, get_promise); return Promise.resolve(); }, /** @param {any} value */ set(value) { const p = (promise = Promise.resolve(value)); - get_cache(__, state)[payload] = p; + get_cache(__, event)[payload] = p; - refresh(event, state, __, payload, () => p); + refresh(event, __, payload, () => p); }, /** @type {Promise['then']} */ then(onfulfilled, onrejected) { @@ -489,11 +478,10 @@ function create_query_resource(__, payload, event, state, fn) { * @param {RemoteQueryLiveInternals} __ * @param {string} payload — the stringified raw argument (i.e. the cache key the client will use) * @param {RequestEvent} event - * @param {RequestState} state * @param {() => AsyncGenerator} get_generator * @returns {RemoteLiveQuery} */ -function create_live_query_resource(__, payload, event, state, get_generator) { +function create_live_query_resource(__, payload, event, get_generator) { /** @type {Promise | null} */ let promise = null; @@ -505,7 +493,7 @@ function create_live_query_resource(__, payload, event, state, get_generator) { }; const get_promise = () => { - return (promise ??= get_response(__, payload, event, state, get_first_value)); + return (promise ??= get_response(__, payload, event, get_first_value)); }; const populate_hydratable = () => { @@ -551,9 +539,9 @@ function create_live_query_resource(__, payload, event, state, get_generator) { }, reconnect() { promise = null; - delete get_cache(__, state)[payload]; + delete get_cache(__, event)[payload]; - refresh(event, state, __, payload, get_promise); + refresh(event, __, payload, get_promise); return Promise.resolve(); }, @@ -563,7 +551,7 @@ function create_live_query_resource(__, payload, event, state, get_generator) { }, [Symbol.asyncIterator]() { const key = create_remote_key(__.id, payload); - const cache = (state.remote.live_iterators ??= new Map()); + const cache = (event.state.remote.live_iterators ??= new Map()); let cached = cache.get(key); if (!cached) { cached = create_shared_live_iterator(event.request.signal, get_generator); diff --git a/packages/kit/src/runtime/app/server/remote/requested.js b/packages/kit/src/runtime/app/server/remote/requested.js index 79fea7852bf3..4d915ea3c446 100644 --- a/packages/kit/src/runtime/app/server/remote/requested.js +++ b/packages/kit/src/runtime/app/server/remote/requested.js @@ -1,6 +1,6 @@ /** @import { RemoteLiveQuery, RemoteLiveQueryFunction, RemoteQuery, RemoteQueryFunction, RequestedResult, RemoteQueryRequestedResult, RemoteLiveQueryRequestedResult } from '$app/server' */ /** @import { MaybePromise, RemoteAnyQueryInternals } from 'types' */ -import { get_request_store } from '@sveltejs/kit/internal/server'; +import { get_event } from '@sveltejs/kit/internal/server'; import { create_remote_key, parse_remote_arg } from '../../../shared.js'; import { noop } from '../../../../utils/functions.js'; import { get_cache } from './shared.js'; @@ -101,7 +101,8 @@ import { refresh } from './query.js'; * @returns {RequestedResult} */ export function requested(query, limit) { - const { event, state } = get_request_store(); + const event = get_event(); + const state = event.state; const internals = /** @type {RemoteAnyQueryInternals | undefined} */ ( /** @type {any} */ (query).__ ); @@ -156,8 +157,8 @@ export function requested(query, limit) { const promise = Promise.reject(error); promise.catch(noop); - get_cache(__, state)[payload] = promise; - refresh(event, state, __, payload, () => promise); + get_cache(__, event)[payload] = promise; + refresh(event, __, payload, () => promise); }; for (const payload of skipped) consume(payload); diff --git a/packages/kit/src/runtime/app/server/remote/shared.js b/packages/kit/src/runtime/app/server/remote/shared.js index f3b4eec105db..54d6e2742f88 100644 --- a/packages/kit/src/runtime/app/server/remote/shared.js +++ b/packages/kit/src/runtime/app/server/remote/shared.js @@ -1,8 +1,8 @@ /** @import { RequestEvent } from '@sveltejs/kit/internal/server' */ -/** @import { MaybePromise, RequestState, RemoteInternals, RemoteLiveQueryUserFunctionReturnType } from 'types' */ +/** @import { MaybePromise, RemoteInternals, RemoteLiveQueryUserFunctionReturnType } from 'types' */ import { error } from '@sveltejs/kit'; import { ValidationError } from '@sveltejs/kit/internal'; -import { with_request_store } from '@sveltejs/kit/internal/server'; +import { with_event } from '@sveltejs/kit/internal/server'; /** * @param {any} validate_or_fn @@ -55,20 +55,19 @@ export function create_validator(validate_or_fn, maybe_fn) { * @param {RemoteInternals} internals * @param {string} payload — the stringified raw argument (i.e. the cache key the client will use) * @param {RequestEvent} event - * @param {RequestState} state * @param {() => Promise} get_result * @returns {Promise} */ -export async function get_response(internals, payload, event, state, get_result) { +export async function get_response(internals, payload, event, get_result) { // wait a beat, in case `myQuery().set(...)` or `myQuery().refresh()` is immediately called // eslint-disable-next-line @typescript-eslint/await-thenable await 0; - const cache = get_cache(internals, state); + const cache = get_cache(internals, event); if (!event.in_query) { // if this is a top-level (not nested) `await myQuery()`, include it in the serialized response - get_implicit_lookup(internals, state)[payload] = get_result; + get_implicit_lookup(internals, event)[payload] = get_result; } return (cache[payload] ??= get_result()); @@ -78,35 +77,33 @@ export async function get_response(internals, payload, event, state, get_result) * Like `with_event` but removes things from `event` you cannot see/call in remote functions, such as `setHeaders`. * @template T * @param {RequestEvent} event - * @param {RequestState} state * @param {number} kind * @param {() => any} get_input * @param {(arg?: any) => T} fn */ -export async function run_remote_function(event, state, kind, get_input, fn) { - const store = { event: event.clone(kind), state }; +export async function run_remote_function(event, kind, get_input, fn) { + const derived = event.clone(kind); // In two parts, each with_event, so that runtimes without async local storage can still get the event at the start of the function - const input = await with_request_store(store, get_input); - return with_request_store(store, () => fn(input)); + const input = await with_event(derived, get_input); + return with_event(derived, () => fn(input)); } /** * Like `with_event` but removes things from `event` you cannot see/call in remote functions, such as `setHeaders`. * @template T * @param {RequestEvent} event - * @param {RequestState} state * @param {number} kind * @param {() => any} get_input * @param {(arg?: any) => RemoteLiveQueryUserFunctionReturnType} fn * @param {string} name */ -export async function* run_remote_generator(event, state, kind, get_input, fn, name) { - const store = { event: event.clone(kind), state }; +export async function* run_remote_generator(event, kind, get_input, fn, name) { + const derived = event.clone(kind); // In two parts, each with_event, so that runtimes without async local storage can still get the event at the start of the function / calls to next - const input = await with_request_store(store, get_input); - const source = await with_request_store(store, () => fn(input)); + const input = await with_event(derived, get_input); + const source = await with_event(derived, () => fn(input)); const iterator = to_iterator(source, name); let done = false; @@ -117,7 +114,7 @@ export async function* run_remote_generator(event, state, kind, get_input, fn, n // access to the request context in generator functions, we have to // provide it to every invocation of `.next`. (It's more obvious that // this is necessary with plain iterators.) - const result = await with_request_store(store, () => iterator.next()); + const result = await with_event(derived, () => iterator.next()); if (result.done) { done = true; return result.value; @@ -126,7 +123,7 @@ export async function* run_remote_generator(event, state, kind, get_input, fn, n } } finally { if (!done && typeof iterator.return === 'function') { - await with_request_store(store, () => iterator.return?.(undefined)); + await with_event(derived, () => iterator.return?.(undefined)); } } } @@ -157,20 +154,18 @@ function to_iterator(source, name) { } /** - * Note that `state` is deliberately not optional: resources that capture the request - * state at creation must pass it explicitly, because reading it from the request store - * at call time is only equivalent on runtimes with `AsyncLocalStorage` support. - * Callers without a captured state (such as the module-level `form` instance getters) - * should pass `get_request_store().state` themselves. + * `event` is deliberately not optional: resources capture it at creation, since reading it + * from the store at call time is only equivalent on runtimes with `AsyncLocalStorage` * @param {RemoteInternals} internals - * @param {RequestState} state + * @param {RequestEvent} event */ -export function get_cache(internals, state) { - let cache = state.remote.data?.get(internals); +export function get_cache(internals, event) { + const { remote } = event.state; + let cache = remote.data?.get(internals); if (cache === undefined) { cache = {}; - (state.remote.data ??= new Map()).set(internals, cache); + (remote.data ??= new Map()).set(internals, cache); } return cache; @@ -178,14 +173,15 @@ export function get_cache(internals, state) { /** * @param {RemoteInternals} internals - * @param {RequestState} state + * @param {RequestEvent} event */ -export function get_implicit_lookup(internals, state) { - let cache = state.remote.implicit?.get(internals); +export function get_implicit_lookup(internals, event) { + const { remote } = event.state; + let cache = remote.implicit?.get(internals); if (cache === undefined) { cache = {}; - (state.remote.implicit ??= new Map()).set(internals, cache); + (remote.implicit ??= new Map()).set(internals, cache); } return cache; diff --git a/packages/kit/src/runtime/server/data/index.js b/packages/kit/src/runtime/server/data/index.js index afa9038fb83c..d8bd15775127 100644 --- a/packages/kit/src/runtime/server/data/index.js +++ b/packages/kit/src/runtime/server/data/index.js @@ -12,13 +12,12 @@ import { manifest } from '../internal.js'; /** * @param {import('@sveltejs/kit/internal/server').RequestEvent} event - * @param {import('types').RequestState} state * @param {{ page: Pick | null }} route * @param {boolean[] | undefined} invalidated_data_nodes * @param {import('types').TrailingSlash} trailing_slash * @returns {Promise} */ -export async function render_data(event, state, route, invalidated_data_nodes, trailing_slash) { +export async function render_data(event, route, invalidated_data_nodes, trailing_slash) { if (!route.page) { // requesting /__data.json should fail for a +server.js return with_version_header(new Response(undefined, { status: 404 })); @@ -49,7 +48,6 @@ export async function render_data(event, state, route, invalidated_data_nodes, t // load this. for the child, return as is. for the final result, stream things return load_server_data({ event: new_event, - state, node, parent: async () => { /** @type {Record} */ @@ -83,7 +81,7 @@ export async function render_data(event, state, route, invalidated_data_nodes, t return fn(); }); - const data_serializer = server_data_serializer_json(event, state); + const data_serializer = server_data_serializer_json(event); await Promise.all( promises.map(async (p, i) => { const node = await p.catch(async (error) => { @@ -91,7 +89,7 @@ export async function render_data(event, state, route, invalidated_data_nodes, t throw error; } - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); return /** @type {import('types').ServerErrorNode} */ ({ type: 'error', @@ -126,7 +124,7 @@ export async function render_data(event, state, route, invalidated_data_nodes, t if (error instanceof Redirect) { return redirect_json_response(error); } else { - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); return json_response(transformed, transformed.status); } } diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index ee7134f90122..33003b53ed55 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -1,16 +1,16 @@ import { Redirect } from '@sveltejs/kit/internal'; -import { with_request_store } from '@sveltejs/kit/internal/server'; +import { with_event } from '@sveltejs/kit/internal/server'; import { BODY_DEPENDENT_METHODS, ENDPOINT_METHODS, PAGE_METHODS } from '../../constants.js'; import { negotiate } from '../../utils/http.js'; import { method_not_allowed } from './utils.js'; /** * @param {import('@sveltejs/kit/internal/server').RequestEvent} event - * @param {import('types').RequestState} state * @param {import('types').SSREndpoint} mod * @returns {Promise} */ -export async function render_endpoint(event, state, mod) { +export async function render_endpoint(event, mod) { + const state = event.state; const method = /** @type {import('types').HttpMethod} */ (event.request.method); let handler = mod[method] || mod.fallback; @@ -46,7 +46,7 @@ export async function render_endpoint(event, state, mod) { } try { - const response = await with_request_store({ event, state }, () => handler(event)); + const response = await with_event(event, () => handler(event)); if (!(response instanceof Response)) { throw new Error( diff --git a/packages/kit/src/runtime/server/errors.js b/packages/kit/src/runtime/server/errors.js index f46db4614278..5ae6c615b9ce 100644 --- a/packages/kit/src/runtime/server/errors.js +++ b/packages/kit/src/runtime/server/errors.js @@ -4,18 +4,17 @@ import { SvelteKitError, ValidationError } from '@sveltejs/kit/internal'; -import { with_request_store } from '@sveltejs/kit/internal/server'; +import { with_event } from '@sveltejs/kit/internal/server'; import { add_deprecated_handle_error_properties, coalesce_to_error } from '../../utils/error.js'; // `$app/server` reaches this module, so it must not import anything generated import { fix_stack_trace, hooks } from './internal.js'; /** * @param {import('@sveltejs/kit/internal/server').RequestEvent} event - * @param {import('types').RequestState} state * @param {any} error * @returns {App.Error | Promise} */ -export function handle_error_and_jsonify(event, state, error) { +export function handle_error_and_jsonify(event, error) { if (error instanceof HandledHttpError) { return error.body; } @@ -62,7 +61,7 @@ export function handle_error_and_jsonify(event, state, error) { const input = { ...caught, event }; if (__SVELTEKIT_DEV__) add_deprecated_handle_error_properties(input, fallback); - result = with_request_store({ event, state }, () => hooks.handleError(input)); + result = with_event(event, () => hooks.handleError(input)); } catch (hook_error) { log_handle_error_hook_failure(error, hook_error); return { status: fallback.status, message: 'Internal Error' }; diff --git a/packages/kit/src/runtime/server/fetch.js b/packages/kit/src/runtime/server/fetch.js index 823ab261da10..5d355b1ce38a 100644 --- a/packages/kit/src/runtime/server/fetch.js +++ b/packages/kit/src/runtime/server/fetch.js @@ -9,13 +9,13 @@ import { fork_state_for_subrequest } from './state.js'; /** * @param {{ * event: import('@sveltejs/kit/internal/server').RequestEvent; - * state: import('types').RequestState; * get_cookie_header: (url: URL, header: string | null) => string; * set_internal: (name: string, value: string, opts: import('./page/types.js').Cookie['options']) => void; * }} opts * @returns {typeof fetch} */ -export function create_fetch({ event, state, get_cookie_header, set_internal }) { +export function create_fetch({ event, get_cookie_header, set_internal }) { + const state = event.state; /** * @type {typeof fetch} */ diff --git a/packages/kit/src/runtime/server/page/actions.js b/packages/kit/src/runtime/server/page/actions.js index d415efce386e..63f83ba7dca6 100644 --- a/packages/kit/src/runtime/server/page/actions.js +++ b/packages/kit/src/runtime/server/page/actions.js @@ -4,7 +4,7 @@ /** @import { SSRNode, ServerNode, ServerActionResult } from 'types' */ import { DEV } from 'esm-env'; import { HttpError, Redirect, ActionFailure, SvelteKitError } from '@sveltejs/kit/internal'; -import { with_request_store, merge_tracing, record_span } from '@sveltejs/kit/internal/server'; +import { with_event, merge_tracing, record_span } from '@sveltejs/kit/internal/server'; import { normalize_error } from '../../../utils/error.js'; import { is_form_content_type, negotiate } from '../../../utils/http.js'; import { with_version_header } from '../utils.js'; @@ -23,27 +23,25 @@ export function is_action_json_request(event) { /** * @param {RequestEvent} event - * @param {import('types').RequestState} state * @param {SSRNode['server'] | undefined} server */ -export async function handle_action_json_request(event, state, server) { - const result = await handle_action_request(event, state, server); - return action_result_json(event, state, result); +export async function handle_action_json_request(event, server) { + const result = await handle_action_request(event, server); + return action_result_json(event, result); } /** * @param {RequestEvent} event - * @param {import('types').RequestState} state * @param {ServerActionResult} result * @returns {Promise} */ -async function action_result_json(event, state, result) { +async function action_result_json(event, result) { if (result.type === 'redirect') { return action_json(result); } if (result.type === 'error') { - const error = await handle_error_and_jsonify(event, state, result.error); + const error = await handle_error_and_jsonify(event, result.error); return action_json({ ...result, error }, { status: error.status }); } @@ -63,7 +61,7 @@ async function action_result_json(event, state, result) { { status: result.status } ); } catch (e) { - return action_result_json(event, state, action_error_result(e, result.location)); + return action_result_json(event, action_error_result(e, result.location)); } } @@ -156,11 +154,10 @@ export function is_action_request(event) { /** * @param {RequestEvent} event - * @param {import('types').RequestState} state * @param {SSRNode['server'] | undefined} server * @returns {Promise} */ -export async function handle_action_request(event, state, server) { +export async function handle_action_request(event, server) { const actions = server?.actions; const location = get_action_location(event.url); @@ -172,7 +169,7 @@ export async function handle_action_request(event, state, server) { check_named_default_separate(actions); try { - const data = await call_action(event, state, actions); + const data = await call_action(event, actions); if (DEV) { validate_action_return(data); @@ -215,11 +212,10 @@ function check_named_default_separate(actions) { /** * @param {RequestEvent} event - * @param {import('types').RequestState} state * @param {NonNullable} actions * @throws {Redirect | HttpError | SvelteKitError | Error} */ -async function call_action(event, state, actions) { +async function call_action(event, actions) { const url = new URL(event.request.url); let name = 'default'; @@ -258,9 +254,7 @@ async function call_action(event, state, actions) { fn: async (current) => { const traced_event = merge_tracing(event, current); - const result = await with_request_store({ event: traced_event, state }, () => - action(traced_event) - ); + const result = await with_event(traced_event, () => action(traced_event)); if (result instanceof ActionFailure) { current.setAttributes({ diff --git a/packages/kit/src/runtime/server/page/data_serializer.js b/packages/kit/src/runtime/server/page/data_serializer.js index c2aef76ca7a3..10969cf215d5 100644 --- a/packages/kit/src/runtime/server/page/data_serializer.js +++ b/packages/kit/src/runtime/server/page/data_serializer.js @@ -9,10 +9,9 @@ import { encoders } from '#app/internal/transport'; * If the serialized data contains promises, `chunks` will be an * async iterable containing their resolutions * @param {import('@sveltejs/kit/internal/server').RequestEvent} event - * @param {import('types').RequestState} state * @returns {import('./types.js').ServerDataSerializer} */ -export function server_data_serializer(event, state) { +export function server_data_serializer(event) { let promise_id = 1; let max_nodes = -1; @@ -30,7 +29,7 @@ export function server_data_serializer(event, state) { .then(/** @param {any} data */ (data) => ({ data })) .catch( /** @param {any} error */ async (error) => ({ - error: await handle_error_and_jsonify(event, state, error) + error: await handle_error_and_jsonify(event, error) }) ) .then( @@ -44,7 +43,6 @@ export function server_data_serializer(event, state) { } catch (e) { error = await handle_error_and_jsonify( event, - state, new Error(`Failed to serialize promise while rendering ${event.route.id}`, { cause: e }) @@ -124,10 +122,9 @@ export function server_data_serializer(event, state) { * If the serialized data contains promises, `chunks` will be an * async iterable containing their resolutions * @param {import('@sveltejs/kit/internal/server').RequestEvent} event - * @param {import('types').RequestState} state * @returns {import('./types.js').ServerDataSerializerJson} */ -export function server_data_serializer_json(event, state) { +export function server_data_serializer_json(event) { let promise_id = 1; const iterator = create_async_iterator(); @@ -149,7 +146,7 @@ export function server_data_serializer_json(event, state) { .catch( /** @param {any} e */ async (e) => { key = 'error'; - return handle_error_and_jsonify(event, state, /** @type {any} */ (e)); + return handle_error_and_jsonify(event, /** @type {any} */ (e)); } ) .then( @@ -161,7 +158,6 @@ export function server_data_serializer_json(event, state) { } catch (e) { const error = await handle_error_and_jsonify( event, - state, new Error(`Failed to serialize promise while rendering ${event.route.id}`, { cause: e }) diff --git a/packages/kit/src/runtime/server/page/index.js b/packages/kit/src/runtime/server/page/index.js index 0cb892d35d5f..879db0d72de6 100644 --- a/packages/kit/src/runtime/server/page/index.js +++ b/packages/kit/src/runtime/server/page/index.js @@ -1,5 +1,5 @@ /** @import { RequestEvent } from '@sveltejs/kit/internal/server' */ -/** @import { PageNodeIndexes, RequestState, RequiredResolveOptions, ServerDataNode, SSRNode } from 'types' */ +/** @import { PageNodeIndexes, RequiredResolveOptions, ServerDataNode, SSRNode } from 'types' */ import { text } from '@sveltejs/kit'; import { Redirect } from '@sveltejs/kit/internal'; import { compact } from '../../../utils/array.js'; @@ -31,13 +31,13 @@ const MAX_DEPTH = 10; /** * @param {RequestEvent} event - * @param {RequestState} state * @param {PageNodeIndexes} page * @param {import('../../../utils/page_nodes.js').PageNodes} nodes * @param {RequiredResolveOptions} resolve_opts * @returns {Promise} */ -export async function render_page(event, state, page, nodes, resolve_opts) { +export async function render_page(event, page, nodes, resolve_opts) { + const state = event.state; if (state.depth > MAX_DEPTH) { // infinite request cycle detected return text(`Not found: ${event.url.pathname}`, { @@ -47,7 +47,7 @@ export async function render_page(event, state, page, nodes, resolve_opts) { if (is_action_json_request(event)) { const node = await manifest.nodes[page.leaf](); - return handle_action_json_request(event, state, node?.server); + return handle_action_json_request(event, node?.server); } try { @@ -61,11 +61,11 @@ export async function render_page(event, state, page, nodes, resolve_opts) { if (is_action_request(event)) { const remote_id = get_remote_action(event.url); if (remote_id) { - action_result = await handle_remote_form_post(event, state, remote_id); + action_result = await handle_remote_form_post(event, remote_id); } else { // for action requests, first call handler in +page.server.js // (this also determines status code) - action_result = await handle_action_request(event, state, leaf_node.server); + action_result = await handle_action_request(event, leaf_node.server); } if (action_result?.type === 'redirect') { @@ -148,9 +148,8 @@ export async function render_page(event, state, page, nodes, resolve_opts) { status, error: null, event, - state, resolve_opts, - data_serializer: server_data_serializer(event, state) + data_serializer: server_data_serializer(event) }); } @@ -160,10 +159,10 @@ export async function render_page(event, state, page, nodes, resolve_opts) { /** @type {Error | null} */ let load_error = null; - const data_serializer = server_data_serializer(event, state); + const data_serializer = server_data_serializer(event); const data_serializer_json = (state.prerendering || state.prerender_default === true) && should_prerender_data - ? server_data_serializer_json(event, state) + ? server_data_serializer_json(event) : null; /** @type {Array>} */ @@ -183,7 +182,6 @@ export async function render_page(event, state, page, nodes, resolve_opts) { const server_data = await load_server_data({ event, - state, node, parent: async () => { /** @type {Record} */ @@ -217,7 +215,6 @@ export async function render_page(event, state, page, nodes, resolve_opts) { try { return await load_data({ event, - state, fetched, node, parent: async () => { @@ -271,7 +268,7 @@ export async function render_page(event, state, page, nodes, resolve_opts) { return redirect_response(err.status, err.location); } - const error = await handle_error_and_jsonify(event, state, err); + const error = await handle_error_and_jsonify(event, err); const status = error.status; for (const { error: index, idx } of nearest_error_pages(i, branch, page.errors)) { @@ -289,7 +286,6 @@ export async function render_page(event, state, page, nodes, resolve_opts) { return await render_response({ event, - state, resolve_opts, page_config: { ssr: nodes.ssr(), @@ -333,7 +329,6 @@ export async function render_page(event, state, page, nodes, resolve_opts) { return await render_response({ event, - state, resolve_opts, page_config: { csr, @@ -344,7 +339,7 @@ export async function render_page(event, state, page, nodes, resolve_opts) { branch: compact(branch), action_result, fetched, - data_serializer: !ssr ? server_data_serializer(event, state) : data_serializer, + data_serializer: !ssr ? server_data_serializer(event) : data_serializer, error_components: await load_error_components(ssr, branch, page) }); } catch (e) { @@ -357,7 +352,6 @@ export async function render_page(event, state, page, nodes, resolve_opts) { // but the page failed to render, or that a prerendering error occurred return await respond_with_error({ event, - state, error: e, resolve_opts }); diff --git a/packages/kit/src/runtime/server/page/load_data.js b/packages/kit/src/runtime/server/page/load_data.js index a2b64e6a91fc..148f60768b18 100644 --- a/packages/kit/src/runtime/server/page/load_data.js +++ b/packages/kit/src/runtime/server/page/load_data.js @@ -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 { fetch_cache_url, validate_depends, validate_load_response } from '../../shared.js'; -import { with_request_store, merge_tracing, record_span } from '@sveltejs/kit/internal/server'; +import { with_event, merge_tracing, record_span } from '@sveltejs/kit/internal/server'; import { base64_encode } from '../../utils.js'; import { NULL_BODY_STATUS } from '../constants.js'; import { get_node_type } from '../utils.js'; @@ -11,13 +11,13 @@ import { get_node_type } from '../utils.js'; * Calls the user's server `load` function. * @param {{ * event: import('@sveltejs/kit/internal/server').RequestEvent; - * state: import('types').RequestState; * node: import('types').SSRNode | undefined; * parent: () => Promise>; * }} opts * @returns {Promise} */ -export async function load_server_data({ event, state, node, parent }) { +export async function load_server_data({ event, node, parent }) { + const state = event.state; if (!node?.server) return null; let is_tracking = true; @@ -81,7 +81,7 @@ export async function load_server_data({ event, state, node, parent }) { }, fn: async (current) => { const traced_event = merge_tracing(event, current); - const result = await with_request_store({ event: traced_event, state }, () => + const result = await with_event(traced_event, () => load.call(null, { ...traced_event, fetch: (info, init) => { @@ -192,7 +192,6 @@ export async function load_server_data({ event, state, node, parent }) { * Calls the user's `load` function. * @param {{ * event: import('@sveltejs/kit/internal/server').RequestEvent; - * state: import('types').RequestState; * fetched: import('./types.js').Fetched[]; * node: import('types').SSRNode | undefined; * parent: () => Promise>; @@ -204,7 +203,6 @@ export async function load_server_data({ event, state, node, parent }) { */ export async function load_data({ event, - state, fetched, node, parent, @@ -212,6 +210,7 @@ export async function load_data({ resolve_opts, csr }) { + const state = event.state; const server_data_node = await server_data_promise; const load = node?.universal?.load; @@ -231,7 +230,7 @@ export async function load_data({ fn: async (current) => { const traced_event = merge_tracing(event, current); - return await with_request_store({ event: traced_event, state }, () => + return await with_event(traced_event, () => load.call(null, { url: event.url, params: event.params, diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index ee6ade8dc62a..b6a6da2a5569 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -18,7 +18,7 @@ import { add_resolution_suffix, route_id_resolution_pathname } from '../../pathname.js'; -import { try_get_request_store, with_request_store, RENDER } from '@sveltejs/kit/internal/server'; +import { try_get_event, with_event, RENDER } from '@sveltejs/kit/internal/server'; import { stream_text } from '../../utils.js'; import { count_non_ssi_comments } from '../utils.js'; import { handle_error_and_jsonify } from '../errors.js'; @@ -42,7 +42,6 @@ import { options } from '/server.js'; * status: number; * error: App.Error | null; * event: import('@sveltejs/kit/internal/server').RequestEvent; - * state: import('types').RequestState; * resolve_opts: import('types').RequiredResolveOptions; * action_result?: import('types').ServerActionResult; * data_serializer: import('./types.js').ServerDataSerializer; @@ -56,12 +55,12 @@ export async function render_response({ status, error = null, event, - state, resolve_opts, action_result, data_serializer, error_components }) { + const state = event.state; if (state.prerendering || state.prerender_default === true) { if (options.csp.mode === 'nonce') { throw new Error('Cannot use prerendering if config.csp.mode === "nonce"'); @@ -201,7 +200,7 @@ export async function render_response({ throw e; } - const handled = handle_error_and_jsonify(render_event, state, e); + const handled = handle_error_and_jsonify(render_event, e); // TODO 4.0 make this an async function and await `handled` if (handled instanceof Promise) { @@ -232,7 +231,7 @@ export async function render_response({ throw new Error( `Cannot call \`fetch\` eagerly during server-side rendering with relative URL (${info}) — put your \`fetch\` calls inside \`onMount\` or a \`load\` function instead` ); - } else if (!warned && !(try_get_request_store()?.event ?? event).in_remote) { + } else if (!warned && !(try_get_event() ?? event).in_remote) { console.warn( 'Avoid calling `fetch` eagerly during server-side rendering — put your `fetch` calls inside `onMount` or a `load` function instead' ); @@ -243,7 +242,7 @@ export async function render_response({ }; } - rendered = await with_request_store({ event: render_event, state }, async () => { + rendered = await with_event(render_event, async () => { return render(Root, { ...render_opts, props }); }); @@ -518,7 +517,7 @@ export async function render_response({ args.push(`{\n${indent}\t${hydrate.join(`,\n${indent}\t`)}\n${indent}}`); } - const remote_data = await collect_remote_data({}, event, state); + const remote_data = await collect_remote_data({}, event); const serialized_data = Object.keys(remote_data).length > 0 diff --git a/packages/kit/src/runtime/server/page/respond_with_error.js b/packages/kit/src/runtime/server/page/respond_with_error.js index 6769a1d5729e..e56d4c5d664b 100644 --- a/packages/kit/src/runtime/server/page/respond_with_error.js +++ b/packages/kit/src/runtime/server/page/respond_with_error.js @@ -18,15 +18,15 @@ import { escape_html } from '../../../utils/escape.js'; /** * @param {{ * event: import('@sveltejs/kit/internal/server').RequestEvent; - * state: import('types').RequestState; * error: unknown; * resolve_opts: import('types').RequiredResolveOptions; * }} opts */ -export async function respond_with_error({ event, state, error, resolve_opts }) { +export async function respond_with_error({ event, error, resolve_opts }) { + const state = event.state; // reroute to the fallback page to prevent an infinite chain of requests. if (event.request.headers.get('x-sveltekit-error')) { - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); return static_error_page(transformed.status, transformed.message); } @@ -38,16 +38,15 @@ export async function respond_with_error({ event, state, error, resolve_opts }) const nodes = new PageNodes([default_layout]); const ssr = nodes.ssr(); const csr = nodes.csr(); - const data_serializer = server_data_serializer(event, state); + const data_serializer = server_data_serializer(event); // Do this here first in case the awaits below before rendering themselves error - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); if (ssr) { state.error = true; const server_data_promise = load_server_data({ event, - state, node: default_layout, // eslint-disable-next-line @typescript-eslint/require-await parent: async () => ({}) @@ -58,7 +57,6 @@ export async function respond_with_error({ event, state, error, resolve_opts }) const data = await load_data({ event, - state, fetched, node: default_layout, // eslint-disable-next-line @typescript-eslint/require-await @@ -93,7 +91,6 @@ export async function respond_with_error({ event, state, error, resolve_opts }) error_components: [], fetched, event, - state, resolve_opts, data_serializer }); @@ -104,7 +101,7 @@ export async function respond_with_error({ event, state, error, resolve_opts }) return redirect_response(e.status, e.location); } - const transformed = await handle_error_and_jsonify(event, state, e); + const transformed = await handle_error_and_jsonify(event, e); return static_error_page(transformed.status, transformed.message); } @@ -132,11 +129,10 @@ export function static_error_page(status, message) { /** * @param {import('@sveltejs/kit/internal/server').RequestEvent} event - * @param {import('types').RequestState} state * @param {unknown} error */ -export async function handle_fatal_error(event, state, error) { - const body = await handle_error_and_jsonify(event, state, error); +export async function handle_fatal_error(event, error) { + const body = await handle_error_and_jsonify(event, error); const status = body.status; // sec-fetch-dest would be nicer, but non-browser clients and plain HTTP hosts don't send it diff --git a/packages/kit/src/runtime/server/remote-functions.js b/packages/kit/src/runtime/server/remote-functions.js index dac97d0661ce..92d0d5af044d 100644 --- a/packages/kit/src/runtime/server/remote-functions.js +++ b/packages/kit/src/runtime/server/remote-functions.js @@ -1,10 +1,10 @@ /** @import { RequestEvent } from '@sveltejs/kit/internal/server' */ /** @import { RemoteForm } from '$app/server' */ -/** @import { RemoteFormInternals, RemoteFunctionData, RemoteFunctionResponse, RemoteInternals, RequestState, ServerActionResult } from 'types' */ +/** @import { RemoteFormInternals, RemoteFunctionData, RemoteFunctionResponse, RemoteInternals, ServerActionResult } from 'types' */ import { error } from '@sveltejs/kit'; import { Redirect, SvelteKitError } from '@sveltejs/kit/internal'; -import { with_request_store, merge_tracing, record_span } from '@sveltejs/kit/internal/server'; +import { with_event, merge_tracing, record_span } from '@sveltejs/kit/internal/server'; import { app_dir, base } from '#app/paths'; import { is_form_content_type } from '../../utils/http.js'; import { create_remote_key, parse_remote_arg, split_remote_key } from '../shared.js'; @@ -29,11 +29,10 @@ const KEEP_ALIVE_INTERVAL = 30_000; /** * @param {RequestEvent} event - * @param {RequestState} state * @param {import('types').RemoteQueryLiveInternals} internals * @param {any} arg */ -export function create_live_query_response(event, state, internals, arg) { +export function create_live_query_response(event, internals, arg) { const cancellation = new AbortController(); const live_event = event.clone(0, { request: new Request(event.request, { @@ -41,7 +40,7 @@ export function create_live_query_response(event, state, internals, arg) { }) }); - const generator = internals.run(live_event, state, arg); + const generator = internals.run(live_event, arg); let open = true; let pulling = false; @@ -116,7 +115,7 @@ export function create_live_query_response(event, state, internals, arg) { if (error instanceof Redirect) { send({ type: 'redirect', location: error.location }); } else { - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); send({ type: 'error', error: transformed }); } @@ -140,7 +139,7 @@ export function create_live_query_response(event, state, internals, arg) { } /** @type {typeof handle_remote_call_internal} */ -export async function handle_remote_call(event, state, id) { +export async function handle_remote_call(event, id) { return record_span({ name: 'sveltekit.remote.call', attributes: { @@ -148,8 +147,8 @@ export async function handle_remote_call(event, state, 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, id) + const response = await with_event(traced_event, () => + handle_remote_call_internal(traced_event, id) ); return with_version_header(response); } @@ -158,10 +157,10 @@ export async function handle_remote_call(event, state, id) { /** * @param {RequestEvent} event - * @param {RequestState} state * @param {string} id */ -async function handle_remote_call_internal(event, state, id) { +async function handle_remote_call_internal(event, id) { + const state = event.state; const [hash, name, additional_args] = id.split('/'); const remotes = manifest.remotes; @@ -201,7 +200,7 @@ async function handle_remote_call_internal(event, state, id) { new URL(event.request.url).searchParams.get('payload') ); - return create_live_query_response(event, state, internals, parse_remote_arg(payload)); + return create_live_query_response(event, internals, parse_remote_arg(payload)); } case 'query_batch': { @@ -218,7 +217,7 @@ async function handle_remote_call_internal(event, state, id) { const args = await Promise.all(payloads.map((payload) => parse_remote_arg(payload))); - data._ = await with_request_store({ event, state }, () => internals.run(args)); + data._ = await with_event(event, () => internals.run(args)); break; } @@ -256,7 +255,7 @@ async function handle_remote_call_internal(event, state, id) { } const fn = internals.fn; - data._ = await with_request_store({ event, state }, () => fn(input, meta, form_data)); + data._ = await with_event(event, () => fn(input, meta, form_data)); if (data._.issues) { // special case — don't serialize refreshes/reconnects @@ -278,15 +277,13 @@ async function handle_remote_call_internal(event, state, id) { state.remote.requested = create_requested_map(refreshes); const arg = parse_remote_arg(payload); - data._ = await with_request_store({ event, state }, () => fn(arg)); + data._ = await with_event(event, () => fn(arg)); break; } case 'prerender': { - data._ = await with_request_store({ event, state }, () => - fn(parse_remote_arg(additional_args)) - ); + data._ = await with_event(event, () => fn(parse_remote_arg(additional_args))); break; } @@ -297,13 +294,13 @@ async function handle_remote_call_internal(event, state, id) { new URL(event.request.url).searchParams.get('payload') ); - data._ = await with_request_store({ event, state }, () => fn(parse_remote_arg(payload))); + data._ = await with_event(event, () => fn(parse_remote_arg(payload))); break; } } - await collect_remote_data(data, event, state); + await collect_remote_data(data, event); if (state.remote.ignored?.size) data.i = Array.from(state.remote.ignored); return Response.json( @@ -315,7 +312,7 @@ async function handle_remote_call_internal(event, state, id) { ); } catch (error) { if (error instanceof Redirect) { - const data = await collect_remote_data({ redirect: error.location }, event, state); + const data = await collect_remote_data({ redirect: error.location }, event); return Response.json( /** @type {RemoteFunctionResponse} */ ({ @@ -326,7 +323,7 @@ async function handle_remote_call_internal(event, state, id) { ); } - const transformed = await handle_error_and_jsonify(event, state, error); + const transformed = await handle_error_and_jsonify(event, error); return Response.json( /** @type {RemoteFunctionResponse} */ ({ @@ -350,9 +347,9 @@ async function handle_remote_call_internal(event, state, id) { * during the request and adds it to `data` * @param {RemoteFunctionData} data * @param {RequestEvent} event - * @param {RequestState} state */ -export async function collect_remote_data(data, event, state) { +export async function collect_remote_data(data, event) { + const state = event.state; /** * * @param {unknown} error @@ -360,7 +357,7 @@ export async function collect_remote_data(data, event, state) { */ function convert_error(error) { // TODO 4.0 remove the `Promise.resolve(...)` - return Promise.resolve(handle_error_and_jsonify(event, state, error)); + return Promise.resolve(handle_error_and_jsonify(event, error)); } /** @type {Promise[]} */ @@ -506,7 +503,7 @@ function create_requested_map(refreshes) { } /** @type {typeof handle_remote_form_post_internal} */ -export async function handle_remote_form_post(event, state, id) { +export async function handle_remote_form_post(event, id) { return record_span({ name: 'sveltekit.remote.form.post', attributes: { @@ -514,20 +511,17 @@ export async function handle_remote_form_post(event, state, 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, id) - ); + return with_event(traced_event, () => handle_remote_form_post_internal(traced_event, id)); } }); } /** * @param {RequestEvent} event - * @param {RequestState} state * @param {string} id * @returns {Promise} */ -async function handle_remote_form_post_internal(event, state, id) { +async function handle_remote_form_post_internal(event, id) { const location = get_action_location(event.url); // `hash` and `name` can never contain a `/`, but the JSON-stringified key of a // keyed (`form.for(key)`) instance can — rejoin the remaining segments @@ -546,7 +540,7 @@ async function handle_remote_form_post_internal(event, state, id) { if (action_id) { // @ts-expect-error - form = with_request_store({ event, state }, () => form.for(JSON.parse(action_id))); + form = with_event(event, () => form.for(JSON.parse(action_id))); } try { @@ -558,7 +552,7 @@ async function handle_remote_form_post_internal(event, state, id) { data.id = JSON.parse(decodeURIComponent(action_id)); } - await with_request_store({ event, state }, () => __.fn(data, meta, form_data)); + await with_event(event, () => __.fn(data, meta, form_data)); // We don't want the data to appear on `let { form } = $props()`, which is why we're not returning it. // It is instead available on `myForm.result`, setting of which happens within the remote `form` function. diff --git a/packages/kit/src/runtime/server/remote-functions.spec.js b/packages/kit/src/runtime/server/remote-functions.spec.js index 38f72575f5d7..2cd3bcde8e03 100644 --- a/packages/kit/src/runtime/server/remote-functions.spec.js +++ b/packages/kit/src/runtime/server/remote-functions.spec.js @@ -1,6 +1,6 @@ import { beforeAll, expect, test, vi } from 'vitest'; import { init_transport, parse } from '#app/internal/transport'; -import { get_request_store, RequestEvent } from '@sveltejs/kit/internal/server'; +import { get_event, RequestEvent } from '@sveltejs/kit/internal/server'; const decoder = new TextDecoder(); @@ -25,15 +25,15 @@ beforeAll(async () => { */ function create_response(run) { const event = new RequestEvent( - /** @type {import('@sveltejs/kit').RequestEvent} */ ({ + /** @type {any} */ ({ request: new Request('http://localhost/_app/remote/test?payload=undefined') }), - 0 + 0, + /** @type {any} */ ({}) ); return create_live_query_response( event, - /** @type {import('types').RequestState} */ ({}), /** @type {import('types').RemoteQueryLiveInternals} */ (/** @type {unknown} */ ({ run })), undefined ); @@ -106,7 +106,7 @@ test('cancellation aborts the generator request signal and runs cleanup', async test('serializes explicitly ignored requested updates', async () => { const command = () => { - get_request_store().state.remote.ignored = new Set(['hash/query/[-1]']); + get_event().state.remote.ignored = new Set(['hash/query/[-1]']); return null; }; Object.assign(command, { __: { type: 'command', name: 'command', fn: command } }); @@ -118,7 +118,7 @@ test('serializes explicitly ignored requested updates', async () => { }) ); - const response = await handle_remote_call( + const event = new RequestEvent( /** @type {any} */ ({ request: new Request('http://localhost/_app/remote/hash/command', { method: 'POST', @@ -126,10 +126,12 @@ test('serializes explicitly ignored requested updates', async () => { }), tracing: { current: { setAttributes: vi.fn() } } }), - /** @type {any} */ ({ remote: { requested: null, ignored: null } }), - 'hash/command' + 0, + /** @type {any} */ ({ remote: { requested: null, ignored: null } }) ); + const response = await handle_remote_call(event, 'hash/command'); + const result = await response.json(); expect(parse(result.data)).toEqual({ _: null, i: ['hash/query/[-1]'] }); }); diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index 7442dcde9b2e..e842e957a003 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -6,7 +6,7 @@ import { merge_tracing, otel, record_span, - with_request_store, + with_event, RequestEvent } from '@sveltejs/kit/internal/server'; import { base, app_dir } from '#app/paths'; @@ -209,7 +209,6 @@ export async function internal_respond(request, state) { event.fetch = create_fetch({ event, - state, get_cookie_header, set_internal }); @@ -296,7 +295,7 @@ export async function internal_respond(request, state) { statusText: response.statusText }); } catch (error) { - return await handle_fatal_error(event, state, error); + return await handle_fatal_error(event, error); } } @@ -340,7 +339,7 @@ export async function internal_respond(request, state) { event.params = result.params; } } catch (e) { - return await handle_fatal_error(event, state, e); + return await handle_fatal_error(event, e); } } @@ -420,10 +419,10 @@ export async function internal_respond(request, state) { add_cookies_to_headers(response.headers, new_cookies.values()); return response; } catch (err) { - return await handle_fatal_error(event, state, err); + return await handle_fatal_error(event, err); } } - return await handle_fatal_error(event, state, e); + return await handle_fatal_error(event, e); } async function handle() { @@ -451,7 +450,7 @@ export async function internal_respond(request, state) { } }); - return await with_request_store({ event: traced_event, state }, () => + return await with_event(traced_event, () => hooks.handle({ event: traced_event, resolve: (event, opts) => { @@ -463,7 +462,7 @@ export async function internal_respond(request, state) { fn: (resolve_span) => { // 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, () => + return with_event(null, () => resolve(merge_tracing(event, resolve_span), page_nodes, opts).then( (response) => { // add headers/cookies here, rather than inside `resolve`, so that we @@ -557,7 +556,6 @@ export async function internal_respond(request, state) { if (resolved_path === null) { return await respond_with_error({ event, - state, error: new SvelteKitError( 400, 'Malformed URI', @@ -570,7 +568,6 @@ export async function internal_respond(request, state) { if (__SVELTEKIT_HASH_ROUTING__ || state.prerendering?.fallback) { return await render_response({ event, - state, page_config: { ssr: false, csr: true }, status: 200, error: null, @@ -584,12 +581,12 @@ export async function internal_respond(request, state) { ], fetched: [], resolve_opts, - data_serializer: server_data_serializer(event, state) + data_serializer: server_data_serializer(event) }); } if (remote_id) { - return await handle_remote_call(event, state, remote_id); + return await handle_remote_call(event, remote_id); } if (route) { @@ -599,7 +596,7 @@ export async function internal_respond(request, state) { let response; if (is_data_request) { - response = await render_data(event, state, route, invalidated_data_nodes, trailing_slash); + response = await render_data(event, route, invalidated_data_nodes, trailing_slash); } else { let endpoint; if ( @@ -621,12 +618,12 @@ export async function internal_respond(request, state) { } if (endpoint) { - response = await render_endpoint(event, state, endpoint); + response = await render_endpoint(event, endpoint); } else if (route.page) { if (!page_nodes) { throw new Error('page_nodes not found. This should never happen'); } else if (page_methods.has(method)) { - response = await render_page(event, state, route.page, page_nodes, resolve_opts); + response = await render_page(event, route.page, page_nodes, resolve_opts); } else { const allowed_methods = new Set(allowed_page_methods); const node = await manifest.nodes[route.page.leaf](); @@ -709,7 +706,6 @@ export async function internal_respond(request, state) { ) { return await render_data( event, - state, { page: { layouts: [], leaf: 0 } }, invalidated_data_nodes, // there is no route to take a trailing slash option from, and the @@ -727,7 +723,6 @@ export async function internal_respond(request, state) { return await respond_with_error({ event, - state, error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`), resolve_opts }); @@ -748,7 +743,7 @@ export async function internal_respond(request, state) { // and I don't even know how to describe it. need to investigate at some point // HttpError from endpoint can end up here - TODO should it be handled there instead? - return await handle_fatal_error(event, state, e); + return await handle_fatal_error(event, e); } finally { state.responded = true; event.cookies.set = () => { diff --git a/packages/kit/src/types/internal.d.ts b/packages/kit/src/types/internal.d.ts index 51d0304e579e..8742ee7ea824 100644 --- a/packages/kit/src/types/internal.d.ts +++ b/packages/kit/src/types/internal.d.ts @@ -625,7 +625,10 @@ export interface RemoteQueryInternals extends BaseRemoteInternals { export interface RemoteQueryLiveInternals extends BaseRemoteInternals { type: 'query_live'; validate: (arg?: any) => MaybePromise; - run(event: RequestEvent, state: RequestState, arg: any): AsyncGenerator; + run( + event: import('../exports/internal/server/event.js').RequestEvent, + arg: any + ): AsyncGenerator; /** * Creates a `RemoteLiveQuery` bound directly to a specific client payload (the * stringified raw argument) and a pre-validated argument, skipping the query @@ -786,11 +789,6 @@ export interface RequestState { }; } -export interface RequestStore { - event: import('../exports/internal/server/event.js').RequestEvent; - state: RequestState; -} - /** Type of the `__sveltekit_abc123` object in the init `