@pyreon/router 0.24.4 → 0.24.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -6
- package/src/components.tsx +0 -650
- package/src/env.d.ts +0 -6
- package/src/index.ts +0 -106
- package/src/loader.ts +0 -200
- package/src/manifest.ts +0 -399
- package/src/match.ts +0 -921
- package/src/not-found.ts +0 -75
- package/src/redirect.ts +0 -63
- package/src/router.ts +0 -1424
- package/src/scroll.ts +0 -93
- package/src/tests/integration.test.tsx +0 -298
- package/src/tests/loader.test.ts +0 -1024
- package/src/tests/manifest-snapshot.test.ts +0 -101
- package/src/tests/match.test.ts +0 -782
- package/src/tests/native-markers.test.ts +0 -18
- package/src/tests/redirect.test.ts +0 -96
- package/src/tests/router.browser.test.tsx +0 -509
- package/src/tests/router.test.ts +0 -5498
- package/src/tests/routerlink-reactive-to.browser.test.tsx +0 -158
- package/src/tests/scroll.test.ts +0 -31
- package/src/tests/setup.ts +0 -3
- package/src/types.ts +0 -517
package/src/not-found.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { ComponentFn, Props, VNodeChild } from '@pyreon/core'
|
|
2
|
-
import { ErrorBoundary, h } from '@pyreon/core'
|
|
3
|
-
|
|
4
|
-
// ─── NotFound symbol + throw ────────────────────────────────────────────────
|
|
5
|
-
|
|
6
|
-
const NOT_FOUND = Symbol.for('pyreon.notFound')
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Throw inside a route loader or component to trigger the nearest
|
|
10
|
-
* NotFoundBoundary. Inspired by Next.js's `notFound()`.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* // In a loader:
|
|
15
|
-
* loader: async ({ params }) => {
|
|
16
|
-
* const user = await fetchUser(params.id)
|
|
17
|
-
* if (!user) notFound()
|
|
18
|
-
* return user
|
|
19
|
-
* }
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export function notFound(message?: string): never {
|
|
23
|
-
const err = new Error(message ?? 'Not Found')
|
|
24
|
-
;(err as unknown as Record<symbol, unknown>)[NOT_FOUND] = true
|
|
25
|
-
throw err
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Check if an error is a NotFoundError thrown by `notFound()`. */
|
|
29
|
-
export function isNotFoundError(err: unknown): boolean {
|
|
30
|
-
return (
|
|
31
|
-
typeof err === 'object' &&
|
|
32
|
-
err !== null &&
|
|
33
|
-
(err as Record<string | symbol, unknown>)[NOT_FOUND] === true
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ─── NotFoundBoundary ──────────────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
export interface NotFoundBoundaryProps extends Props {
|
|
40
|
-
/** Component or VNode to render when notFound() is thrown */
|
|
41
|
-
fallback: ComponentFn | VNodeChild
|
|
42
|
-
children?: VNodeChild
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Catches `notFound()` errors from child route components or loaders
|
|
47
|
-
* and renders the fallback. Wraps Pyreon's ErrorBoundary with notFound
|
|
48
|
-
* detection — non-notFound errors propagate to parent error boundaries.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```tsx
|
|
52
|
-
* <NotFoundBoundary fallback={<NotFoundPage />}>
|
|
53
|
-
* <RouterView />
|
|
54
|
-
* </NotFoundBoundary>
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export const NotFoundBoundary: ComponentFn<NotFoundBoundaryProps> = (props) => {
|
|
58
|
-
return h(
|
|
59
|
-
ErrorBoundary,
|
|
60
|
-
{
|
|
61
|
-
fallback: (err: unknown, reset: () => void) => {
|
|
62
|
-
if (!isNotFoundError(err)) {
|
|
63
|
-
// Re-throw non-notFound errors so they propagate
|
|
64
|
-
throw err
|
|
65
|
-
}
|
|
66
|
-
const fb = props.fallback
|
|
67
|
-
if (typeof fb === 'function' && fb.length <= 1) {
|
|
68
|
-
return h(fb as ComponentFn, { error: err, reset })
|
|
69
|
-
}
|
|
70
|
-
return fb as VNodeChild
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
props.children,
|
|
74
|
-
)
|
|
75
|
-
}
|
package/src/redirect.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// ─── Redirect symbol + throw ────────────────────────────────────────────────
|
|
2
|
-
|
|
3
|
-
const REDIRECT = Symbol.for('pyreon.redirect')
|
|
4
|
-
|
|
5
|
-
/** Standard redirect status codes. 307/308 preserve the request method, 302/303 don't. */
|
|
6
|
-
export type RedirectStatus = 301 | 302 | 303 | 307 | 308
|
|
7
|
-
|
|
8
|
-
interface RedirectInfo {
|
|
9
|
-
url: string
|
|
10
|
-
status: RedirectStatus
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Throw inside a route loader to redirect the navigation server-side
|
|
15
|
-
* (during SSR returns a 302/307 `Location:` response) and client-side
|
|
16
|
-
* (during CSR triggers `router.replace()` before the layout renders).
|
|
17
|
-
*
|
|
18
|
-
* The auth-gate use case: replaces the fragile `onMount + router.push()`
|
|
19
|
-
* workaround. `onMount` doesn't fire reliably under nested-layout dev SSR +
|
|
20
|
-
* hydration — so the layout renders briefly before the push happens, leaking
|
|
21
|
-
* authenticated UI to unauthenticated users. `redirect()` runs in the loader
|
|
22
|
-
* BEFORE the layout's component is invoked, so the unauthenticated UI never
|
|
23
|
-
* mounts in the first place.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* // src/routes/app/_layout.tsx
|
|
28
|
-
* export const loader = async ({ request }) => {
|
|
29
|
-
* const session = await getSession(request)
|
|
30
|
-
* if (!session) redirect('/login')
|
|
31
|
-
* return { user: session.user }
|
|
32
|
-
* }
|
|
33
|
-
* ```
|
|
34
|
-
*
|
|
35
|
-
* @param url - Target URL (typically a path like `/login` or absolute URL for cross-origin).
|
|
36
|
-
* @param status - HTTP redirect status. Default `307` (Temporary Redirect, method-preserving).
|
|
37
|
-
* Use `301`/`308` for permanent moves, `302`/`303` to force GET on the target.
|
|
38
|
-
*/
|
|
39
|
-
export function redirect(url: string, status: RedirectStatus = 307): never {
|
|
40
|
-
const err = new Error(`Redirect to ${url}`)
|
|
41
|
-
;(err as unknown as Record<symbol, RedirectInfo>)[REDIRECT] = { url, status }
|
|
42
|
-
throw err
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Check if an error is a RedirectError thrown by `redirect()`. */
|
|
46
|
-
export function isRedirectError(err: unknown): boolean {
|
|
47
|
-
return (
|
|
48
|
-
typeof err === 'object' &&
|
|
49
|
-
err !== null &&
|
|
50
|
-
typeof (err as Record<symbol, unknown>)[REDIRECT] === 'object'
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Extract the redirect URL and status from a thrown RedirectError. Returns
|
|
56
|
-
* `null` if `err` isn't a RedirectError. Used by the router's loader-runner
|
|
57
|
-
* (CSR) and the SSR handler to convert the thrown error into the right kind
|
|
58
|
-
* of response (a `router.replace()` call or a `302`/`307` Response).
|
|
59
|
-
*/
|
|
60
|
-
export function getRedirectInfo(err: unknown): RedirectInfo | null {
|
|
61
|
-
if (!isRedirectError(err)) return null
|
|
62
|
-
return (err as Record<symbol, RedirectInfo>)[REDIRECT] ?? null
|
|
63
|
-
}
|