-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
feat: native support for Websockets #12973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
LukeHagar
wants to merge
235
commits into
sveltejs:main
Choose a base branch
from
LukeHagar:crossws
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,174
−135
Draft
Changes from 11 commits
Commits
Show all changes
235 commits
Select commit
Hold shift + click to select a range
d0b7f09
example crossws implementation with `hooks.server.js` websocketHooks …
LukeHagar b69b2e0
Migrated from hooks to server.js export named socket, validated funct…
LukeHagar aa69e1c
Formatting and fix a test
LukeHagar 38c919c
removed global comment
LukeHagar 2a022b5
regenerated types
LukeHagar c3a0bf7
removed some log statements
LukeHagar c86e4e9
cleaning up previous implementation
LukeHagar 5858b49
Thoroughly tested handle implementation
LukeHagar 9d56c50
Cleaning
LukeHagar 46c8682
regenerated types and ran formatter
LukeHagar 7791759
generate types
teemingc 70202e3
adjusted implementation to only use responses and the updated crossws…
LukeHagar 92e3e41
corrected example
LukeHagar db517f6
swapped from browser to onMount
LukeHagar a43c49b
cleaned log statements
LukeHagar 6469816
added a docs page
LukeHagar ee0c6ee
updated node adapter
LukeHagar e737e02
fixed imports and resolve type
LukeHagar 42e2f2d
updating adapters
LukeHagar 0abeb17
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar 2a9971f
Update packages/kit/src/exports/index.js
LukeHagar cc58820
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar 29fdfec
ditching reject function for existing error
LukeHagar fda8a68
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar ff58988
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar 1fed29d
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar 0ea72ab
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar 6408350
moved adapter integration, added response getter to HttpError
LukeHagar 182a666
TABS
LukeHagar dda7298
corrected package.json versions
LukeHagar 192840a
normalize on error and the response prop
LukeHagar ec0b797
Merge branch 'main' into crossws
LukeHagar f3bed08
recreated lockfile
LukeHagar 2f11dca
ran formatter
LukeHagar 3f2679e
fix lint errors
LukeHagar de37505
Update documentation/docs/25-build-and-deploy/99-writing-adapters.md
LukeHagar 8dfad0c
fix lint errors
LukeHagar 21cb866
added an s
LukeHagar f70aea1
correcting lockfile issues
LukeHagar c0a5e3d
regenerated types
LukeHagar a6bcf60
adjusting types
LukeHagar d3a48d7
cleaning a log
LukeHagar fa52645
adding ts comments
LukeHagar e63dfc3
adjusting ts comments
LukeHagar a0c54ab
adjusting lib for Generic error
LukeHagar c9457a4
adjusting ts version for Generic error
LukeHagar 51d4729
updating lockfile
LukeHagar 04b011d
updating generated types
LukeHagar 2ab789f
downgrade typescript and address some types issues
benmccann 4a6c8b3
upgrade @types/node to fix remaining types error
benmccann 9bdfc04
adjusting tests for updated test app
LukeHagar 894f38b
adjusting tests for updated test app
LukeHagar e7726a6
Update packages/kit/types/index.d.ts
LukeHagar 8de07d1
Update packages/kit/src/exports/index.js
LukeHagar c18b4e8
Update packages/adapter-node/package.json
LukeHagar ddc9bc1
Update packages/adapter-cloudflare/package.json
LukeHagar 80e14fe
Update packages/adapter-cloudflare-workers/package.json
LukeHagar 3e58143
Update packages/adapter-node/src/index.js
LukeHagar 7563cb3
Update packages/adapter-node/src/index.js
LukeHagar fd5b98b
Update packages/kit/src/exports/index.js
LukeHagar e79716c
updating lockfile
LukeHagar 3f884b1
updating generated types
LukeHagar dea0952
re-export crossws Hooks type as Socket
teemingc 25f039a
oopsie this should be +server.js instead of +page.server.js
teemingc 4072369
Update 15-websockets.md
LukeHagar 875536b
re-export Peer and Message types
teemingc 84a1aa1
de-duplicate test id
teemingc 93d40b2
revert server initialisation timing during dev
teemingc 24f3b52
Update packages/kit/src/runtime/server/resolve.js
LukeHagar 8c10aa4
Update packages/kit/src/runtime/server/resolve.js
teemingc 52d607a
Update packages/kit/src/runtime/server/resolve.js
teemingc 1ac7ccf
Update packages/kit/src/runtime/server/resolve.js
teemingc d9c4b1f
moving on call to after listen
LukeHagar 6a3581b
restoring server options back to private
LukeHagar e762693
adjusting exports for node adapter
LukeHagar 5c1f334
Update documentation/docs/30-advanced/15-websockets.md
teemingc 8f98d61
revert typescript changes
teemingc ac788fb
Merge branch 'main' into pr/LukeHagar/12973
teemingc 0a160fd
add Socket type to test app
teemingc d6f4ee5
spruce up docs
teemingc 5e07cba
re-generate types
teemingc a0629ba
bump TS to 5.7
teemingc fef9dbe
add comment
teemingc 940eb3d
follow mdn recommendation
teemingc e6caf6c
socket closes by itself if we navigate away
teemingc d437299
emphasise all websocket hooks are required
teemingc f203b8d
handle protocol upgrade to websocket
teemingc e6fed10
add ws to vite preview
teemingc f13af3b
i'm dumb
teemingc 278c283
clarify
teemingc a458ff3
document node adapter upgradeHandler for custom servers
teemingc b766e06
formatting pass
LukeHagar 3dc373c
tigthen up types
teemingc 9597c7f
remove accept helper
teemingc 9a839b5
de-duplicate respond logic
teemingc 183117f
format
teemingc a9a3f9b
dynamically resolve hooks
teemingc e201b3b
comment
teemingc 74937fd
remove cast and ensure headers are added to response
teemingc 68bedce
move ws test pages from options-2 to basics
teemingc ec630b8
Update documentation/docs/30-advanced/15-websockets.md
LukeHagar 19f273b
Update documentation/docs/30-advanced/15-websockets.md
teemingc 8517855
Merge branch 'crossws' of https://github.com/lukehagar/kit into pr/Lu…
teemingc be4346d
add @since jsdoc
teemingc 63cfe11
Merge branch 'main' into pr/LukeHagar/12973
teemingc 7eb180f
revert installed typescript version
teemingc c8de055
re-generate types
teemingc 6b06673
format
teemingc 09c1e2a
revert typescript changes in lockfile
teemingc 2fd6711
changeset
teemingc b03206d
re-generate types
teemingc d997737
add buttons to open/close websocket in test
teemingc 06063f1
recursively adjusted TS Version back to 5.5.4
LukeHagar fef8521
Merge branch 'main' into crossws
LukeHagar 0c1de43
updating lockfile after main merge
LukeHagar 6411a4c
formatting run
LukeHagar db7f8c8
Regenerated types
LukeHagar 23ad389
Update packages/kit/src/runtime/server/respond.js
LukeHagar 3ffe264
removed unused hooks
LukeHagar 367df8f
consolidating logic
LukeHagar 3bc744d
bump crossws version
LukeHagar 31d5617
formatting pass
LukeHagar fd05a21
correcting return types
LukeHagar bf9d9d3
restored handle_request overloads to make TS happy
LukeHagar ffadf9a
added overload comment
LukeHagar bb7aeb4
added verbatimModuleSyntax to package tsconfig
LukeHagar d4ca5eb
lowering TS version once more for package build errors
LukeHagar 2b13bba
Update 15-websockets.md
LukeHagar 427aeef
Update 15-websockets.md
LukeHagar 2b6be27
Update 15-websockets.md
LukeHagar 4f7b7ec
Update 15-websockets.md
LukeHagar f4e6c05
Update 15-websockets.md
LukeHagar be2a624
Update 15-websockets.md
LukeHagar 651c15e
Update 15-websockets.md
LukeHagar c902fe8
Update public.d.ts
LukeHagar 304e8a5
Update index.d.ts
LukeHagar 63646f3
attempting to configure supports for websockets
LukeHagar 64fff72
formatting pass
LukeHagar 5570227
regenerated types
LukeHagar 6e12953
adjusted supports usage
LukeHagar ac17702
regenerated types
LukeHagar 6640525
rename test file from ts to js
teemingc c5c9f0a
ensure hooks call handleError when error is thrown
teemingc 5ee9478
ensure dev updates work on websockets
teemingc 74fcc83
dont reset test messages
teemingc 2896ecf
Merge branch 'crossws' of https://github.com/lukehagar/kit into pr/Lu…
teemingc 7905670
three dots instead of two
teemingc 0560640
we no longer need to upgrade node types because TS is less than 5.7
teemingc a72bac6
inline getClientAddress
teemingc 32981e0
only handle websocket upgrade requests
teemingc f7a88dd
clarify when kit hooks run
teemingc 87c3071
remove verbatimModuleSyntax tsconfig option
teemingc 5ec65b0
integrate adapter supports API
teemingc 330c325
make adapter backwards compatible with older kit versions
teemingc 9582975
no clue when the error hook actually runs
teemingc 1c314ef
check feature when endpoint is accessed
teemingc 0c497bb
clarify why we manually validate exports
teemingc 51783ae
only handle upgrades if socket export exists
teemingc 737d352
pass read and emulator to vite preview ws hooks resolver
teemingc fd956cb
Update documentation/docs/30-advanced/20-hooks.md
teemingc 3977af6
revert blankspace removal
teemingc fbc9a8a
Merge branch 'crossws' of https://github.com/lukehagar/kit into pr/Lu…
teemingc 7d0b219
better comment
teemingc 448f46a
standardise node request and reject upgrade if socket doesn't exist
teemingc ba58ee7
add partial tests
teemingc fe48df9
fix handle hook returning response during upgrade
teemingc 335f58c
fix vite preview server listening for upgrade
teemingc e933ea7
test unsuccessful upgrade requests
teemingc 7f74b95
Merge branch 'main' into pr/LukeHagar/12973
teemingc 12f7a97
format
teemingc 7a6615e
fix test endpoint url
teemingc 82e35ea
change response property to a getter
teemingc 71cb0c5
generate types
teemingc 5d65b6f
support redirect
teemingc e73415c
update error hook description
teemingc d122476
finish up tests
teemingc 71376db
format
teemingc 10e9274
respond with error if incorrect basepath of manifest error
teemingc 5ff6324
remove response property from control classes
teemingc 5595d34
reduce test flakiness
teemingc 628323a
wait for error to be written to disk
teemingc 16ddd0c
try waiting for open event before message
teemingc 52677d7
better upgrade / reject tests
teemingc d6e64ab
client must have sent the same protocol to accept it
teemingc 98c2021
include crossws as workers entry dep
teemingc 5de28ec
trim header string values
teemingc 0a80c3c
Merge branch 'main' into pr/LukeHagar/12973
teemingc 13113c2
pass request event to upgrade hook and export publish and peers helpers
teemingc be8f67e
Merge branch 'main' into pr/LukeHagar/12973
teemingc 5e2bfc8
oops
teemingc 4d89bba
return error response format based on request accept header
teemingc b34d7c8
fix tests and try running in parallel on ci
teemingc 4746851
fix doc
teemingc 74e2a86
expect type error in docs
teemingc ef0619d
again
teemingc dfaa63d
add context to the upgrade hook parameter
teemingc 56b91df
this property is already inherited
teemingc 514fb6d
pass context to upgrade hook event and apply patches
teemingc 4c0ee68
Merge branch 'main' into pr/LukeHagar/12973
teemingc 2b36ccc
fix lint
teemingc 13d11c5
generate types
teemingc c64ce20
oops
teemingc 4bab022
refactor
teemingc 6ca1034
close websockets during graceful shutdown
teemingc 440e71c
change the upgrade param name to event
teemingc a1f9e05
set body if response is returned from upgrade
teemingc 6931bfa
update type docs
teemingc 802d925
update @since version
teemingc f46d2bf
fix lint
teemingc b99608e
update docs for writing adapters
teemingc 1998d7b
fix links to doc
teemingc cf3361a
Merge branch 'main' into pr/LukeHagar/12973
teemingc ef444e2
Merge branch 'main' into pr/LukeHagar/12973
teemingc 23b4f31
Merge branch 'main' into pr/LukeHagar/12973
teemingc 20ee709
Merge branch 'main' into pr/LukeHagar/12973
teemingc 0402340
fix route id and params typing
teemingc 8eb64dc
add request event to peer
teemingc 3de9608
Update .changeset/tricky-drinks-develop.md
teemingc 2ec6f55
Update documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md
teemingc 5fbc9c8
probably don't need this docs change
teemingc 8cbc879
mentions the supports property
teemingc 03bce3e
reduce indentation
teemingc b625c85
add cloudflare tests
teemingc 53ca1fa
Update .changeset/two-islands-sleep.md
teemingc 1d812e1
add node integration test suite
teemingc d65212c
Merge branch 'main' into pr/LukeHagar/12973
teemingc ed0b01d
these should be imported from HANDLER
teemingc 276c828
add node tests
teemingc 7db389f
Merge branch 'main' into pr/LukeHagar/12973
teemingc 3059744
merge main
Rich-Harris 08a3fcc
format
teemingc d8d803f
Merge branch 'crossws' of https://github.com/lukehagar/kit into pr/Lu…
teemingc 12d1602
Merge branch 'main' into crossws
LukeHagar c0a1145
updating pnpm lock
LukeHagar 24e8475
formatting and linting pass
LukeHagar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import { BROWSER, DEV } from 'esm-env'; | ||
import { validate_server_exports } from '../../utils/exports.js'; | ||
import { exec } from '../../utils/routing.js'; | ||
import { decode_pathname, decode_params } from '../../utils/url.js'; | ||
import { base } from '__sveltekit/paths'; | ||
|
||
/** | ||
* @param {import('types').SSROptions} options | ||
* @param {import('@sveltejs/kit').SSRManifest} manifest | ||
* @param {import('types').SSRState} state | ||
* @returns {(info: Request | import('crossws').Peer) => import('types').MaybePromise<Partial<import('crossws').Hooks>>} | ||
*/ | ||
export function resolve(options, manifest, state) { | ||
return async (info) => { | ||
/** @type {Request} */ | ||
let request; | ||
|
||
// These types all need to be straightened out | ||
if (info.request) { | ||
request = info.request; | ||
} else { | ||
request = info; | ||
} | ||
|
||
/** URL but stripped from the potential `/__data.json` suffix and its search param */ | ||
teemingc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
const url = new URL(request.url); | ||
|
||
// reroute could alter the given URL, so we pass a copy | ||
let rerouted_path; | ||
try { | ||
rerouted_path = options.hooks.reroute({ url }) ?? url.pathname; | ||
} catch { | ||
return {}; | ||
} | ||
|
||
let decoded; | ||
try { | ||
decoded = decode_pathname(rerouted_path); | ||
} catch (e) { | ||
console.error(e); | ||
return {}; | ||
} | ||
|
||
if (base && decoded.startsWith(base)) { | ||
decoded = decoded.slice(base.length) || '/'; | ||
} | ||
LukeHagar marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
/** @type {import('types').SSRRoute | null} */ | ||
let route = null; | ||
|
||
/** @type {Record<string, string>} */ | ||
let params = {}; | ||
|
||
try { | ||
// TODO this could theoretically break - should probably be inside a try-catch | ||
const matchers = await manifest._.matchers(); | ||
|
||
for (const candidate of manifest._.routes) { | ||
const match = candidate.pattern.exec(decoded); | ||
|
||
if (!match) continue; | ||
|
||
const matched = exec(match, candidate.params, matchers); | ||
if (matched) { | ||
route = candidate; | ||
params = decode_params(matched); | ||
break; | ||
} | ||
} | ||
} catch (e) { | ||
console.error(e); | ||
return {}; | ||
} | ||
|
||
/** @type {Record<string, string>} */ | ||
const headers = {}; | ||
|
||
try { | ||
// determine whether we need to redirect to add/remove a trailing slash | ||
teemingc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
if (route && route.endpoint) { | ||
// if `paths.base === '/a/b/c`, then the root route is `/a/b/c/`, | ||
// regardless of the `trailingSlash` route option | ||
|
||
teemingc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
const node = await route.endpoint(); | ||
|
||
if (DEV) { | ||
validate_server_exports(node, /** @type {string} */ (route.endpoint_id)); | ||
} | ||
|
||
return { | ||
...node.socket, | ||
upgrade: async (req) => { | ||
/** @type {import('@sveltejs/kit').RequestEvent} */ | ||
const event = { | ||
// @ts-expect-error `cookies` and `fetch` need to be created after the `event` itself | ||
cookies: null, | ||
// @ts-expect-error | ||
fetch: null, | ||
getClientAddress: | ||
state.getClientAddress || | ||
(() => { | ||
throw new Error( | ||
`${__SVELTEKIT_ADAPTER_NAME__} does not specify getClientAddress. Please raise an issue` | ||
); | ||
}), | ||
locals: {}, | ||
params, | ||
platform: state.platform, | ||
request: req, | ||
socket: { | ||
/** | ||
* Accept a WebSocket Upgrade request | ||
* @param {RequestInit} init | ||
* @returns {RequestInit} | ||
*/ | ||
accept: (init) => { | ||
return { ...init }; | ||
}, | ||
/** | ||
* Reject a WebSocket Upgrade request | ||
* @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599. | ||
* @param {{ message: string } extends App.Error ? App.Error | string | undefined : never} body An object that conforms to the App.Error type. If a string is passed, it will be used as the message property. | ||
* @return {Response} A Response object | ||
* @throws {Error} If the provided status is invalid (not between 400 and 599). | ||
*/ | ||
reject: (status, body) => { | ||
if ((!BROWSER || DEV) && (isNaN(status) || status < 400 || status > 599)) { | ||
throw new Error( | ||
`HTTP error status codes must be between 400 and 599 — ${status} is invalid` | ||
); | ||
} | ||
|
||
try { | ||
const jsonBody = JSON.stringify(body); | ||
return new Response(jsonBody, { | ||
status, | ||
headers: { | ||
'content-type': 'application/json' | ||
} | ||
}); | ||
} catch (e) { | ||
console.error(e); | ||
throw new Error('Failed to serialize error body'); | ||
} | ||
} | ||
}, | ||
route: { id: route?.id ?? null }, | ||
setHeaders: (new_headers) => { | ||
for (const key in new_headers) { | ||
const lower = key.toLowerCase(); | ||
const value = new_headers[key]; | ||
|
||
if (lower === 'set-cookie') { | ||
throw new Error( | ||
'Use `event.cookies.set(name, value, options)` instead of `event.setHeaders` to set cookies' | ||
); | ||
} else if (lower in headers) { | ||
throw new Error(`"${key}" header is already set`); | ||
} else { | ||
headers[lower] = value; | ||
|
||
if (state.prerendering && lower === 'cache-control') { | ||
state.prerendering.cache = /** @type {string} */ (value); | ||
} | ||
} | ||
} | ||
}, | ||
url, | ||
isDataRequest: false, | ||
isSubRequest: state.depth > 0 | ||
}; | ||
|
||
const response = await options.hooks.handle({ | ||
event, | ||
resolve: async (event) => { | ||
if (node.socket && node.socket.upgrade) { | ||
return await node.socket.upgrade(event.request); | ||
} else { | ||
return new Response('Not Implemented', { status: 501 }); | ||
} | ||
} | ||
}); | ||
|
||
return response ?? new Response('Not Implemented', { status: 501 }); | ||
} | ||
}; | ||
} | ||
} catch (e) { | ||
console.error(e); | ||
return {}; | ||
} | ||
}; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.