@timber-js/app 0.1.1 → 0.1.3
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/adapters/cloudflare.ts +325 -0
- package/src/adapters/nitro.ts +366 -0
- package/src/adapters/types.ts +63 -0
- package/src/cache/index.ts +91 -0
- package/src/cache/redis-handler.ts +91 -0
- package/src/cache/register-cached-function.ts +99 -0
- package/src/cache/singleflight.ts +26 -0
- package/src/cache/stable-stringify.ts +21 -0
- package/src/cache/timber-cache.ts +116 -0
- package/src/cli.ts +201 -0
- package/src/client/browser-entry.ts +663 -0
- package/src/client/error-boundary.tsx +209 -0
- package/src/client/form.tsx +200 -0
- package/src/client/head.ts +61 -0
- package/src/client/history.ts +46 -0
- package/src/client/index.ts +60 -0
- package/src/client/link-navigate-interceptor.tsx +62 -0
- package/src/client/link-status-provider.tsx +40 -0
- package/src/client/link.tsx +310 -0
- package/src/client/nuqs-adapter.tsx +117 -0
- package/src/client/router-ref.ts +25 -0
- package/src/client/router.ts +563 -0
- package/src/client/segment-cache.ts +194 -0
- package/src/client/segment-context.ts +57 -0
- package/src/client/ssr-data.ts +95 -0
- package/src/client/types.ts +4 -0
- package/src/client/unload-guard.ts +34 -0
- package/src/client/use-cookie.ts +122 -0
- package/src/client/use-link-status.ts +46 -0
- package/src/client/use-navigation-pending.ts +47 -0
- package/src/client/use-params.ts +71 -0
- package/src/client/use-pathname.ts +43 -0
- package/src/client/use-query-states.ts +133 -0
- package/src/client/use-router.ts +77 -0
- package/src/client/use-search-params.ts +74 -0
- package/src/client/use-selected-layout-segment.ts +110 -0
- package/src/content/index.ts +13 -0
- package/src/cookies/define-cookie.ts +137 -0
- package/src/cookies/index.ts +9 -0
- package/src/fonts/ast.ts +359 -0
- package/src/fonts/css.ts +68 -0
- package/src/fonts/fallbacks.ts +248 -0
- package/src/fonts/google.ts +332 -0
- package/src/fonts/local.ts +177 -0
- package/src/fonts/types.ts +88 -0
- package/src/index.ts +420 -0
- package/src/plugins/adapter-build.ts +118 -0
- package/src/plugins/build-manifest.ts +323 -0
- package/src/plugins/build-report.ts +353 -0
- package/src/plugins/cache-transform.ts +199 -0
- package/src/plugins/chunks.ts +90 -0
- package/src/plugins/content.ts +136 -0
- package/src/plugins/dev-error-overlay.ts +230 -0
- package/src/plugins/dev-logs.ts +280 -0
- package/src/plugins/dev-server.ts +391 -0
- package/src/plugins/dynamic-transform.ts +161 -0
- package/src/plugins/entries.ts +214 -0
- package/src/plugins/fonts.ts +581 -0
- package/src/plugins/mdx.ts +179 -0
- package/src/plugins/react-prod.ts +56 -0
- package/src/plugins/routing.ts +419 -0
- package/src/plugins/server-action-exports.ts +220 -0
- package/src/plugins/server-bundle.ts +113 -0
- package/src/plugins/shims.ts +168 -0
- package/src/plugins/static-build.ts +207 -0
- package/src/routing/codegen.ts +396 -0
- package/src/routing/index.ts +14 -0
- package/src/routing/interception.ts +173 -0
- package/src/routing/scanner.ts +487 -0
- package/src/routing/status-file-lint.ts +114 -0
- package/src/routing/types.ts +100 -0
- package/src/search-params/analyze.ts +192 -0
- package/src/search-params/codecs.ts +153 -0
- package/src/search-params/create.ts +314 -0
- package/src/search-params/index.ts +23 -0
- package/src/search-params/registry.ts +31 -0
- package/src/server/access-gate.tsx +142 -0
- package/src/server/action-client.ts +473 -0
- package/src/server/action-handler.ts +325 -0
- package/src/server/actions.ts +236 -0
- package/src/server/asset-headers.ts +81 -0
- package/src/server/body-limits.ts +102 -0
- package/src/server/build-manifest.ts +234 -0
- package/src/server/canonicalize.ts +90 -0
- package/src/server/client-module-map.ts +58 -0
- package/src/server/csrf.ts +79 -0
- package/src/server/deny-renderer.ts +302 -0
- package/src/server/dev-logger.ts +419 -0
- package/src/server/dev-span-processor.ts +78 -0
- package/src/server/dev-warnings.ts +282 -0
- package/src/server/early-hints-sender.ts +55 -0
- package/src/server/early-hints.ts +142 -0
- package/src/server/error-boundary-wrapper.ts +69 -0
- package/src/server/error-formatter.ts +184 -0
- package/src/server/flush.ts +182 -0
- package/src/server/form-data.ts +176 -0
- package/src/server/form-flash.ts +93 -0
- package/src/server/html-injectors.ts +445 -0
- package/src/server/index.ts +222 -0
- package/src/server/instrumentation.ts +136 -0
- package/src/server/logger.ts +145 -0
- package/src/server/manifest-status-resolver.ts +215 -0
- package/src/server/metadata-render.ts +527 -0
- package/src/server/metadata-routes.ts +189 -0
- package/src/server/metadata.ts +263 -0
- package/src/server/middleware-runner.ts +32 -0
- package/src/server/nuqs-ssr-provider.tsx +63 -0
- package/src/server/pipeline.ts +555 -0
- package/src/server/prerender.ts +139 -0
- package/src/server/primitives.ts +264 -0
- package/src/server/proxy.ts +43 -0
- package/src/server/request-context.ts +554 -0
- package/src/server/route-element-builder.ts +395 -0
- package/src/server/route-handler.ts +153 -0
- package/src/server/route-matcher.ts +316 -0
- package/src/server/rsc-entry/api-handler.ts +112 -0
- package/src/server/rsc-entry/error-renderer.ts +177 -0
- package/src/server/rsc-entry/helpers.ts +147 -0
- package/src/server/rsc-entry/index.ts +688 -0
- package/src/server/rsc-entry/ssr-bridge.ts +18 -0
- package/src/server/slot-resolver.ts +359 -0
- package/src/server/ssr-entry.ts +161 -0
- package/src/server/ssr-render.ts +200 -0
- package/src/server/status-code-resolver.ts +282 -0
- package/src/server/tracing.ts +281 -0
- package/src/server/tree-builder.ts +354 -0
- package/src/server/types.ts +150 -0
- package/src/shims/font-google.ts +67 -0
- package/src/shims/headers.ts +11 -0
- package/src/shims/image.ts +48 -0
- package/src/shims/link.ts +9 -0
- package/src/shims/navigation-client.ts +52 -0
- package/src/shims/navigation.ts +31 -0
- package/src/shims/server-only-noop.js +5 -0
- package/src/utils/directive-parser.ts +529 -0
- package/src/utils/format.ts +10 -0
- package/src/utils/startup-timer.ts +102 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Server-side type definitions
|
|
2
|
+
|
|
3
|
+
import type { EarlyHint } from './early-hints.js';
|
|
4
|
+
|
|
5
|
+
export interface MiddlewareContext {
|
|
6
|
+
req: Request;
|
|
7
|
+
requestHeaders: Headers;
|
|
8
|
+
headers: Headers;
|
|
9
|
+
params: Record<string, string | string[]>;
|
|
10
|
+
searchParams: unknown;
|
|
11
|
+
/** Declare early hints for critical resources. Appends Link headers. */
|
|
12
|
+
earlyHints: (hints: EarlyHint[]) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RouteContext {
|
|
16
|
+
req: Request;
|
|
17
|
+
params: Record<string, string | string[]>;
|
|
18
|
+
searchParams: URLSearchParams;
|
|
19
|
+
headers: Headers;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AccessContext {
|
|
23
|
+
params: Record<string, string | string[]>;
|
|
24
|
+
searchParams: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface Metadata {
|
|
28
|
+
title?: string | { default?: string; template?: string; absolute?: string };
|
|
29
|
+
description?: string;
|
|
30
|
+
generator?: string;
|
|
31
|
+
applicationName?: string;
|
|
32
|
+
authors?: Array<{ name?: string; url?: string }> | { name?: string; url?: string };
|
|
33
|
+
creator?: string;
|
|
34
|
+
publisher?: string;
|
|
35
|
+
robots?:
|
|
36
|
+
| string
|
|
37
|
+
| {
|
|
38
|
+
index?: boolean;
|
|
39
|
+
follow?: boolean;
|
|
40
|
+
googleBot?: string | { index?: boolean; follow?: boolean; [key: string]: unknown };
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
};
|
|
43
|
+
referrer?: string;
|
|
44
|
+
keywords?: string | string[];
|
|
45
|
+
category?: string;
|
|
46
|
+
openGraph?: {
|
|
47
|
+
title?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
url?: string;
|
|
50
|
+
siteName?: string;
|
|
51
|
+
images?:
|
|
52
|
+
| string
|
|
53
|
+
| { url: string; width?: number; height?: number; alt?: string }
|
|
54
|
+
| Array<{ url: string; width?: number; height?: number; alt?: string }>;
|
|
55
|
+
videos?: Array<{ url: string; width?: number; height?: number }>;
|
|
56
|
+
audio?: Array<{ url: string }>;
|
|
57
|
+
locale?: string;
|
|
58
|
+
type?: string;
|
|
59
|
+
publishedTime?: string;
|
|
60
|
+
modifiedTime?: string;
|
|
61
|
+
authors?: string[];
|
|
62
|
+
};
|
|
63
|
+
twitter?: {
|
|
64
|
+
card?: string;
|
|
65
|
+
site?: string;
|
|
66
|
+
siteId?: string;
|
|
67
|
+
title?: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
images?:
|
|
70
|
+
| string
|
|
71
|
+
| string[]
|
|
72
|
+
| { url: string; alt?: string; width?: number; height?: number }
|
|
73
|
+
| Array<{ url: string; alt?: string; width?: number; height?: number }>;
|
|
74
|
+
creator?: string;
|
|
75
|
+
creatorId?: string;
|
|
76
|
+
/** Player card fields — embedded media player. Requires card: 'player'. */
|
|
77
|
+
players?: Array<{
|
|
78
|
+
playerUrl: string;
|
|
79
|
+
streamUrl?: string;
|
|
80
|
+
width?: number;
|
|
81
|
+
height?: number;
|
|
82
|
+
}>;
|
|
83
|
+
/** App card fields — link to a native app. Requires card: 'app'. */
|
|
84
|
+
app?: {
|
|
85
|
+
name?: string;
|
|
86
|
+
id?: { iPhone?: string; iPad?: string; googlePlay?: string };
|
|
87
|
+
url?: { iPhone?: string; iPad?: string; googlePlay?: string };
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
icons?: {
|
|
91
|
+
icon?: string | Array<{ url: string; sizes?: string; type?: string; media?: string }>;
|
|
92
|
+
shortcut?: string | string[];
|
|
93
|
+
apple?: string | Array<{ url: string; sizes?: string; type?: string }>;
|
|
94
|
+
other?: Array<{ rel: string; url: string; sizes?: string; type?: string }>;
|
|
95
|
+
};
|
|
96
|
+
manifest?: string;
|
|
97
|
+
alternates?: {
|
|
98
|
+
canonical?: string;
|
|
99
|
+
languages?: Record<string, string>;
|
|
100
|
+
media?: Record<string, string>;
|
|
101
|
+
types?: Record<string, string>;
|
|
102
|
+
};
|
|
103
|
+
verification?: {
|
|
104
|
+
google?: string;
|
|
105
|
+
yahoo?: string;
|
|
106
|
+
yandex?: string;
|
|
107
|
+
other?: Record<string, string | string[]>;
|
|
108
|
+
};
|
|
109
|
+
metadataBase?: URL | null;
|
|
110
|
+
appleWebApp?: {
|
|
111
|
+
capable?: boolean;
|
|
112
|
+
title?: string;
|
|
113
|
+
statusBarStyle?: string;
|
|
114
|
+
startupImage?: string | Array<{ url: string; media?: string }>;
|
|
115
|
+
};
|
|
116
|
+
formatDetection?: { email?: boolean; address?: boolean; telephone?: boolean };
|
|
117
|
+
/** App Links — deep linking to native apps (al:* meta property tags). */
|
|
118
|
+
appLinks?: {
|
|
119
|
+
ios?: Array<{ url: string; app_store_id?: string; app_name?: string }>;
|
|
120
|
+
android?: Array<{ url: string; package?: string; class?: string; app_name?: string }>;
|
|
121
|
+
windows?: Array<{ url: string; app_id?: string; app_name?: string }>;
|
|
122
|
+
windowsPhone?: Array<{ url: string; app_id?: string; app_name?: string }>;
|
|
123
|
+
windowsUniversal?: Array<{ url: string; app_id?: string; app_name?: string }>;
|
|
124
|
+
web?: { url?: string; shouldFallback?: boolean };
|
|
125
|
+
};
|
|
126
|
+
/** apple-itunes-app meta tag — link to an iOS app in the App Store. */
|
|
127
|
+
itunes?: { appId: string; appArgument?: string; affiliateData?: string };
|
|
128
|
+
other?: Record<string, string | string[]>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
132
|
+
export namespace MetadataRoute {
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
134
|
+
export interface Sitemap extends Array<SitemapEntry> {}
|
|
135
|
+
export interface SitemapEntry {
|
|
136
|
+
url: string;
|
|
137
|
+
lastModified?: Date | string;
|
|
138
|
+
changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
139
|
+
priority?: number;
|
|
140
|
+
}
|
|
141
|
+
export interface Robots {
|
|
142
|
+
rules: Array<{
|
|
143
|
+
userAgent?: string | string[];
|
|
144
|
+
allow?: string | string[];
|
|
145
|
+
disallow?: string | string[];
|
|
146
|
+
}>;
|
|
147
|
+
sitemap?: string | string[];
|
|
148
|
+
host?: string;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback shim for `next/font/google` → `@timber/fonts/google`.
|
|
3
|
+
*
|
|
4
|
+
* At build time, the timber-fonts plugin's transform hook replaces font
|
|
5
|
+
* function calls with static FontResult objects containing real class names
|
|
6
|
+
* and font stacks. This file serves two purposes:
|
|
7
|
+
*
|
|
8
|
+
* 1. **TypeScript resolution** — provides types for IDEs and `tsc` outside
|
|
9
|
+
* of Vite's module graph (where the virtual module handles it).
|
|
10
|
+
* 2. **Runtime fallback** — returns empty className/fontFamily values when
|
|
11
|
+
* the plugin hasn't processed a call (e.g. in tests or non-Vite environments).
|
|
12
|
+
*
|
|
13
|
+
* The shim resolution path (`next/font/google` → `\0@timber/fonts/google`)
|
|
14
|
+
* is unchanged — this file is NOT on that resolution path. It exists as a
|
|
15
|
+
* physical module for direct imports and type re-exports.
|
|
16
|
+
*
|
|
17
|
+
* Design doc: 24-fonts.md, "Next.js Font Compatibility"
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { GoogleFontConfig, FontResult } from '#/fonts/types.js';
|
|
21
|
+
|
|
22
|
+
export type { GoogleFontConfig, FontResult };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create a stub FontResult with empty values.
|
|
26
|
+
*
|
|
27
|
+
* The timber-fonts plugin replaces these calls at build time with real
|
|
28
|
+
* class names and font stacks. This stub ensures code that imports
|
|
29
|
+
* font functions outside of the build pipeline (tests, type-checking)
|
|
30
|
+
* gets a valid FontResult shape without runtime errors.
|
|
31
|
+
*/
|
|
32
|
+
function createStubFontResult(config?: GoogleFontConfig): FontResult {
|
|
33
|
+
return {
|
|
34
|
+
className: '',
|
|
35
|
+
style: { fontFamily: '' },
|
|
36
|
+
variable: config?.variable,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generic font loader — accepts any font name, returns a stub FontResult.
|
|
42
|
+
*
|
|
43
|
+
* Named exports like `Inter`, `Roboto`, etc. are generated dynamically
|
|
44
|
+
* by the virtual module at build time. This function provides a catch-all
|
|
45
|
+
* for non-Vite contexts.
|
|
46
|
+
*/
|
|
47
|
+
export function createFont(_family: string, config?: GoogleFontConfig): FontResult {
|
|
48
|
+
return createStubFontResult(config);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Common Google Font exports for TypeScript autocomplete.
|
|
52
|
+
// These are stubs — the virtual module and transform hook provide real values.
|
|
53
|
+
export const Inter = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
54
|
+
export const Roboto = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
55
|
+
export const Open_Sans = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
56
|
+
export const Lato = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
57
|
+
export const Montserrat = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
58
|
+
export const Poppins = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
59
|
+
export const Geist = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
60
|
+
export const Geist_Mono = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
61
|
+
export const JetBrains_Mono = (config?: GoogleFontConfig): FontResult =>
|
|
62
|
+
createStubFontResult(config);
|
|
63
|
+
export const Source_Code_Pro = (config?: GoogleFontConfig): FontResult =>
|
|
64
|
+
createStubFontResult(config);
|
|
65
|
+
export const Playfair_Display = (config?: GoogleFontConfig): FontResult =>
|
|
66
|
+
createStubFontResult(config);
|
|
67
|
+
export const Merriweather = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shim: next/headers → timber request context
|
|
3
|
+
*
|
|
4
|
+
* Re-exports timber's ALS-backed headers() and cookies() for libraries
|
|
5
|
+
* that import from next/headers. These are real implementations backed
|
|
6
|
+
* by AsyncLocalStorage, not stubs.
|
|
7
|
+
*
|
|
8
|
+
* See design/14-ecosystem.md §"next/headers" for the full shim audit.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { headers, cookies } from '#/server/request-context.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shim: next/image → stub
|
|
3
|
+
*
|
|
4
|
+
* timber.js does not implement an image optimization pipeline.
|
|
5
|
+
* This shim exports a pass-through <img> component so libraries
|
|
6
|
+
* that import next/image still render correctly.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createElement } from 'react';
|
|
10
|
+
import type { ImgHTMLAttributes } from 'react';
|
|
11
|
+
|
|
12
|
+
export type ImageProps = ImgHTMLAttributes<HTMLImageElement> & {
|
|
13
|
+
/** next/image width — passed through as the HTML attribute */
|
|
14
|
+
width?: number | string;
|
|
15
|
+
/** next/image height — passed through as the HTML attribute */
|
|
16
|
+
height?: number | string;
|
|
17
|
+
/** next/image priority — ignored (no optimization pipeline) */
|
|
18
|
+
priority?: boolean;
|
|
19
|
+
/** next/image quality — ignored */
|
|
20
|
+
quality?: number;
|
|
21
|
+
/** next/image fill — ignored */
|
|
22
|
+
fill?: boolean;
|
|
23
|
+
/** next/image sizes — passed through */
|
|
24
|
+
sizes?: string;
|
|
25
|
+
/** next/image placeholder — ignored */
|
|
26
|
+
placeholder?: 'blur' | 'empty';
|
|
27
|
+
/** next/image blurDataURL — ignored */
|
|
28
|
+
blurDataURL?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Pass-through image component.
|
|
33
|
+
*
|
|
34
|
+
* Renders a plain <img> tag, ignoring next/image-specific optimization
|
|
35
|
+
* props (priority, quality, fill, placeholder, blurDataURL).
|
|
36
|
+
*/
|
|
37
|
+
export function Image({
|
|
38
|
+
priority: _priority,
|
|
39
|
+
quality: _quality,
|
|
40
|
+
fill: _fill,
|
|
41
|
+
placeholder: _placeholder,
|
|
42
|
+
blurDataURL: _blurDataURL,
|
|
43
|
+
...rest
|
|
44
|
+
}: ImageProps) {
|
|
45
|
+
return createElement('img', rest);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default Image;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shim: next/link → @timber/app/client Link
|
|
3
|
+
*
|
|
4
|
+
* Re-exports timber's Link component so libraries that import next/link
|
|
5
|
+
* get the timber equivalent without modification.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { Link as default, Link } from '#/client/link.js';
|
|
9
|
+
export type { LinkProps } from '#/client/link.js';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shim: next/navigation (client environment only)
|
|
3
|
+
*
|
|
4
|
+
* Re-exports only the client-side hooks from timber's navigation shims.
|
|
5
|
+
* Server-only functions (redirect, notFound, etc.) are excluded to prevent
|
|
6
|
+
* server/primitives.ts from being pulled into the browser bundle.
|
|
7
|
+
*
|
|
8
|
+
* The full shim (navigation.ts) is still used in the RSC and SSR environments
|
|
9
|
+
* where both client hooks and server functions are needed.
|
|
10
|
+
*
|
|
11
|
+
* See design/14-ecosystem.md §"next/navigation" for the full shim audit.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Hooks (client-side only)
|
|
15
|
+
export { useParams } from '#/client/use-params.js';
|
|
16
|
+
export { usePathname } from '#/client/use-pathname.js';
|
|
17
|
+
export { useSearchParams } from '#/client/use-search-params.js';
|
|
18
|
+
export { useRouter } from '#/client/use-router.js';
|
|
19
|
+
export {
|
|
20
|
+
useSelectedLayoutSegment,
|
|
21
|
+
useSelectedLayoutSegments,
|
|
22
|
+
} from '#/client/use-selected-layout-segment.js';
|
|
23
|
+
|
|
24
|
+
// RedirectType enum is safe (no server code dependency) and used by some
|
|
25
|
+
// client-side libraries for type checking.
|
|
26
|
+
export const RedirectType = {
|
|
27
|
+
push: 'push',
|
|
28
|
+
replace: 'replace',
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
// Server-only stubs — throw at runtime if called from the client.
|
|
32
|
+
// These exist for type compatibility with libraries that import the types
|
|
33
|
+
// but should never execute in the browser.
|
|
34
|
+
export function redirect(): never {
|
|
35
|
+
throw new Error(
|
|
36
|
+
'redirect() is a server-only function and cannot be called from client components. ' +
|
|
37
|
+
'Use useRouter().push() or useRouter().replace() for client-side navigation.'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function permanentRedirect(): never {
|
|
42
|
+
throw new Error(
|
|
43
|
+
'permanentRedirect() is a server-only function and cannot be called from client components. ' +
|
|
44
|
+
'Use useRouter().push() or useRouter().replace() for client-side navigation.'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function notFound(): never {
|
|
49
|
+
throw new Error(
|
|
50
|
+
'notFound() is a server-only function and cannot be called from client components.'
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shim: next/navigation → timber navigation primitives
|
|
3
|
+
*
|
|
4
|
+
* Re-exports timber's navigation hooks and functions for libraries
|
|
5
|
+
* that import from next/navigation. Covers the App Router API surface
|
|
6
|
+
* used by ecosystem libraries (nuqs, next-intl, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Note: nuqs imports next/navigation.js (with .js extension).
|
|
9
|
+
* The timber-shims plugin strips .js before matching.
|
|
10
|
+
*
|
|
11
|
+
* Intentional divergences from Next.js:
|
|
12
|
+
* - useRouter().replace() currently uses pushState (same as push) —
|
|
13
|
+
* timber's router doesn't distinguish push/replace yet.
|
|
14
|
+
* - redirect() does not accept a RedirectType argument — timber
|
|
15
|
+
* always uses replace semantics for redirects.
|
|
16
|
+
* - permanentRedirect() delegates to redirect(path, 308).
|
|
17
|
+
* See design/14-ecosystem.md for the full shim audit.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Hooks (client-side)
|
|
21
|
+
export { useParams } from '#/client/use-params.js';
|
|
22
|
+
export { usePathname } from '#/client/use-pathname.js';
|
|
23
|
+
export { useSearchParams } from '#/client/use-search-params.js';
|
|
24
|
+
export { useRouter } from '#/client/use-router.js';
|
|
25
|
+
export {
|
|
26
|
+
useSelectedLayoutSegment,
|
|
27
|
+
useSelectedLayoutSegments,
|
|
28
|
+
} from '#/client/use-selected-layout-segment.js';
|
|
29
|
+
|
|
30
|
+
// Functions (server-side)
|
|
31
|
+
export { redirect, permanentRedirect, notFound, RedirectType } from '#/server/primitives.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// No-op shim for server-only/client-only packages.
|
|
2
|
+
// In dev mode, Vite externalizes node_modules and loads them via Node's
|
|
3
|
+
// require(). Deps like `bright` that import `server-only` would hit the
|
|
4
|
+
// real CJS package which throws. This shim replaces it with a no-op
|
|
5
|
+
// in server environments (RSC/SSR) where the import is always safe.
|