@paramour-js/next 0.4.0 → 0.4.1

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.
Files changed (48) hide show
  1. package/dist/app.d.ts +48 -49
  2. package/dist/app.js +11 -12
  3. package/dist/cli-args.d.ts +4 -4
  4. package/dist/cli-args.js +4 -4
  5. package/dist/cli-inputs.d.ts +6 -7
  6. package/dist/cli-inputs.js +6 -7
  7. package/dist/cli.js +1 -1
  8. package/dist/collisions.d.ts +8 -8
  9. package/dist/collisions.js +9 -9
  10. package/dist/commands/generate.d.ts +7 -7
  11. package/dist/commands/generate.js +16 -16
  12. package/dist/commands/init.js +1 -1
  13. package/dist/config.d.ts +10 -10
  14. package/dist/config.js +4 -4
  15. package/dist/devtools-seam.d.ts +19 -19
  16. package/dist/devtools-seam.js +3 -3
  17. package/dist/doctor/checks.js +1 -1
  18. package/dist/emit.d.ts +12 -12
  19. package/dist/emit.js +13 -13
  20. package/dist/generate.d.ts +14 -14
  21. package/dist/generate.js +11 -11
  22. package/dist/list/discover-route-defs.d.ts +4 -4
  23. package/dist/list/discover-route-defs.js +4 -4
  24. package/dist/lock.d.ts +8 -9
  25. package/dist/lock.js +11 -12
  26. package/dist/navigation-adapter.d.ts +17 -18
  27. package/dist/navigation-adapter.js +4 -4
  28. package/dist/observe.d.ts +14 -14
  29. package/dist/observe.js +4 -4
  30. package/dist/pages.d.ts +30 -31
  31. package/dist/pages.js +10 -10
  32. package/dist/run-cli.d.ts +1 -1
  33. package/dist/run-cli.js +1 -1
  34. package/dist/scan-app.d.ts +10 -10
  35. package/dist/scan-app.js +30 -30
  36. package/dist/scan-pages.d.ts +6 -6
  37. package/dist/scan-pages.js +28 -26
  38. package/dist/scan.d.ts +13 -10
  39. package/dist/scan.js +7 -7
  40. package/dist/select.d.ts +40 -40
  41. package/dist/select.js +30 -30
  42. package/dist/testing.d.ts +28 -32
  43. package/dist/testing.js +15 -15
  44. package/dist/watch.d.ts +12 -12
  45. package/dist/watch.js +13 -13
  46. package/dist/with-typed-routes.d.ts +11 -10
  47. package/dist/with-typed-routes.js +42 -39
  48. package/package.json +2 -2
package/dist/select.d.ts CHANGED
@@ -1,63 +1,63 @@
1
1
  import type { AnyRoute, ParamsSource, SafeResult } from "paramour";
2
2
  /**
3
- * Shared internals of the read hooks' selector surface (design-07): the
4
- * raw-slice stabilization layer (SEL4) and the selector layer (SEL2/SEL3).
5
- * Deliberately NO `"use client"` directive: app.ts (which carries one) and
6
- * pages.ts (which must not carry one, design-06 PR2) both import from here,
7
- * and the directive belongs on the entry modules, not a shared leaf.
3
+ * Shared internals of the read hooks' selector surface: the raw-slice
4
+ * stabilization layer and the selector layer. Deliberately NO `"use client"`
5
+ * directive: app.ts (which carries one) and pages.ts (which must not carry
6
+ * one) both import from here, and the directive belongs on the entry
7
+ * modules, not a shared leaf.
8
8
  *
9
- * Both layers are `useRef` caches mutated during render (SEL8) — the
10
- * Redux/TanStack selector pattern, and the one sanctioned departure from the
11
- * hooks' pure-`useMemo` discipline: result equality needs memory across
12
- * renders, which no pure memo can provide. Every cache is cleared BEFORE a
13
- * compute that can throw, so a throwing decode or selector never strands a
14
- * stale entry.
9
+ * Both layers are `useRef` caches mutated during render — the Redux/TanStack
10
+ * selector pattern, and the one sanctioned departure from the hooks'
11
+ * pure-`useMemo` discipline: result equality needs memory across renders,
12
+ * which no pure memo can provide. Every cache is cleared BEFORE a compute
13
+ * that can throw, so a throwing decode or selector never strands a stale
14
+ * entry.
15
15
  */
16
16
  /**
17
- * Options bag accepted by every read hook (design-07 SEL1).
17
+ * Options bag accepted by every read hook.
18
18
  */
