@timber-js/app 0.1.13 → 0.1.15
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/client/index.js +13 -10
- package/dist/client/index.js.map +1 -1
- package/dist/client/use-router.d.ts +8 -3
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/index.js +27 -4
- package/dist/index.js.map +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client/use-router.ts +14 -8
- package/src/plugins/shims.ts +31 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../../src/plugins/shims.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6DhD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../../src/plugins/shims.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6DhD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAkIvD"}
|
package/package.json
CHANGED
package/src/client/use-router.ts
CHANGED
|
@@ -42,21 +42,24 @@ const SSR_NOOP_ROUTER: AppRouterInstance = {
|
|
|
42
42
|
*
|
|
43
43
|
* Compatible with Next.js's `useRouter()` from `next/navigation`.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* Methods lazily resolve the global router when invoked (during user
|
|
46
|
+
* interaction) rather than capturing it at render time. This is critical
|
|
47
|
+
* because during hydration, React synchronously executes component render
|
|
48
|
+
* functions *before* the router is bootstrapped in browser-entry.ts.
|
|
49
|
+
* If we eagerly captured the router during render, components would get
|
|
50
|
+
* the SSR_NOOP_ROUTER and be stuck with silent no-ops forever.
|
|
51
|
+
*
|
|
52
|
+
* Returns safe no-ops during SSR (typeof window === 'undefined').
|
|
48
53
|
*/
|
|
49
54
|
export function useRouter(): AppRouterInstance {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
router = getRouter();
|
|
53
|
-
} catch {
|
|
54
|
-
// Router not yet bootstrapped — SSR or early client render before bootstrap().
|
|
55
|
+
// SSR guard — on the server there's no router and no window.
|
|
56
|
+
if (typeof window === 'undefined') {
|
|
55
57
|
return SSR_NOOP_ROUTER;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
return {
|
|
59
61
|
push(href: string, options?: { scroll?: boolean }) {
|
|
62
|
+
const router = getRouter();
|
|
60
63
|
// Wrap in startTransition so React 19 tracks the async navigation.
|
|
61
64
|
// React 19's startTransition accepts async callbacks — it keeps
|
|
62
65
|
// isPending=true until the returned promise resolves. This means
|
|
@@ -67,11 +70,13 @@ export function useRouter(): AppRouterInstance {
|
|
|
67
70
|
});
|
|
68
71
|
},
|
|
69
72
|
replace(href: string, options?: { scroll?: boolean }) {
|
|
73
|
+
const router = getRouter();
|
|
70
74
|
startTransition(async () => {
|
|
71
75
|
await router.navigate(href, { scroll: options?.scroll, replace: true });
|
|
72
76
|
});
|
|
73
77
|
},
|
|
74
78
|
refresh() {
|
|
79
|
+
const router = getRouter();
|
|
75
80
|
startTransition(async () => {
|
|
76
81
|
await router.refresh();
|
|
77
82
|
});
|
|
@@ -83,6 +88,7 @@ export function useRouter(): AppRouterInstance {
|
|
|
83
88
|
window.history.forward();
|
|
84
89
|
},
|
|
85
90
|
prefetch(href: string) {
|
|
91
|
+
const router = getRouter();
|
|
86
92
|
router.prefetch(href);
|
|
87
93
|
},
|
|
88
94
|
};
|
package/src/plugins/shims.ts
CHANGED
|
@@ -177,11 +177,38 @@ export function timberShims(_ctx: PluginContext): Plugin {
|
|
|
177
177
|
// Server modules must never be bundled into the browser — if this
|
|
178
178
|
// module is reached, there is a broken import chain that needs fixing.
|
|
179
179
|
if (id === '\0timber:server-empty') {
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
// Export named stubs instead of throwing at evaluation time.
|
|
181
|
+
// Throwing at eval breaks the module system — the browser can't
|
|
182
|
+
// resolve named imports like `import { notFound } from '...'`.
|
|
183
|
+
// Instead, each stub throws at call time with a clear message.
|
|
184
|
+
return `
|
|
185
|
+
const msg = "[timber] @timber-js/app/server was imported from client code. " +
|
|
182
186
|
"Server modules (headers, cookies, redirect, deny, etc.) cannot be used in client components. " +
|
|
183
|
-
"If you need these APIs, move the import to a server component or middleware."
|
|
184
|
-
)
|
|
187
|
+
"If you need these APIs, move the import to a server component or middleware.";
|
|
188
|
+
function stub() { throw new Error(msg); }
|
|
189
|
+
export const headers = stub;
|
|
190
|
+
export const cookies = stub;
|
|
191
|
+
export const searchParams = stub;
|
|
192
|
+
export const deny = stub;
|
|
193
|
+
export const notFound = stub;
|
|
194
|
+
export const redirect = stub;
|
|
195
|
+
export const permanentRedirect = stub;
|
|
196
|
+
export const redirectExternal = stub;
|
|
197
|
+
export const waitUntil = stub;
|
|
198
|
+
export const RenderError = stub;
|
|
199
|
+
export const RedirectType = {};
|
|
200
|
+
export const DenySignal = stub;
|
|
201
|
+
export const RedirectSignal = stub;
|
|
202
|
+
export const createPipeline = stub;
|
|
203
|
+
export const revalidatePath = stub;
|
|
204
|
+
export const revalidateTag = stub;
|
|
205
|
+
export const createActionClient = stub;
|
|
206
|
+
export const ActionError = stub;
|
|
207
|
+
export const validated = stub;
|
|
208
|
+
export const getFormFlash = stub;
|
|
209
|
+
export const parseFormData = stub;
|
|
210
|
+
export const coerce = stub;
|
|
211
|
+
`;
|
|
185
212
|
}
|
|
186
213
|
},
|
|
187
214
|
};
|