@paramour-js/next 0.3.1 → 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 +48 -21
  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 +59 -0
  27. package/dist/navigation-adapter.js +9 -0
  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 +25 -9
  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 +68 -0
  43. package/dist/testing.js +113 -0
  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 +6 -2
@@ -7,18 +7,18 @@ import { resolveRouteDirs } from "./scan.js";
7
7
  import { watchRouteDirs } from "./watch.js";
8
8
  /**
9
9
  * Phase constants from `next/constants`, hardcoded so the package stays
10
- * hermetic (TR4 hermeticity ruling): the values are stable, documented
11
- * public API, and importing them would make `next` a runtime dependency.
10
+ * hermetic: the values are stable, documented public API, and importing them
11
+ * would make `next` a runtime dependency.
12
12
  */
13
13
  const PHASE_DEVELOPMENT_SERVER = "phase-development-server";
14
14
  const PHASE_PRODUCTION_BUILD = "phase-production-build";
15
15
  /**
16
- * TR6 guard 1 — the in-process singleton, keyed by route dirs + artifact
17
- * path. Load-bearing even for a single `next dev`: the spike-#1 census found
18
- * Turbopack dev invokes the config function twice in the same process.
16
+ * The in-process single-writer guard — a singleton keyed by route dirs +
17
+ * artifact path. Load-bearing even for a single `next dev`: Turbopack dev
18
+ * invokes the config function twice in the same process.
19
19
  */
20
20
  const devWatcherTeardowns = new Map();
21
- /** Messages already logged — "log once" (TR5) across repeat evaluations. */
21
+ /** Messages already logged — "log once" across repeat evaluations. */
22
22
  const warnedOnce = new Set();
23
23
  /** @internal Test seam: the number of live dev-watcher singletons. */