19
19
  export interface SelectOptions<T, U> {
20
20
  /**
21
- * Result-equality mode for the selected value (SEL3): `Object.is` by
22
- * default — free and correct for primitive selections — with one-level
23
- * `"shallow"` as the opt-in for tuple/object selections.
21
+ * Result-equality mode for the selected value: `Object.is` by default —
22
+ * free and correct for primitive selections — with one-level `"shallow"`
23
+ * as the opt-in for tuple/object selections.
24
24
  */
25
25
  readonly equality?: "shallow";
26
26
  /**
27
- * Pure projection of the decoded value; runs only on the success arm
28
- * (SEL2). Identity is never compared, so inline arrows are fine — and when
29
- * the underlying result is reference-stable the selector is NOT re-run
30
- * (SEL6), so it must not read changing outside state. A throw propagates to
31
- * the nearest error boundary (SEL5): a selector bug is a code bug, never
32
- * the `SafeResult` error arm, which is reserved for URL data problems.
27
+ * Pure projection of the decoded value; runs only on the success arm.
28
+ * Identity is never compared, so inline arrows are fine — and when the
29
+ * underlying result is reference-stable the selector is NOT re-run, so it
30
+ * must not read changing outside state. A throw propagates to the nearest
31
+ * error boundary: a selector bug is a code bug, never the `SafeResult`
32
+ * error arm, which is reserved for URL data problems.
33
33
  */
34
34
  readonly select: (value: T) => U;
35
35
  }
36
36
  /**
37
- * Fingerprint of the pages hooks' pre-`isReady` state (design-06 PR5). Every
38
- * real fingerprint is a `JSON.stringify`'d array (starts with `[`), so this
39
- * can never collide with one.
37
+ * Fingerprint of the pages hooks' pre-`isReady` state. Every real
38
+ * fingerprint is a `JSON.stringify`'d array (starts with `[`), so this can
39
+ * never collide with one.
40
40
  */
41
41
  export declare const PENDING_FINGERPRINT = "pending";
42
42
  /**
43
- * Raw slice of a params source (SEL4): the route's dynamic segment names'
44
- * raw values, from the define-time `~segments` token cache. Unknown keys —
43
+ * Raw slice of a params source: the route's dynamic segment names' raw
44
+ * values, from the define-time `~segments` token cache. Unknown keys —
45
45
  * e.g. a parallel route's params in the same `useParams()` bag — never bust
46
46
  * the fingerprint, because the decode never reads them.
47
47
  */
48
48
  export declare function paramsFingerprint(route: AnyRoute, source: ParamsSource): string;
49
49
  /**
50
- * Raw slice of a pages `router.query` bag for the search half (SEL4). A
51
- * codec-map route reads exactly its declared keys (query junk and the
52
- * route's own path params are invisible to the decode, PR9 disjointness); a
50
+ * Raw slice of a pages `router.query` bag for the search half. A codec-map
51
+ * route reads exactly its declared keys (query junk and the route's own path
52
+ * params are invisible to the decode — the two namespaces are disjoint); a
53
53
  * `rawSearch` route has no enumerable declared-key set — the schema sees
54
- * every key except the route's path params (design-06 PR5 subtraction), so
55
- * exactly that slice is fingerprinted, in sorted-key order for record-order
56
- * independence.
54
+ * every key except the route's path params (by subtracting them from the
55
+ * bag), so exactly that slice is fingerprinted, in sorted-key order for
56
+ * record-order independence.
57
57
  */
58
58
  export declare function queryFingerprint(route: AnyRoute, query: ParamsSource): string;
59
59
  /**
60
- * Raw slice of an app `useSearchParams()` source (SEL4): the declared keys'
60
+ * Raw slice of an app `useSearchParams()` source: the declared keys'
61
61
  * `[key, value]` pairs in wire order — order is load-bearing for repeated
62
62
  * keys (array codecs decode in wire order, P5/S5), and iterating the live
63
63
  * pairs preserves the relative order of declared entries while `?utm_*`
@@ -66,8 +66,8 @@ export declare function queryFingerprint(route: AnyRoute, query: ParamsSource):
66
66
  */
67
67
  export declare function searchParamsFingerprint(route: AnyRoute, source: URLSearchParams): string;
68
68
  /**
69
- * The selector layer for the safe hooks (SEL2): projects the success arm and
70
- * reference-stabilizes the projected WRAPPER by result equality (SEL3) — a
69
+ * The selector layer for the safe hooks: projects the success arm and
70
+ * reference-stabilizes the projected WRAPPER by result equality — a
71
71
  * stable `data` inside a fresh wrapper would still churn every consumer.
72
72
  * Error and pending arms pass through untouched; they are already
73
73
  * reference-stabilized by {@link useStableResult}'s raw-slice layer.
@@ -79,16 +79,16 @@ export declare function useSelectedResult<T, U>(result: SafeResult<T> | {
79
79
  status: "pending";
80
80
  };
81
81
  /**
82
- * {@link useSelectedResult}'s twin for the `*OrThrow` hooks (SEL2): same
83
- * layering, no wrapper — the hook's return IS the (selected) value.
82
+ * {@link useSelectedResult}'s twin for the `*OrThrow` hooks: same layering,
83
+ * no wrapper — the hook's return IS the (selected) value.
84
84
  */
