Repository: sveltejs/kit (JavaScript)

Issue:
[kit 2.1.0] Runtime error when `onNavigate` callback returns a function
### Describe the bug

When an `onNavigate` callback returns a function, a runtime error occurs:

```
ReferenceError: callbacks is not defined
```

The problem comes from https://github.com/sveltejs/kit/pull/11547, specifically this line: https://github.com/sveltejs/kit/pull/11547/files#diff-6bc786c5d82299b5eed36bb073cd7e3c8347af2951019da2b5dff1d5e3bad611R1289.

Its preceded by a `@ts-ignore`, thats probably why it was missed during the refactor.

### Reproduction

Go to https://stackblitz.com/edit/sveltejs-kit-template-default-jsehy7?description=The%20default%20SvelteKit%20template,%20generated%20with%20create-svelte&file=src%2Froutes%2F%2Blayout.svelte&title=SvelteKit%20Default%20Template and navigate by clicking a link. The error will appear in the console.

### Logs

_No response_

### System Info

```Shell
System:
    OS: macOS 12.7.1
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 390.63 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 20.6.0 - ~/.nvm/versions/node/v20.6.0/bin/node
    npm: 9.8.1 - ~/.nvm/versions/node/v20.6.0/bin/npm
    pnpm: 8.7.4 - ~/.nvm/versions/node/v20.6.0/bin/pnpm
    bun: 1.0.0 - ~/.nvm/versions/node/v20.6.0/bin/bun
  Browsers:
    Brave Browser: 116.1.57.53
    Chrome: 120.0.6099.199
    Safari: 17.1.2
  npmPackages:
    @sveltejs/adapter-vercel: 4.0.4 => 4.0.4 
    @sveltejs/kit: 2.3.0 => 2.3.0 
    @sveltejs/vite-plugin-svelte: 3.0.1 => 3.0.1 
    svelte: 4.2.8 => 4.2.8
```


### Severity

blocking all usage of SvelteKit

### Additional Information

_No response_


Discussion:

Patch:
diff --git a/.changeset/tiny-news-clap.md b/.changeset/tiny-news-clap.md
new file mode 100644
index 000000000000..ebae0e54dca8
--- /dev/null
+++ b/.changeset/tiny-news-clap.md
@@ -0,0 +1,5 @@
+---
+"@sveltejs/kit": patch
+---
+
+fix: handle `onNavigate` callbacks correctly
diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js
index de0325aa5865..e1bc5f7368d3 100644
--- a/packages/kit/src/runtime/client/client.js
+++ b/packages/kit/src/runtime/client/client.js
@@ -1330,7 +1330,7 @@ async function navigate({
 					fn(/** @type {import('@sveltejs/kit').OnNavigate} */ (nav.navigation))
 				)
 			)
-		).filter((value) => typeof value === 'function');
+		).filter(/** @returns {value is () => void} */ (value) => typeof value === 'function');
 
 		if (after_navigate.length > 0) {
 			function cleanup() {
@@ -1341,9 +1341,7 @@ async function navigate({
 			}
 
 			after_navigate.push(cleanup);
-
-			// @ts-ignore
-			callbacks.after_navigate.push(...after_navigate);
+			after_navigate_callbacks.push(...after_navigate);
 		}
 
 		root.$set(navigation_result.props);


Test patch:
diff --git a/packages/kit/test/apps/basics/src/routes/navigation-lifecycle/on-navigate/[x]/+page.svelte b/packages/kit/test/apps/basics/src/routes/navigation-lifecycle/on-navigate/[x]/+page.svelte
index 35e8ebb73349..f05f035822f3 100644
--- a/packages/kit/test/apps/basics/src/routes/navigation-lifecycle/on-navigate/[x]/+page.svelte
+++ b/packages/kit/test/apps/basics/src/routes/navigation-lifecycle/on-navigate/[x]/+page.svelte
@@ -10,12 +10,20 @@
 	/** @type {Omit<import('@sveltejs/kit').NavigationType, 'enter' | 'leave'>} */
 	let type;
 
+	let called_return = false;
+
 	onNavigate((navigation) => {
 		from = navigation.from;
 		to = navigation.to;
 		type = navigation.type;
 	});
+
+	onNavigate(() => {
+		return () => {
+			called_return = true;
+		};
+	});
 </script>
 
-<h1>{from?.url.pathname} -> {to?.url.pathname} ({type ?? '...'})</h1>
+<h1>{from?.url.pathname} -> {to?.url.pathname} ({type ?? '...'}) {called_return}</h1>
 <a href="/navigation-lifecycle/on-navigate/b">/b</a>
diff --git a/packages/kit/test/apps/basics/test/cross-platform/client.test.js b/packages/kit/test/apps/basics/test/cross-platform/client.test.js
index 19dd898d46be..804b4f06d4cd 100644
--- a/packages/kit/test/apps/basics/test/cross-platform/client.test.js
+++ b/packages/kit/test/apps/basics/test/cross-platform/client.test.js
@@ -240,11 +240,11 @@ test.describe('Navigation lifecycle functions', () => {
 
 	test('onNavigate calls callback', async ({ page, clicknav }) => {
 		await page.goto('/navigation-lifecycle/on-navigate/a');
-		expect(await page.textContent('h1')).toBe('undefined -> undefined (...)');
+		expect(await page.textContent('h1')).toBe('undefined -> undefined (...) false');
 
 		await clicknav('[href="/navigation-lifecycle/on-navigate/b"]');
 		expect(await page.textContent('h1')).toBe(
-			'/navigation-lifecycle/on-navigate/a -> /navigation-lifecycle/on-navigate/b (link)'
+			'/navigation-lifecycle/on-navigate/a -> /navigation-lifecycle/on-navigate/b (link) true'
 		);
 	});
 });