@timber-js/app 0.2.0-alpha.210 → 0.2.0-alpha.212

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 (158) hide show
  1. package/agent-skill.md +10 -5
  2. package/dist/_chunks/{actions-Rjk4htmA.js → actions-CCdnVtWm.js} +8 -6
  3. package/dist/_chunks/actions-CCdnVtWm.js.map +1 -0
  4. package/dist/_chunks/{als-registry-DaxkVjt5.js → als-registry-BZqHCtq-.js} +2 -4
  5. package/dist/_chunks/als-registry-BZqHCtq-.js.map +1 -0
  6. package/dist/_chunks/{cache-api-DGdYfNJn.js → cache-api-LA3sBpUS.js} +5 -5
  7. package/dist/_chunks/{cache-api-DGdYfNJn.js.map → cache-api-LA3sBpUS.js.map} +1 -1
  8. package/dist/_chunks/{chains-BoO51joc.js → chains-BfoPFraI.js} +5 -146
  9. package/dist/_chunks/chains-BfoPFraI.js.map +1 -0
  10. package/dist/_chunks/classify-BT66U83D.js +147 -0
  11. package/dist/_chunks/classify-BT66U83D.js.map +1 -0
  12. package/dist/_chunks/{cli-check-ajNY3B2e.js → cli-check-BfQ54-UJ.js} +3 -3
  13. package/dist/_chunks/{cli-check-ajNY3B2e.js.map → cli-check-BfQ54-UJ.js.map} +1 -1
  14. package/dist/_chunks/{cli-schema-sync-D2eI8jEg.js → cli-schema-sync-czh2dsLs.js} +2 -2
  15. package/dist/_chunks/{cli-schema-sync-D2eI8jEg.js.map → cli-schema-sync-czh2dsLs.js.map} +1 -1
  16. package/dist/_chunks/client-dep-entries-CQwpb8dI.js +66 -0
  17. package/dist/_chunks/client-dep-entries-CQwpb8dI.js.map +1 -0
  18. package/dist/_chunks/{convention-lint-DLmhGsRS.js → convention-lint-BEVW4EID.js} +3 -3
  19. package/dist/_chunks/{convention-lint-DLmhGsRS.js.map → convention-lint-BEVW4EID.js.map} +1 -1
  20. package/dist/_chunks/{dev-server-v97rQH4b.js → dev-server-FKxptbnI.js} +2 -2
  21. package/dist/_chunks/{dev-server-v97rQH4b.js.map → dev-server-FKxptbnI.js.map} +1 -1
  22. package/dist/_chunks/{json-lossy-check-CVuRs2hG.js → json-lossy-check-C8zBY2uZ.js} +2 -2
  23. package/dist/_chunks/{json-lossy-check-CVuRs2hG.js.map → json-lossy-check-C8zBY2uZ.js.map} +1 -1
  24. package/dist/_chunks/{live-graph-9cSnn_h9.js → live-graph-C_4v-fHv.js} +4 -3
  25. package/dist/_chunks/{live-graph-9cSnn_h9.js.map → live-graph-C_4v-fHv.js.map} +1 -1
  26. package/dist/_chunks/{logger-BP0LN6vP.js → logger-CbLdcy-W.js} +2 -2
  27. package/dist/_chunks/{logger-BP0LN6vP.js.map → logger-CbLdcy-W.js.map} +1 -1
  28. package/dist/_chunks/{poison-scan-vGV7Re0B.js → poison-scan-C92liMAr.js} +2 -4
  29. package/dist/_chunks/poison-scan-C92liMAr.js.map +1 -0
  30. package/dist/_chunks/{scanner-DmqdxzbW.js → scanner-CQt12vE2.js} +2 -2
  31. package/dist/_chunks/{scanner-DmqdxzbW.js.map → scanner-CQt12vE2.js.map} +1 -1
  32. package/dist/_chunks/{sizeof-BM1409x2.js → sizeof-QPE5nd3u.js} +2 -2
  33. package/dist/_chunks/{sizeof-BM1409x2.js.map → sizeof-QPE5nd3u.js.map} +1 -1
  34. package/dist/_chunks/{walkers-Czu2jXFq.js → walkers-DAT4avhZ.js} +3 -3
  35. package/dist/_chunks/{walkers-Czu2jXFq.js.map → walkers-DAT4avhZ.js.map} +1 -1
  36. package/dist/adapters/cloudflare-kv-cache.js +1 -1
  37. package/dist/analyze/classify.d.ts +2 -0
  38. package/dist/analyze/classify.d.ts.map +1 -1
  39. package/dist/analyze/crawl-entry.js +3 -2
  40. package/dist/analyze/crawl-entry.js.map +1 -1
  41. package/dist/analyze/graph-command.js +2 -2
  42. package/dist/analyze/poison-scan.d.ts.map +1 -1
  43. package/dist/cache/index.js +2 -2
  44. package/dist/cache/stores/memory.js +1 -1
  45. package/dist/cdn/workers-cache-purge.js +1 -1
  46. package/dist/cli.js +3 -3
  47. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  48. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  49. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  50. package/dist/client/form.d.ts +17 -64
  51. package/dist/client/form.d.ts.map +1 -1
  52. package/dist/client/index.d.ts +2 -2
  53. package/dist/client/index.d.ts.map +1 -1
  54. package/dist/client/index.js +23 -51
  55. package/dist/client/index.js.map +1 -1
  56. package/dist/client/internal.js +25 -25
  57. package/dist/client/internal.js.map +1 -1
  58. package/dist/client/navigation-api.d.ts +25 -63
  59. package/dist/client/navigation-api.d.ts.map +1 -1
  60. package/dist/client/router-lifecycle.d.ts +17 -11
  61. package/dist/client/router-lifecycle.d.ts.map +1 -1
  62. package/dist/client/router-pipeline.d.ts +0 -1
  63. package/dist/client/router-pipeline.d.ts.map +1 -1
  64. package/dist/client/router-types.d.ts +14 -45
  65. package/dist/client/router-types.d.ts.map +1 -1
  66. package/dist/client/router.d.ts.map +1 -1
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +44 -7
  69. package/dist/index.js.map +1 -1
  70. package/dist/plugins/client-dep-entries.d.ts +44 -0
  71. package/dist/plugins/client-dep-entries.d.ts.map +1 -0
  72. package/dist/plugins/content.d.ts.map +1 -1
  73. package/dist/plugins/entries.d.ts +6 -0
  74. package/dist/plugins/entries.d.ts.map +1 -1
  75. package/dist/plugins/shims.d.ts.map +1 -1
  76. package/dist/routing/index.js +2 -2
  77. package/dist/rsc-runtime/rsc.d.ts +1 -1
  78. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  79. package/dist/server/action-client.d.ts +9 -5
  80. package/dist/server/action-client.d.ts.map +1 -1
  81. package/dist/server/action-handler.d.ts +27 -8
  82. package/dist/server/action-handler.d.ts.map +1 -1
  83. package/dist/server/als-registry.d.ts +22 -2
  84. package/dist/server/als-registry.d.ts.map +1 -1
  85. package/dist/server/client-error-message.d.ts +12 -0
  86. package/dist/server/client-error-message.d.ts.map +1 -0
  87. package/dist/server/form-state-embed.d.ts +32 -0
  88. package/dist/server/form-state-embed.d.ts.map +1 -0
  89. package/dist/server/index.d.ts +0 -2
  90. package/dist/server/index.d.ts.map +1 -1
  91. package/dist/server/index.js +7 -40
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/server/internal.js +10 -6
  94. package/dist/server/internal.js.map +1 -1
  95. package/dist/server/logger.d.ts +1 -0
  96. package/dist/server/logger.d.ts.map +1 -1
  97. package/dist/server/pipeline.d.ts +20 -6
  98. package/dist/server/pipeline.d.ts.map +1 -1
  99. package/dist/server/request-context.d.ts +27 -2
  100. package/dist/server/request-context.d.ts.map +1 -1
  101. package/dist/server/route-element-builder.d.ts.map +1 -1
  102. package/dist/server/rsc-entry/action-dispatcher.d.ts +6 -5
  103. package/dist/server/rsc-entry/action-dispatcher.d.ts.map +1 -1
  104. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  105. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  106. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  107. package/dist/server/ssr-bridge-types.d.ts +8 -0
  108. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  109. package/dist/server/ssr-entry.d.ts.map +1 -1
  110. package/dist/server/ssr-render.d.ts +3 -0
  111. package/dist/server/ssr-render.d.ts.map +1 -1
  112. package/docs/api/31-api-client.mdx +9 -3
  113. package/docs/learn/08-forms-and-actions.mdx +21 -28
  114. package/package.json +1 -1
  115. package/src/analyze/classify.ts +1 -1
  116. package/src/analyze/poison-scan.ts +1 -4
  117. package/src/client/browser-entry/action-dispatch.ts +74 -18
  118. package/src/client/browser-entry/hydrate.ts +18 -0
  119. package/src/client/browser-entry/router-init.ts +4 -18
  120. package/src/client/form.tsx +33 -98
  121. package/src/client/index.ts +2 -2
  122. package/src/client/navigation-api.ts +47 -173
  123. package/src/client/navigation-transition.ts +2 -2
  124. package/src/client/router-lifecycle.ts +40 -20
  125. package/src/client/router-pipeline.ts +3 -9
  126. package/src/client/router-types.ts +14 -49
  127. package/src/client/router.ts +38 -58
  128. package/src/index.ts +21 -2
  129. package/src/plugins/client-dep-entries.ts +78 -0
  130. package/src/plugins/content.ts +26 -1
  131. package/src/plugins/entries.ts +7 -0
  132. package/src/plugins/shims.ts +0 -2
  133. package/src/rsc-runtime/rsc.ts +3 -0
  134. package/src/rsc-runtime/vendor-types.d.ts +14 -0
  135. package/src/server/action-client.ts +18 -20
  136. package/src/server/action-handler.ts +133 -95
  137. package/src/server/als-registry.ts +23 -9
  138. package/src/server/client-error-message.ts +18 -0
  139. package/src/server/form-state-embed.ts +63 -0
  140. package/src/server/index.ts +0 -4
  141. package/src/server/logger.ts +6 -1
  142. package/src/server/pipeline.ts +27 -8
  143. package/src/server/request-context.ts +39 -2
  144. package/src/server/route-element-builder.ts +12 -1
  145. package/src/server/rsc-entry/action-dispatcher.ts +37 -34
  146. package/src/server/rsc-entry/error-renderer.ts +2 -1
  147. package/src/server/rsc-entry/rsc-stream.ts +20 -11
  148. package/src/server/rsc-entry/ssr-renderer.ts +14 -1
  149. package/src/server/ssr-bridge-types.ts +9 -0
  150. package/src/server/ssr-entry.ts +1 -0
  151. package/src/server/ssr-render.ts +5 -0
  152. package/dist/_chunks/actions-Rjk4htmA.js.map +0 -1
  153. package/dist/_chunks/als-registry-DaxkVjt5.js.map +0 -1
  154. package/dist/_chunks/chains-BoO51joc.js.map +0 -1
  155. package/dist/_chunks/poison-scan-vGV7Re0B.js.map +0 -1
  156. package/dist/server/form-flash.d.ts +0 -78
  157. package/dist/server/form-flash.d.ts.map +0 -1
  158. package/src/server/form-flash.ts +0 -89