85
85
  export declare function useSelectedValue<T, U>(value: T, options: SelectOptions<T, U> | undefined): T | U;
86
86
  /**
87
- * The raw-slice stabilization layer (SEL4): while `route` and `fingerprint`
88
- * are unchanged from the previous render, the previous result — success OR
87
+ * The raw-slice stabilization layer: while `route` and `fingerprint` are
88
+ * unchanged from the previous render, the previous result — success OR
89
89
  * error arm — is returned without recomputing, so a fresh `useSearchParams()`
90
90
  * / `query` object whose DECLARED slice is unchanged (`?utm_source=` churn)
91
91
  * costs neither a decode nor anyone's referential equality. This replaces
92
- * the pre-design-07 "memo keyed on Next's object reference" behavior.
92
+ * the earlier "memo keyed on Next's object reference" behavior.
93
93
  */
94
94
  export declare function useStableResult<T>(route: AnyRoute, fingerprint: string, compute: () => T): T;
package/dist/select.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { useRef } from "react";
2
2
  /**
3
- * Fingerprint of the pages hooks' pre-`isReady` state (design-06 PR5). Every
4
- * real fingerprint is a `JSON.stringify`'d array (starts with `[`), so this
5
- * can never collide with one.
3
+ * Fingerprint of the pages hooks' pre-`isReady` state. Every real
4
+ * fingerprint is a `JSON.stringify`'d array (starts with `[`), so this can
5
+ * never collide with one.
6
6
  */
7
7
  export const PENDING_FINGERPRINT = "pending";
8
8
  /**
9
- * Raw slice of a params source (SEL4): the route's dynamic segment names'
10
- * raw values, from the define-time `~segments` token cache. Unknown keys —
9
+ * Raw slice of a params source: the route's dynamic segment names' raw
10
+ * values, from the define-time `~segments` token cache. Unknown keys —
11
11
  * e.g. a parallel route's params in the same `useParams()` bag — never bust
12
12
  * the fingerprint, because the decode never reads them.
13
13
  */
@@ -15,13 +15,13 @@ export function paramsFingerprint(route, source) {
15
15
  return recordFingerprint(dynamicSegmentNames(route), source);
16
16
  }
17
17
  /**
18
- * Raw slice of a pages `router.query` bag for the search half (SEL4). A
19
- * codec-map route reads exactly its declared keys (query junk and the
20
- * route's own path params are invisible to the decode, PR9 disjointness); a
18
+ * Raw slice of a pages `router.query` bag for the search half. A codec-map
19
+ * route reads exactly its declared keys (query junk and the route's own path
20
+ * params are invisible to the decode — the two namespaces are disjoint); a
21
21
  * `rawSearch` route has no enumerable declared-key set — the schema sees
22
- * every key except the route's path params (design-06 PR5 subtraction), so
23
- * exactly that slice is fingerprinted, in sorted-key order for record-order
24
- * independence.
22
+ * every key except the route's path params (by subtracting them from the
23
+ * bag), so exactly that slice is fingerprinted, in sorted-key order for
24
+ * record-order independence.
25
25
  */
