@timber-js/app 0.1.17 → 0.1.19

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.
@@ -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,CAkIvD"}
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;AAiDhD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAoIvD"}
@@ -3,7 +3,10 @@
3
3
  *
4
4
  * Re-exports timber's Link component so libraries that import next/link
5
5
  * get the timber equivalent without modification.
6
+ *
7
+ * Imports from @timber-js/app/client (not #/) so the component resolves
8
+ * to the same module instance as user code in Vite dev.
6
9
  */
7
- export { Link as default, Link } from '#/client/link.js';
8
- export type { LinkProps } from '#/client/link.js';
10
+ export { Link as default, Link } from '@timber-js/app/client';
11
+ export type { LinkProps } from '@timber-js/app/client';
9
12
  //# sourceMappingURL=link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/shims/link.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/shims/link.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1,20 +1,21 @@
1
1
  /**
2
2
  * Shim: next/navigation (client environment only)
3
3
  *
4
- * Re-exports only the client-side hooks from timber's navigation shims.
4
+ * Re-exports only the client-side hooks from timber's client API.
5
5
  * Server-only functions (redirect, notFound, etc.) are excluded to prevent
6
6
  * server/primitives.ts from being pulled into the browser bundle.
7
7
  *
8
8
  * The full shim (navigation.ts) is still used in the RSC and SSR environments
9
9
  * where both client hooks and server functions are needed.
10
10
  *
11
+ * Imports use @timber-js/app/client (not #/ subpath imports) so they resolve
12
+ * to the same module instances as user code in Vite dev — preventing module
13
+ * duplication where setGlobalRouter() writes to one instance and useRouter()
14
+ * reads from another.
15
+ *
11
16
  * See design/14-ecosystem.md §"next/navigation" for the full shim audit.
12
17
  */
13
- export { useParams } from '#/client/use-params.js';
14
- export { usePathname } from '#/client/use-pathname.js';
15
- export { useSearchParams } from '#/client/use-search-params.js';
16
- export { useRouter } from '#/client/use-router.js';
17
- export { useSelectedLayoutSegment, useSelectedLayoutSegments, } from '#/client/use-selected-layout-segment.js';
18
+ export { useParams, usePathname, useSearchParams, useRouter, useSelectedLayoutSegment, useSelectedLayoutSegments, } from '@timber-js/app/client';
18
19
  export declare const RedirectType: {
19
20
  readonly push: "push";
20
21
  readonly replace: "replace";
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-client.d.ts","sourceRoot":"","sources":["../../src/shims/navigation-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,yCAAyC,CAAC;AAIjD,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAKX,wBAAgB,QAAQ,IAAI,KAAK,CAKhC;AAED,wBAAgB,iBAAiB,IAAI,KAAK,CAKzC;AAED,wBAAgB,QAAQ,IAAI,KAAK,CAIhC"}
1
+ {"version":3,"file":"navigation-client.d.ts","sourceRoot":"","sources":["../../src/shims/navigation-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EACL,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,EACT,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAI/B,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAKX,wBAAgB,QAAQ,IAAI,KAAK,CAKhC;AAED,wBAAgB,iBAAiB,IAAI,KAAK,CAKzC;AAED,wBAAgB,QAAQ,IAAI,KAAK,CAIhC"}
@@ -1,15 +1,10 @@
1
1
  /**
2
2
  * Shim: next/navigation → timber navigation primitives
3
3
  *
4
- * Client hooks use #/ source imports (individual files with 'use client' directives
5
- * that the RSC plugin detects).
6
- * Server functions use @timber-js/app/server (resolved to dist/ via native exports)
7
- * for ALS singleton consistency.
4
+ * Client hooks import from @timber-js/app/client (the public barrel) so they
5
+ * resolve to the same module instances as user code in Vite dev. Server
6
+ * functions import from @timber-js/app/server for ALS singleton consistency.
8
7
  */
9
- export { useParams } from '#/client/use-params.js';
10
- export { usePathname } from '#/client/use-pathname.js';
11
- export { useSearchParams } from '#/client/use-search-params.js';
12
- export { useRouter } from '#/client/use-router.js';
13
- export { useSelectedLayoutSegment, useSelectedLayoutSegments, } from '#/client/use-selected-layout-segment.js';
8
+ export { useParams, usePathname, useSearchParams, useRouter, useSelectedLayoutSegment, useSelectedLayoutSegments, } from '@timber-js/app/client';
14
9
  export { redirect, permanentRedirect, notFound, RedirectType } from '@timber-js/app/server';
15
10
  //# sourceMappingURL=navigation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/shims/navigation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/shims/navigation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,EACT,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timber-js/app",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
5
5
  "keywords": [
6
6
  "cloudflare-workers",
@@ -30,13 +30,25 @@ import {
30
30
  setServerCallback,
31
31
  encodeReply,
32
32
  } from '@vitejs/plugin-rsc/browser';
33
- import { createRouter } from './router.js';
34
- import type { RouterDeps, RouterInstance } from './router.js';
33
+ // Shared-state modules MUST be imported from @timber-js/app/client (the public
34
+ // barrel) so they resolve to the same module instances as user code. In Vite dev,
35
+ // user code imports @timber-js/app/client from dist/ via package.json exports.
36
+ // If we used relative imports (./router-ref.js), Vite would load separate src/
37
+ // copies with separate module-level state — e.g., globalRouter set here but
38
+ // read as null from the dist/ copy used by useRouter().
39
+ import {
40
+ createRouter,
41
+ setGlobalRouter,
42
+ getRouter,
43
+ setCurrentParams,
44
+ } from '@timber-js/app/client';
45
+ import type { RouterDeps, RouterInstance } from '@timber-js/app/client';
46
+
47
+ // Internal-only modules (no shared mutable state with user code) use relative
48
+ // imports — they don't need singleton behavior across module graphs.
35
49
  import { applyHeadElements } from './head.js';
36
- import { setGlobalRouter, getRouter } from './router-ref.js';
37
50
  import { TimberNuqsAdapter } from './nuqs-adapter.js';
38
51
  import { isPageUnloading } from './unload-guard.js';
39
- import { setCurrentParams } from './use-params.js';
40
52
  import { ON_NAVIGATE_KEY } from './link-navigate-interceptor.js';
41
53
 
42
54
  // ─── Server Action Dispatch ──────────────────────────────────────
@@ -18,7 +18,7 @@ export type {
18
18
  export { useNavigationPending } from './use-navigation-pending';
19
19
  export { useLinkStatus, LinkStatusContext } from './use-link-status';
20
20
  export type { LinkStatus } from './use-link-status';
21
- export { getRouter } from './router-ref';
21
+ export { getRouter, setGlobalRouter } from './router-ref';
22
22
  export { useRouter } from './use-router';
23
23
  export type { AppRouterInstance } from './use-router';
24
24
  export { usePathname } from './use-pathname';
@@ -1,9 +1,18 @@
1
1
  // Global router reference — shared between browser-entry and client hooks.
2
2
  // This module has no dependencies on virtual modules, so it can be safely
3
3
  // imported by client hooks without pulling in browser-entry's virtual imports.
4
+ //
5
+ // The router is stored as a module-level variable. browser-entry.ts and all
6
+ // shim files import from @timber-js/app/client (the public barrel) rather
7
+ // than relative paths or #/ subpath imports. This ensures all import chains
8
+ // resolve to the same module instance via Vite's dep optimizer, preventing
9
+ // the duplication that previously required a window.__timber_router workaround.
10
+ //
11
+ // See design/18-build-system.md §"Module Singleton Strategy"
4
12
 
5
13
  import type { RouterInstance } from './router.js';
6
14
 
15
+ /** Module-level singleton — set once during bootstrap. */
7
16
  let globalRouter: RouterInstance | null = null;
8
17
 
9
18
  /**
@@ -32,3 +41,12 @@ export function getRouter(): RouterInstance {
32
41
  export function getRouterOrNull(): RouterInstance | null {
33
42
  return globalRouter;
34
43
  }
44
+
45
+ /**
46
+ * Reset the global router to null. Used only in tests to isolate
47
+ * module-level state between test cases.
48
+ * @internal
49
+ */
50
+ export function resetGlobalRouter(): void {
51
+ globalRouter = null;
52
+ }
@@ -27,16 +27,6 @@ export interface AppRouterInstance {
27
27
  prefetch(href: string): void;
28
28
  }
29
29
 
30
- /** No-op router returned during SSR or before bootstrap. All methods are safe no-ops. */
31
- const SSR_NOOP_ROUTER: AppRouterInstance = {
32
- push() {},
33
- replace() {},
34
- refresh() {},
35
- back() {},
36
- forward() {},
37
- prefetch() {},
38
- };
39
-
40
30
  /**
41
31
  * Get a router instance for programmatic navigation.
42
32
  *
@@ -47,7 +37,7 @@ const SSR_NOOP_ROUTER: AppRouterInstance = {
47
37
  * because during hydration, React synchronously executes component render
48
38
  * functions *before* the router is bootstrapped in browser-entry.ts.
49
39
  * If we eagerly captured the router during render, components would get
50
- * the SSR_NOOP_ROUTER and be stuck with silent no-ops forever.
40
+ * a null reference and be stuck with silent no-ops forever.
51
41
  *
52
42
  * Returns safe no-ops during SSR or before bootstrap. The `typeof window`
53
43
  * check is insufficient because Vite's client SSR environment defines
@@ -55,18 +55,6 @@ const SHIM_MAP: Record<string, string> = {
55
55
  'next/font/local': '\0@timber/fonts/local',
56
56
  };
57
57
 
58
- /**
59
- * Client-only shim overrides for the browser environment.
60
- *
61
- * next/navigation in the client environment resolves to navigation-client.ts
62
- * which only re-exports client hooks — not server functions like redirect()
63
- * and deny(). This prevents server/primitives.ts from being pulled into the
64
- * browser bundle via tree-shaking-resistant imports.
65
- */
66
- const CLIENT_SHIM_OVERRIDES: Record<string, string> = {
67
- 'next/navigation': resolve(SHIMS_DIR, 'navigation-client.ts'),
68
- };
69
-
70
58
  /**
71
59
  * Strip .js extension from an import specifier.
72
60
  *
@@ -115,12 +103,14 @@ export function timberShims(_ctx: PluginContext): Plugin {
115
103
  const cleanId = stripJsExtension(id);
116
104
 
117
105
  // Check next/* shim map.
118
- // In the client (browser) environment, use client-only shim overrides
119
- // to avoid pulling server code (primitives.ts) into the browser bundle.
106
+ // In the client (browser) environment, next/navigation resolves to
107
+ // navigation-client.ts which only re-exports client hooks not server
108
+ // functions like redirect() and deny(). This prevents server/primitives.ts
109
+ // from being pulled into the browser bundle.
120
110
  if (cleanId in SHIM_MAP) {
121
111
  const envName = (this as unknown as { environment?: { name?: string } }).environment?.name;
122
- if (envName === 'client' && cleanId in CLIENT_SHIM_OVERRIDES) {
123
- return CLIENT_SHIM_OVERRIDES[cleanId];
112
+ if (envName === 'client' && cleanId === 'next/navigation') {
113
+ return resolve(SHIMS_DIR, 'navigation-client.ts');
124
114
  }
125
115
  return SHIM_MAP[cleanId];
126
116
  }
package/src/shims/link.ts CHANGED
@@ -5,7 +5,10 @@
5
5
  *
6
6
  * Re-exports timber's Link component so libraries that import next/link
7
7
  * get the timber equivalent without modification.
8
+ *
9
+ * Imports from @timber-js/app/client (not #/) so the component resolves
10
+ * to the same module instance as user code in Vite dev.
8
11
  */
9
12
 
10
- export { Link as default, Link } from '#/client/link.js';
11
- export type { LinkProps } from '#/client/link.js';
13
+ export { Link as default, Link } from '@timber-js/app/client';
14
+ export type { LinkProps } from '@timber-js/app/client';
@@ -1,25 +1,30 @@
1
1
  /**
2
2
  * Shim: next/navigation (client environment only)
3
3
  *
4
- * Re-exports only the client-side hooks from timber's navigation shims.
4
+ * Re-exports only the client-side hooks from timber's client API.
5
5
  * Server-only functions (redirect, notFound, etc.) are excluded to prevent
6
6
  * server/primitives.ts from being pulled into the browser bundle.
7
7
  *
8
8
  * The full shim (navigation.ts) is still used in the RSC and SSR environments
9
9
  * where both client hooks and server functions are needed.
10
10
  *
11
+ * Imports use @timber-js/app/client (not #/ subpath imports) so they resolve
12
+ * to the same module instances as user code in Vite dev — preventing module
13
+ * duplication where setGlobalRouter() writes to one instance and useRouter()
14
+ * reads from another.
15
+ *
11
16
  * See design/14-ecosystem.md §"next/navigation" for the full shim audit.
12
17
  */
13
18
 
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
+ // Hooks imported from the public barrel for module singleton consistency.
19
20
  export {
21
+ useParams,
22
+ usePathname,
23
+ useSearchParams,
24
+ useRouter,
20
25
  useSelectedLayoutSegment,
21
26
  useSelectedLayoutSegments,
22
- } from '#/client/use-selected-layout-segment.js';
27
+ } from '@timber-js/app/client';
23
28
 
24
29
  // RedirectType enum is safe (no server code dependency) and used by some
25
30
  // client-side libraries for type checking.
@@ -1,21 +1,20 @@
1
1
  /**
2
2
  * Shim: next/navigation → timber navigation primitives
3
3
  *
4
- * Client hooks use #/ source imports (individual files with 'use client' directives
5
- * that the RSC plugin detects).
6
- * Server functions use @timber-js/app/server (resolved to dist/ via native exports)
7
- * for ALS singleton consistency.
4
+ * Client hooks import from @timber-js/app/client (the public barrel) so they
5
+ * resolve to the same module instances as user code in Vite dev. Server
6
+ * functions import from @timber-js/app/server for ALS singleton consistency.
8
7
  */
9
8
 
10
- // Hooks (client-side — must use source imports for RSC 'use client' detection)
11
- export { useParams } from '#/client/use-params.js';
12
- export { usePathname } from '#/client/use-pathname.js';
13
- export { useSearchParams } from '#/client/use-search-params.js';
14
- export { useRouter } from '#/client/use-router.js';
9
+ // Hooks (client-side — imported from public barrel for module singleton)
15
10
  export {
11
+ useParams,
12
+ usePathname,
13
+ useSearchParams,
14
+ useRouter,
16
15
  useSelectedLayoutSegment,
17
16
  useSelectedLayoutSegments,
18
- } from '#/client/use-selected-layout-segment.js';
17
+ } from '@timber-js/app/client';
19
18
 
20
- // Functions (server-side — resolved to dist/ for ALS singleton consistency)
19
+ // Functions (server-side)
21
20
  export { redirect, permanentRedirect, notFound, RedirectType } from '@timber-js/app/server';