Repository: sveltejs/kit
Pull request #6925 (2022-09-20 18:51:03)

add cookies.serialize function and always set headers/cookies
Successor to https://github.com/sveltejs/kit/pull/6888

Closes https://github.com/sveltejs/kit/issues/6735

- fixes a bug where cookies and headers were only set when the request matched a route
- implements `cookies.serialize`

### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [x] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it solves.
- [x] Ideally, include a test that fails without this PR but passes with it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` and `pnpm check`

### Changesets
- [ ] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. All changesets should be `patch` until SvelteKit 1.0


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 734e13d5093beea70bc7d759ef5e08b8c5093b6b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/david-plugge/svelte-kit/new/serialize-cookie?filename=.changeset/perfect-queens-fail.md&value=---%0A%22%40sveltejs%2Fkit%22%3A%20patch%0A%22test-basics%22%3A%20patch%0A---%0A%0Aadd%20cookies.serialize%20function%20and%20always%20set%20headers%2Fcookies%0A)


david-plugge: While working on this I noticed here:
https://github.com/sveltejs/kit/blob/5a54eb4af542a4b0c3b4c589c3df3ea520f5ca00/packages/kit/src/runtime/server/cookie.js#L40
the cookie headers is parsed on every `cookies.get` call. I think the parsed cookies should be cached

Patch:
diff --git a/.changeset/dry-snails-remain.md b/.changeset/dry-snails-remain.md
new file mode 100644
index 000000000..448501302
--- /dev/null
+++ b/.changeset/dry-snails-remain.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] add missing depends function to ServerLoadEvent type
diff --git a/.changeset/dull-cows-sneeze.md b/.changeset/dull-cows-sneeze.md
new file mode 100644
index 000000000..fd084fe7d
--- /dev/null
+++ b/.changeset/dull-cows-sneeze.md
@@ -0,0 +1,6 @@
+---
+'@sveltejs/adapter-cloudflare': patch
+'@sveltejs/adapter-cloudflare-workers': patch
+---
+
+Include ambient.d.ts files in adapter packages.
diff --git a/.changeset/early-olives-burn.md b/.changeset/early-olives-burn.md
new file mode 100644
index 000000000..ae81419bf
--- /dev/null
+++ b/.changeset/early-olives-burn.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/adapter-node': patch
+---
+
+Add missing Rollup dependency
diff --git a/.changeset/flat-owls-care.md b/.changeset/flat-owls-care.md
new file mode 100644
index 000000000..484be96f9
--- /dev/null
+++ b/.changeset/flat-owls-care.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Add cookies.serialize method
diff --git a/.changeset/odd-beds-smile.md b/.changeset/odd-beds-smile.md
new file mode 100644
index 000000000..63aa75272
--- /dev/null
+++ b/.changeset/odd-beds-smile.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/adapter-node': patch
+---
+
+Bundle with rollup instead of esbuild
diff --git a/.changeset/pre.json b/.changeset/pre.json
index 08cce8d6b..3a632e993 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -224,6 +224,7 @@
     "dry-jokes-explain",
     "dry-yaks-clean",
     "dull-cheetahs-clean",
+    "dull-cows-sneeze",
     "dull-ducks-report",
     "dull-emus-tap",
     "dull-lobsters-act",
@@ -237,6 +238,7 @@
     "early-eagles-boil",
     "early-lemons-collect",
     "early-news-taste",
+    "early-olives-burn",
     "early-pants-unite",
     "early-snakes-peel",
     "early-wasps-obey",
@@ -725,6 +727,7 @@
     "ninety-tables-switch",
     "ninety-vans-talk",
     "ninety-walls-heal",
+    "odd-beds-smile",
     "odd-bottles-drop",
     "odd-coats-shake",
     "odd-coins-lie",
@@ -971,6 +974,7 @@
     "shy-toes-punch",
     "silent-crews-change",
     "silent-cycles-reply",
+    "silent-jeans-vanish",
     "silly-ants-battle",
     "silly-grapes-cover",
     "silly-jokes-hug",
@@ -1017,6 +1021,7 @@
     "smart-apes-drum",
     "smart-bears-leave",
     "smart-deers-approve",
+    "smart-forks-double",
     "smart-humans-eat",
     "smart-mugs-chew",
     "smart-nails-work",
diff --git a/.changeset/short-spies-relax.md b/.changeset/short-spies-relax.md
new file mode 100644
index 000000000..b358986e8
--- /dev/null
+++ b/.changeset/short-spies-relax.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Always apply cookies, not just for matched routes
diff --git a/.changeset/smart-forks-double.md b/.changeset/smart-forks-double.md
new file mode 100644
index 000000000..e98f3bbab
--- /dev/null
+++ b/.changeset/smart-forks-double.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/package': patch
+---
+
+fix check for undefined on application/ strip
diff --git a/packages/adapter-auto/CHANGELOG.md b/packages/adapter-auto/CHANGELOG.md
index 8343aa61a..160ad4f61 100644
--- a/packages/adapter-auto/CHANGELOG.md
+++ b/packages/adapter-auto/CHANGELOG.md
@@ -1,5 +1,12 @@
 # @sveltejs/adapter-auto
 
+## 1.0.0-next.77
+
+### Patch Changes
+
+- Updated dependencies [[`e40acb56`](https://github.com/sveltejs/kit/commit/e40acb561e32a2ee5bcb6d289ebd1284d7af247b)]:
+  - @sveltejs/adapter-cloudflare@1.0.0-next.36
+
 ## 1.0.0-next.76
 
 ### Patch Changes
diff --git a/packages/adapter-auto/package.json b/packages/adapter-auto/package.json
index 10e404e4a..bc1fbfa3e 100644
--- a/packages/adapter-auto/package.json
+++ b/packages/adapter-auto/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-auto",
-	"version": "1.0.0-next.76",
+	"version": "1.0.0-next.77",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/adapter-cloudflare-workers/CHANGELOG.md b/packages/adapter-cloudflare-workers/CHANGELOG.md
index b2322760e..2927372a0 100644
--- a/packages/adapter-cloudflare-workers/CHANGELOG.md
+++ b/packages/adapter-cloudflare-workers/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/adapter-cloudflare-workers
 
+## 1.0.0-next.57
+
+### Patch Changes
+
+- Include ambient.d.ts files in adapter packages. ([#6917](https://github.com/sveltejs/kit/pull/6917))
+
 ## 1.0.0-next.56
 
 ### Patch Changes
diff --git a/packages/adapter-cloudflare-workers/package.json b/packages/adapter-cloudflare-workers/package.json
index f856b8e32..2504210b5 100644
--- a/packages/adapter-cloudflare-workers/package.json
+++ b/packages/adapter-cloudflare-workers/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-cloudflare-workers",
-	"version": "1.0.0-next.56",
+	"version": "1.0.0-next.57",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -19,6 +19,7 @@
 	"main": "index.js",
 	"types": "index.d.ts",
 	"files": [
+		"ambient.d.ts",
 		"files",
 		"index.d.ts"
 	],
diff --git a/packages/adapter-cloudflare/CHANGELOG.md b/packages/adapter-cloudflare/CHANGELOG.md
index 456216ec9..407113129 100644
--- a/packages/adapter-cloudflare/CHANGELOG.md
+++ b/packages/adapter-cloudflare/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/adapter-cloudflare
 
+## 1.0.0-next.36
+
+### Patch Changes
+
+- Include ambient.d.ts files in adapter packages. ([#6917](https://github.com/sveltejs/kit/pull/6917))
+
 ## 1.0.0-next.35
 
 ### Patch Changes
diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json
index a27f5eaac..e5c93726c 100644
--- a/packages/adapter-cloudflare/package.json
+++ b/packages/adapter-cloudflare/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-cloudflare",
-	"version": "1.0.0-next.35",
+	"version": "1.0.0-next.36",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -20,7 +20,8 @@
 	"files": [
 		"files",
 		"index.js",
-		"index.d.ts"
+		"index.d.ts",
+		"ambient.d.ts"
 	],
 	"main": "index.js",
 	"scripts": {
diff --git a/packages/adapter-node/CHANGELOG.md b/packages/adapter-node/CHANGELOG.md
index 43ac0fa07..ef2976151 100644
--- a/packages/adapter-node/CHANGELOG.md
+++ b/packages/adapter-node/CHANGELOG.md
@@ -1,5 +1,17 @@
 # @sveltejs/adapter-node
 
+## 1.0.0-next.94
+
+### Patch Changes
+
+- Add missing Rollup dependency ([#6927](https://github.com/sveltejs/kit/pull/6927))
+
+## 1.0.0-next.93
+
+### Patch Changes
+
+- Bundle with rollup instead of esbuild ([#6896](https://github.com/sveltejs/kit/pull/6896))
+
 ## 1.0.0-next.92
 
 ### Patch Changes
diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js
index cc3d0da78..17bb5310c 100644
--- a/packages/adapter-node/index.js
+++ b/packages/adapter-node/index.js
@@ -1,6 +1,9 @@
 import { readFileSync, writeFileSync } from 'fs';
 import { fileURLToPath } from 'url';
-import * as esbuild from 'esbuild';
+import { rollup } from 'rollup';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import json from '@rollup/plugin-json';
 
 const files = fileURLToPath(new URL('./files', import.meta.url).href);
 
@@ -49,16 +52,23 @@ export default function (opts = {}) {
 
 			const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
 
-			await esbuild.build({
-				platform: 'node',
-				sourcemap: 'linked',
-				target: 'es2022',
-				entryPoints: [`${tmp}/index.js`, `${tmp}/manifest.js`],
-				outdir: `${out}/server`,
-				splitting: true,
+			// we bundle the Vite output so that deployments only need
+			// their production dependencies. Anything in devDependencies
+			// will get included in the bundled code
+			const bundle = await rollup({
+				input: {
+					index: `${tmp}/index.js`,
+					manifest: `${tmp}/manifest.js`
+				},
+				external: [...Object.keys(pkg.dependencies || {})],
+				plugins: [nodeResolve(), commonjs(), json()]
+			});
+
+			await bundle.write({
+				dir: `${out}/server`,
 				format: 'esm',
-				bundle: true,
-				external: [...Object.keys(pkg.dependencies || {})]
+				sourcemap: true,
+				chunkFileNames: `chunks/[name]-[hash].js`
 			});
 
 			builder.copy(files, out, {
diff --git a/packages/adapter-node/package.json b/packages/adapter-node/package.json
index c5d40c7fb..828853a80 100644
--- a/packages/adapter-node/package.json
+++ b/packages/adapter-node/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-node",
-	"version": "1.0.0-next.92",
+	"version": "1.0.0-next.94",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -32,19 +32,20 @@
 		"prepublishOnly": "npm run build"
 	},
 	"devDependencies": {
-		"@rollup/plugin-json": "^4.1.0",
 		"@sveltejs/kit": "workspace:*",
 		"@types/node": "^16.11.36",
 		"c8": "^7.11.3",
 		"node-fetch": "^3.2.4",
 		"polka": "^1.0.0-next.22",
 		"rimraf": "^3.0.2",
-		"rollup": "^2.78.1",
 		"sirv": "^2.0.2",
 		"typescript": "^4.8.2",
 		"uvu": "^0.5.3"
 	},
 	"dependencies": {
-		"esbuild": "^0.15.7"
+		"@rollup/plugin-commonjs": "^22.0.1",
+		"@rollup/plugin-json": "^4.1.0",
+		"@rollup/plugin-node-resolve": "^14.1.0",
+		"rollup": "^2.78.1"
 	}
 }
diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md
index a1848b42a..b7f63620b 100644
--- a/packages/kit/CHANGELOG.md
+++ b/packages/kit/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/kit
 
+## 1.0.0-next.491
+
+### Patch Changes
+
+- [fix] symlink routes ([#6796](https://github.com/sveltejs/kit/pull/6796))
+
 ## 1.0.0-next.490
 
 ### Patch Changes
diff --git a/packages/kit/package.json b/packages/kit/package.json
index 4d18742c0..5dba00e88 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/kit",
-	"version": "1.0.0-next.490",
+	"version": "1.0.0-next.491",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/kit/src/runtime/server/cookie.js b/packages/kit/src/runtime/server/cookie.js
index 559dcce3e..69177f213 100644
--- a/packages/kit/src/runtime/server/cookie.js
+++ b/packages/kit/src/runtime/server/cookie.js
@@ -71,6 +71,18 @@ export function get_cookies(request, url) {
 					maxAge: 0
 				}
 			});
+		},
+
+		/**
+		 * @param {string} name
+		 * @param {string} value
+		 * @param {import('cookie').CookieSerializeOptions} opts
+		 */
+		serialize(name, value, opts) {
+			return serialize(name, value, {
+				...DEFAULT_SERIALIZE_OPTIONS,
+				...opts
+			});
 		}
 	};
 
diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js
index 9070608a0..7b1daadde 100644
--- a/packages/kit/src/runtime/server/index.js
+++ b/packages/kit/src/runtime/server/index.js
@@ -236,17 +236,6 @@ export async function respond(request, options, state) {
 					throw new Error('This should never happen');
 				}
 
-				if (!is_data_request) {
-					// we only want to set cookies on __data.js requests, we don't
-					// want to cache stuff erroneously etc
-					for (const key in headers) {
-						const value = headers[key];
-						response.headers.set(key, /** @type {string} */ (value));
-					}
-				}
-
-				add_cookies_to_headers(response.headers, Array.from(new_cookies.values()));
-
 				return response;
 			}
 
@@ -294,7 +283,21 @@ export async function respond(request, options, state) {
 	try {
 		const response = await options.hooks.handle({
 			event,
-			resolve,
+			resolve: (event, opts) =>
+				resolve(event, opts).then((response) => {
+					// add headers/cookies here, rather than inside `resolve`, so that we
+					// can do it once for all responses instead of once per `return`
+					if (!is_data_request) {
+						// we only want to set cookies on __data.js requests, we don't
+						// want to cache stuff erroneously etc
+						for (const key in headers) {
+							const value = headers[key];
+							response.headers.set(key, /** @type {string} */ (value));
+						}
+					}
+					add_cookies_to_headers(response.headers, Array.from(new_cookies.values()));
+					return response;
+				}),
 			// TODO remove for 1.0
 			// @ts-expect-error
 			get request() {
diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts
index b26a0a932..b2b00d240 100644
--- a/packages/kit/types/index.d.ts
+++ b/packages/kit/types/index.d.ts
@@ -155,6 +155,19 @@ export interface Cookies {
 	 * Deletes a cookie by setting its value to an empty string and setting the expiry date in the past.
 	 */
 	delete(name: string, opts?: import('cookie').CookieSerializeOptions): void;
+
+	/**
+	 * Serialize a cookie name-value pair into a Set-Cookie header string.
+	 *
+	 * The `httpOnly` and `secure` options are `true` by default, and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The `sameSite` option defaults to `lax`.
+	 *
+	 * By default, the `path` of a cookie is the current pathname. In most cases you should explicitly set `path: '/'` to make the cookie available throughout your app.
+	 *
+	 * @param name the name for the cookie
+	 * @param value value to set the cookie to
+	 * @param options object containing serialization options
+	 */
+	serialize(name: string, value: string, opts?: import('cookie').CookieSerializeOptions): string;
 }
 
 export interface KitConfig {
@@ -368,6 +381,7 @@ export interface ServerLoadEvent<
 	ParentData extends Record<string, any> = Record<string, any>
 > extends RequestEvent<Params> {
 	parent: () => Promise<ParentData>;
+	depends: (...deps: string[]) => void;
 }
 
 export interface Action<
diff --git a/packages/package/CHANGELOG.md b/packages/package/CHANGELOG.md
index 0fbb8b088..2d6c7cb57 100644
--- a/packages/package/CHANGELOG.md
+++ b/packages/package/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/package
 
+## 1.0.0-next.5
+
+### Patch Changes
+
+- fix check for undefined on application/ strip ([#6932](https://github.com/sveltejs/kit/pull/6932))
+
 ## 1.0.0-next.4
 
 ### Patch Changes
diff --git a/packages/package/package.json b/packages/package/package.json
index b5bf86863..731fa5ec7 100644
--- a/packages/package/package.json
+++ b/packages/package/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/package",
-	"version": "1.0.0-next.4",
+	"version": "1.0.0-next.5",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/package/src/utils.js b/packages/package/src/utils.js
index 0b263857b..001970610 100644
--- a/packages/package/src/utils.js
+++ b/packages/package/src/utils.js
@@ -52,7 +52,7 @@ export function strip_lang_tags(content) {
 		.replace(
 			/(<!--[^]*?-->)|(<script[^>]*?)\s(?:type|lang)=(["'])(.*?)\3/g,
 			// things like application/ld+json should be kept as-is. Preprocessed languages are "ts" etc
-			(match, s1, s2, _, s4) => (s4.startsWith('application/') ? match : (s1 ?? '') + (s2 ?? ''))
+			(match, s1, s2, _, s4) => (s4?.startsWith('application/') ? match : (s1 ?? '') + (s2 ?? ''))
 		)
 		.replace(/(<!--[^]*?-->)|(<style[^>]*?)\s(?:type|lang)=(["']).*?\3/g, '$1$2');
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4f29e6486..f1a309a23 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -114,11 +114,12 @@ importers:
 
   packages/adapter-node:
     specifiers:
+      '@rollup/plugin-commonjs': ^22.0.1
       '@rollup/plugin-json': ^4.1.0
+      '@rollup/plugin-node-resolve': ^14.1.0
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       c8: ^7.11.3
-      esbuild: ^0.15.7
       node-fetch: ^3.2.4
       polka: ^1.0.0-next.22
       rimraf: ^3.0.2
@@ -127,16 +128,17 @@ importers:
       typescript: ^4.8.2
       uvu: ^0.5.3
     dependencies:
-      esbuild: 0.15.7
-    devDependencies:
+      '@rollup/plugin-commonjs': 22.0.1_rollup@2.78.1
       '@rollup/plugin-json': 4.1.0_rollup@2.78.1
+      '@rollup/plugin-node-resolve': 14.1.0_rollup@2.78.1
+      rollup: 2.78.1
+    devDependencies:
       '@sveltejs/kit': link:../kit
       '@types/node': 16.11.42
       c8: 7.11.3
       node-fetch: 3.2.6
       polka: 1.0.0-next.22
       rimraf: 3.0.2
-      rollup: 2.78.1
       sirv: 2.0.2
       typescript: 4.8.2
       uvu: 0.5.4
@@ -1085,9 +1087,8 @@ packages:
       glob: 7.2.3
       is-reference: 1.2.1
       magic-string: 0.25.9
-      resolve: 1.22.0
+      resolve: 1.22.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/plugin-json/4.1.0_rollup@2.78.1:
     resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==}
@@ -1096,7 +1097,6 @@ packages:
     dependencies:
       '@rollup/pluginutils': 3.1.0_rollup@2.78.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/plugin-node-resolve/14.1.0_rollup@2.78.1:
     resolution: {integrity: sha512-5G2niJroNCz/1zqwXtk0t9+twOSDlG00k1Wfd7bkbbXmwg8H8dvgHdIWAun53Ps/rckfvOC7scDBjuGFg5OaWw==}
@@ -1111,7 +1111,6 @@ packages:
       is-module: 1.0.0
       resolve: 1.22.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/pluginutils/3.1.0_rollup@2.78.1:
     resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
@@ -1123,7 +1122,6 @@ packages:
       estree-walker: 1.0.1
       picomatch: 2.3.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/pluginutils/4.2.1:
     resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
@@ -1183,11 +1181,9 @@ packages:
 
   /@types/estree/0.0.39:
     resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
-    dev: true
 
   /@types/estree/0.0.52:
     resolution: {integrity: sha512-BZWrtCU0bMVAIliIV+HJO1f1PR41M7NKjfxrFJwwhKI1KwhwOxYw1SXg9ao+CIMt774nFuGiG6eU+udtbEI9oQ==}
-    dev: true
 
   /@types/gitignore-parser/0.0.0:
     resolution: {integrity: sha512-qxOKILdhl4e639fWdkMySS4tBkRYHkrU2ZNScsMu84EPicliFRr+gAXCLPrs7kTFWdDpgAIlxtUr+YCRtVjsKw==}
@@ -1229,7 +1225,6 @@ packages:
 
   /@types/node/18.0.0:
     resolution: {integrity: sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==}
-    dev: true
 
   /@types/normalize-package-data/2.4.1:
     resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@@ -1253,7 +1248,6 @@ packages:
     resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
     dependencies:
       '@types/node': 18.0.0
-    dev: true
 
   /@types/sade/1.7.4:
     resolution: {integrity: sha512-6ys13kmtlY0aIOz4KtMdeBD9BHs6vSE3aRcj4vAZqXjypT2el8WZt6799CMjElVgh1cbOH/t3vrpQ4IpwytcPA==}
@@ -1504,7 +1498,6 @@ packages:
   /builtin-modules/3.3.0:
     resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
     engines: {node: '>=6'}
-    dev: true
 
   /c8/7.11.3:
     resolution: {integrity: sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==}
@@ -1693,7 +1686,6 @@ packages:
 
   /commondir/1.0.1:
     resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
-    dev: true
 
   /concat-map/0.0.1:
     resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
@@ -2168,7 +2160,6 @@ packages:
 
   /estree-walker/1.0.1:
     resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
-    dev: true
 
   /estree-walker/2.0.2:
     resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
@@ -2622,7 +2613,6 @@ packages:
     engines: {node: '>=6'}
     dependencies:
       builtin-modules: 3.3.0
-    dev: true
 
   /is-callable/1.2.4:
     resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==}
@@ -2641,12 +2631,6 @@ packages:
     dependencies:
       has: 1.0.3
 
-  /is-core-module/2.9.0:
-    resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==}
-    dependencies:
-      has: 1.0.3
-    dev: true
-
   /is-date-object/1.0.5:
     resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
     engines: {node: '>= 0.4'}
@@ -2682,7 +2666,6 @@ packages:
 
   /is-module/1.0.0:
     resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
-    dev: true
 
   /is-negative-zero/2.0.2:
     resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
@@ -2713,7 +2696,6 @@ packages:
     resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
     dependencies:
       '@types/estree': 0.0.52
-    dev: true
 
   /is-regex/1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
@@ -2922,7 +2904,6 @@ packages:
     resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
     dependencies:
       sourcemap-codec: 1.4.8
-    dev: true
 
   /magic-string/0.26.2:
     resolution: {integrity: sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==}
@@ -3658,15 +3639,6 @@ packages:
     deprecated: https://github.com/lydell/resolve-url#deprecated
     dev: true
 
-  /resolve/1.22.0:
-    resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
-    hasBin: true
-    dependencies:
-      is-core-module: 2.9.0
-      path-parse: 1.0.7
-      supports-preserve-symlinks-flag: 1.0.0
-    dev: true
-
   /resolve/1.22.1:
     resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
     hasBin: true


Test patch:
diff --git a/packages/kit/test/apps/basics/src/hooks.server.js b/packages/kit/test/apps/basics/src/hooks.server.js
index bf5d6b7fe..18f1c7a03 100644
--- a/packages/kit/test/apps/basics/src/hooks.server.js
+++ b/packages/kit/test/apps/basics/src/hooks.server.js
@@ -47,6 +47,15 @@ export const handle = sequence(
 		event.locals.name = /** @type {string} */ (event.cookies.get('name'));
 		return resolve(event);
 	},
+	async ({ event, resolve }) => {
+		if (event.url.pathname === '/cookies/serialize') {
+			event.cookies.set('before', 'before');
+			const response = await resolve(event);
+			response.headers.append('set-cookie', event.cookies.serialize('after', 'after'));
+			return response;
+		}
+		return resolve(event);
+	},
 	async ({ event, resolve }) => {
 		if (event.url.pathname === '/errors/error-in-handle') {
 			throw new Error('Error in handle');
diff --git a/packages/kit/test/apps/basics/src/routes/cookies/serialize/+server.js b/packages/kit/test/apps/basics/src/routes/cookies/serialize/+server.js
new file mode 100644
index 000000000..f46459823
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/cookies/serialize/+server.js
@@ -0,0 +1,8 @@
+/** @type {import('@sveltejs/kit').RequestHandler} */
+export const GET = ({ cookies }) => {
+	const response = new Response('success', {
+		status: 200
+	});
+	response.headers.append('set-cookie', cookies.serialize('endpoint', 'endpoint'));
+	return response;
+};
diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.js b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.js
new file mode 100644
index 000000000..2d4c6d175
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.js
@@ -0,0 +1,8 @@
+/** @type {import('./$types').PageLoad} */
+export function load({ data, depends }) {
+	depends('invalidate-depends:shared');
+	return {
+		shared: new Date().getTime(),
+		...data
+	};
+}
diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.server.js b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.server.js
new file mode 100644
index 000000000..fb81ddb99
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.server.js
@@ -0,0 +1,7 @@
+/** @type {import('./$types').PageServerLoad} */
+export function load({ depends }) {
+	depends('invalidate-depends:server');
+	return {
+		server: new Date().getTime()
+	};
+}
diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte
new file mode 100644
index 000000000..1ce33105c
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte
@@ -0,0 +1,24 @@
+<script>
+	import { invalidate } from '$app/navigation';
+
+	/** @type {import('./$types').PageData} */
+	export let data;
+</script>
+
+<p class="shared">{data.shared}</p>
+<button
+	type="button"
+	class="shared"
+	on:click={() => invalidate('invalidate-depends:shared')}
+>
+	invalidate shared
+</button>
+
+<p class="server">{data.server}</p>
+<button
+	type="button"
+	class="server"
+	on:click={() => invalidate('invalidate-depends:server')}
+>
+	invalidate server
+</button>
diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js
index 628e64dd1..185b5e514 100644
--- a/packages/kit/test/apps/basics/test/client.test.js
+++ b/packages/kit/test/apps/basics/test/client.test.js
@@ -760,6 +760,36 @@ test.describe.serial('Invalidation', () => {
 		await page.waitForTimeout(200);
 		expect(await page.textContent('h1')).toBe('a: 4, b: 5');
 	});
+
+	test('+layout(.server).js is re-run when server dep is invalidated', async ({ page }) => {
+		await page.goto('/load/invalidation/depends');
+		const server = await page.textContent('p.server');
+		const shared = await page.textContent('p.shared');
+		expect(server).toBeDefined();
+		expect(shared).toBeDefined();
+
+		await Promise.all([page.click('button.server'), page.waitForLoadState('networkidle')]);
+		await page.waitForTimeout(200);
+		const next_server = await page.textContent('p.server');
+		const next_shared = await page.textContent('p.shared');
+		expect(server).not.toBe(next_server);
+		expect(shared).not.toBe(next_shared);
+	});
+
+	test('+layout.js is re-run when shared dep is invalidated', async ({ page }) => {
+		await page.goto('/load/invalidation/depends');
+		const server = await page.textContent('p.server');
+		const shared = await page.textContent('p.shared');
+		expect(server).toBeDefined();
+		expect(shared).toBeDefined();
+
+		await Promise.all([page.click('button.shared'), page.waitForLoadState('networkidle')]);
+		await page.waitForTimeout(200);
+		const next_server = await page.textContent('p.server');
+		const next_shared = await page.textContent('p.shared');
+		expect(server).toBe(next_server);
+		expect(shared).not.toBe(next_shared);
+	});
 });
 
 test.describe('data-sveltekit attributes', () => {
diff --git a/packages/kit/test/apps/basics/test/server.test.js b/packages/kit/test/apps/basics/test/server.test.js
index 0404859e5..87bb6ea0b 100644
--- a/packages/kit/test/apps/basics/test/server.test.js
+++ b/packages/kit/test/apps/basics/test/server.test.js
@@ -336,6 +336,18 @@ test.describe('setHeaders', () => {
 	});
 });
 
+test.describe('cookies', () => {
+	test('cookie.serialize created correct cookie header string', async ({ page }) => {
+		const response = await page.goto('/cookies/serialize');
+		const cookies = await response.headerValue('set-cookie');
+		expect(
+			cookies.includes('before=before') &&
+				cookies.includes('after=after') &&
+				cookies.includes('endpoint=endpoint')
+		).toBe(true);
+	});
+});
+
 test.describe('Miscellaneous', () => {
 	test('does not serve version.json with an immutable cache header', async ({ request }) => {
 		// this isn't actually a great test, because caching behaviour is down to adapters.