26
26
  export function queryFingerprint(route, query) {
27
27
  const declared = declaredSearchKeys(route);
@@ -34,7 +34,7 @@ export function queryFingerprint(route, query) {
34
34
  return recordFingerprint(keys, query);
35
35
  }
36
36
  /**
37
- * Raw slice of an app `useSearchParams()` source (SEL4): the declared keys'
37
+ * Raw slice of an app `useSearchParams()` source: the declared keys'
38
38
  * `[key, value]` pairs in wire order — order is load-bearing for repeated
39
39
  * keys (array codecs decode in wire order, P5/S5), and iterating the live
40
40
  * pairs preserves the relative order of declared entries while `?utm_*`
@@ -62,15 +62,15 @@ export function useSelectedResult(result, options) {
62
62
  return result;
63
63
  const previous = cache.current;
64
64
  if (previous !== null && Object.is(previous.input, result.data)) {
65
- // Reference-stable input ⇒ equal output by selector purity (SEL6); the
66
- // selector is deliberately not re-run.
65
+ // Reference-stable input ⇒ equal output by selector purity; the selector
66
+ // is deliberately not re-run.
67
67
  return previous.wrapped;
68
68
  }
69
- const selected = options.select(result.data); // a throw propagates (SEL5)
69
+ const selected = options.select(result.data); // a throw propagates
70
70
  if (previous !== null &&
71
71
  selectedEquals(options.equality, previous.wrapped.data, selected)) {
72
- // Same selection out of a new decode: keep the previous wrapper (SEL2)
73
- // and re-key the cache so the next render takes the reference fast path.
72
+ // Same selection out of a new decode: keep the previous wrapper and
73
+ // re-key the cache so the next render takes the reference fast path.
74
74
  previous.input = result.data;
75
75
  return previous.wrapped;
76
76
  }
@@ -82,8 +82,8 @@ export function useSelectedResult(result, options) {
82
82
  return wrapped;
83
83
  }
84
84
  /**
85
- * {@link useSelectedResult}'s twin for the `*OrThrow` hooks (SEL2): same
86
- * layering, no wrapper — the hook's return IS the (selected) value.
85
+ * {@link useSelectedResult}'s twin for the `*OrThrow` hooks: same layering,
86
+ * no wrapper — the hook's return IS the (selected) value.
87
87
  */
88
88
  export function useSelectedValue(value, options) {
89
89
  const cache = useRef(null);
@@ -91,9 +91,9 @@ export function useSelectedValue(value, options) {
91
91
  return value;
92
92
  const previous = cache.current;
93
93
  if (previous !== null && Object.is(previous.input, value)) {
94
- return previous.selected; // SEL6: selector purity, not re-run
94
+ return previous.selected; // selector purity: not re-run
95
95
  }
96
- const selected = options.select(value); // a throw propagates (SEL5)
96
+ const selected = options.select(value); // a throw propagates
97
97
  if (previous !== null &&
98
98
  selectedEquals(options.equality, previous.selected, selected)) {
99
99
  previous.input = value;
@@ -103,12 +103,12 @@ export function useSelectedValue(value, options) {
103
103
  return selected;
104
104
  }
105
105
  /**
106
- * The raw-slice stabilization layer (SEL4): while `route` and `fingerprint`
107
- * are unchanged from the previous render, the previous result — success OR
106
+ * The raw-slice stabilization layer: while `route` and `fingerprint` are
107
+ * unchanged from the previous render, the previous result — success OR
108
108
  * error arm — is returned without recomputing, so a fresh `useSearchParams()`
109
109
  * / `query` object whose DECLARED slice is unchanged (`?utm_source=` churn)
110
110
  * costs neither a decode nor anyone's referential equality. This replaces
111
- * the pre-design-07 "memo keyed on Next's object reference" behavior.
111
+ * the earlier "memo keyed on Next's object reference" behavior.
112
112
  */
113
113
  export function useStableResult(route, fingerprint, compute) {
114
114
  const cache = useRef(null);
@@ -120,7 +120,7 @@ export function useStableResult(route, fingerprint, compute) {
120
120
  throw cached.outcome.thrown;
121
121
  return cached.outcome.value;
122
122
  }
123
- // Cleared BEFORE computing (SEL8): no half-computed state may survive a
123
+ // Cleared BEFORE computing: no half-computed state may survive a
124
124
  // throw, and a NEW fingerprint always recomputes — an error boundary
125
125
  // reset after the URL is fixed can never be served a stale entry.
126
126
  cache.current = null;
@@ -152,7 +152,7 @@ export function useStableResult(route, fingerprint, compute) {
152
152
  * Declared search keys of a route's `~search` slot, or `null` for a
153
153
  * `rawSearch` route (whose schema owns every key, so no declared subset
154
154
  * exists). The `~kind` marker is unambiguous against a codec map, which
155
- * never carries a top-level `~`-prefixed key (design-04 SS2).
155
+ * never carries a top-level `~`-prefixed key (SS2).
156
156
  */
157
157
  function declaredSearchKeys(route) {
158
158
  const config = route["~search"];
@@ -185,16 +185,16 @@ function recordFingerprint(keys, source) {
185
185
  Object.hasOwn(source, key) ? (source[key] ?? null) : null,
186
186
  ]));
187
187
  }
188
- /** SEL3: `Object.is`, widened one level by the `"shallow"` opt-in. */
188
+ /** Result equality: `Object.is`, widened one level by `"shallow"`. */
189
189
  function selectedEquals(equality, a, b) {
190
190
  if (Object.is(a, b))
191
191
  return true;
192
192
  return equality === "shallow" && shallowEqual(a, b);
193
193
  }
194
194
  /**
195
- * One-level equality for the `"shallow"` opt-in (SEL3): arrays element-wise,
196
- * plain objects by own enumerable keys — `Object.is` at each leaf, nothing
197
- * recursive (deep comparison in a render path is a non-goal, design-07).
195
+ * One-level equality for the `"shallow"` opt-in: arrays element-wise, plain
196
+ * objects by own enumerable keys — `Object.is` at each leaf, nothing
197
+ * recursive (deep comparison in a render path is a non-goal).
198
198
  */
199
199
  function shallowEqual(a, b) {
200
200
  if (typeof a !== "object" ||
package/dist/testing.d.ts CHANGED
@@ -1,46 +1,42 @@
1
1
  import type { ParamsSource } from "paramour";
2
2
  import type { ReactElement, ReactNode } from "react";
3
3
  /**
4
- * `@paramour-js/next/testing` (design-16): a provider that overrides the
5
- * hooks' framework reads through the adapter seam (TA1), so client
6
- * components calling `useSearch`/`useRouteParams` (either flavor) can be
7
- * unit-tested without runner-specific `next/*` module mocking. One provider
8
- * feeds BOTH flavor contexts (TA5) — hybrid apps and pages components need
9
- * no second import. Server code needs none of this: `parse`/`safeParse` and
10
- * server components are pure functions over props (TA8).
4
+ * `@paramour-js/next/testing`: a provider that overrides the hooks'
5
+ * framework reads through the adapter seam, so client components calling
6
+ * `useSearch`/`useRouteParams` (either flavor) can be unit-tested without
7
+ * runner-specific `next/*` module mocking. One provider feeds BOTH flavor
8
+ * contexts — hybrid apps and pages components need no second import. Server
9
+ * code needs none of this: `parse`/`safeParse` and server components are
10
+ * pure functions over props.
11
11
  *
12
12
  * This module imports ONLY react and the (Next-free) adapter-seam module —
13
- * no `next/*` specifier and no `@testing-library/*` (TA5; dist.test.ts pins
14
- * the bundle graph, and the hermeticity check there is why these docs never
15
- * spell out the two Next specifiers). It carries `"use client"` like
16
- * app.ts.
13
+ * no `next/*` specifier and no `@testing-library/*`; dist.test.ts pins the
14
+ * bundle graph, and the hermeticity check there is why these docs never
15
+ * spell out the two Next specifiers. It carries `"use client"` like app.ts.
17
16
  *
18
- * Stability contract (TA4): the provider holds ONE adapter pair for its
19
- * lifetime, created once and closing over a latest-props ref that is
20
- * reassigned every render — prop changes mutate what the stable adapters
21
- * RETURN, they never mint new adapters, so the hooks' context reads stay
22
- * identity-stable and mid-test URL changes are driven by ordinary rerenders
23
- * with new props.
17
+ * Stability contract: the provider holds ONE adapter pair for its lifetime,
18
+ * created once and closing over a latest-props ref that is reassigned every
19
+ * render — prop changes mutate what the stable adapters RETURN, they never
20
+ * mint new adapters, so the hooks' context reads stay identity-stable and
21
+ * mid-test URL changes are driven by ordinary rerenders with new props.
24
22
  */
25
23
  /**
26
- * Input shape mirrors what Next hands the hooks (TA6) — no `url`
27
- * reverse-matching in v1 (deferred: needs a core matcher). `params: null`
28
- * and `mounted: false` are first-class because they are the two states
29
- * nobody hand-rolling a mock models.
24
+ * Input shape mirrors what Next hands the hooks — no `url` reverse-matching
25
+ * in v1 (deferred: needs a core matcher). `params: null` and
26
+ * `mounted: false` are first-class because they are the two states nobody
27
+ * hand-rolling a mock models.
30
28
  */
31
29
  export interface ParamourTestingOptions {
32
30
  /**
33
31
  * Pages flavor only: `false` is the pre-hydration state of a
34
- * statically-optimized page (`query` not yet populated — the PR5
35
- * `pending` arm). Defaults to `true`. design-16 listed this as deferred,
36
- * but TA7 migrates the whole pages suite — which pins the pending arm —
37
- * to this provider, so it was promoted from the deferred list.
32
+ * statically-optimized page (`query` not yet populated — the hooks'
33
+ * `pending` arm). Defaults to `true`.
38
34
  */
39
35
  isReady?: boolean;
40
36
  /**
41
37
  * Pages flavor only: `false` reproduces the pages router's
42
- * throw-on-unmounted state under `app/` (PR5) — pages.ts translates it to
43
- * a `ParamourError` naming the actual mistake.
38
+ * throw-on-unmounted state under `app/` — pages.ts translates it to a
39
+ * `ParamourError` naming the actual mistake.
44
40
  */
45
41
  mounted?: boolean;
46
42
  /** Captures `replace(href)` from either flavor's router. */
@@ -56,16 +52,16 @@ export interface ParamourTestingOptions {
56
52
  search?: string | URLSearchParams;
57
53
  }
58
54
  /**
59
- * Renders BOTH flavor contexts' providers around `children` (TA5). Exported
60
- * for people composing their own wrappers (Storybook decorators, custom
61
- * render helpers); testing-library users want {@link withParamourTesting}.
55
+ * Renders BOTH flavor contexts' providers around `children`. Exported for
56
+ * people composing their own wrappers (Storybook decorators, custom render
57
+ * helpers); testing-library users want {@link withParamourTesting}.
62
58
  */
63
59
  export declare function ParamourTestingProvider(props: ParamourTestingOptions & {
64
60
  children?: ReactNode;
65
61
  }): ReactElement;
66
62
  /**
67
- * Wrapper-component form for testing-library's `wrapper` option (TA5,
68
- * mirroring `withNuqsTestingAdapter`).
63
+ * Wrapper-component form for testing-library's `wrapper` option, mirroring
64
+ * `withNuqsTestingAdapter`.
69
65
  */
70
66
  export declare function withParamourTesting(options?: ParamourTestingOptions): (props: {
71
67
  children?: ReactNode;
package/dist/testing.js CHANGED
@@ -3,21 +3,21 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useRef, useState } from "react";
4
4
  import { AppNavigationContext, PagesNavigationContext, } from "./navigation-adapter.js";
5
5
  /**
6
- * Renders BOTH flavor contexts' providers around `children` (TA5). Exported
7
- * for people composing their own wrappers (Storybook decorators, custom
8
- * render helpers); testing-library users want {@link withParamourTesting}.
6
+ * Renders BOTH flavor contexts' providers around `children`. Exported for
7
+ * people composing their own wrappers (Storybook decorators, custom render
8
+ * helpers); testing-library users want {@link withParamourTesting}.
9
9
  */
10
10
  export function ParamourTestingProvider(props) {
11
- // Latest-ref pattern (TA4): reassigned every render so the stable
12
- // adapters below always read the CURRENT render's props.
11
+ // Latest-ref pattern: reassigned every render so the stable adapters
12
+ // below always read the CURRENT render's props.
13
13
  const latest = useRef(props);
14
14
  latest.current = props;
15
15
  const [adapters] = useState(() => createAdapters(latest));
16
16
  return (_jsx(AppNavigationContext.Provider, { value: adapters.app, children: _jsx(PagesNavigationContext.Provider, { value: adapters.pages, children: props.children }) }));
17
17
  }
18
18
  /**
19
- * Wrapper-component form for testing-library's `wrapper` option (TA5,
20
- * mirroring `withNuqsTestingAdapter`).
19
+ * Wrapper-component form for testing-library's `wrapper` option, mirroring
20
+ * `withNuqsTestingAdapter`.
21
21
  */
22
22
  export function withParamourTesting(options = {}) {
23
23
  return function ParamourTestingWrapper({ children, }) {
@@ -25,10 +25,10 @@ export function withParamourTesting(options = {}) {
25
25
  };
26
26
  }
27
27
  /**
28
- * The one adapter pair a provider instance ever holds (TA4). Every read
29
- * defers to `latest.current`, so the adapters are stable while their
30
- * answers track prop updates. Fresh `URLSearchParams` per call is fine —
31
- * the hooks fingerprint the declared slice (SEL4), not the instance.
28
+ * The one adapter pair a provider instance ever holds. Every read defers to
29
+ * `latest.current`, so the adapters are stable while their answers track
30
+ * prop updates. Fresh `URLSearchParams` per call is fine — the hooks
31
+ * fingerprint the declared slice, not the instance.
32
32
  */
33
33
  function createAdapters(latest) {
34
34
  const app = {
@@ -57,20 +57,20 @@ function createAdapters(latest) {
57
57
  const options = latest.current;
58
58
  if (options.mounted === false) {
59
59
  // Verbatim prefix of next/router's real unmounted error — pages.ts
60
- // matches on the message to translate it (PR5).
60
+ // matches on the message to translate it.
61
61
  throw new Error("NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted");
62
62
  }
63
63
  const search = normalizeSearch(options.search);
64
64
  return {
65
- // asPath derives from pathname + normalized search (TA6) —
65
+ // asPath derives from pathname + normalized search —
66
66
  // basePath-relative, what the devtools navigate capability resolves
67
- // against (DT8).
67
+ // against.
68
68
  asPath: (options.pathname ?? "/") + (search === "" ? "" : `?${search}`),
69
69
  isReady: options.isReady ?? true,
70
70
  query: mergedQuery(options),
71
71
  replace(url) {
72
72
  latest.current.onReplace?.(url);
73
- // Real next/router resolves `true` on a completed replace (TA6).
73
+ // Real next/router resolves `true` on a completed replace.
74
74
  return Promise.resolve(true);
75
75
  },
76
76
  };
package/dist/watch.d.ts CHANGED
@@ -9,31 +9,31 @@ export interface WatchRouteDirsOptions {
9
9
  debounceMs?: number;
10
10
  /**
11
11
  * Absolute paths whose events are ignored — the artifact file, so a
12
- * regeneration write can't re-trigger the watcher (TR5 feedback loop).
12
+ * regeneration write can't re-trigger the watcher in a feedback loop.
13
13
  */
14
14
  ignorePaths?: readonly string[];
15
15
  /**
16
16
  * Watcher startup/runtime failures and `onRescan` throws land here.
17
- * Surfaced, not logged: TR5's "log once, dev continues" behavior belongs
18
- * to the composition points (TR4/TR7), not this module.
17
+ * Surfaced, not logged: the "log once, dev continues" behavior belongs to
18
+ * the composition points, not this module.
19
19
  */
20
20
  onError?: (error: unknown) => void;
21
- /** The regenerate callback — full rescan → write-if-changed (TR5). */
21
+ /** The regenerate callback — full rescan → write-if-changed. */
22
22
  onRescan: () => void;
23
23
  }
24
- /** TR5: ~100 ms — long enough to coalesce an editor save storm. */
24
+ /** ~100 ms — long enough to coalesce an editor save storm. */
25
25
  export declare const DEFAULT_DEBOUNCE_MS = 100;
26
26
  /**
27
27
  * Debounced full-rescan watcher over the route dirs — both of them in a
28
- * hybrid project (PR8), sharing one debounce so an editor operation touching
29
- * both coalesces into a single rescan. Because a scan is milliseconds (TR2),
30
- * no event fidelity is needed: any event → debounce → `onRescan`. Native
28
+ * hybrid project, sharing one debounce so an editor operation touching both
29
+ * coalesces into a single rescan. Because a scan is milliseconds, no event
30
+ * fidelity is needed: any event → debounce → `onRescan`. Native
31
31
  * `fs.watch({ recursive: true })`, no chokidar; this start/close interface
32
32
  * is the seam chokidar would drop in behind if a platform hole appears.
33
33
  *
34
- * A missing dir is skipped — not watched, not an error (PR8): callers pass
35
- * the dirs discovery resolved, so absence here is a raced deletion, and dev
36
- * continuing in stale-types mode is exactly TR5's posture. Genuine watch
37
- * startup failures still surface through `onError`.
34
+ * A missing dir is skipped — not watched, not an error: callers pass the
35
+ * dirs discovery resolved, so absence here is a raced deletion, and dev
36
+ * continuing in stale-types mode is exactly the intended posture. Genuine
37
+ * watch startup failures still surface through `onError`.
38
38
  */
39
39
  export declare function watchRouteDirs(dirs: readonly string[], options: WatchRouteDirsOptions): RouteDirsWatcher;
package/dist/watch.js CHANGED
@@ -1,24 +1,24 @@
1
1
  import { statSync, watch } from "node:fs";
2
2
  import { resolve } from "node:path";
3
- /** TR5: ~100 ms — long enough to coalesce an editor save storm. */
3
+ /** ~100 ms — long enough to coalesce an editor save storm. */
4
4
  export const DEFAULT_DEBOUNCE_MS = 100;
5
5
  /**
6
6
  * Directory names whose subtrees are ignored if they ever fall under a
7
- * watched root (TR5).
7
+ * watched root.
8
8
  */
9
9
  const IGNORED_SEGMENTS = new Set([".next", "node_modules"]);
10
10
  /**
11
11
  * Debounced full-rescan watcher over the route dirs — both of them in a
12
- * hybrid project (PR8), sharing one debounce so an editor operation touching
13
- * both coalesces into a single rescan. Because a scan is milliseconds (TR2),
14
- * no event fidelity is needed: any event → debounce → `onRescan`. Native
12
+ * hybrid project, sharing one debounce so an editor operation touching both
13
+ * coalesces into a single rescan. Because a scan is milliseconds, no event
14
+ * fidelity is needed: any event → debounce → `onRescan`. Native
15
15
  * `fs.watch({ recursive: true })`, no chokidar; this start/close interface
16
16
  * is the seam chokidar would drop in behind if a platform hole appears.
17
17
  *
18
- * A missing dir is skipped — not watched, not an error (PR8): callers pass
19
- * the dirs discovery resolved, so absence here is a raced deletion, and dev
20
- * continuing in stale-types mode is exactly TR5's posture. Genuine watch
21
- * startup failures still surface through `onError`.
18
+ * A missing dir is skipped — not watched, not an error: callers pass the
19
+ * dirs discovery resolved, so absence here is a raced deletion, and dev
20
+ * continuing in stale-types mode is exactly the intended posture. Genuine
21
+ * watch startup failures still surface through `onError`.
22
22
  */
23
23
  export function watchRouteDirs(dirs, options) {
24
24
  const { debounceMs = DEFAULT_DEBOUNCE_MS, ignorePaths = [], onError, onRescan, } = options;
@@ -31,7 +31,7 @@ export function watchRouteDirs(dirs, options) {
31
31
  onRescan();
32
32
  }
33
33
  catch (error) {
34
- // A throwing regeneration must not kill the watcher (TR5 non-fatal).
34
+ // A throwing regeneration must not kill the watcher — non-fatal.
35
35
  onError?.(error);
36
36
  }
37
37
  }, debounceMs);
@@ -50,7 +50,7 @@ export function watchRouteDirs(dirs, options) {
50
50
  watcher = watch(dir, { recursive: true }, (_eventType, filename) => {
51
51
  // `filename` can be null (platform-dependent); with nothing to
52
52
  // filter on, err toward rescanning — a spurious pass is a no-op
53
- // write (TR3).
53
+ // write.
54
54
  if (filename !== null) {
55
55
  if (ignored.has(resolve(dir, filename)))
56
56
  return;
@@ -63,8 +63,8 @@ export function watchRouteDirs(dirs, options) {
63
63
  });
64
64
  }
65
65
  catch (error) {
66
- // TR5: watcher failure is non-fatal — dev continues in stale-types
67
- // mode, and the other dir's watcher (if any) keeps running.
66
+ // Watcher failure is non-fatal — dev continues in stale-types mode,
67
+ // and the other dir's watcher (if any) keeps running.
68
68
  onError?.(error);
69
69
  continue;
70
70
  }
@@ -1,15 +1,15 @@
1
- /** Options for {@link withTypedRoutes} (TR4). */
1
+ /** Options for {@link withTypedRoutes}. */
2
2
  export interface WithTypedRoutesOptions {
3
3
  /**
4
4
  * Artifact location, for monorepos where the Next app root isn't where the
5
- * file should live (TR3 escape hatch). Relative paths resolve against the
5
+ * file should live — the escape hatch. Relative paths resolve against the
6
6
  * project root. Default: `paramour-env.d.ts` at the project root.
7
7
  */
8
8
  outFile?: string;
9
9
  /**
10
- * Upgrade build-phase drift from a loud warning to a build failure (TR4)
11
- * — for teams that want the committed artifact to be the law. Default
12
- * `false`, friendly to gitignored-file workflows and CI images.
10
+ * Upgrade build-phase drift from a loud warning to a build failure — for
11
+ * teams that want the committed artifact to be the law. Default `false`,
12
+ * friendly to gitignored-file workflows and CI images.
13
13
  */
14
14
  strict?: boolean;
15
15
  }
@@ -24,21 +24,22 @@ export declare function devWatcherCountForTests(): number;
24
24
  */
25
25
  export declare function resetDevWatchersForTests(): void;
26
26
  /**
27
- * Wrap a Next config with route-registry generation (TR4). Returns the
27
+ * Wrap a Next config with route-registry generation. Returns the
28
28
  * config-function form; Next's phase argument is the mode discriminator:
29
29
  *
30
30
  * - production build → one generation pass before the config is returned
31
31
  * (the build type-checks against fresh routes); drift warns loudly, or
32
32
  * fails the build under `strict: true`.
33
33
  * - dev server → one immediate generation pass, then the debounced watcher
34
- * (TR5) behind both single-writer guards (TR6).
34
+ * behind both single-writer guards (the in-process singleton and the
35
+ * cross-process pidfile lock).
35
36
  * - every other phase → pass-through, no generation.
36
37
  *
37
38
  * Two states throw during config evaluation instead of degrading to
38
39
  * stale-types mode, both phases alike, because Next itself has no valid
39
- * build for them: an app↔pages route collision (PR9), and discovery's
40
- * populated-ignored-dir config error (spike-2 ruling — Next is silently
41
- * serving none of those pages).
40
+ * build for them: an app↔pages route collision, and discovery's
41
+ * populated-ignored-dir config error (Next is silently serving none of those
42
+ * pages).
42
43
  */
43
44
  export declare function withTypedRoutes<C extends object>(config: C | ConfigFunction<C>, options?: WithTypedRoutesOptions): ConfigFunction<C>;
44
45
  export {};