@@ -121,13 +121,16 @@ function isAbortError(error) {
121
121
  if (error instanceof Error && error.name === "AbortError") return true;
122
122
  return false;
123
123
  }
124
- function createNavigationLifecycle(deps) {
124
+ function createNavigationLifecycle() {
125
125
  let current = null;
126
126
  let pendingCommit = null;
127
127
  let routerPhase = { phase: "idle" };
128
128
  const pendingListeners = /* @__PURE__ */ new Set();
129
129
  let navigationSeq = 0;
130
130
  let idleTask = null;
131
+ const idleListeners = /* @__PURE__ */ new Set();
132
+ const treeCommitListeners = /* @__PURE__ */ new Set();
133
+ const ownerSeq = /* @__PURE__ */ new WeakMap();
131
134
  /**
132
135
  * Whether a handed-off tree has not yet committed. Derived from the slot:
133
136
  * true when `current` is handed off but not yet settled.
@@ -155,23 +158,18 @@ function createNavigationLifecycle(deps) {
155
158
  * in-flight navigation. Optionally links to an external signal (e.g.,
156
159
  * from the Navigation API's NavigateEvent.signal).
157
160
  *
158
- * Superseding is one operation with three parts:
161
+ * Superseding is one operation with two parts:
159
162
  * 1. Abort the previous navigation's fetch — UNLESS its tree is the one on
160
163
  * screen, in which case tearing the stream down would error the page the
161
164
  * user is currently looking at. See `RenderOwner.handedOff`.
162
165
  * 2. Settle the previous owner as 'superseded' so its transition detects
163
166
  * it lost and never hands a stale tree to React. This replaces both
164
167
  * `supersedeNavigationTransitions()` and the transition counter bump.
165
- * 3. Resolve its Navigation API deferred — the superseded navigation's
166
- * finally block is staleness-guarded (see TIM-1034) and no longer
167
- * cleans up after itself, so the browser's native loading state for
168
- * the dead navigation is cleared here.
169
168
  */
170
169
  function createNavOwner(kind, externalSignal) {
171
170
  if (current) {
172
171
  abortUnlessHandedOff(current);
173
172
  current.settle("superseded");
174
- deps.completeRouterNavigation?.();
175
173
  }
176
174
  if (pendingCommit) {
177
175
  pendingCommit.settle("superseded");
@@ -179,6 +177,7 @@ function createNavigationLifecycle(deps) {
179
177
  }
180
178
  navigationSeq += 1;
181
179
  const owner = createRenderOwner(kind);
180
+ ownerSeq.set(owner, navigationSeq);
182
181
  current = owner;
183
182
  if (externalSignal) {
184
183
  if (externalSignal.aborted) abortUnlessHandedOff(owner);
@@ -214,13 +213,14 @@ function createNavigationLifecycle(deps) {
214
213
  if (current === owner) {
215
214
  current = null;
216
215
  setPending(false);
217
- deps.completeRouterNavigation?.();
218
216
  flushIdleTask();
219
217
  }
220
218
  }
221
219
  }
222
220
  function flushIdleTask() {
223
- if (routerPhase.phase !== "idle" || hasUncommittedNav() || !idleTask) return;
221
+ if (routerPhase.phase !== "idle" || hasUncommittedNav()) return;
222
+ for (const listener of [...idleListeners]) listener();
223
+ if (!idleTask) return;
224
224
  const task = idleTask;
225
225
  idleTask = null;
226
226
  task();
@@ -237,9 +237,12 @@ function createNavigationLifecycle(deps) {
237
237
  forgetOlderHandoffs(owner) {
238
238
  owner.settle("committed");
239
239
  if (pendingCommit === owner) pendingCommit = null;
240
+ const seq = ownerSeq.get(owner) ?? navigationSeq;
241
+ for (const listener of [...treeCommitListeners]) listener(seq);
240
242
  flushIdleTask();
241
243
  },
242
244
  placeRevalidationOwner(owner) {
245
+ ownerSeq.set(owner, navigationSeq);
243
246
  current = owner;
244
247
  },
245
248
  isPending: () => routerPhase.phase === "navigating",
@@ -264,6 +267,14 @@ function createNavigationLifecycle(deps) {
264
267
  }
265
268
  idleTask = task;
266
269
  },
270
+ onIdle(listener) {
271
+ idleListeners.add(listener);
272
+ return () => idleListeners.delete(listener);
273
+ },
274
+ onTreeCommit(listener) {
275
+ treeCommitListeners.add(listener);
276
+ return () => treeCommitListeners.delete(listener);
277
+ },
267
278
  settleHandoffs() {
268
279
  if (pendingCommit) {
269
280
  pendingCommit.settle("superseded");
@@ -461,9 +472,7 @@ function createNavigationPipeline({ deps, prefetchCache, currentStateTree, prepa
461
472
  result = await fetchRscPayload(url, deps, freshStateTree, currentUrl, options.signal);
462
473
  }
463
474
  const commitHistoryUrl = () => {
464
- if (options.skipHistory) return;
465
475
  const commitUrl = options.commitUrl ?? url;
466
- deps.setRouterNavigating?.(true);
467
476
  if (options.replace) deps.replaceState({
468
477
  timber: true,
469
478
  scrollY: 0
@@ -472,7 +481,6 @@ function createNavigationPipeline({ deps, prefetchCache, currentStateTree, prepa
472
481
  timber: true,
473
482
  scrollY: 0
474
483
  }, "", commitUrl);
475
- deps.setRouterNavigating?.(false);
476
484
  };
477
485
  const params = await result.params;
478
486
  const { navState, commit } = prepareNavigation(url, {
@@ -513,7 +521,7 @@ function createRouter(deps) {
513
521
  historyStack,
514
522
  clientSegmentCache: () => deps.clientSegmentCache
515
523
  });
516
- const lifecycle = createNavigationLifecycle(deps);
524
+ const lifecycle = createNavigationLifecycle();
517
525
  const { currentOwner, createNavOwner, runNavigation, markHandedOff, forgetOlderHandoffs, isPending, getPendingUrl, onPendingChange } = lifecycle;
518
526
  const { performNavigationFetch, renderViaTransition } = createNavigationPipeline({
519
527
  deps,
@@ -541,13 +549,11 @@ function createRouter(deps) {
541
549
  async function navigate(url, options = {}) {
542
550
  const scroll = options.scroll !== false;
543
551
  const replace = options.replace === true;
544
- const externalSignal = options._signal;
545
- const skipHistory = options._skipHistory === true;
546
552
  const types = options._renderTypes ?? ["navigation-forward", ...options.transitionTypes ?? []];
547
553
  const hashIndex = url.indexOf("#");
548
554
  const hash = hashIndex === -1 ? "" : url.slice(hashIndex);
549
555
  const fetchUrl = hashIndex === -1 ? url : url.slice(0, hashIndex);
550
- const departingUrl = options._departingUrl ?? deps.getCurrentUrl();
556
+ const departingUrl = deps.getCurrentUrl();
551
557
  const currentScrollY = deps.getScrollY();
552
558
  if (deps.saveNavigationEntryScroll) deps.saveNavigationEntryScroll(currentScrollY);
553
559
  else deps.replaceState({
@@ -555,20 +561,12 @@ function createRouter(deps) {
555
561
  scrollY: currentScrollY
556
562
  }, "", deps.getCurrentUrl());
557
563
  if (isClientStale()) await leaveSpaSuperseding(url, departingUrl);
558
- let effectiveSkipHistory = skipHistory;
559
564
  await runNavigation(url, async (owner) => {
560
- if (!effectiveSkipHistory && deps.navigationNavigate) {
561
- deps.setRouterNavigating?.(true);
562
- deps.navigationNavigate(url, replace);
563
- deps.setRouterNavigating?.(false);
564
- effectiveSkipHistory = true;
565
- }
566
565
  try {
567
566
  await renderViaTransition(fetchUrl, owner, types, () => performNavigationFetch(fetchUrl, {
568
567
  replace,
569
568
  commitUrl: url,
570
569
  signal: owner.fetchAbort.signal,
571
- skipHistory: effectiveSkipHistory,
572
570
  departingUrl
573
571
  }), options.onCommit);
574
572
  if (scroll && hash) scrollToHashAfterPaint(hash);
@@ -577,7 +575,7 @@ function createRouter(deps) {
577
575
  if (await recoverFromNavigationError(error, owner, url, departingUrl, types)) return;
578
576
  throw error;
579
577
  }
580
- }, externalSignal);
578
+ });
581
579
  }
582
580
  /**
583
581
  * Fetch a URL's RSC payload, commit it, and render — the pipeline shared by
@@ -717,6 +715,8 @@ function createRouter(deps) {
717
715
  return outcome === "committed";
718
716
  },
719
717
  runWhenIdle: (task) => lifecycle.runWhenIdle(task),
718
+ onIdle: (listener) => lifecycle.onIdle(listener),
719
+ onTreeCommit: (listener) => lifecycle.onTreeCommit(listener),
720
720
  settleHandoffs: () => lifecycle.settleHandoffs(),
721
721
  suppressSegmentReuse() {
722
722
  segmentCache.invalidateReuse();