From 1c6067e5de00c9d8b5b2e19dc3eaef08bde13987 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 17:42:58 +0000 Subject: [PATCH 01/14] Saving progress on websockets for discussion --- packages/kit/src/exports/public.d.ts | 52 +++-- packages/kit/src/exports/vite/dev/index.js | 84 ++++++-- packages/kit/src/runtime/app/server/index.js | 1 + packages/kit/src/runtime/server/endpoint.js | 49 +++-- packages/kit/src/runtime/server/index.js | 5 +- packages/kit/src/runtime/server/respond.js | 26 ++- packages/kit/src/types/internal.d.ts | 19 +- packages/kit/src/utils/exports.js | 1 + packages/kit/test/apps/ws/README.md | 1 + packages/kit/test/apps/ws/package.json | 27 +++ .../kit/test/apps/ws/playwright.config.js | 1 + packages/kit/test/apps/ws/src/app.html | 11 + .../kit/test/apps/ws/src/routes/+page.svelte | 29 +++ .../kit/test/apps/ws/src/routes/ws/+server.ts | 18 ++ packages/kit/test/apps/ws/svelte.config.js | 6 + packages/kit/test/apps/ws/test/test.js | 89 ++++++++ packages/kit/test/apps/ws/tsconfig.json | 8 + packages/kit/test/apps/ws/vite.config.js | 14 ++ pnpm-lock.yaml | 200 ++++++++++++++++++ 19 files changed, 570 insertions(+), 71 deletions(-) create mode 100644 packages/kit/test/apps/ws/README.md create mode 100644 packages/kit/test/apps/ws/package.json create mode 100644 packages/kit/test/apps/ws/playwright.config.js create mode 100644 packages/kit/test/apps/ws/src/app.html create mode 100644 packages/kit/test/apps/ws/src/routes/+page.svelte create mode 100644 packages/kit/test/apps/ws/src/routes/ws/+server.ts create mode 100644 packages/kit/test/apps/ws/svelte.config.js create mode 100644 packages/kit/test/apps/ws/test/test.js create mode 100644 packages/kit/test/apps/ws/tsconfig.json create mode 100644 packages/kit/test/apps/ws/vite.config.js diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 77be062a3163..a8357260f964 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -19,6 +19,8 @@ import { } from '../types/private.js'; import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types'; import type { PluginOptions } from '@sveltejs/vite-plugin-svelte'; +import type { IncomingMessage } from 'node:http'; +import type { Duplex } from 'node:stream'; export { PrerenderOption } from '../types/private.js'; @@ -315,7 +317,7 @@ export interface KitConfig { /** * The directory where SvelteKit keeps its stuff, including static assets (such as JS and CSS) and internally-used routes. * - * If `paths.assets` is specified, there will be two app directories — `${paths.assets}/${appDir}` and `${paths.base}/${appDir}`. + * If `paths.assets` is specified, there will be two app directories - `${paths.assets}/${appDir}` and `${paths.base}/${appDir}`. * @default "_app" */ appDir?: string; @@ -548,10 +550,10 @@ export interface KitConfig { /** * How to respond to HTTP errors encountered while prerendering the app. * - * - `'fail'` — fail the build + * - `'fail'` - fail the build * - `'ignore'` - silently ignore the failure and continue - * - `'warn'` — continue, but print a warning - * - `(details) => void` — a custom error handler that takes a `details` object with `status`, `path`, `referrer`, `referenceType` and `message` properties. If you `throw` from this function, the build will fail + * - `'warn'` - continue, but print a warning + * - `(details) => void` - a custom error handler that takes a `details` object with `status`, `path`, `referrer`, `referenceType` and `message` properties. If you `throw` from this function, the build will fail * * ```js * /// file: svelte.config.js @@ -580,10 +582,10 @@ export interface KitConfig { /** * How to respond when hash links from one prerendered page to another don't correspond to an `id` on the destination page. * - * - `'fail'` — fail the build + * - `'fail'` - fail the build * - `'ignore'` - silently ignore the failure and continue - * - `'warn'` — continue, but print a warning - * - `(details) => void` — a custom error handler that takes a `details` object with `path`, `id`, `referrers` and `message` properties. If you `throw` from this function, the build will fail + * - `'warn'` - continue, but print a warning + * - `(details) => void` - a custom error handler that takes a `details` object with `path`, `id`, `referrers` and `message` properties. If you `throw` from this function, the build will fail * * @default "fail" * @since 1.15.7 @@ -592,10 +594,10 @@ export interface KitConfig { /** * How to respond when an entry generated by the `entries` export doesn't match the route it was generated from. * - * - `'fail'` — fail the build + * - `'fail'` - fail the build * - `'ignore'` - silently ignore the failure and continue - * - `'warn'` — continue, but print a warning - * - `(details) => void` — a custom error handler that takes a `details` object with `generatedFromId`, `entry`, `matchedId` and `message` properties. If you `throw` from this function, the build will fail + * - `'warn'` - continue, but print a warning + * - `(details) => void` - a custom error handler that takes a `details` object with `generatedFromId`, `entry`, `matchedId` and `message` properties. If you `throw` from this function, the build will fail * * @default "fail" * @since 1.16.0 @@ -685,8 +687,8 @@ export interface KitConfig { */ export type Handle = (input: { event: RequestEvent; - resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise; -}) => MaybePromise; + resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise; +}) => MaybePromise; /** * The server-side [`handleError`](https://svelte.dev/docs/kit/hooks#shared-hooks-handleError) hook runs when an unexpected error is thrown while responding to a request. @@ -785,9 +787,9 @@ export interface LoadEvent< * } * ``` * - * Setting the same header multiple times (even in separate `load` functions) is an error — you can only set a given header once. + * Setting the same header multiple times (even in separate `load` functions) is an error - you can only set a given header once. * - * You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API in a server-only `load` function instead. + * You cannot add a `set-cookie` header with `setHeaders` - use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API in a server-only `load` function instead. * * `setHeaders` has no effect when a `load` function runs in the browser. */ @@ -802,7 +804,7 @@ export interface LoadEvent< /** * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * - * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. + * Most of the time you won't need this, as `fetch` calls `depends` on your behalf - it's only necessary if you're using a custom API client that bypasses `fetch`. * * URLs can be absolute or relative to the page being loaded, and must be [encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding). * @@ -1076,6 +1078,10 @@ export interface RequestEvent< * The original request object */ request: Request; + /** + * The upgrade request object + */ + upgrade?: {request: IncomingMessage, socket: Duplex, head: Buffer} /** * Info about the current route */ @@ -1103,9 +1109,9 @@ export interface RequestEvent< * } * ``` * - * Setting the same header multiple times (even in separate `load` functions) is an error — you can only set a given header once. + * Setting the same header multiple times (even in separate `load` functions) is an error - you can only set a given header once. * - * You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API instead. + * You cannot add a `set-cookie` header with `setHeaders` - use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API instead. */ setHeaders(headers: Record): void; /** @@ -1133,6 +1139,16 @@ export type RequestHandler< RouteId extends string | null = string | null > = (event: RequestEvent) => MaybePromise; +/** + * A `(event: UpgradeEvent) => void` function exported from a `+server.js` file with the name UPGRADE and handles server upgrade requests. + * + * It receives `Params` as the first generic argument, which you can skip by using [generated types](https://svelte.dev/docs/kit/types#Generated-types) instead. + */ +export type UpgradeHandler< + Params extends Partial> = Partial>, + RouteId extends string | null = string | null +> = (event: RequestEvent) => MaybePromise; + export interface ResolveOptions { /** * Applies custom transforms to HTML. If `done` is true, it's the final chunk. Chunks are not guaranteed to be well-formed HTML @@ -1226,7 +1242,7 @@ export interface ServerLoadEvent< /** * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * - * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. + * Most of the time you won't need this, as `fetch` calls `depends` on your behalf - it's only necessary if you're using a custom API client that bypasses `fetch`. * * URLs can be absolute or relative to the page being loaded, and must be [encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding). * diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index 0dbc912940a2..6f92ae590ada 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -43,7 +43,7 @@ export async function dev(vite, vite_config, svelte_config) { globalThis.fetch = (info, init) => { if (typeof info === 'string' && !SCHEME.test(info)) { throw new Error( - `Cannot use relative URL (${info}) with global fetch — use \`event.fetch\` instead: https://svelte.dev/docs/kit/web-standards#fetch-apis` + `Cannot use relative URL (${info}) with global fetch - use \`event.fetch\` instead: https://svelte.dev/docs/kit/web-standards#fetch-apis` ); } @@ -431,6 +431,52 @@ export async function dev(vite, vite_config, svelte_config) { // serving routes with those names. See https://github.com/vitejs/vite/issues/7363 remove_static_middlewares(vite.middlewares); + vite.httpServer?.on('upgrade', async (req, socket, head) => { + const base = `${vite.config.server.https ? 'wss' : 'ws'}://${ + req.headers[':authority'] || req.headers.host + }`; + + // we have to import `Server` before calling `set_assets` + const { Server } = /** @type {import('types').ServerModule} */ ( + await vite.ssrLoadModule(`${runtime_base}/server/index.js`, { fixStacktrace: true }) + ); + + const server = new Server(manifest); + + await server.init({ + env, + read: (file) => createReadableStream(from_fs(file)) + }); + + const request = await getRequest({ + base, + request: req + }); + + await server.respond( + request, + { + getClientAddress: () => { + const { remoteAddress } = req.socket; + if (remoteAddress) return remoteAddress; + throw new Error('Could not determine clientAddress'); + }, + read: (file) => { + if (file in manifest._.server_assets) { + return fs.readFileSync(from_fs(file)); + } + + return fs.readFileSync(path.join(svelte_config.kit.files.assets, file)); + }, + before_handle: (event, config, prerender) => { + async_local_storage.enterWith({ event, config, prerender }); + }, + emulator + }, + { request: req, socket, head } + ); + }); + vite.middlewares.use(async (req, res) => { // Vite's base middleware strips out the base path. Restore it const original_url = req.url; @@ -521,24 +567,28 @@ export async function dev(vite, vite_config, svelte_config) { return; } - const rendered = await server.respond(request, { - getClientAddress: () => { - const { remoteAddress } = req.socket; - if (remoteAddress) return remoteAddress; - throw new Error('Could not determine clientAddress'); - }, - read: (file) => { - if (file in manifest._.server_assets) { - return fs.readFileSync(from_fs(file)); - } + const rendered = await server.respond( + request, + { + getClientAddress: () => { + const { remoteAddress } = req.socket; + if (remoteAddress) return remoteAddress; + throw new Error('Could not determine clientAddress'); + }, + read: (file) => { + if (file in manifest._.server_assets) { + return fs.readFileSync(from_fs(file)); + } - return fs.readFileSync(path.join(svelte_config.kit.files.assets, file)); + return fs.readFileSync(path.join(svelte_config.kit.files.assets, file)); + }, + before_handle: (event, config, prerender) => { + async_local_storage.enterWith({ event, config, prerender }); + }, + emulator }, - before_handle: (event, config, prerender) => { - async_local_storage.enterWith({ event, config, prerender }); - }, - emulator - }); + undefined + ); if (rendered.status === 404) { // @ts-expect-error diff --git a/packages/kit/src/runtime/app/server/index.js b/packages/kit/src/runtime/app/server/index.js index 33c9b0a0d1ba..8a3c7283d6a8 100644 --- a/packages/kit/src/runtime/app/server/index.js +++ b/packages/kit/src/runtime/app/server/index.js @@ -71,3 +71,4 @@ export function read(asset) { throw new Error(`Asset does not exist: ${file}`); } + diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 55bcd87807b9..162e774474ff 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -7,9 +7,10 @@ import { method_not_allowed } from './utils.js'; * @param {import('@sveltejs/kit').RequestEvent} event * @param {import('types').SSREndpoint} mod * @param {import('types').SSRState} state - * @returns {Promise} + * @returns {Promise} */ export async function render_endpoint(event, mod, state) { + console.log(event); const method = /** @type {import('types').HttpMethod} */ (event.request.method); let handler = mod[method] || mod.fallback; @@ -40,28 +41,36 @@ export async function render_endpoint(event, mod, state) { } try { - let response = await handler( - /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) - ); - - if (!(response instanceof Response)) { - throw new Error( - `Invalid response from route ${event.url.pathname}: handler should return a Response object` + if (method === 'GET' && event.request.headers.has('upgrade') && event.upgrade && mod.UPGRADE) { + console.log('upgrade'); + await mod.UPGRADE(/** @type {import('@sveltejs/kit').RequestEvent>} */ (event)); + } else { + console.log('not upgrade'); + let response = await handler( + /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) ); - } - if (state.prerendering) { - // the returned Response might have immutable Headers - // so we should clone them before trying to mutate them - response = new Response(response.body, { - status: response.status, - statusText: response.statusText, - headers: new Headers(response.headers) - }); - response.headers.set('x-sveltekit-prerender', String(prerender)); + if (!(response instanceof Response)) { + throw new Error( + `Invalid response from route ${event.url.pathname}: handler should return a Response object` + ); + } + + if (state.prerendering) { + // the returned Response might have immutable Headers + // so we should clone them before trying to mutate them + response = new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: new Headers(response.headers) + }); + response.headers.set('x-sveltekit-prerender', String(prerender)); + } + + console.log(response); + + return response; } - - return response; } catch (e) { if (e instanceof Redirect) { return new Response(undefined, { diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 36cbd04be16f..53c22589a5dd 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -92,13 +92,14 @@ export class Server { /** * @param {Request} request + * @param {{request: import('http').IncomingMessage, socket: import('stream').Duplex , head: Buffer}?} webhookRequest * @param {import('types').RequestOptions} options */ - async respond(request, options) { + async respond(request, webhookRequest, options) { return respond(request, this.#options, this.#manifest, { ...options, error: false, depth: 0 - }); + }, webhookRequest); } } diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index f81f52ef2557..a26bd2c18e92 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -54,10 +54,12 @@ const allowed_page_methods = new Set(['GET', 'HEAD', 'OPTIONS']); * @param {import('types').SSROptions} options * @param {import('@sveltejs/kit').SSRManifest} manifest * @param {import('types').SSRState} state - * @returns {Promise} + * @param {{request: import('http').IncomingMessage, socket: import('stream').Duplex , head: Buffer}?} upgradeRequest + * @returns {Promise} */ -export async function respond(request, options, manifest, state) { +export async function respond(request, options, manifest, state, upgradeRequest) { /** URL but stripped from the potential `/__data.json` suffix and its search param */ + console.log('hit respond'); const url = new URL(request.url); if (options.csrf_check_origin) { @@ -81,6 +83,7 @@ export async function respond(request, options, manifest, state) { } } + console.log('hit reroute'); // reroute could alter the given URL, so we pass a copy let rerouted_path; try { @@ -91,6 +94,7 @@ export async function respond(request, options, manifest, state) { }); } + console.log('hit decode'); let decoded; try { decoded = decode_pathname(rerouted_path); @@ -139,7 +143,7 @@ export async function respond(request, options, manifest, state) { } if (!state.prerendering?.fallback) { - // TODO this could theoretically break — should probably be inside a try-catch + // TODO this could theoretically break - should probably be inside a try-catch const matchers = await manifest._.matchers(); for (const candidate of manifest._.routes) { @@ -206,6 +210,12 @@ export async function respond(request, options, manifest, state) { isDataRequest: is_data_request, isSubRequest: state.depth > 0 }; + console.log('hit create event'); + + if(upgradeRequest) { + console.log('hit upgrade event'); + event.upgrade = upgradeRequest; + } /** @type {import('types').RequiredResolveOptions} */ let resolve_opts = { @@ -324,10 +334,12 @@ export async function respond(request, options, manifest, state) { if (state.prerendering && !state.prerendering.fallback) disable_search(url); + console.log('hit handle'); const response = await options.hooks.handle({ event, resolve: (event, opts) => resolve(event, opts).then((response) => { + if(!response) return; // 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) { @@ -346,7 +358,7 @@ export async function respond(request, options, manifest, state) { }); // respond with 304 if etag matches - if (response.status === 200 && response.headers.has('etag')) { + if (response?.status === 200 && response?.headers.has('etag')) { let if_none_match_value = request.headers.get('if-none-match'); // ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives @@ -381,7 +393,7 @@ export async function respond(request, options, manifest, state) { // Edge case: If user does `return Response(30x)` in handle hook while processing a data request, // we need to transform the redirect response to a corresponding JSON response. - if (is_data_request && response.status >= 300 && response.status <= 308) { + if (is_data_request && response && response.status >= 300 && response.status <= 308) { const location = response.headers.get('location'); if (location) { return redirect_json_response(new Redirect(/** @type {any} */ (response.status), location)); @@ -434,7 +446,7 @@ export async function respond(request, options, manifest, state) { if (route) { const method = /** @type {import('types').HttpMethod} */ (event.request.method); - /** @type {Response} */ + /** @type {void | Response} */ let response; if (is_data_request) { @@ -484,7 +496,7 @@ export async function respond(request, options, manifest, state) { // If the route contains a page and an endpoint, we need to add a // `Vary: Accept` header to the response because of browser caching - if (request.method === 'GET' && route.page && route.endpoint) { + if (request.method === 'GET' && route.page && route.endpoint && response) { const vary = response.headers .get('vary') ?.split(',') diff --git a/packages/kit/src/types/internal.d.ts b/packages/kit/src/types/internal.d.ts index c9dbb51ce007..d60972a97447 100644 --- a/packages/kit/src/types/internal.d.ts +++ b/packages/kit/src/types/internal.d.ts @@ -17,7 +17,8 @@ import { RequestEvent, SSRManifest, Emulator, - Adapter + Adapter, + UpgradeHandler } from '@sveltejs/kit'; import { HttpMethod, @@ -26,6 +27,8 @@ import { RequestOptions, TrailingSlash } from './private.js'; +import type { IncomingMessage } from 'node:http'; +import type { Duplex } from 'node:stream'; export interface ServerModule { Server: typeof InternalServer; @@ -131,7 +134,8 @@ export class InternalServer extends Server { /** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated */ before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void; emulator?: Emulator; - } + }, + webhookRequest?: {request: IncomingMessage, socket: Duplex, head: Buffer}, ): Promise; } @@ -386,11 +390,12 @@ export interface PageNodeIndexes { export type PrerenderEntryGenerator = () => MaybePromise>>; export type SSREndpoint = Partial> & { - prerender?: PrerenderOption; - trailingSlash?: TrailingSlash; - config?: any; - entries?: PrerenderEntryGenerator; - fallback?: RequestHandler; + UPGRADE?: UpgradeHandler; + prerender?: PrerenderOption; + trailingSlash?: TrailingSlash; + config?: any; + entries?: PrerenderEntryGenerator; + fallback?: RequestHandler; }; export interface SSRRoute { diff --git a/packages/kit/src/utils/exports.js b/packages/kit/src/utils/exports.js index ed685edb7ded..93860c5b5377 100644 --- a/packages/kit/src/utils/exports.js +++ b/packages/kit/src/utils/exports.js @@ -72,6 +72,7 @@ const valid_page_exports = new Set([...valid_layout_exports, 'entries']); const valid_layout_server_exports = new Set([...valid_layout_exports]); const valid_page_server_exports = new Set([...valid_layout_server_exports, 'actions', 'entries']); const valid_server_exports = new Set([ + 'UPGRADE', 'GET', 'POST', 'PATCH', diff --git a/packages/kit/test/apps/ws/README.md b/packages/kit/test/apps/ws/README.md new file mode 100644 index 000000000000..dddfaa2ca89c --- /dev/null +++ b/packages/kit/test/apps/ws/README.md @@ -0,0 +1 @@ +This app exists to test websocket implementations. diff --git a/packages/kit/test/apps/ws/package.json b/packages/kit/test/apps/ws/package.json new file mode 100644 index 000000000000..20d0a22b928b --- /dev/null +++ b/packages/kit/test/apps/ws/package.json @@ -0,0 +1,27 @@ +{ + "name": "test-ws", + "private": true, + "version": "0.0.1", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && tsc && svelte-check", + "test": "pnpm test:dev && pnpm test:build", + "test:dev": "cross-env DEV=true playwright test", + "test:build": "playwright test" + }, + "devDependencies": { + "@sveltejs/adapter-node": "workspace:^", + "@sveltejs/kit": "workspace:^", + "@sveltejs/vite-plugin-svelte": "^3.0.1", + "cross-env": "^7.0.3", + "socket.io": "^4.8.1", + "svelte": "^4.2.10", + "svelte-check": "^4.0.1", + "typescript": "^5.3.3", + "vite": "^5.3.2", + "ws": "^8.18.0" + }, + "type": "module" +} diff --git a/packages/kit/test/apps/ws/playwright.config.js b/packages/kit/test/apps/ws/playwright.config.js new file mode 100644 index 000000000000..33d36b651014 --- /dev/null +++ b/packages/kit/test/apps/ws/playwright.config.js @@ -0,0 +1 @@ +export { config as default } from '../../utils.js'; diff --git a/packages/kit/test/apps/ws/src/app.html b/packages/kit/test/apps/ws/src/app.html new file mode 100644 index 000000000000..b8ba4699b2ba --- /dev/null +++ b/packages/kit/test/apps/ws/src/app.html @@ -0,0 +1,11 @@ + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/packages/kit/test/apps/ws/src/routes/+page.svelte b/packages/kit/test/apps/ws/src/routes/+page.svelte new file mode 100644 index 000000000000..e83274902d05 --- /dev/null +++ b/packages/kit/test/apps/ws/src/routes/+page.svelte @@ -0,0 +1,29 @@ + + +

Hello

+ +
+ {#each events as event} +

{event}

+ {/each} +
diff --git a/packages/kit/test/apps/ws/src/routes/ws/+server.ts b/packages/kit/test/apps/ws/src/routes/ws/+server.ts new file mode 100644 index 000000000000..b15fdc03a0f9 --- /dev/null +++ b/packages/kit/test/apps/ws/src/routes/ws/+server.ts @@ -0,0 +1,18 @@ +import { WebSocketServer } from 'ws'; +// import { Server } from "socket.io"; + +const wss = new WebSocketServer({ noServer: true }); +// const io = new Server(); + +export function UPGRADE({upgrade}) { + console.log(request); + wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { + wss.emit('connection', ws, request); + }); +} + +export function GET({request}) { + console.log(request); + + return new Response('ok'); +} diff --git a/packages/kit/test/apps/ws/svelte.config.js b/packages/kit/test/apps/ws/svelte.config.js new file mode 100644 index 000000000000..821c14379ec8 --- /dev/null +++ b/packages/kit/test/apps/ws/svelte.config.js @@ -0,0 +1,6 @@ +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: {} +}; + +export default config; diff --git a/packages/kit/test/apps/ws/test/test.js b/packages/kit/test/apps/ws/test/test.js new file mode 100644 index 000000000000..1633e55d28b4 --- /dev/null +++ b/packages/kit/test/apps/ws/test/test.js @@ -0,0 +1,89 @@ +import process from 'node:process'; +import { expect } from '@playwright/test'; +import { test } from '../../../utils.js'; + +/** @typedef {import('@playwright/test').Response} Response */ + +test.describe.configure({ mode: 'parallel' }); + +test.describe('env', () => { + test('resolves upwards', async ({ page }) => { + await page.goto('/basepath/env'); + expect(await page.textContent('[data-testid="static"]')).toBe('static: resolves upwards!'); + expect(await page.textContent('[data-testid="dynamic"]')).toBe('dynamic: resolves upwards!'); + }); +}); + +test.describe('paths', () => { + test('serves /basepath', async ({ page }) => { + await page.goto('/basepath'); + expect(await page.textContent('h1')).toBe('Hello'); + }); + + test('serves assets from /basepath', async ({ request }) => { + const response = await request.get('/basepath/answer.txt'); + expect(await response.text()).toBe('42'); + }); + + test('uses relative paths during SSR', async ({ page, javaScriptEnabled }) => { + await page.goto('/basepath'); + + let base = javaScriptEnabled ? '/basepath' : '.'; + expect(await page.textContent('[data-testid="base"]')).toBe(`base: ${base}`); + expect(await page.textContent('[data-testid="assets"]')).toBe(`assets: ${base}`); + + await page.goto('/basepath/deeply/nested/page'); + + base = javaScriptEnabled ? '/basepath' : '../..'; + expect(await page.textContent('[data-testid="base"]')).toBe(`base: ${base}`); + expect(await page.textContent('[data-testid="assets"]')).toBe(`assets: ${base}`); + }); + + test('serves /basepath with trailing slash always', async ({ page }) => { + await page.goto('/basepath'); + expect(new URL(page.url()).pathname).toBe('/basepath/'); + }); + + test('respects trailing slash option when navigating from /basepath', async ({ + page, + clicknav + }) => { + await page.goto('/basepath'); + expect(new URL(page.url()).pathname).toBe('/basepath/'); + await clicknav('[data-testid="link"]'); + expect(new URL(page.url()).pathname).toBe('/basepath/hello'); + }); +}); + +test.describe('Service worker', () => { + if (process.env.DEV) return; + + test('build /basepath/service-worker.js', async ({ baseURL, request }) => { + const response = await request.get('/basepath/service-worker.js'); + const content = await response.text(); + + const fn = new Function('self', 'location', content); + + const self = { + addEventListener: () => {}, + base: null, + build: null + }; + + const pathname = '/basepath/service-worker.js'; + + fn(self, { + href: baseURL + pathname, + pathname + }); + + expect(self.base).toBe('/basepath'); + expect(self.build[0]).toMatch(/\/basepath\/_app\/immutable\/entry\/start\.[\w-]+\.js/); + expect(self.image_src).toMatch(/\/basepath\/_app\/immutable\/assets\/image\.[\w-]+\.jpg/); + }); + + test('does not register /basepath/service-worker.js', async ({ page }) => { + await page.goto('/basepath'); + expect(await page.content()).not.toMatch(/navigator\.serviceWorker/); + }); +}); diff --git a/packages/kit/test/apps/ws/tsconfig.json b/packages/kit/test/apps/ws/tsconfig.json new file mode 100644 index 000000000000..b1096bf168cd --- /dev/null +++ b/packages/kit/test/apps/ws/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "noEmit": true + }, + "extends": "./.svelte-kit/tsconfig.json" +} diff --git a/packages/kit/test/apps/ws/vite.config.js b/packages/kit/test/apps/ws/vite.config.js new file mode 100644 index 000000000000..8e2cdfd37133 --- /dev/null +++ b/packages/kit/test/apps/ws/vite.config.js @@ -0,0 +1,14 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import path from 'path'; + +/** @type {import('vite').UserConfig} */ +const config = { + plugins: [sveltekit()], + server: { + fs: { + allow: [path.resolve('../../../src')] + } + }, +}; + +export default config; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a360411ab50..0496bf454bfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -644,6 +644,39 @@ importers: specifier: ^5.3.2 version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) + packages/kit/test/apps/ws: + devDependencies: + '@sveltejs/adapter-node': + specifier: workspace:^ + version: link:../../../../adapter-node + '@sveltejs/kit': + specifier: workspace:^ + version: link:../../.. + '@sveltejs/vite-plugin-svelte': + specifier: ^3.0.1 + version: 3.1.0(svelte@4.2.19)(vite@5.3.6(@types/node@18.19.50)(lightningcss@1.24.1)) + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + socket.io: + specifier: ^4.8.1 + version: 4.8.1 + svelte: + specifier: ^4.2.10 + version: 4.2.19 + svelte-check: + specifier: ^4.0.1 + version: 4.0.1(picomatch@4.0.2)(svelte@4.2.19)(typescript@5.6.3) + typescript: + specifier: ^5.3.3 + version: 5.6.3 + vite: + specifier: ^5.3.2 + version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) + ws: + specifier: ^8.18.0 + version: 8.18.0 + packages/kit/test/build-errors: devDependencies: vitest: @@ -1911,6 +1944,9 @@ packages: '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@stylistic/eslint-plugin-js@2.1.0': resolution: {integrity: sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1962,9 +1998,15 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/cookie@0.4.1': + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/cors@2.8.17': + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + '@types/eslint@8.56.12': resolution: {integrity: sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==} @@ -2078,6 +2120,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -2168,6 +2214,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -2283,6 +2333,14 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -2393,6 +2451,14 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + + engine.io@6.6.2: + resolution: {integrity: sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==} + engines: {node: '>=10.2.0'} + enhanced-resolve@5.17.1: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} @@ -2954,6 +3020,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -3023,6 +3097,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -3436,6 +3514,17 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + socket.io-adapter@2.5.5: + resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + + socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + + socket.io@4.8.1: + resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} + engines: {node: '>=10.2.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3703,6 +3792,10 @@ packages: engines: {node: '>=8'} hasBin: true + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vite-imagetools@7.0.1: resolution: {integrity: sha512-23jnLhkTH0HR9Vd9LxMYnajOLeo0RJNEAHhtlsQP6kfPuOBoTzt54rWbEWB9jmhEXAOflLQpM+FrmilVPAoyGA==} engines: {node: '>=18.0.0'} @@ -3818,6 +3911,18 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -4493,6 +4598,8 @@ snapshots: '@sinclair/typebox@0.27.8': {} + '@socket.io/component-emitter@3.1.2': {} + '@stylistic/eslint-plugin-js@2.1.0(eslint@9.6.0)': dependencies: '@types/eslint': 8.56.12 @@ -4593,8 +4700,14 @@ snapshots: dependencies: '@types/node': 18.19.50 + '@types/cookie@0.4.1': {} + '@types/cookie@0.6.0': {} + '@types/cors@2.8.17': + dependencies: + '@types/node': 18.19.50 + '@types/eslint@8.56.12': dependencies: '@types/estree': 1.0.6 @@ -4760,6 +4873,11 @@ snapshots: abbrev@1.1.1: {} + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + acorn-import-attributes@1.9.5(acorn@8.12.1): dependencies: acorn: 8.12.1 @@ -4833,6 +4951,8 @@ snapshots: balanced-match@1.0.2: {} + base64id@2.0.0: {} + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -4948,6 +5068,13 @@ snapshots: cookie@0.6.0: {} + cookie@0.7.2: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cross-env@7.0.3: dependencies: cross-spawn: 7.0.3 @@ -5033,6 +5160,25 @@ snapshots: emoji-regex@8.0.0: {} + engine.io-parser@5.2.3: {} + + engine.io@6.6.2: + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.17 + '@types/node': 18.19.50 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.7.2 + cors: 2.8.5 + debug: 4.3.5 + engine.io-parser: 5.2.3 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 @@ -5638,6 +5784,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mime@3.0.0: {} mimic-fn@4.0.0: {} @@ -5700,6 +5852,8 @@ snapshots: natural-compare@1.4.0: {} + negotiator@0.6.3: {} + no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -6089,6 +6243,36 @@ snapshots: slash@3.0.0: {} + socket.io-adapter@2.5.5: + dependencies: + debug: 4.3.5 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-parser@4.2.4: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 + transitivePeerDependencies: + - supports-color + + socket.io@4.8.1: + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.5 + engine.io: 6.6.2 + socket.io-adapter: 2.5.5 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + source-map-js@1.2.1: {} source-map@0.6.1: {} @@ -6155,6 +6339,18 @@ snapshots: transitivePeerDependencies: - picomatch + svelte-check@4.0.1(picomatch@4.0.2)(svelte@4.2.19)(typescript@5.6.3): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + chokidar: 3.6.0 + fdir: 6.3.0(picomatch@4.0.2) + picocolors: 1.1.0 + sade: 1.8.1 + svelte: 4.2.19 + typescript: 5.6.3 + transitivePeerDependencies: + - picomatch + svelte-eslint-parser@0.39.2(svelte@5.1.9): dependencies: eslint-scope: 7.2.2 @@ -6344,6 +6540,8 @@ snapshots: kleur: 4.1.5 sade: 1.8.1 + vary@1.1.2: {} + vite-imagetools@7.0.1(rollup@4.24.0): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.24.0) @@ -6478,6 +6676,8 @@ snapshots: wrappy@1.0.2: {} + ws@8.17.1: {} + ws@8.18.0: {} xxhash-wasm@1.0.2: {} From ffe1eadf0d6b15de9f24589ee0a1ad1a09176315 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 18:07:13 +0000 Subject: [PATCH 02/14] functional implementation --- packages/kit/src/runtime/server/endpoint.js | 1 - packages/kit/src/runtime/server/index.js | 4 ++-- packages/kit/src/runtime/server/respond.js | 1 + .../kit/test/apps/ws/src/routes/ws/+server.ts | 20 +++++++++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 162e774474ff..cb5c8bed0ea6 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -10,7 +10,6 @@ import { method_not_allowed } from './utils.js'; * @returns {Promise} */ export async function render_endpoint(event, mod, state) { - console.log(event); const method = /** @type {import('types').HttpMethod} */ (event.request.method); let handler = mod[method] || mod.fallback; diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 53c22589a5dd..655159a2e567 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -92,10 +92,10 @@ export class Server { /** * @param {Request} request - * @param {{request: import('http').IncomingMessage, socket: import('stream').Duplex , head: Buffer}?} webhookRequest * @param {import('types').RequestOptions} options + * @param {{request: import('http').IncomingMessage, socket: import('stream').Duplex , head: Buffer}?} webhookRequest */ - async respond(request, webhookRequest, options) { + async respond(request, options, webhookRequest) { return respond(request, this.#options, this.#manifest, { ...options, error: false, diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index a26bd2c18e92..b6a425189df3 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -214,6 +214,7 @@ export async function respond(request, options, manifest, state, upgradeRequest) if(upgradeRequest) { console.log('hit upgrade event'); + console.log(upgradeRequest); event.upgrade = upgradeRequest; } diff --git a/packages/kit/test/apps/ws/src/routes/ws/+server.ts b/packages/kit/test/apps/ws/src/routes/ws/+server.ts index b15fdc03a0f9..9003acc299f3 100644 --- a/packages/kit/test/apps/ws/src/routes/ws/+server.ts +++ b/packages/kit/test/apps/ws/src/routes/ws/+server.ts @@ -4,14 +4,22 @@ import { WebSocketServer } from 'ws'; const wss = new WebSocketServer({ noServer: true }); // const io = new Server(); -export function UPGRADE({upgrade}) { - console.log(request); - wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { - wss.emit('connection', ws, request); - }); +wss.on('connection', (ws) => { + ws.on('error', console.error); + + ws.on('message', (message) => { + console.log('received: %s', message); + }); +}); + +export function UPGRADE({ upgrade }) { + wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { + console.log('UPGRADED'); + wss.emit('connection', ws, upgrade.request); + }); } -export function GET({request}) { +export function GET({ request }) { console.log(request); return new Response('ok'); From b0f2ee13852d75c640749c3d23af075bd994496e Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 18:52:21 +0000 Subject: [PATCH 03/14] cleaned logs --- packages/kit/src/runtime/server/endpoint.js | 4 ---- packages/kit/src/runtime/server/respond.js | 7 ------- 2 files changed, 11 deletions(-) diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index cb5c8bed0ea6..ba0f10c9e10c 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -41,10 +41,8 @@ export async function render_endpoint(event, mod, state) { try { if (method === 'GET' && event.request.headers.has('upgrade') && event.upgrade && mod.UPGRADE) { - console.log('upgrade'); await mod.UPGRADE(/** @type {import('@sveltejs/kit').RequestEvent>} */ (event)); } else { - console.log('not upgrade'); let response = await handler( /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) ); @@ -66,8 +64,6 @@ export async function render_endpoint(event, mod, state) { response.headers.set('x-sveltekit-prerender', String(prerender)); } - console.log(response); - return response; } } catch (e) { diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index b6a425189df3..3b013d32ac8a 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -59,7 +59,6 @@ const allowed_page_methods = new Set(['GET', 'HEAD', 'OPTIONS']); */ export async function respond(request, options, manifest, state, upgradeRequest) { /** URL but stripped from the potential `/__data.json` suffix and its search param */ - console.log('hit respond'); const url = new URL(request.url); if (options.csrf_check_origin) { @@ -83,7 +82,6 @@ export async function respond(request, options, manifest, state, upgradeRequest) } } - console.log('hit reroute'); // reroute could alter the given URL, so we pass a copy let rerouted_path; try { @@ -94,7 +92,6 @@ export async function respond(request, options, manifest, state, upgradeRequest) }); } - console.log('hit decode'); let decoded; try { decoded = decode_pathname(rerouted_path); @@ -210,11 +207,8 @@ export async function respond(request, options, manifest, state, upgradeRequest) isDataRequest: is_data_request, isSubRequest: state.depth > 0 }; - console.log('hit create event'); if(upgradeRequest) { - console.log('hit upgrade event'); - console.log(upgradeRequest); event.upgrade = upgradeRequest; } @@ -335,7 +329,6 @@ export async function respond(request, options, manifest, state, upgradeRequest) if (state.prerendering && !state.prerendering.fallback) disable_search(url); - console.log('hit handle'); const response = await options.hooks.handle({ event, resolve: (event, opts) => From 6972d8fa12062c54a86959e93c4a7dd5da418dd9 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 18:52:40 +0000 Subject: [PATCH 04/14] swapped test app to basics --- packages/kit/test/apps/basics/package.json | 4 +- .../src/routes/socketIO}/+server.ts | 0 .../test/apps/basics/src/routes/ws/+server.ts | 26 ++++++ packages/kit/test/apps/ws/README.md | 1 - packages/kit/test/apps/ws/package.json | 27 ------ .../kit/test/apps/ws/playwright.config.js | 1 - packages/kit/test/apps/ws/src/app.html | 11 --- .../kit/test/apps/ws/src/routes/+page.svelte | 29 ------ packages/kit/test/apps/ws/svelte.config.js | 6 -- packages/kit/test/apps/ws/test/test.js | 89 ------------------- packages/kit/test/apps/ws/tsconfig.json | 8 -- packages/kit/test/apps/ws/vite.config.js | 14 --- pnpm-lock.yaml | 51 ++--------- 13 files changed, 35 insertions(+), 232 deletions(-) rename packages/kit/test/apps/{ws/src/routes/ws => basics/src/routes/socketIO}/+server.ts (100%) create mode 100644 packages/kit/test/apps/basics/src/routes/ws/+server.ts delete mode 100644 packages/kit/test/apps/ws/README.md delete mode 100644 packages/kit/test/apps/ws/package.json delete mode 100644 packages/kit/test/apps/ws/playwright.config.js delete mode 100644 packages/kit/test/apps/ws/src/app.html delete mode 100644 packages/kit/test/apps/ws/src/routes/+page.svelte delete mode 100644 packages/kit/test/apps/ws/svelte.config.js delete mode 100644 packages/kit/test/apps/ws/test/test.js delete mode 100644 packages/kit/test/apps/ws/tsconfig.json delete mode 100644 packages/kit/test/apps/ws/vite.config.js diff --git a/packages/kit/test/apps/basics/package.json b/packages/kit/test/apps/basics/package.json index eadca24b6a31..fdf201943958 100644 --- a/packages/kit/test/apps/basics/package.json +++ b/packages/kit/test/apps/basics/package.json @@ -18,10 +18,12 @@ "@sveltejs/vite-plugin-svelte": "^3.0.1", "cross-env": "^7.0.3", "marked": "^14.0.0", + "socket.io": "^4.8.1", "svelte": "^4.2.10", "svelte-check": "^4.0.1", "typescript": "^5.3.3", - "vite": "^5.3.2" + "vite": "^5.3.2", + "ws": "^8.18.0" }, "type": "module" } diff --git a/packages/kit/test/apps/ws/src/routes/ws/+server.ts b/packages/kit/test/apps/basics/src/routes/socketIO/+server.ts similarity index 100% rename from packages/kit/test/apps/ws/src/routes/ws/+server.ts rename to packages/kit/test/apps/basics/src/routes/socketIO/+server.ts diff --git a/packages/kit/test/apps/basics/src/routes/ws/+server.ts b/packages/kit/test/apps/basics/src/routes/ws/+server.ts new file mode 100644 index 000000000000..9003acc299f3 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/ws/+server.ts @@ -0,0 +1,26 @@ +import { WebSocketServer } from 'ws'; +// import { Server } from "socket.io"; + +const wss = new WebSocketServer({ noServer: true }); +// const io = new Server(); + +wss.on('connection', (ws) => { + ws.on('error', console.error); + + ws.on('message', (message) => { + console.log('received: %s', message); + }); +}); + +export function UPGRADE({ upgrade }) { + wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { + console.log('UPGRADED'); + wss.emit('connection', ws, upgrade.request); + }); +} + +export function GET({ request }) { + console.log(request); + + return new Response('ok'); +} diff --git a/packages/kit/test/apps/ws/README.md b/packages/kit/test/apps/ws/README.md deleted file mode 100644 index dddfaa2ca89c..000000000000 --- a/packages/kit/test/apps/ws/README.md +++ /dev/null @@ -1 +0,0 @@ -This app exists to test websocket implementations. diff --git a/packages/kit/test/apps/ws/package.json b/packages/kit/test/apps/ws/package.json deleted file mode 100644 index 20d0a22b928b..000000000000 --- a/packages/kit/test/apps/ws/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "test-ws", - "private": true, - "version": "0.0.1", - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && tsc && svelte-check", - "test": "pnpm test:dev && pnpm test:build", - "test:dev": "cross-env DEV=true playwright test", - "test:build": "playwright test" - }, - "devDependencies": { - "@sveltejs/adapter-node": "workspace:^", - "@sveltejs/kit": "workspace:^", - "@sveltejs/vite-plugin-svelte": "^3.0.1", - "cross-env": "^7.0.3", - "socket.io": "^4.8.1", - "svelte": "^4.2.10", - "svelte-check": "^4.0.1", - "typescript": "^5.3.3", - "vite": "^5.3.2", - "ws": "^8.18.0" - }, - "type": "module" -} diff --git a/packages/kit/test/apps/ws/playwright.config.js b/packages/kit/test/apps/ws/playwright.config.js deleted file mode 100644 index 33d36b651014..000000000000 --- a/packages/kit/test/apps/ws/playwright.config.js +++ /dev/null @@ -1 +0,0 @@ -export { config as default } from '../../utils.js'; diff --git a/packages/kit/test/apps/ws/src/app.html b/packages/kit/test/apps/ws/src/app.html deleted file mode 100644 index b8ba4699b2ba..000000000000 --- a/packages/kit/test/apps/ws/src/app.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/packages/kit/test/apps/ws/src/routes/+page.svelte b/packages/kit/test/apps/ws/src/routes/+page.svelte deleted file mode 100644 index e83274902d05..000000000000 --- a/packages/kit/test/apps/ws/src/routes/+page.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - -

Hello

- -
- {#each events as event} -

{event}

- {/each} -
diff --git a/packages/kit/test/apps/ws/svelte.config.js b/packages/kit/test/apps/ws/svelte.config.js deleted file mode 100644 index 821c14379ec8..000000000000 --- a/packages/kit/test/apps/ws/svelte.config.js +++ /dev/null @@ -1,6 +0,0 @@ -/** @type {import('@sveltejs/kit').Config} */ -const config = { - kit: {} -}; - -export default config; diff --git a/packages/kit/test/apps/ws/test/test.js b/packages/kit/test/apps/ws/test/test.js deleted file mode 100644 index 1633e55d28b4..000000000000 --- a/packages/kit/test/apps/ws/test/test.js +++ /dev/null @@ -1,89 +0,0 @@ -import process from 'node:process'; -import { expect } from '@playwright/test'; -import { test } from '../../../utils.js'; - -/** @typedef {import('@playwright/test').Response} Response */ - -test.describe.configure({ mode: 'parallel' }); - -test.describe('env', () => { - test('resolves upwards', async ({ page }) => { - await page.goto('/basepath/env'); - expect(await page.textContent('[data-testid="static"]')).toBe('static: resolves upwards!'); - expect(await page.textContent('[data-testid="dynamic"]')).toBe('dynamic: resolves upwards!'); - }); -}); - -test.describe('paths', () => { - test('serves /basepath', async ({ page }) => { - await page.goto('/basepath'); - expect(await page.textContent('h1')).toBe('Hello'); - }); - - test('serves assets from /basepath', async ({ request }) => { - const response = await request.get('/basepath/answer.txt'); - expect(await response.text()).toBe('42'); - }); - - test('uses relative paths during SSR', async ({ page, javaScriptEnabled }) => { - await page.goto('/basepath'); - - let base = javaScriptEnabled ? '/basepath' : '.'; - expect(await page.textContent('[data-testid="base"]')).toBe(`base: ${base}`); - expect(await page.textContent('[data-testid="assets"]')).toBe(`assets: ${base}`); - - await page.goto('/basepath/deeply/nested/page'); - - base = javaScriptEnabled ? '/basepath' : '../..'; - expect(await page.textContent('[data-testid="base"]')).toBe(`base: ${base}`); - expect(await page.textContent('[data-testid="assets"]')).toBe(`assets: ${base}`); - }); - - test('serves /basepath with trailing slash always', async ({ page }) => { - await page.goto('/basepath'); - expect(new URL(page.url()).pathname).toBe('/basepath/'); - }); - - test('respects trailing slash option when navigating from /basepath', async ({ - page, - clicknav - }) => { - await page.goto('/basepath'); - expect(new URL(page.url()).pathname).toBe('/basepath/'); - await clicknav('[data-testid="link"]'); - expect(new URL(page.url()).pathname).toBe('/basepath/hello'); - }); -}); - -test.describe('Service worker', () => { - if (process.env.DEV) return; - - test('build /basepath/service-worker.js', async ({ baseURL, request }) => { - const response = await request.get('/basepath/service-worker.js'); - const content = await response.text(); - - const fn = new Function('self', 'location', content); - - const self = { - addEventListener: () => {}, - base: null, - build: null - }; - - const pathname = '/basepath/service-worker.js'; - - fn(self, { - href: baseURL + pathname, - pathname - }); - - expect(self.base).toBe('/basepath'); - expect(self.build[0]).toMatch(/\/basepath\/_app\/immutable\/entry\/start\.[\w-]+\.js/); - expect(self.image_src).toMatch(/\/basepath\/_app\/immutable\/assets\/image\.[\w-]+\.jpg/); - }); - - test('does not register /basepath/service-worker.js', async ({ page }) => { - await page.goto('/basepath'); - expect(await page.content()).not.toMatch(/navigator\.serviceWorker/); - }); -}); diff --git a/packages/kit/test/apps/ws/tsconfig.json b/packages/kit/test/apps/ws/tsconfig.json deleted file mode 100644 index b1096bf168cd..000000000000 --- a/packages/kit/test/apps/ws/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "noEmit": true - }, - "extends": "./.svelte-kit/tsconfig.json" -} diff --git a/packages/kit/test/apps/ws/vite.config.js b/packages/kit/test/apps/ws/vite.config.js deleted file mode 100644 index 8e2cdfd37133..000000000000 --- a/packages/kit/test/apps/ws/vite.config.js +++ /dev/null @@ -1,14 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import path from 'path'; - -/** @type {import('vite').UserConfig} */ -const config = { - plugins: [sveltekit()], - server: { - fs: { - allow: [path.resolve('../../../src')] - } - }, -}; - -export default config; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0496bf454bfc..9df4c6213689 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -454,6 +454,9 @@ importers: marked: specifier: ^14.0.0 version: 14.1.1 + socket.io: + specifier: ^4.8.1 + version: 4.8.1 svelte: specifier: ^4.2.10 version: 4.2.19 @@ -466,6 +469,9 @@ importers: vite: specifier: ^5.3.2 version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) + ws: + specifier: ^8.18.0 + version: 8.18.0 packages/kit/test/apps/dev-only: devDependencies: @@ -644,39 +650,6 @@ importers: specifier: ^5.3.2 version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) - packages/kit/test/apps/ws: - devDependencies: - '@sveltejs/adapter-node': - specifier: workspace:^ - version: link:../../../../adapter-node - '@sveltejs/kit': - specifier: workspace:^ - version: link:../../.. - '@sveltejs/vite-plugin-svelte': - specifier: ^3.0.1 - version: 3.1.0(svelte@4.2.19)(vite@5.3.6(@types/node@18.19.50)(lightningcss@1.24.1)) - cross-env: - specifier: ^7.0.3 - version: 7.0.3 - socket.io: - specifier: ^4.8.1 - version: 4.8.1 - svelte: - specifier: ^4.2.10 - version: 4.2.19 - svelte-check: - specifier: ^4.0.1 - version: 4.0.1(picomatch@4.0.2)(svelte@4.2.19)(typescript@5.6.3) - typescript: - specifier: ^5.3.3 - version: 5.6.3 - vite: - specifier: ^5.3.2 - version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) - ws: - specifier: ^8.18.0 - version: 8.18.0 - packages/kit/test/build-errors: devDependencies: vitest: @@ -6339,18 +6312,6 @@ snapshots: transitivePeerDependencies: - picomatch - svelte-check@4.0.1(picomatch@4.0.2)(svelte@4.2.19)(typescript@5.6.3): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - chokidar: 3.6.0 - fdir: 6.3.0(picomatch@4.0.2) - picocolors: 1.1.0 - sade: 1.8.1 - svelte: 4.2.19 - typescript: 5.6.3 - transitivePeerDependencies: - - picomatch - svelte-eslint-parser@0.39.2(svelte@5.1.9): dependencies: eslint-scope: 7.2.2 From ff4097e3576e2613b6bd6d96674ea5ed468f455e Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 20:17:57 +0000 Subject: [PATCH 05/14] Fixed formatting overreach --- packages/kit/src/exports/public.d.ts | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index a8357260f964..c8db2c0f8832 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -317,7 +317,7 @@ export interface KitConfig { /** * The directory where SvelteKit keeps its stuff, including static assets (such as JS and CSS) and internally-used routes. * - * If `paths.assets` is specified, there will be two app directories - `${paths.assets}/${appDir}` and `${paths.base}/${appDir}`. + * If `paths.assets` is specified, there will be two app directories — `${paths.assets}/${appDir}` and `${paths.base}/${appDir}`. * @default "_app" */ appDir?: string; @@ -550,10 +550,10 @@ export interface KitConfig { /** * How to respond to HTTP errors encountered while prerendering the app. * - * - `'fail'` - fail the build - * - `'ignore'` - silently ignore the failure and continue - * - `'warn'` - continue, but print a warning - * - `(details) => void` - a custom error handler that takes a `details` object with `status`, `path`, `referrer`, `referenceType` and `message` properties. If you `throw` from this function, the build will fail + * - `'fail'` — fail the build + * - `'ignore'` — silently ignore the failure and continue + * - `'warn'` — continue, but print a warning + * - `(details) => void` — a custom error handler that takes a `details` object with `status`, `path`, `referrer`, `referenceType` and `message` properties. If you `throw` from this function, the build will fail * * ```js * /// file: svelte.config.js @@ -582,10 +582,10 @@ export interface KitConfig { /** * How to respond when hash links from one prerendered page to another don't correspond to an `id` on the destination page. * - * - `'fail'` - fail the build - * - `'ignore'` - silently ignore the failure and continue - * - `'warn'` - continue, but print a warning - * - `(details) => void` - a custom error handler that takes a `details` object with `path`, `id`, `referrers` and `message` properties. If you `throw` from this function, the build will fail + * - `'fail'` — fail the build + * - `'ignore'` — silently ignore the failure and continue + * - `'warn'` — continue, but print a warning + * - `(details) => void` — a custom error handler that takes a `details` object with `path`, `id`, `referrers` and `message` properties. If you `throw` from this function, the build will fail * * @default "fail" * @since 1.15.7 @@ -594,10 +594,10 @@ export interface KitConfig { /** * How to respond when an entry generated by the `entries` export doesn't match the route it was generated from. * - * - `'fail'` - fail the build - * - `'ignore'` - silently ignore the failure and continue - * - `'warn'` - continue, but print a warning - * - `(details) => void` - a custom error handler that takes a `details` object with `generatedFromId`, `entry`, `matchedId` and `message` properties. If you `throw` from this function, the build will fail + * - `'fail'` — fail the build + * - `'ignore'` — silently ignore the failure and continue + * - `'warn'` — continue, but print a warning + * - `(details) => void` — a custom error handler that takes a `details` object with `generatedFromId`, `entry`, `matchedId` and `message` properties. If you `throw` from this function, the build will fail * * @default "fail" * @since 1.16.0 @@ -787,9 +787,9 @@ export interface LoadEvent< * } * ``` * - * Setting the same header multiple times (even in separate `load` functions) is an error - you can only set a given header once. + * Setting the same header multiple times (even in separate `load` functions) is an error — you can only set a given header once. * - * You cannot add a `set-cookie` header with `setHeaders` - use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API in a server-only `load` function instead. + * You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API in a server-only `load` function instead. * * `setHeaders` has no effect when a `load` function runs in the browser. */ @@ -804,7 +804,7 @@ export interface LoadEvent< /** * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * - * Most of the time you won't need this, as `fetch` calls `depends` on your behalf - it's only necessary if you're using a custom API client that bypasses `fetch`. + * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * * URLs can be absolute or relative to the page being loaded, and must be [encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding). * @@ -1109,9 +1109,9 @@ export interface RequestEvent< * } * ``` * - * Setting the same header multiple times (even in separate `load` functions) is an error - you can only set a given header once. + * Setting the same header multiple times (even in separate `load` functions) is an error — you can only set a given header once. * - * You cannot add a `set-cookie` header with `setHeaders` - use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API instead. + * You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://svelte.dev/docs/kit/@sveltejs-kit#Cookies) API instead. */ setHeaders(headers: Record): void; /** @@ -1242,7 +1242,7 @@ export interface ServerLoadEvent< /** * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * - * Most of the time you won't need this, as `fetch` calls `depends` on your behalf - it's only necessary if you're using a custom API client that bypasses `fetch`. + * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * * URLs can be absolute or relative to the page being loaded, and must be [encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding). * From 6d5fb17265b110c30998091368324bda04a409c2 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 20:19:28 +0000 Subject: [PATCH 06/14] swapped to options-2 due to strange handle collision, implemented suggestions, adjusted handling --- packages/kit/src/exports/vite/dev/index.js | 3 +- packages/kit/src/runtime/server/endpoint.js | 57 ++++++++++++------- .../test/apps/basics/src/routes/ws/+server.ts | 26 --------- packages/kit/test/apps/options-2/package.json | 5 +- .../apps/options-2/src/routes/+page.svelte | 4 ++ .../src/routes/socket.io/+page.svelte | 33 +++++++++++ .../options-2/src/routes/socket.io/+server.js | 18 ++++++ .../apps/options-2/src/routes/ws/+page.svelte | 35 ++++++++++++ .../src/routes/ws/+server.js} | 9 +-- pnpm-lock.yaml | 48 ++++++++++++++++ 10 files changed, 179 insertions(+), 59 deletions(-) delete mode 100644 packages/kit/test/apps/basics/src/routes/ws/+server.ts create mode 100644 packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte create mode 100644 packages/kit/test/apps/options-2/src/routes/socket.io/+server.js create mode 100644 packages/kit/test/apps/options-2/src/routes/ws/+page.svelte rename packages/kit/test/apps/{basics/src/routes/socketIO/+server.ts => options-2/src/routes/ws/+server.js} (73%) diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index 6f92ae590ada..ef968967964e 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -586,8 +586,7 @@ export async function dev(vite, vite_config, svelte_config) { async_local_storage.enterWith({ event, config, prerender }); }, emulator - }, - undefined + } ); if (rendered.status === 404) { diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index ba0f10c9e10c..b968c780b1c2 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -12,12 +12,20 @@ import { method_not_allowed } from './utils.js'; export async function render_endpoint(event, mod, state) { const method = /** @type {import('types').HttpMethod} */ (event.request.method); + /** + * The handler function to use for the request + * @type {import('@sveltejs/kit').RequestHandler | import('@sveltejs/kit').UpgradeHandler | undefined} + */ let handler = mod[method] || mod.fallback; - if (method === 'HEAD' && mod.GET && !mod.HEAD) { + if (method === 'HEAD' && (mod.GET && !mod.HEAD)) { handler = mod.GET; } + if (method === 'GET' && !mod.GET && mod.UPGRADE) { + handler = mod.UPGRADE; + } + if (!handler) { return method_not_allowed(mod, method); } @@ -40,32 +48,37 @@ export async function render_endpoint(event, mod, state) { } try { + if (method === 'GET' && event.request.headers.has('upgrade') && event.upgrade && mod.UPGRADE) { - await mod.UPGRADE(/** @type {import('@sveltejs/kit').RequestEvent>} */ (event)); - } else { - let response = await handler( + console.log('upgrade') + await handler( /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) ); + return; + } + + let response = await handler( + /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) + ); + + if (!(response instanceof Response)) { + throw new Error( + `Invalid response from route ${event.url.pathname}: handler should return a Response object` + ); + } - if (!(response instanceof Response)) { - throw new Error( - `Invalid response from route ${event.url.pathname}: handler should return a Response object` - ); - } - - if (state.prerendering) { - // the returned Response might have immutable Headers - // so we should clone them before trying to mutate them - response = new Response(response.body, { - status: response.status, - statusText: response.statusText, - headers: new Headers(response.headers) - }); - response.headers.set('x-sveltekit-prerender', String(prerender)); - } - - return response; + if (state.prerendering) { + // the returned Response might have immutable Headers + // so we should clone them before trying to mutate them + response = new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: new Headers(response.headers) + }); + response.headers.set('x-sveltekit-prerender', String(prerender)); } + + return response; } catch (e) { if (e instanceof Redirect) { return new Response(undefined, { diff --git a/packages/kit/test/apps/basics/src/routes/ws/+server.ts b/packages/kit/test/apps/basics/src/routes/ws/+server.ts deleted file mode 100644 index 9003acc299f3..000000000000 --- a/packages/kit/test/apps/basics/src/routes/ws/+server.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { WebSocketServer } from 'ws'; -// import { Server } from "socket.io"; - -const wss = new WebSocketServer({ noServer: true }); -// const io = new Server(); - -wss.on('connection', (ws) => { - ws.on('error', console.error); - - ws.on('message', (message) => { - console.log('received: %s', message); - }); -}); - -export function UPGRADE({ upgrade }) { - wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { - console.log('UPGRADED'); - wss.emit('connection', ws, upgrade.request); - }); -} - -export function GET({ request }) { - console.log(request); - - return new Response('ok'); -} diff --git a/packages/kit/test/apps/options-2/package.json b/packages/kit/test/apps/options-2/package.json index 963d87a3c03e..79d850f540da 100644 --- a/packages/kit/test/apps/options-2/package.json +++ b/packages/kit/test/apps/options-2/package.json @@ -16,10 +16,13 @@ "@sveltejs/kit": "workspace:^", "@sveltejs/vite-plugin-svelte": "^3.0.1", "cross-env": "^7.0.3", + "socket.io": "^4.8.1", + "socket.io-client": "^4.8.1", "svelte": "^4.2.10", "svelte-check": "^4.0.1", "typescript": "^5.3.3", - "vite": "^5.3.2" + "vite": "^5.3.2", + "ws": "^8.18.0" }, "type": "module" } diff --git a/packages/kit/test/apps/options-2/src/routes/+page.svelte b/packages/kit/test/apps/options-2/src/routes/+page.svelte index badacc8173d8..b869628a945d 100644 --- a/packages/kit/test/apps/options-2/src/routes/+page.svelte +++ b/packages/kit/test/apps/options-2/src/routes/+page.svelte @@ -8,3 +8,7 @@

assets: {assets}

Go to /hello +
+Go to /ws +
+Go to /socket.io diff --git a/packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte b/packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte new file mode 100644 index 000000000000..4e85476b189e --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte @@ -0,0 +1,33 @@ + + +

Messages:

+ +
+ {#each messages as message} +

{message}

+ {/each} +
diff --git a/packages/kit/test/apps/options-2/src/routes/socket.io/+server.js b/packages/kit/test/apps/options-2/src/routes/socket.io/+server.js new file mode 100644 index 000000000000..97fae0007788 --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/socket.io/+server.js @@ -0,0 +1,18 @@ +import { createServer } from 'node:http'; +import { Server }from 'socket.io'; + +const httpServer = createServer(); +const io = new Server(httpServer); + +io.on('connection', (socket) => { + socket.on('error', console.error); + + socket.on('chat message', (data) => { + console.log('received message: %s', data); + socket.emit('chat message', data); + }); +}); + +export function UPGRADE({ upgrade }) { + io.engine.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head) +} diff --git a/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte b/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte new file mode 100644 index 000000000000..fd6ee5196764 --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte @@ -0,0 +1,35 @@ + + +

Messages:

+ +
+ {#each messages as message} +

{message}

+ {/each} +
diff --git a/packages/kit/test/apps/basics/src/routes/socketIO/+server.ts b/packages/kit/test/apps/options-2/src/routes/ws/+server.js similarity index 73% rename from packages/kit/test/apps/basics/src/routes/socketIO/+server.ts rename to packages/kit/test/apps/options-2/src/routes/ws/+server.js index 9003acc299f3..c839e67c0fb1 100644 --- a/packages/kit/test/apps/basics/src/routes/socketIO/+server.ts +++ b/packages/kit/test/apps/options-2/src/routes/ws/+server.js @@ -1,14 +1,13 @@ import { WebSocketServer } from 'ws'; -// import { Server } from "socket.io"; const wss = new WebSocketServer({ noServer: true }); -// const io = new Server(); wss.on('connection', (ws) => { ws.on('error', console.error); ws.on('message', (message) => { console.log('received: %s', message); + ws.send(String(message)); }); }); @@ -18,9 +17,3 @@ export function UPGRADE({ upgrade }) { wss.emit('connection', ws, upgrade.request); }); } - -export function GET({ request }) { - console.log(request); - - return new Response('ok'); -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9df4c6213689..9aff84134510 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -457,6 +457,9 @@ importers: socket.io: specifier: ^4.8.1 version: 4.8.1 + socket.io-client: + specifier: ^4.8.1 + version: 4.8.1 svelte: specifier: ^4.2.10 version: 4.2.19 @@ -613,6 +616,12 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + socket.io: + specifier: ^4.8.1 + version: 4.8.1 + socket.io-client: + specifier: ^4.8.1 + version: 4.8.1 svelte: specifier: ^4.2.10 version: 4.2.19 @@ -625,6 +634,9 @@ importers: vite: specifier: ^5.3.2 version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) + ws: + specifier: ^8.18.0 + version: 8.18.0 packages/kit/test/apps/writes: devDependencies: @@ -2424,6 +2436,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + engine.io-client@6.6.2: + resolution: {integrity: sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==} + engine.io-parser@5.2.3: resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} engines: {node: '>=10.0.0'} @@ -3490,6 +3505,10 @@ packages: socket.io-adapter@2.5.5: resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + socket.io-client@4.8.1: + resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} + engines: {node: '>=10.0.0'} + socket.io-parser@4.2.4: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} @@ -3908,6 +3927,10 @@ packages: utf-8-validate: optional: true + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} + xxhash-wasm@1.0.2: resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} @@ -5133,6 +5156,18 @@ snapshots: emoji-regex@8.0.0: {} + engine.io-client@6.6.2: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 + engine.io-parser: 5.2.3 + ws: 8.17.1 + xmlhttprequest-ssl: 2.1.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + engine.io-parser@5.2.3: {} engine.io@6.6.2: @@ -6225,6 +6260,17 @@ snapshots: - supports-color - utf-8-validate + socket.io-client@4.8.1: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 + engine.io-client: 6.6.2 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.2 @@ -6641,6 +6687,8 @@ snapshots: ws@8.18.0: {} + xmlhttprequest-ssl@2.1.2: {} + xxhash-wasm@1.0.2: {} yallist@2.1.2: {} From cf06d39c3b96f977a37e68911b9eef6d6dbbd218 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:16:04 +0000 Subject: [PATCH 07/14] simplified example --- packages/kit/src/exports/public.d.ts | 2 +- packages/kit/src/runtime/server/endpoint.js | 1 - packages/kit/src/runtime/server/respond.js | 5 +-- .../src/routes/socket.io/+page.svelte | 33 ----------------- .../options-2/src/routes/socket.io/+server.js | 18 ---------- .../options-2/src/routes/uws/+page.svelte | 35 +++++++++++++++++++ .../apps/options-2/src/routes/uws/+server.js | 19 ++++++++++ .../apps/options-2/src/routes/ws/+page.svelte | 3 +- pnpm-lock.yaml | 3 -- 9 files changed, 58 insertions(+), 61 deletions(-) delete mode 100644 packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte delete mode 100644 packages/kit/test/apps/options-2/src/routes/socket.io/+server.js create mode 100644 packages/kit/test/apps/options-2/src/routes/uws/+page.svelte create mode 100644 packages/kit/test/apps/options-2/src/routes/uws/+server.js diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index c8db2c0f8832..f0b5edc35aac 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1081,7 +1081,7 @@ export interface RequestEvent< /** * The upgrade request object */ - upgrade?: {request: IncomingMessage, socket: Duplex, head: Buffer} + upgrade: {request: IncomingMessage, socket: Duplex, head: Buffer} | null /** * Info about the current route */ diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index b968c780b1c2..00cb5ed36c98 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -50,7 +50,6 @@ export async function render_endpoint(event, mod, state) { try { if (method === 'GET' && event.request.headers.has('upgrade') && event.upgrade && mod.UPGRADE) { - console.log('upgrade') await handler( /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) ); diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index 3b013d32ac8a..91c8e130fabd 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -182,6 +182,7 @@ export async function respond(request, options, manifest, state, upgradeRequest) params, platform: state.platform, request, + upgrade: upgradeRequest || null, route: { id: route?.id ?? null }, setHeaders: (new_headers) => { for (const key in new_headers) { @@ -208,10 +209,6 @@ export async function respond(request, options, manifest, state, upgradeRequest) isSubRequest: state.depth > 0 }; - if(upgradeRequest) { - event.upgrade = upgradeRequest; - } - /** @type {import('types').RequiredResolveOptions} */ let resolve_opts = { transformPageChunk: default_transform, diff --git a/packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte b/packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte deleted file mode 100644 index 4e85476b189e..000000000000 --- a/packages/kit/test/apps/options-2/src/routes/socket.io/+page.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - -

Messages:

- -
- {#each messages as message} -

{message}

- {/each} -
diff --git a/packages/kit/test/apps/options-2/src/routes/socket.io/+server.js b/packages/kit/test/apps/options-2/src/routes/socket.io/+server.js deleted file mode 100644 index 97fae0007788..000000000000 --- a/packages/kit/test/apps/options-2/src/routes/socket.io/+server.js +++ /dev/null @@ -1,18 +0,0 @@ -import { createServer } from 'node:http'; -import { Server }from 'socket.io'; - -const httpServer = createServer(); -const io = new Server(httpServer); - -io.on('connection', (socket) => { - socket.on('error', console.error); - - socket.on('chat message', (data) => { - console.log('received message: %s', data); - socket.emit('chat message', data); - }); -}); - -export function UPGRADE({ upgrade }) { - io.engine.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head) -} diff --git a/packages/kit/test/apps/options-2/src/routes/uws/+page.svelte b/packages/kit/test/apps/options-2/src/routes/uws/+page.svelte new file mode 100644 index 000000000000..fd6ee5196764 --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/uws/+page.svelte @@ -0,0 +1,35 @@ + + +

Messages:

+ +
+ {#each messages as message} +

{message}

+ {/each} +
diff --git a/packages/kit/test/apps/options-2/src/routes/uws/+server.js b/packages/kit/test/apps/options-2/src/routes/uws/+server.js new file mode 100644 index 000000000000..c839e67c0fb1 --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/uws/+server.js @@ -0,0 +1,19 @@ +import { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ noServer: true }); + +wss.on('connection', (ws) => { + ws.on('error', console.error); + + ws.on('message', (message) => { + console.log('received: %s', message); + ws.send(String(message)); + }); +}); + +export function UPGRADE({ upgrade }) { + wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { + console.log('UPGRADED'); + wss.emit('connection', ws, upgrade.request); + }); +} diff --git a/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte b/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte index fd6ee5196764..5a2b6e9be63c 100644 --- a/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte +++ b/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte @@ -20,8 +20,9 @@ socket.onmessage = (event) => { console.log(event.data) - messages.push(event.data) + messages = [...messages, event.data]; console.log(messages) + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9aff84134510..7797ae2858b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -457,9 +457,6 @@ importers: socket.io: specifier: ^4.8.1 version: 4.8.1 - socket.io-client: - specifier: ^4.8.1 - version: 4.8.1 svelte: specifier: ^4.2.10 version: 4.2.19 From f28ff1c70535c7c656097d4e3c9315e22bd58f1f Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:18:16 +0000 Subject: [PATCH 08/14] restore previous formatting --- packages/kit/src/exports/public.d.ts | 6 +++--- packages/kit/src/exports/vite/dev/index.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index f0b5edc35aac..57948a354329 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -551,7 +551,7 @@ export interface KitConfig { * How to respond to HTTP errors encountered while prerendering the app. * * - `'fail'` — fail the build - * - `'ignore'` — silently ignore the failure and continue + * - `'ignore'` - silently ignore the failure and continue * - `'warn'` — continue, but print a warning * - `(details) => void` — a custom error handler that takes a `details` object with `status`, `path`, `referrer`, `referenceType` and `message` properties. If you `throw` from this function, the build will fail * @@ -583,7 +583,7 @@ export interface KitConfig { * How to respond when hash links from one prerendered page to another don't correspond to an `id` on the destination page. * * - `'fail'` — fail the build - * - `'ignore'` — silently ignore the failure and continue + * - `'ignore'` - silently ignore the failure and continue * - `'warn'` — continue, but print a warning * - `(details) => void` — a custom error handler that takes a `details` object with `path`, `id`, `referrers` and `message` properties. If you `throw` from this function, the build will fail * @@ -595,7 +595,7 @@ export interface KitConfig { * How to respond when an entry generated by the `entries` export doesn't match the route it was generated from. * * - `'fail'` — fail the build - * - `'ignore'` — silently ignore the failure and continue + * - `'ignore'` - silently ignore the failure and continue * - `'warn'` — continue, but print a warning * - `(details) => void` — a custom error handler that takes a `details` object with `generatedFromId`, `entry`, `matchedId` and `message` properties. If you `throw` from this function, the build will fail * diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index ef968967964e..f4daa46fe98d 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -43,7 +43,7 @@ export async function dev(vite, vite_config, svelte_config) { globalThis.fetch = (info, init) => { if (typeof info === 'string' && !SCHEME.test(info)) { throw new Error( - `Cannot use relative URL (${info}) with global fetch - use \`event.fetch\` instead: https://svelte.dev/docs/kit/web-standards#fetch-apis` + `Cannot use relative URL (${info}) with global fetch — use \`event.fetch\` instead: https://svelte.dev/docs/kit/web-standards#fetch-apis` ); } From cb2458e1b3df1c064d0de919f833caa29e5fb625 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:21:26 +0000 Subject: [PATCH 09/14] fixed basics deps --- packages/kit/test/apps/basics/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/kit/test/apps/basics/package.json b/packages/kit/test/apps/basics/package.json index fdf201943958..eadca24b6a31 100644 --- a/packages/kit/test/apps/basics/package.json +++ b/packages/kit/test/apps/basics/package.json @@ -18,12 +18,10 @@ "@sveltejs/vite-plugin-svelte": "^3.0.1", "cross-env": "^7.0.3", "marked": "^14.0.0", - "socket.io": "^4.8.1", "svelte": "^4.2.10", "svelte-check": "^4.0.1", "typescript": "^5.3.3", - "vite": "^5.3.2", - "ws": "^8.18.0" + "vite": "^5.3.2" }, "type": "module" } From f9806b7325259d211af5a03bb2a3ea71b0b2be92 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:22:18 +0000 Subject: [PATCH 10/14] removed un-needed parenthesis --- packages/kit/src/runtime/server/endpoint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 00cb5ed36c98..218b5a3ca7db 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -18,7 +18,7 @@ export async function render_endpoint(event, mod, state) { */ let handler = mod[method] || mod.fallback; - if (method === 'HEAD' && (mod.GET && !mod.HEAD)) { + if (method === 'HEAD' && mod.GET && !mod.HEAD) { handler = mod.GET; } From 1bdcc5fc0a3229f505b28b9707b0eb66467df38a Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:46:46 +0000 Subject: [PATCH 11/14] updated lockfile --- pnpm-lock.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7797ae2858b2..d0b1290e9165 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -454,9 +454,6 @@ importers: marked: specifier: ^14.0.0 version: 14.1.1 - socket.io: - specifier: ^4.8.1 - version: 4.8.1 svelte: specifier: ^4.2.10 version: 4.2.19 @@ -469,9 +466,6 @@ importers: vite: specifier: ^5.3.2 version: 5.3.6(@types/node@18.19.50)(lightningcss@1.24.1) - ws: - specifier: ^8.18.0 - version: 8.18.0 packages/kit/test/apps/dev-only: devDependencies: From 8832329d8e11a2b82412e982c5dadacf7f9af7dc Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:50:17 +0000 Subject: [PATCH 12/14] cleaning and formatting --- packages/kit/src/exports/public.d.ts | 4 +- packages/kit/src/exports/vite/dev/index.js | 37 +++++++++---------- packages/kit/src/runtime/app/server/index.js | 1 - packages/kit/src/runtime/server/endpoint.js | 7 ++-- packages/kit/src/runtime/server/index.js | 16 +++++--- packages/kit/src/runtime/server/respond.js | 2 +- packages/kit/src/types/internal.d.ts | 14 +++---- .../apps/options-2/src/routes/+page.svelte | 4 +- .../options-2/src/routes/uws/+page.svelte | 35 ------------------ .../apps/options-2/src/routes/uws/+server.js | 19 ---------- .../apps/options-2/src/routes/ws/+page.svelte | 27 +++++++------- 11 files changed, 56 insertions(+), 110 deletions(-) delete mode 100644 packages/kit/test/apps/options-2/src/routes/uws/+page.svelte delete mode 100644 packages/kit/test/apps/options-2/src/routes/uws/+server.js diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 57948a354329..0e101ba1e744 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1078,10 +1078,10 @@ export interface RequestEvent< * The original request object */ request: Request; - /** + /** * The upgrade request object */ - upgrade: {request: IncomingMessage, socket: Duplex, head: Buffer} | null + upgrade: { request: IncomingMessage; socket: Duplex; head: Buffer } | null; /** * Info about the current route */ diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index f4daa46fe98d..eda1f1298f9a 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -567,27 +567,24 @@ export async function dev(vite, vite_config, svelte_config) { return; } - const rendered = await server.respond( - request, - { - getClientAddress: () => { - const { remoteAddress } = req.socket; - if (remoteAddress) return remoteAddress; - throw new Error('Could not determine clientAddress'); - }, - read: (file) => { - if (file in manifest._.server_assets) { - return fs.readFileSync(from_fs(file)); - } + const rendered = await server.respond(request, { + getClientAddress: () => { + const { remoteAddress } = req.socket; + if (remoteAddress) return remoteAddress; + throw new Error('Could not determine clientAddress'); + }, + read: (file) => { + if (file in manifest._.server_assets) { + return fs.readFileSync(from_fs(file)); + } - return fs.readFileSync(path.join(svelte_config.kit.files.assets, file)); - }, - before_handle: (event, config, prerender) => { - async_local_storage.enterWith({ event, config, prerender }); - }, - emulator - } - ); + return fs.readFileSync(path.join(svelte_config.kit.files.assets, file)); + }, + before_handle: (event, config, prerender) => { + async_local_storage.enterWith({ event, config, prerender }); + }, + emulator + }); if (rendered.status === 404) { // @ts-expect-error diff --git a/packages/kit/src/runtime/app/server/index.js b/packages/kit/src/runtime/app/server/index.js index 8a3c7283d6a8..33c9b0a0d1ba 100644 --- a/packages/kit/src/runtime/app/server/index.js +++ b/packages/kit/src/runtime/app/server/index.js @@ -71,4 +71,3 @@ export function read(asset) { throw new Error(`Asset does not exist: ${file}`); } - diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 218b5a3ca7db..c3614e6da46d 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -13,9 +13,9 @@ export async function render_endpoint(event, mod, state) { const method = /** @type {import('types').HttpMethod} */ (event.request.method); /** - * The handler function to use for the request - * @type {import('@sveltejs/kit').RequestHandler | import('@sveltejs/kit').UpgradeHandler | undefined} - */ + * The handler function to use for the request + * @type {import('@sveltejs/kit').RequestHandler | import('@sveltejs/kit').UpgradeHandler | undefined} + */ let handler = mod[method] || mod.fallback; if (method === 'HEAD' && mod.GET && !mod.HEAD) { @@ -48,7 +48,6 @@ export async function render_endpoint(event, mod, state) { } try { - if (method === 'GET' && event.request.headers.has('upgrade') && event.upgrade && mod.UPGRADE) { await handler( /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 655159a2e567..c95d68370cf7 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -96,10 +96,16 @@ export class Server { * @param {{request: import('http').IncomingMessage, socket: import('stream').Duplex , head: Buffer}?} webhookRequest */ async respond(request, options, webhookRequest) { - return respond(request, this.#options, this.#manifest, { - ...options, - error: false, - depth: 0 - }, webhookRequest); + return respond( + request, + this.#options, + this.#manifest, + { + ...options, + error: false, + depth: 0 + }, + webhookRequest + ); } } diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index 91c8e130fabd..852aee368d1d 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -330,7 +330,7 @@ export async function respond(request, options, manifest, state, upgradeRequest) event, resolve: (event, opts) => resolve(event, opts).then((response) => { - if(!response) return; + if (!response) return; // 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) { diff --git a/packages/kit/src/types/internal.d.ts b/packages/kit/src/types/internal.d.ts index d60972a97447..7b0ef17cec3e 100644 --- a/packages/kit/src/types/internal.d.ts +++ b/packages/kit/src/types/internal.d.ts @@ -135,7 +135,7 @@ export class InternalServer extends Server { before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void; emulator?: Emulator; }, - webhookRequest?: {request: IncomingMessage, socket: Duplex, head: Buffer}, + webhookRequest?: { request: IncomingMessage; socket: Duplex; head: Buffer } ): Promise; } @@ -390,12 +390,12 @@ export interface PageNodeIndexes { export type PrerenderEntryGenerator = () => MaybePromise>>; export type SSREndpoint = Partial> & { - UPGRADE?: UpgradeHandler; - prerender?: PrerenderOption; - trailingSlash?: TrailingSlash; - config?: any; - entries?: PrerenderEntryGenerator; - fallback?: RequestHandler; + UPGRADE?: UpgradeHandler; + prerender?: PrerenderOption; + trailingSlash?: TrailingSlash; + config?: any; + entries?: PrerenderEntryGenerator; + fallback?: RequestHandler; }; export interface SSRRoute { diff --git a/packages/kit/test/apps/options-2/src/routes/+page.svelte b/packages/kit/test/apps/options-2/src/routes/+page.svelte index b869628a945d..a8faccaba6e3 100644 --- a/packages/kit/test/apps/options-2/src/routes/+page.svelte +++ b/packages/kit/test/apps/options-2/src/routes/+page.svelte @@ -8,7 +8,7 @@

assets: {assets}

Go to /hello -
+
Go to /ws -
+
Go to /socket.io diff --git a/packages/kit/test/apps/options-2/src/routes/uws/+page.svelte b/packages/kit/test/apps/options-2/src/routes/uws/+page.svelte deleted file mode 100644 index fd6ee5196764..000000000000 --- a/packages/kit/test/apps/options-2/src/routes/uws/+page.svelte +++ /dev/null @@ -1,35 +0,0 @@ - - -

Messages:

- -
- {#each messages as message} -

{message}

- {/each} -
diff --git a/packages/kit/test/apps/options-2/src/routes/uws/+server.js b/packages/kit/test/apps/options-2/src/routes/uws/+server.js deleted file mode 100644 index c839e67c0fb1..000000000000 --- a/packages/kit/test/apps/options-2/src/routes/uws/+server.js +++ /dev/null @@ -1,19 +0,0 @@ -import { WebSocketServer } from 'ws'; - -const wss = new WebSocketServer({ noServer: true }); - -wss.on('connection', (ws) => { - ws.on('error', console.error); - - ws.on('message', (message) => { - console.log('received: %s', message); - ws.send(String(message)); - }); -}); - -export function UPGRADE({ upgrade }) { - wss.handleUpgrade(upgrade.request, upgrade.socket, upgrade.head, (ws) => { - console.log('UPGRADED'); - wss.emit('connection', ws, upgrade.request); - }); -} diff --git a/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte b/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte index 5a2b6e9be63c..d68ebdcc35c3 100644 --- a/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte +++ b/packages/kit/test/apps/options-2/src/routes/ws/+page.svelte @@ -1,29 +1,28 @@ From b3ce4267585b19a4001b6c45b117b0632f948cab Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 21:56:26 +0000 Subject: [PATCH 13/14] fixed exports test --- packages/kit/src/utils/exports.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/utils/exports.spec.js b/packages/kit/src/utils/exports.spec.js index e27817c17b5c..4f0e52781d40 100644 --- a/packages/kit/src/utils/exports.spec.js +++ b/packages/kit/src/utils/exports.spec.js @@ -174,7 +174,7 @@ test('validates +server.js', () => { validate_server_exports({ answer: 42 }); - }, "Invalid export 'answer' (valid exports are GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD, fallback, prerender, trailingSlash, config, entries, or anything with a '_' prefix)"); + }, "Invalid export 'answer' (valid exports are UPGRADE, GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD, fallback, prerender, trailingSlash, config, entries, or anything with a '_' prefix)"); check_error(() => { validate_server_exports({ From 44e84aedb8c851cd97bbf292d17bbabc48a7025c Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 5 Nov 2024 22:00:07 +0000 Subject: [PATCH 14/14] regenerated types --- packages/kit/types/index.d.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 491de54d9698..d352912d5d9c 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -4,6 +4,8 @@ declare module '@sveltejs/kit' { import type { CompileOptions } from 'svelte/compiler'; import type { PluginOptions } from '@sveltejs/vite-plugin-svelte'; + import type { IncomingMessage } from 'node:http'; + import type { Duplex } from 'node:stream'; /** * [Adapters](https://svelte.dev/docs/kit/adapters) are responsible for taking the production build and turning it into something that can be deployed to a platform of your choosing. */ @@ -667,8 +669,8 @@ declare module '@sveltejs/kit' { */ export type Handle = (input: { event: RequestEvent; - resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise; - }) => MaybePromise; + resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise; + }) => MaybePromise; /** * The server-side [`handleError`](https://svelte.dev/docs/kit/hooks#shared-hooks-handleError) hook runs when an unexpected error is thrown while responding to a request. @@ -1058,6 +1060,10 @@ declare module '@sveltejs/kit' { * The original request object */ request: Request; + /** + * The upgrade request object + */ + upgrade: { request: IncomingMessage; socket: Duplex; head: Buffer } | null; /** * Info about the current route */ @@ -1115,6 +1121,16 @@ declare module '@sveltejs/kit' { RouteId extends string | null = string | null > = (event: RequestEvent) => MaybePromise; + /** + * A `(event: UpgradeEvent) => void` function exported from a `+server.js` file with the name UPGRADE and handles server upgrade requests. + * + * It receives `Params` as the first generic argument, which you can skip by using [generated types](https://svelte.dev/docs/kit/types#Generated-types) instead. + */ + export type UpgradeHandler< + Params extends Partial> = Partial>, + RouteId extends string | null = string | null + > = (event: RequestEvent) => MaybePromise; + export interface ResolveOptions { /** * Applies custom transforms to HTML. If `done` is true, it's the final chunk. Chunks are not guaranteed to be well-formed HTML @@ -1734,6 +1750,7 @@ declare module '@sveltejs/kit' { type PrerenderEntryGenerator = () => MaybePromise>>; type SSREndpoint = Partial> & { + UPGRADE?: UpgradeHandler; prerender?: PrerenderOption; trailingSlash?: TrailingSlash; config?: any;