24
24
  export function devWatcherCountForTests() {
@@ -36,21 +36,22 @@ export function resetDevWatchersForTests() {
36
36
  warnedOnce.clear();
37
37
  }
38
38
  /**
39
- * Wrap a Next config with route-registry generation (TR4). Returns the
39
+ * Wrap a Next config with route-registry generation. Returns the
40
40
  * config-function form; Next's phase argument is the mode discriminator:
41
41
  *
42
42
  * - production build → one generation pass before the config is returned
43
43
  * (the build type-checks against fresh routes); drift warns loudly, or
44
44
  * fails the build under `strict: true`.
45
45
  * - dev server → one immediate generation pass, then the debounced watcher
46
- * (TR5) behind both single-writer guards (TR6).
46
+ * behind both single-writer guards (the in-process singleton and the
47
+ * cross-process pidfile lock).
47
48
  * - every other phase → pass-through, no generation.
48
49
  *
49
50
  * Two states throw during config evaluation instead of degrading to
50
51
  * stale-types mode, both phases alike, because Next itself has no valid
51
- * build for them: an app↔pages route collision (PR9), and discovery's
52
- * populated-ignored-dir config error (spike-2 ruling — Next is silently
53
- * serving none of those pages).
52
+ * build for them: an app↔pages route collision, and discovery's
53
+ * populated-ignored-dir config error (Next is silently serving none of those
54
+ * pages).
54
55
  */
55
56
  export function withTypedRoutes(config, options = {}) {
56
57
  return async (phase, ctx) => {
@@ -58,16 +59,17 @@ export function withTypedRoutes(config, options = {}) {
58
59
  if (phase !== PHASE_DEVELOPMENT_SERVER && phase !== PHASE_PRODUCTION_BUILD)
59
60
  return resolved;
60
61
  // The dev server and every build worker evaluate the config with the
61
- // project root as cwd (spike-#1 census); TR7's CLI flags are the home
62
- // for anything more configurable than this.
62
+ // project root as cwd; the CLI flags are the home for anything more
63
+ // configurable than this.
63
64
  const projectRoot = process.cwd();
64
65
  const artifactPath = resolve(projectRoot, options.outFile ?? "paramour-env.d.ts");
65
66
  const pageExtensions = resolved.pageExtensions ?? DEFAULT_PAGE_EXTENSIONS;
66
- // May throw the spike-2 config error — deliberately not caught (above).
67
+ // May throw the populated-ignored-dir config error — deliberately not
68
+ // caught (see above).
67
69
  const dirs = resolveRouteDirs(projectRoot, pageExtensions);
68
70
  if (dirs.appDir === undefined && dirs.pagesDir === undefined) {
69
- // §7.3: codegen is never load-bearing — a config wrapper must not
70
- // take down `next dev`/`next build` over a missing route dir.
71
+ // Codegen is never load-bearing — a config wrapper must not take down
72
+ // `next dev`/`next build` over a missing route dir.
71
73
  warnOnce(`paramour: no route directory (app/, pages/, src/app/, or src/pages/) under ${projectRoot}; route generation skipped`);
72
74
  return resolved;
73
75
  }
@@ -81,12 +83,12 @@ export function withTypedRoutes(config, options = {}) {
81
83
  };
82
84
  }
83
85
  /**
84
- * Build-phase pass (TR4): regenerate, then warn loudly on drift — naming the
85
- * paths that appeared/disappeared and the router they moved in — but
86
- * continue; `strict` upgrades drift to a thrown error *after* the file is
87
- * already corrected. A missing artifact counts as drift: that is exactly the
88
- * CI-degrades-to-world-A scenario the committed file exists to prevent
89
- * (TR3). A route collision is NOT incidental failure and rethrows (PR9).
86
+ * Build-phase pass: regenerate, then warn loudly on drift — naming the paths
87
+ * that appeared/disappeared and the router they moved in — but continue;
88
+ * `strict` upgrades drift to a thrown error *after* the file is already
89
+ * corrected. A missing artifact counts as drift: that is exactly the
90
+ * CI-degrades-to-world-A scenario the committed file exists to prevent. A
91
+ * route collision is NOT incidental failure and rethrows.
90
92
  */
91
93
  function generateForBuild(dirs, pageExtensions, artifactPath, strict) {
92
94
  let result;
@@ -94,13 +96,13 @@ function generateForBuild(dirs, pageExtensions, artifactPath, strict) {
94
96
  result = generate({ ...dirs, artifactPath, pageExtensions });
95
97
  }
96
98
  catch (error) {
97
- // PR9: Next fails this build anyway; surfacing the collision from the
98
- // config evaluation names the actual problem instead of leaving a stale
99
+ // Next fails this build anyway; surfacing the collision from the config
100
+ // evaluation names the actual problem instead of leaving a stale
99
101
  // artifact to confuse the type errors that follow.
100
102
  if (error instanceof RouteCollisionError)
101
103
  throw error;
102
- // §7.3 again: incidental generation failure is stale types, not a
103
- // broken build. Only *drift* is allowed to fail a strict build.
104
+ // Again: incidental generation failure is stale types, not a broken
105
+ // build. Only *drift* is allowed to fail a strict build.
104
106
  console.warn("paramour: route generation failed; building with stale route types", error);
105
107
  return;
106
108
  }
@@ -119,9 +121,10 @@ function generateForBuild(dirs, pageExtensions, artifactPath, strict) {
119
121
  console.warn(message);
120
122
  }
121
123
  /**
122
- * Dev-phase generation (TR4): failure warns and continues (§7.3) — except a
123
- * route collision, which throws from the config evaluation here exactly as
124
- * in the build phase (PR9; only the running WATCHER treats it non-fatally).
124
+ * Dev-phase generation: failure warns and continues (codegen is never
125
+ * load-bearing) — except a route collision, which throws from the config
126
+ * evaluation here exactly as in the build phase; only the running WATCHER
127
+ * treats it non-fatally.
125
128
  */
126
129
  function generateSafely(dirs, pageExtensions, artifactPath) {
127
130
  try {
@@ -134,8 +137,8 @@ function generateSafely(dirs, pageExtensions, artifactPath) {
134
137
  }
135
138
  }
136
139
  /**
137
- * Start the dev watcher behind both TR6 guards. Failure at any layer leaves
138
- * dev running in stale-types mode — never fatal (TR5).
140
+ * Start the dev watcher behind both single-writer guards. Failure at any
141
+ * layer leaves dev running in stale-types mode — never fatal.
139
142
  */
140
143
  function startDevWatcher(projectRoot, dirs, pageExtensions, artifactPath) {
141
144
  const watchedDirs = [dirs.appDir, dirs.pagesDir].filter((dir) => dir !== undefined);
@@ -147,14 +150,14 @@ function startDevWatcher(projectRoot, dirs, pageExtensions, artifactPath) {
147
150
  lock = acquireWatcherLock(watcherLockPath(projectRoot));
148
151
  }
149
152
  catch (error) {
150
- // §7.3: a corrupt lock location (e.g. a directory at the pidfile path)
151
- // must not take down `next dev` — stale-types mode, like every other
153
+ // A corrupt lock location (e.g. a directory at the pidfile path) must
154
+ // not take down `next dev` — stale-types mode, like every other
152
155
  // watcher-layer failure.
153
156
  warnOnce("paramour: dev watcher failed; dev continues with stale route types", error);
154
157
  return;
155
158
  }
156
159
  if (!lock.acquired) {
157
- // TR6: another live process owns the watcher (e.g. `paramour generate
160
+ // Another live process owns the watcher (e.g. `paramour generate
158
161
  // --watch` beside `next dev`). Initial generation above already ran, so
159
162
  // dev is still correct from second zero.
160
163
  console.warn(`paramour: watcher already running (pid ${String(lock.ownerPid)})`);
@@ -171,13 +174,13 @@ function startDevWatcher(projectRoot, dirs, pageExtensions, artifactPath) {
171
174
  }
172
175
  catch (error) {
173
176
  if (error instanceof RouteCollisionError) {
174
- // PR9's watch exception: a mid-watch collision is usually a file
175
- // mid-move — log loudly every time (not once: it stays broken
176
- // until fixed), keep the last good artifact, keep running (TR5).
177
+ // The collision watch exception: a mid-watch collision is usually
178
+ // a file mid-move — log loudly every time (not once: it stays
179
+ // broken until fixed), keep the last good artifact, keep running.
177
180
  console.warn(`paramour: ${error.message}; dev continues with the last good artifact`);
178
181
  return;
179
182
  }
180
- throw error; // routed to onError by the watcher (TR5 non-fatal)
183
+ throw error; // routed to onError by the watcher — non-fatal
181
184
  }
182
185
  },
183
186
  });
@@ -188,7 +191,7 @@ function startDevWatcher(projectRoot, dirs, pageExtensions, artifactPath) {
188
191
  lock.release?.();
189
192
  });
190
193
  }
191
- /** TR5 "log once": repeat evaluations/events don't spam the dev console. */
194
+ /** "Log once": repeat evaluations/events don't spam the dev console. */
192
195
  function warnOnce(message, detail) {
193
196
  if (warnedOnce.has(message))
194
197
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paramour-js/next",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -17,6 +17,10 @@
17
17
  "./pages": {
18
18
  "types": "./dist/pages.d.ts",
19
19
  "default": "./dist/pages.js"
20
+ },
21
+ "./testing": {
22
+ "types": "./dist/testing.d.ts",
23
+ "default": "./dist/testing.js"
20
24
  }
21
25
  },
22
26
  "sideEffects": false,
@@ -30,7 +34,7 @@
30
34
  "jiti": "^2.7.0",
31
35
  "magicast": "^0.3.5",
32
36
  "tinyglobby": "^0.2.15",
33
- "paramour": "0.5.1"
37
+ "paramour": "0.6.0"
34
38
  },
35
39
  "peerDependencies": {
36
40
  "next": ">=15",