@timber-js/app 0.1.0

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 (310) hide show
  1. package/bin/timber.mjs +5 -0
  2. package/dist/_chunks/error-boundary-dj-WO5uq.js +121 -0
  3. package/dist/_chunks/error-boundary-dj-WO5uq.js.map +1 -0
  4. package/dist/_chunks/format-DNt20Kt8.js +163 -0
  5. package/dist/_chunks/format-DNt20Kt8.js.map +1 -0
  6. package/dist/_chunks/interception-DIaZN1bF.js +669 -0
  7. package/dist/_chunks/interception-DIaZN1bF.js.map +1 -0
  8. package/dist/_chunks/metadata-routes-BDnswgRO.js +141 -0
  9. package/dist/_chunks/metadata-routes-BDnswgRO.js.map +1 -0
  10. package/dist/_chunks/registry-DUIpYD_x.js +20 -0
  11. package/dist/_chunks/registry-DUIpYD_x.js.map +1 -0
  12. package/dist/_chunks/request-context-D6XHINkR.js +330 -0
  13. package/dist/_chunks/request-context-D6XHINkR.js.map +1 -0
  14. package/dist/_chunks/tracing-BtOwb8O6.js +174 -0
  15. package/dist/_chunks/tracing-BtOwb8O6.js.map +1 -0
  16. package/dist/_chunks/use-cookie-8ZlA0rr3.js +125 -0
  17. package/dist/_chunks/use-cookie-8ZlA0rr3.js.map +1 -0
  18. package/dist/adapters/cloudflare.d.ts +92 -0
  19. package/dist/adapters/cloudflare.d.ts.map +1 -0
  20. package/dist/adapters/cloudflare.js +188 -0
  21. package/dist/adapters/cloudflare.js.map +1 -0
  22. package/dist/adapters/nitro.d.ts +72 -0
  23. package/dist/adapters/nitro.d.ts.map +1 -0
  24. package/dist/adapters/nitro.js +217 -0
  25. package/dist/adapters/nitro.js.map +1 -0
  26. package/dist/adapters/types.d.ts +53 -0
  27. package/dist/adapters/types.d.ts.map +1 -0
  28. package/dist/cache/index.d.ts +52 -0
  29. package/dist/cache/index.d.ts.map +1 -0
  30. package/dist/cache/index.js +283 -0
  31. package/dist/cache/index.js.map +1 -0
  32. package/dist/cache/redis-handler.d.ts +45 -0
  33. package/dist/cache/redis-handler.d.ts.map +1 -0
  34. package/dist/cache/register-cached-function.d.ts +17 -0
  35. package/dist/cache/register-cached-function.d.ts.map +1 -0
  36. package/dist/cache/singleflight.d.ts +11 -0
  37. package/dist/cache/singleflight.d.ts.map +1 -0
  38. package/dist/cache/stable-stringify.d.ts +7 -0
  39. package/dist/cache/stable-stringify.d.ts.map +1 -0
  40. package/dist/cache/timber-cache.d.ts +21 -0
  41. package/dist/cache/timber-cache.d.ts.map +1 -0
  42. package/dist/cli.d.ts +44 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +135 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/client/browser-entry.d.ts +22 -0
  47. package/dist/client/browser-entry.d.ts.map +1 -0
  48. package/dist/client/error-boundary.d.ts +42 -0
  49. package/dist/client/error-boundary.d.ts.map +1 -0
  50. package/dist/client/form.d.ts +115 -0
  51. package/dist/client/form.d.ts.map +1 -0
  52. package/dist/client/head.d.ts +16 -0
  53. package/dist/client/head.d.ts.map +1 -0
  54. package/dist/client/history.d.ts +29 -0
  55. package/dist/client/history.d.ts.map +1 -0
  56. package/dist/client/index.d.ts +32 -0
  57. package/dist/client/index.d.ts.map +1 -0
  58. package/dist/client/index.js +1218 -0
  59. package/dist/client/index.js.map +1 -0
  60. package/dist/client/link-navigate-interceptor.d.ts +28 -0
  61. package/dist/client/link-navigate-interceptor.d.ts.map +1 -0
  62. package/dist/client/link-status-provider.d.ts +11 -0
  63. package/dist/client/link-status-provider.d.ts.map +1 -0
  64. package/dist/client/link.d.ts +119 -0
  65. package/dist/client/link.d.ts.map +1 -0
  66. package/dist/client/nuqs-adapter.d.ts +11 -0
  67. package/dist/client/nuqs-adapter.d.ts.map +1 -0
  68. package/dist/client/router-ref.d.ts +11 -0
  69. package/dist/client/router-ref.d.ts.map +1 -0
  70. package/dist/client/router.d.ts +85 -0
  71. package/dist/client/router.d.ts.map +1 -0
  72. package/dist/client/segment-cache.d.ts +88 -0
  73. package/dist/client/segment-cache.d.ts.map +1 -0
  74. package/dist/client/segment-context.d.ts +32 -0
  75. package/dist/client/segment-context.d.ts.map +1 -0
  76. package/dist/client/ssr-data.d.ts +64 -0
  77. package/dist/client/ssr-data.d.ts.map +1 -0
  78. package/dist/client/types.d.ts +5 -0
  79. package/dist/client/types.d.ts.map +1 -0
  80. package/dist/client/unload-guard.d.ts +18 -0
  81. package/dist/client/unload-guard.d.ts.map +1 -0
  82. package/dist/client/use-cookie.d.ts +37 -0
  83. package/dist/client/use-cookie.d.ts.map +1 -0
  84. package/dist/client/use-link-status.d.ts +35 -0
  85. package/dist/client/use-link-status.d.ts.map +1 -0
  86. package/dist/client/use-navigation-pending.d.ts +26 -0
  87. package/dist/client/use-navigation-pending.d.ts.map +1 -0
  88. package/dist/client/use-params.d.ts +50 -0
  89. package/dist/client/use-params.d.ts.map +1 -0
  90. package/dist/client/use-pathname.d.ts +20 -0
  91. package/dist/client/use-pathname.d.ts.map +1 -0
  92. package/dist/client/use-query-states.d.ts +36 -0
  93. package/dist/client/use-query-states.d.ts.map +1 -0
  94. package/dist/client/use-router.d.ts +39 -0
  95. package/dist/client/use-router.d.ts.map +1 -0
  96. package/dist/client/use-search-params.d.ts +24 -0
  97. package/dist/client/use-search-params.d.ts.map +1 -0
  98. package/dist/client/use-selected-layout-segment.d.ts +68 -0
  99. package/dist/client/use-selected-layout-segment.d.ts.map +1 -0
  100. package/dist/content/index.d.ts +11 -0
  101. package/dist/content/index.d.ts.map +1 -0
  102. package/dist/content/index.js +2 -0
  103. package/dist/cookies/define-cookie.d.ts +61 -0
  104. package/dist/cookies/define-cookie.d.ts.map +1 -0
  105. package/dist/cookies/index.d.ts +3 -0
  106. package/dist/cookies/index.d.ts.map +1 -0
  107. package/dist/cookies/index.js +82 -0
  108. package/dist/cookies/index.js.map +1 -0
  109. package/dist/fonts/ast.d.ts +38 -0
  110. package/dist/fonts/ast.d.ts.map +1 -0
  111. package/dist/fonts/css.d.ts +43 -0
  112. package/dist/fonts/css.d.ts.map +1 -0
  113. package/dist/fonts/fallbacks.d.ts +36 -0
  114. package/dist/fonts/fallbacks.d.ts.map +1 -0
  115. package/dist/fonts/google.d.ts +122 -0
  116. package/dist/fonts/google.d.ts.map +1 -0
  117. package/dist/fonts/local.d.ts +76 -0
  118. package/dist/fonts/local.d.ts.map +1 -0
  119. package/dist/fonts/types.d.ts +85 -0
  120. package/dist/fonts/types.d.ts.map +1 -0
  121. package/dist/index.d.ts +150 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +14701 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/plugins/adapter-build.d.ts +18 -0
  126. package/dist/plugins/adapter-build.d.ts.map +1 -0
  127. package/dist/plugins/build-manifest.d.ts +79 -0
  128. package/dist/plugins/build-manifest.d.ts.map +1 -0
  129. package/dist/plugins/build-report.d.ts +63 -0
  130. package/dist/plugins/build-report.d.ts.map +1 -0
  131. package/dist/plugins/cache-transform.d.ts +36 -0
  132. package/dist/plugins/cache-transform.d.ts.map +1 -0
  133. package/dist/plugins/chunks.d.ts +45 -0
  134. package/dist/plugins/chunks.d.ts.map +1 -0
  135. package/dist/plugins/content.d.ts +19 -0
  136. package/dist/plugins/content.d.ts.map +1 -0
  137. package/dist/plugins/dev-error-overlay.d.ts +60 -0
  138. package/dist/plugins/dev-error-overlay.d.ts.map +1 -0
  139. package/dist/plugins/dev-logs.d.ts +46 -0
  140. package/dist/plugins/dev-logs.d.ts.map +1 -0
  141. package/dist/plugins/dev-server.d.ts +22 -0
  142. package/dist/plugins/dev-server.d.ts.map +1 -0
  143. package/dist/plugins/dynamic-transform.d.ts +72 -0
  144. package/dist/plugins/dynamic-transform.d.ts.map +1 -0
  145. package/dist/plugins/entries.d.ts +21 -0
  146. package/dist/plugins/entries.d.ts.map +1 -0
  147. package/dist/plugins/fonts.d.ts +77 -0
  148. package/dist/plugins/fonts.d.ts.map +1 -0
  149. package/dist/plugins/mdx.d.ts +21 -0
  150. package/dist/plugins/mdx.d.ts.map +1 -0
  151. package/dist/plugins/react-prod.d.ts +18 -0
  152. package/dist/plugins/react-prod.d.ts.map +1 -0
  153. package/dist/plugins/routing.d.ts +13 -0
  154. package/dist/plugins/routing.d.ts.map +1 -0
  155. package/dist/plugins/server-action-exports.d.ts +26 -0
  156. package/dist/plugins/server-action-exports.d.ts.map +1 -0
  157. package/dist/plugins/server-bundle.d.ts +15 -0
  158. package/dist/plugins/server-bundle.d.ts.map +1 -0
  159. package/dist/plugins/shims.d.ts +18 -0
  160. package/dist/plugins/shims.d.ts.map +1 -0
  161. package/dist/plugins/static-build.d.ts +55 -0
  162. package/dist/plugins/static-build.d.ts.map +1 -0
  163. package/dist/routing/codegen.d.ts +29 -0
  164. package/dist/routing/codegen.d.ts.map +1 -0
  165. package/dist/routing/index.d.ts +8 -0
  166. package/dist/routing/index.d.ts.map +1 -0
  167. package/dist/routing/index.js +2 -0
  168. package/dist/routing/interception.d.ts +46 -0
  169. package/dist/routing/interception.d.ts.map +1 -0
  170. package/dist/routing/scanner.d.ts +28 -0
  171. package/dist/routing/scanner.d.ts.map +1 -0
  172. package/dist/routing/status-file-lint.d.ts +33 -0
  173. package/dist/routing/status-file-lint.d.ts.map +1 -0
  174. package/dist/routing/types.d.ts +81 -0
  175. package/dist/routing/types.d.ts.map +1 -0
  176. package/dist/search-params/analyze.d.ts +54 -0
  177. package/dist/search-params/analyze.d.ts.map +1 -0
  178. package/dist/search-params/codecs.d.ts +53 -0
  179. package/dist/search-params/codecs.d.ts.map +1 -0
  180. package/dist/search-params/create.d.ts +106 -0
  181. package/dist/search-params/create.d.ts.map +1 -0
  182. package/dist/search-params/index.d.ts +7 -0
  183. package/dist/search-params/index.d.ts.map +1 -0
  184. package/dist/search-params/index.js +300 -0
  185. package/dist/search-params/index.js.map +1 -0
  186. package/dist/search-params/registry.d.ts +20 -0
  187. package/dist/search-params/registry.d.ts.map +1 -0
  188. package/dist/server/access-gate.d.ts +42 -0
  189. package/dist/server/access-gate.d.ts.map +1 -0
  190. package/dist/server/action-client.d.ts +190 -0
  191. package/dist/server/action-client.d.ts.map +1 -0
  192. package/dist/server/action-handler.d.ts +48 -0
  193. package/dist/server/action-handler.d.ts.map +1 -0
  194. package/dist/server/actions.d.ts +108 -0
  195. package/dist/server/actions.d.ts.map +1 -0
  196. package/dist/server/asset-headers.d.ts +42 -0
  197. package/dist/server/asset-headers.d.ts.map +1 -0
  198. package/dist/server/body-limits.d.ts +30 -0
  199. package/dist/server/body-limits.d.ts.map +1 -0
  200. package/dist/server/build-manifest.d.ts +120 -0
  201. package/dist/server/build-manifest.d.ts.map +1 -0
  202. package/dist/server/canonicalize.d.ts +30 -0
  203. package/dist/server/canonicalize.d.ts.map +1 -0
  204. package/dist/server/client-module-map.d.ts +47 -0
  205. package/dist/server/client-module-map.d.ts.map +1 -0
  206. package/dist/server/csrf.d.ts +34 -0
  207. package/dist/server/csrf.d.ts.map +1 -0
  208. package/dist/server/deny-renderer.d.ts +49 -0
  209. package/dist/server/deny-renderer.d.ts.map +1 -0
  210. package/dist/server/dev-logger.d.ts +44 -0
  211. package/dist/server/dev-logger.d.ts.map +1 -0
  212. package/dist/server/dev-span-processor.d.ts +29 -0
  213. package/dist/server/dev-span-processor.d.ts.map +1 -0
  214. package/dist/server/dev-warnings.d.ts +129 -0
  215. package/dist/server/dev-warnings.d.ts.map +1 -0
  216. package/dist/server/early-hints-sender.d.ts +38 -0
  217. package/dist/server/early-hints-sender.d.ts.map +1 -0
  218. package/dist/server/early-hints.d.ts +83 -0
  219. package/dist/server/early-hints.d.ts.map +1 -0
  220. package/dist/server/error-boundary-wrapper.d.ts +17 -0
  221. package/dist/server/error-boundary-wrapper.d.ts.map +1 -0
  222. package/dist/server/error-formatter.d.ts +17 -0
  223. package/dist/server/error-formatter.d.ts.map +1 -0
  224. package/dist/server/flush.d.ts +74 -0
  225. package/dist/server/flush.d.ts.map +1 -0
  226. package/dist/server/form-data.d.ts +60 -0
  227. package/dist/server/form-data.d.ts.map +1 -0
  228. package/dist/server/form-flash.d.ts +78 -0
  229. package/dist/server/form-flash.d.ts.map +1 -0
  230. package/dist/server/html-injectors.d.ts +101 -0
  231. package/dist/server/html-injectors.d.ts.map +1 -0
  232. package/dist/server/index.d.ts +54 -0
  233. package/dist/server/index.d.ts.map +1 -0
  234. package/dist/server/index.js +2925 -0
  235. package/dist/server/index.js.map +1 -0
  236. package/dist/server/instrumentation.d.ts +61 -0
  237. package/dist/server/instrumentation.d.ts.map +1 -0
  238. package/dist/server/logger.d.ts +83 -0
  239. package/dist/server/logger.d.ts.map +1 -0
  240. package/dist/server/manifest-status-resolver.d.ts +58 -0
  241. package/dist/server/manifest-status-resolver.d.ts.map +1 -0
  242. package/dist/server/metadata-render.d.ts +20 -0
  243. package/dist/server/metadata-render.d.ts.map +1 -0
  244. package/dist/server/metadata-routes.d.ts +67 -0
  245. package/dist/server/metadata-routes.d.ts.map +1 -0
  246. package/dist/server/metadata.d.ts +67 -0
  247. package/dist/server/metadata.d.ts.map +1 -0
  248. package/dist/server/middleware-runner.d.ts +21 -0
  249. package/dist/server/middleware-runner.d.ts.map +1 -0
  250. package/dist/server/nuqs-ssr-provider.d.ts +28 -0
  251. package/dist/server/nuqs-ssr-provider.d.ts.map +1 -0
  252. package/dist/server/pipeline.d.ts +81 -0
  253. package/dist/server/pipeline.d.ts.map +1 -0
  254. package/dist/server/prerender.d.ts +77 -0
  255. package/dist/server/prerender.d.ts.map +1 -0
  256. package/dist/server/primitives.d.ts +131 -0
  257. package/dist/server/primitives.d.ts.map +1 -0
  258. package/dist/server/proxy.d.ts +23 -0
  259. package/dist/server/proxy.d.ts.map +1 -0
  260. package/dist/server/request-context.d.ts +175 -0
  261. package/dist/server/request-context.d.ts.map +1 -0
  262. package/dist/server/route-element-builder.d.ts +66 -0
  263. package/dist/server/route-element-builder.d.ts.map +1 -0
  264. package/dist/server/route-handler.d.ts +35 -0
  265. package/dist/server/route-handler.d.ts.map +1 -0
  266. package/dist/server/route-matcher.d.ts +78 -0
  267. package/dist/server/route-matcher.d.ts.map +1 -0
  268. package/dist/server/rsc-entry/api-handler.d.ts +11 -0
  269. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -0
  270. package/dist/server/rsc-entry/error-renderer.d.ts +30 -0
  271. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -0
  272. package/dist/server/rsc-entry/helpers.d.ts +73 -0
  273. package/dist/server/rsc-entry/helpers.d.ts.map +1 -0
  274. package/dist/server/rsc-entry/index.d.ts +11 -0
  275. package/dist/server/rsc-entry/index.d.ts.map +1 -0
  276. package/dist/server/rsc-entry/ssr-bridge.d.ts +6 -0
  277. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -0
  278. package/dist/server/slot-resolver.d.ts +34 -0
  279. package/dist/server/slot-resolver.d.ts.map +1 -0
  280. package/dist/server/ssr-entry.d.ts +73 -0
  281. package/dist/server/ssr-entry.d.ts.map +1 -0
  282. package/dist/server/ssr-render.d.ts +67 -0
  283. package/dist/server/ssr-render.d.ts.map +1 -0
  284. package/dist/server/status-code-resolver.d.ts +77 -0
  285. package/dist/server/status-code-resolver.d.ts.map +1 -0
  286. package/dist/server/tracing.d.ts +99 -0
  287. package/dist/server/tracing.d.ts.map +1 -0
  288. package/dist/server/tree-builder.d.ts +116 -0
  289. package/dist/server/tree-builder.d.ts.map +1 -0
  290. package/dist/server/types.d.ts +231 -0
  291. package/dist/server/types.d.ts.map +1 -0
  292. package/dist/shims/font-google.d.ts +41 -0
  293. package/dist/shims/font-google.d.ts.map +1 -0
  294. package/dist/shims/headers.d.ts +11 -0
  295. package/dist/shims/headers.d.ts.map +1 -0
  296. package/dist/shims/image.d.ts +328 -0
  297. package/dist/shims/image.d.ts.map +1 -0
  298. package/dist/shims/link.d.ts +9 -0
  299. package/dist/shims/link.d.ts.map +1 -0
  300. package/dist/shims/navigation-client.d.ts +25 -0
  301. package/dist/shims/navigation-client.d.ts.map +1 -0
  302. package/dist/shims/navigation.d.ts +25 -0
  303. package/dist/shims/navigation.d.ts.map +1 -0
  304. package/dist/utils/directive-parser.d.ts +70 -0
  305. package/dist/utils/directive-parser.d.ts.map +1 -0
  306. package/dist/utils/format.d.ts +6 -0
  307. package/dist/utils/format.d.ts.map +1 -0
  308. package/dist/utils/startup-timer.d.ts +34 -0
  309. package/dist/utils/startup-timer.d.ts.map +1 -0
  310. package/package.json +140 -0
package/bin/timber.mjs ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // Thin CLI wrapper — delegates to the compiled CLI entry.
3
+ // This file is the bin entry point and never moves, regardless of build output changes.
4
+ // See design/28-npm-packaging.md §"CLI Binary".
5
+ import '../dist/cli.js';
@@ -0,0 +1,121 @@
1
+ import { Component, createElement } from "react";
2
+ //#region src/client/error-boundary.tsx
3
+ /**
4
+ * Framework-injected React error boundary.
5
+ *
6
+ * Catches errors thrown by children and renders a fallback component
7
+ * with the appropriate props based on error type:
8
+ * - DenySignal (4xx) → { status, dangerouslyPassData }
9
+ * - RenderError (5xx) → { error, digest, reset }
10
+ * - Unhandled error → { error, digest: null, reset }
11
+ *
12
+ * The `status` prop controls which errors this boundary catches:
13
+ * - Specific code (e.g. 403) → only that status
14
+ * - Category (400) → any 4xx
15
+ * - Category (500) → any 5xx
16
+ * - Omitted → catches everything (error.tsx behavior)
17
+ *
18
+ * See design/10-error-handling.md §"Status-Code Files"
19
+ */
20
+ var _isUnloading = false;
21
+ if (typeof window !== "undefined") {
22
+ window.addEventListener("beforeunload", () => {
23
+ _isUnloading = true;
24
+ });
25
+ window.addEventListener("pagehide", () => {
26
+ _isUnloading = true;
27
+ });
28
+ }
29
+ var TimberErrorBoundary = class extends Component {
30
+ constructor(props) {
31
+ super(props);
32
+ this.state = {
33
+ hasError: false,
34
+ error: null
35
+ };
36
+ }
37
+ static getDerivedStateFromError(error) {
38
+ if (_isUnloading) return {
39
+ hasError: false,
40
+ error: null
41
+ };
42
+ return {
43
+ hasError: true,
44
+ error
45
+ };
46
+ }
47
+ componentDidUpdate(prevProps) {
48
+ if (this.state.hasError && prevProps.children !== this.props.children) this.setState({
49
+ hasError: false,
50
+ error: null
51
+ });
52
+ }
53
+ /** Reset the error state so children re-render. */
54
+ reset = () => {
55
+ this.setState({
56
+ hasError: false,
57
+ error: null
58
+ });
59
+ };
60
+ render() {
61
+ if (!this.state.hasError || !this.state.error) return this.props.children;
62
+ const error = this.state.error;
63
+ const parsed = parseDigest(error);
64
+ if (parsed?.type === "redirect") throw error;
65
+ if (this.props.status != null) {
66
+ const errorStatus = getErrorStatus(parsed, error);
67
+ if (errorStatus == null || !statusMatches(this.props.status, errorStatus)) throw error;
68
+ }
69
+ if (parsed?.type === "deny") return createElement(this.props.fallbackComponent, {
70
+ status: parsed.status,
71
+ dangerouslyPassData: parsed.data
72
+ });
73
+ const digest = parsed?.type === "render-error" ? {
74
+ code: parsed.code,
75
+ data: parsed.data
76
+ } : null;
77
+ return createElement(this.props.fallbackComponent, {
78
+ error,
79
+ digest,
80
+ reset: this.reset
81
+ });
82
+ }
83
+ };
84
+ /**
85
+ * Parse the structured digest from the error.
86
+ * React sets `error.digest` from the string returned by RSC's onError.
87
+ */
88
+ function parseDigest(error) {
89
+ const raw = error.digest;
90
+ if (typeof raw !== "string") return null;
91
+ try {
92
+ const parsed = JSON.parse(raw);
93
+ if (parsed && typeof parsed === "object" && typeof parsed.type === "string") return parsed;
94
+ } catch {}
95
+ return null;
96
+ }
97
+ /**
98
+ * Extract the HTTP status code from a parsed digest or error message.
99
+ * Falls back to message pattern matching for errors without a digest.
100
+ */
101
+ function getErrorStatus(parsed, error) {
102
+ if (parsed?.type === "deny") return parsed.status;
103
+ if (parsed?.type === "render-error") return parsed.status;
104
+ if (parsed?.type === "redirect") return parsed.status;
105
+ const match = error.message.match(/^Access denied with status (\d+)$/);
106
+ if (match) return parseInt(match[1], 10);
107
+ return 500;
108
+ }
109
+ /**
110
+ * Check whether an error's status matches the boundary's status filter.
111
+ * Category markers (400, 500) match any status in that range.
112
+ */
113
+ function statusMatches(boundaryStatus, errorStatus) {
114
+ if (boundaryStatus === 400) return errorStatus >= 400 && errorStatus <= 499;
115
+ if (boundaryStatus === 500) return errorStatus >= 500 && errorStatus <= 599;
116
+ return boundaryStatus === errorStatus;
117
+ }
118
+ //#endregion
119
+ export { TimberErrorBoundary as t };
120
+
121
+ //# sourceMappingURL=error-boundary-dj-WO5uq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-boundary-dj-WO5uq.js","names":[],"sources":["../../src/client/error-boundary.tsx"],"sourcesContent":["'use client';\n\n/**\n * Framework-injected React error boundary.\n *\n * Catches errors thrown by children and renders a fallback component\n * with the appropriate props based on error type:\n * - DenySignal (4xx) → { status, dangerouslyPassData }\n * - RenderError (5xx) → { error, digest, reset }\n * - Unhandled error → { error, digest: null, reset }\n *\n * The `status` prop controls which errors this boundary catches:\n * - Specific code (e.g. 403) → only that status\n * - Category (400) → any 4xx\n * - Category (500) → any 5xx\n * - Omitted → catches everything (error.tsx behavior)\n *\n * See design/10-error-handling.md §\"Status-Code Files\"\n */\n\nimport { Component, createElement, type ReactNode } from 'react';\n\n// ─── Page Unload Detection ───────────────────────────────────────────────────\n// Track whether the page is being unloaded (user refreshed or navigated away).\n// When this is true, error boundaries suppress activation — the error is from\n// the aborted connection, not an application error.\nlet _isUnloading = false;\nif (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n _isUnloading = true;\n });\n window.addEventListener('pagehide', () => {\n _isUnloading = true;\n });\n}\n\n// ─── Digest Types ────────────────────────────────────────────────────────────\n\n/** Structured digest returned by RSC onError for DenySignal. */\ninterface DenyDigest {\n type: 'deny';\n status: number;\n data: unknown;\n}\n\n/** Structured digest returned by RSC onError for RenderError. */\ninterface RenderErrorDigest {\n type: 'render-error';\n code: string;\n data: unknown;\n status: number;\n}\n\n/** Structured digest returned by RSC onError for RedirectSignal. */\ninterface RedirectDigest {\n type: 'redirect';\n location: string;\n status: number;\n}\n\ntype ParsedDigest = DenyDigest | RenderErrorDigest | RedirectDigest;\n\n// ─── Props & State ───────────────────────────────────────────────────────────\n\nexport interface TimberErrorBoundaryProps {\n /** The component to render when an error is caught. */\n fallbackComponent: (...args: unknown[]) => ReactNode;\n /**\n * Status code filter. If set, only catches errors matching this status.\n * 400 = any 4xx, 500 = any 5xx, specific number = exact match.\n */\n status?: number;\n children: ReactNode;\n}\n\ninterface TimberErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport class TimberErrorBoundary extends Component<\n TimberErrorBoundaryProps,\n TimberErrorBoundaryState\n> {\n constructor(props: TimberErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): TimberErrorBoundaryState {\n // Suppress error boundaries during page unload (refresh/navigate away).\n // The aborted connection causes React's streaming hydration to error,\n // but the page is about to be replaced — showing an error boundary\n // would be a jarring flash for the user.\n if (_isUnloading) {\n return { hasError: false, error: null };\n }\n return { hasError: true, error };\n }\n\n componentDidUpdate(prevProps: TimberErrorBoundaryProps): void {\n // Reset error state when children change (e.g. client-side navigation).\n // Without this, navigating from one error page to another keeps the\n // stale error — getDerivedStateFromError doesn't re-fire for new children.\n if (this.state.hasError && prevProps.children !== this.props.children) {\n this.setState({ hasError: false, error: null });\n }\n }\n\n /** Reset the error state so children re-render. */\n private reset = () => {\n this.setState({ hasError: false, error: null });\n };\n\n render(): ReactNode {\n if (!this.state.hasError || !this.state.error) {\n return this.props.children;\n }\n\n const error = this.state.error;\n const parsed = parseDigest(error);\n\n // RedirectSignal errors must propagate through all error boundaries\n // so the SSR shell fails and the pipeline catch block can produce a\n // proper HTTP redirect response. See design/04-authorization.md.\n if (parsed?.type === 'redirect') {\n throw error;\n }\n\n // If this boundary has a status filter, check whether the error matches.\n // Non-matching errors re-throw so an outer boundary can catch them.\n if (this.props.status != null) {\n const errorStatus = getErrorStatus(parsed, error);\n if (errorStatus == null || !statusMatches(this.props.status, errorStatus)) {\n // Re-throw: this boundary doesn't handle this error.\n throw error;\n }\n }\n\n // Render the fallback component with the right props shape.\n if (parsed?.type === 'deny') {\n return createElement(this.props.fallbackComponent as never, {\n status: parsed.status,\n dangerouslyPassData: parsed.data,\n });\n }\n\n // 5xx / RenderError / unhandled error\n const digest =\n parsed?.type === 'render-error' ? { code: parsed.code, data: parsed.data } : null;\n\n return createElement(this.props.fallbackComponent as never, {\n error,\n digest,\n reset: this.reset,\n });\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Parse the structured digest from the error.\n * React sets `error.digest` from the string returned by RSC's onError.\n */\nfunction parseDigest(error: Error): ParsedDigest | null {\n const raw = (error as { digest?: string }).digest;\n if (typeof raw !== 'string') return null;\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && typeof parsed.type === 'string') {\n return parsed as ParsedDigest;\n }\n } catch {\n // Not JSON — legacy or unknown digest format\n }\n return null;\n}\n\n/**\n * Extract the HTTP status code from a parsed digest or error message.\n * Falls back to message pattern matching for errors without a digest.\n */\nfunction getErrorStatus(parsed: ParsedDigest | null, error: Error): number | null {\n if (parsed?.type === 'deny') return parsed.status;\n if (parsed?.type === 'render-error') return parsed.status;\n if (parsed?.type === 'redirect') return parsed.status;\n\n // Fallback: parse DenySignal message pattern for errors that lost their digest\n const match = error.message.match(/^Access denied with status (\\d+)$/);\n if (match) return parseInt(match[1], 10);\n\n // Unhandled errors are implicitly 500\n return 500;\n}\n\n/**\n * Check whether an error's status matches the boundary's status filter.\n * Category markers (400, 500) match any status in that range.\n */\nfunction statusMatches(boundaryStatus: number, errorStatus: number): boolean {\n // Category catch-all: 400 matches any 4xx, 500 matches any 5xx\n if (boundaryStatus === 400) return errorStatus >= 400 && errorStatus <= 499;\n if (boundaryStatus === 500) return errorStatus >= 500 && errorStatus <= 599;\n // Exact match\n return boundaryStatus === errorStatus;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA0BA,IAAI,eAAe;AACnB,IAAI,OAAO,WAAW,aAAa;AACjC,QAAO,iBAAiB,sBAAsB;AAC5C,iBAAe;GACf;AACF,QAAO,iBAAiB,kBAAkB;AACxC,iBAAe;GACf;;AAiDJ,IAAa,sBAAb,cAAyC,UAGvC;CACA,YAAY,OAAiC;AAC3C,QAAM,MAAM;AACZ,OAAK,QAAQ;GAAE,UAAU;GAAO,OAAO;GAAM;;CAG/C,OAAO,yBAAyB,OAAwC;AAKtE,MAAI,aACF,QAAO;GAAE,UAAU;GAAO,OAAO;GAAM;AAEzC,SAAO;GAAE,UAAU;GAAM;GAAO;;CAGlC,mBAAmB,WAA2C;AAI5D,MAAI,KAAK,MAAM,YAAY,UAAU,aAAa,KAAK,MAAM,SAC3D,MAAK,SAAS;GAAE,UAAU;GAAO,OAAO;GAAM,CAAC;;;CAKnD,cAAsB;AACpB,OAAK,SAAS;GAAE,UAAU;GAAO,OAAO;GAAM,CAAC;;CAGjD,SAAoB;AAClB,MAAI,CAAC,KAAK,MAAM,YAAY,CAAC,KAAK,MAAM,MACtC,QAAO,KAAK,MAAM;EAGpB,MAAM,QAAQ,KAAK,MAAM;EACzB,MAAM,SAAS,YAAY,MAAM;AAKjC,MAAI,QAAQ,SAAS,WACnB,OAAM;AAKR,MAAI,KAAK,MAAM,UAAU,MAAM;GAC7B,MAAM,cAAc,eAAe,QAAQ,MAAM;AACjD,OAAI,eAAe,QAAQ,CAAC,cAAc,KAAK,MAAM,QAAQ,YAAY,CAEvE,OAAM;;AAKV,MAAI,QAAQ,SAAS,OACnB,QAAO,cAAc,KAAK,MAAM,mBAA4B;GAC1D,QAAQ,OAAO;GACf,qBAAqB,OAAO;GAC7B,CAAC;EAIJ,MAAM,SACJ,QAAQ,SAAS,iBAAiB;GAAE,MAAM,OAAO;GAAM,MAAM,OAAO;GAAM,GAAG;AAE/E,SAAO,cAAc,KAAK,MAAM,mBAA4B;GAC1D;GACA;GACA,OAAO,KAAK;GACb,CAAC;;;;;;;AAUN,SAAS,YAAY,OAAmC;CACtD,MAAM,MAAO,MAA8B;AAC3C,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,UAAU,OAAO,WAAW,YAAY,OAAO,OAAO,SAAS,SACjE,QAAO;SAEH;AAGR,QAAO;;;;;;AAOT,SAAS,eAAe,QAA6B,OAA6B;AAChF,KAAI,QAAQ,SAAS,OAAQ,QAAO,OAAO;AAC3C,KAAI,QAAQ,SAAS,eAAgB,QAAO,OAAO;AACnD,KAAI,QAAQ,SAAS,WAAY,QAAO,OAAO;CAG/C,MAAM,QAAQ,MAAM,QAAQ,MAAM,oCAAoC;AACtE,KAAI,MAAO,QAAO,SAAS,MAAM,IAAI,GAAG;AAGxC,QAAO;;;;;;AAOT,SAAS,cAAc,gBAAwB,aAA8B;AAE3E,KAAI,mBAAmB,IAAK,QAAO,eAAe,OAAO,eAAe;AACxE,KAAI,mBAAmB,IAAK,QAAO,eAAe,OAAO,eAAe;AAExE,QAAO,mBAAmB"}
@@ -0,0 +1,163 @@
1
+ //#region src/server/dev-warnings.ts
2
+ var WarningId = {
3
+ SUSPENSE_WRAPS_CHILDREN: "SUSPENSE_WRAPS_CHILDREN",
4
+ DENY_IN_SUSPENSE: "DENY_IN_SUSPENSE",
5
+ REDIRECT_IN_SUSPENSE: "REDIRECT_IN_SUSPENSE",
6
+ REDIRECT_IN_ACCESS: "REDIRECT_IN_ACCESS",
7
+ STATIC_REQUEST_API: "STATIC_REQUEST_API",
8
+ CACHE_REQUEST_PROPS: "CACHE_REQUEST_PROPS",
9
+ SLOW_SLOT_NO_SUSPENSE: "SLOW_SLOT_NO_SUSPENSE"
10
+ };
11
+ var _emitted = /* @__PURE__ */ new Set();
12
+ /** Vite dev server for forwarding warnings to browser console. */
13
+ var _viteServer = null;
14
+ /**
15
+ * Register the Vite dev server for browser console forwarding.
16
+ * Called by timber-dev-server during configureServer.
17
+ */
18
+ function setViteServer(server) {
19
+ _viteServer = server;
20
+ }
21
+ function isDev() {
22
+ return process.env.NODE_ENV !== "production";
23
+ }
24
+ /**
25
+ * Emit a warning only once per dedup key.
26
+ *
27
+ * Writes to stderr and forwards to browser console via Vite WebSocket.
28
+ * Returns true if emitted (not deduplicated).
29
+ */
30
+ function emitOnce(warningId, location, level, message) {
31
+ if (!isDev()) return false;
32
+ const dedupKey = `${warningId}:${location}`;
33
+ if (_emitted.has(dedupKey)) return false;
34
+ _emitted.add(dedupKey);
35
+ const prefix = level === "error" ? "\x1B[31m[timber]\x1B[0m" : "\x1B[33m[timber]\x1B[0m";
36
+ process.stderr.write(`${prefix} ${message}\n`);
37
+ if (_viteServer?.hot) _viteServer.hot.send("timber:dev-warning", {
38
+ warningId,
39
+ level,
40
+ message: `[timber] ${message}`
41
+ });
42
+ return true;
43
+ }
44
+ /**
45
+ * Warn when a layout wraps {children} in <Suspense>.
46
+ *
47
+ * This defers the page content — the primary resource — behind a fallback.
48
+ * The page's data fetches won't affect the HTTP status code because they
49
+ * resolve after onShellReady. If the page calls deny(404), the status code
50
+ * is already committed as 200.
51
+ *
52
+ * @param layoutFile - Relative path to the layout file (e.g., "app/(dashboard)/layout.tsx")
53
+ */
54
+ function warnSuspenseWrappingChildren(layoutFile) {
55
+ emitOnce(WarningId.SUSPENSE_WRAPS_CHILDREN, layoutFile, "warn", `Layout at ${layoutFile} wraps {children} in <Suspense>. This prevents child pages from setting HTTP status codes. Use useNavigationPending() for loading states instead.`);
56
+ }
57
+ /**
58
+ * Warn when deny() is called inside a Suspense boundary.
59
+ *
60
+ * After the shell has flushed and the status code is committed, deny()
61
+ * cannot change the HTTP response. The signal will be caught by the nearest
62
+ * error boundary instead of producing a correct status code.
63
+ *
64
+ * @param file - Relative path to the file
65
+ * @param line - Line number where deny() was called
66
+ */
67
+ function warnDenyInSuspense(file, line) {
68
+ const location = line ? `${file}:${line}` : file;
69
+ emitOnce(WarningId.DENY_IN_SUSPENSE, location, "error", `deny() called inside <Suspense> at ${location}. The HTTP status is already committed — this will trigger an error boundary with a 200 status. Move deny() outside <Suspense> for correct HTTP semantics.`);
70
+ }
71
+ /**
72
+ * Warn when redirect() is called inside a Suspense boundary.
73
+ *
74
+ * This will perform a client-side navigation instead of an HTTP redirect.
75
+ *
76
+ * @param file - Relative path to the file
77
+ * @param line - Line number where redirect() was called
78
+ */
79
+ function warnRedirectInSuspense(file, line) {
80
+ const location = line ? `${file}:${line}` : file;
81
+ emitOnce(WarningId.REDIRECT_IN_SUSPENSE, location, "error", `redirect() called inside <Suspense> at ${location}. This will perform a client-side navigation instead of an HTTP redirect.`);
82
+ }
83
+ /**
84
+ * Warn when redirect() is called in a slot's access.ts.
85
+ *
86
+ * Slots use deny() for graceful degradation. Redirecting from a slot would
87
+ * redirect the entire page, breaking the contract that slot failure is
88
+ * isolated to the slot.
89
+ *
90
+ * @param accessFile - Relative path to the access.ts file
91
+ * @param line - Line number where redirect() was called
92
+ */
93
+ function warnRedirectInAccess(accessFile, line) {
94
+ const location = line ? `${accessFile}:${line}` : accessFile;
95
+ emitOnce(WarningId.REDIRECT_IN_ACCESS, location, "error", `redirect() called in access.ts at ${location}. Only deny() is valid in slot access checks. Use deny() to block access or move redirect() to middleware.ts.`);
96
+ }
97
+ /**
98
+ * Warn when cookies() or headers() is called during a static build.
99
+ *
100
+ * In output: 'static' mode, there is no per-request context — these APIs
101
+ * read build-time values only. This is almost always a mistake.
102
+ *
103
+ * @param api - The dynamic API name ("cookies" or "headers")
104
+ * @param file - Relative path to the file calling the API
105
+ */
106
+ function warnStaticRequestApi(api, file) {
107
+ emitOnce(WarningId.STATIC_REQUEST_API, `${api}:${file}`, "error", `${api}() called during static generation of ${file}. Dynamic request APIs are not available during prerendering.`);
108
+ }
109
+ /**
110
+ * Warn when a "use cache" component receives request-specific props.
111
+ *
112
+ * Cached components should not depend on per-request data — a userId or
113
+ * sessionId in the props means the cache will either be ineffective
114
+ * (key per user) or dangerous (serve one user's data to another).
115
+ *
116
+ * @param componentName - Name of the cached component
117
+ * @param propName - Name of the suspicious prop
118
+ * @param file - Relative path to the component file
119
+ * @param line - Line number
120
+ */
121
+ function warnCacheRequestProps(componentName, propName, file, line) {
122
+ const location = line ? `${file}:${line}` : file;
123
+ emitOnce(WarningId.CACHE_REQUEST_PROPS, `${componentName}:${propName}:${location}`, "warn", `Cached component ${componentName} receives prop "${propName}" which appears request-specific. Cached components should not depend on per-request data.`);
124
+ }
125
+ /**
126
+ * Warn when a parallel slot resolves slowly without a <Suspense> wrapper.
127
+ *
128
+ * A slow slot without Suspense blocks onShellReady — and therefore the
129
+ * status code commit — for the entire page. Wrapping it in <Suspense>
130
+ * lets the shell flush without waiting for the slot.
131
+ *
132
+ * @param slotName - The slot name (e.g., "@admin")
133
+ * @param durationMs - How long the slot took to resolve
134
+ */
135
+ function warnSlowSlotWithoutSuspense(slotName, durationMs) {
136
+ emitOnce(WarningId.SLOW_SLOT_NO_SUSPENSE, slotName, "warn", `Slot ${slotName} resolved in ${durationMs}ms and is not wrapped in <Suspense>. Consider wrapping to avoid blocking the flush.`);
137
+ }
138
+ /** @deprecated Use warnStaticRequestApi instead */
139
+ var warnDynamicApiInStaticBuild = warnStaticRequestApi;
140
+ /** @deprecated Use warnRedirectInAccess instead */
141
+ function warnRedirectInSlotAccess(slotName) {
142
+ warnRedirectInAccess(`${slotName}/access.ts`);
143
+ }
144
+ /** @deprecated Use warnDenyInSuspense / warnRedirectInSuspense instead */
145
+ function warnDenyAfterFlush(signal) {
146
+ if (signal === "deny") warnDenyInSuspense("unknown");
147
+ else warnRedirectInSuspense("unknown");
148
+ }
149
+ //#endregion
150
+ //#region src/utils/format.ts
151
+ /**
152
+ * Shared formatting utilities.
153
+ */
154
+ /** Format a byte count as a human-readable string (e.g. "1.50 kB"). */
155
+ function formatSize(bytes) {
156
+ if (bytes < 1024) return `${bytes} B`;
157
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;
158
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
159
+ }
160
+ //#endregion
161
+ export { warnDenyAfterFlush as a, warnRedirectInAccess as c, warnSlowSlotWithoutSuspense as d, warnStaticRequestApi as f, warnCacheRequestProps as i, warnRedirectInSlotAccess as l, WarningId as n, warnDenyInSuspense as o, warnSuspenseWrappingChildren as p, setViteServer as r, warnDynamicApiInStaticBuild as s, formatSize as t, warnRedirectInSuspense as u };
162
+
163
+ //# sourceMappingURL=format-DNt20Kt8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-DNt20Kt8.js","names":[],"sources":["../../src/server/dev-warnings.ts","../../src/utils/format.ts"],"sourcesContent":["/**\n * Dev-mode warnings for common timber.js misuse patterns.\n *\n * These fire in development only and are stripped from production builds.\n * Each warning targets a specific misuse identified during design review.\n *\n * Warnings are deduplicated by warningId:filePath:line so the same warning\n * is only emitted once per dev session (per unique source location).\n *\n * Warnings are written to stderr and, when a Vite dev server is available,\n * forwarded to the browser console via Vite's WebSocket.\n *\n * See design/21-dev-server.md §\"Dev-Mode Warnings\"\n * See design/11-platform.md §\"Dev Mode\"\n */\n\nimport type { ViteDevServer } from 'vite';\n\n// ─── Warning IDs ───────────────────────────────────────────────────────────\n\nexport const WarningId = {\n SUSPENSE_WRAPS_CHILDREN: 'SUSPENSE_WRAPS_CHILDREN',\n DENY_IN_SUSPENSE: 'DENY_IN_SUSPENSE',\n REDIRECT_IN_SUSPENSE: 'REDIRECT_IN_SUSPENSE',\n REDIRECT_IN_ACCESS: 'REDIRECT_IN_ACCESS',\n STATIC_REQUEST_API: 'STATIC_REQUEST_API',\n CACHE_REQUEST_PROPS: 'CACHE_REQUEST_PROPS',\n SLOW_SLOT_NO_SUSPENSE: 'SLOW_SLOT_NO_SUSPENSE',\n} as const;\n\nexport type WarningId = (typeof WarningId)[keyof typeof WarningId];\n\n// ─── Configuration ──────────────────────────────────────────────────────────\n\n/** Configuration for dev warning behavior. */\nexport interface DevWarningConfig {\n /** Threshold in ms for \"slow slot\" warnings. Default: 200. */\n slowSlotThresholdMs?: number;\n}\n\n// ─── Deduplication & Server ─────────────────────────────────────────────────\n\nconst _emitted = new Set<string>();\n\n/** Vite dev server for forwarding warnings to browser console. */\nlet _viteServer: ViteDevServer | null = null;\n\n/**\n * Register the Vite dev server for browser console forwarding.\n * Called by timber-dev-server during configureServer.\n */\nexport function setViteServer(server: ViteDevServer | null): void {\n _viteServer = server;\n}\n\nfunction isDev(): boolean {\n return process.env.NODE_ENV !== 'production';\n}\n\n/**\n * Emit a warning only once per dedup key.\n *\n * Writes to stderr and forwards to browser console via Vite WebSocket.\n * Returns true if emitted (not deduplicated).\n */\nfunction emitOnce(\n warningId: WarningId,\n location: string,\n level: 'warn' | 'error',\n message: string\n): boolean {\n if (!isDev()) return false;\n\n const dedupKey = `${warningId}:${location}`;\n if (_emitted.has(dedupKey)) return false;\n _emitted.add(dedupKey);\n\n // Write to stderr\n const prefix = level === 'error' ? '\\x1b[31m[timber]\\x1b[0m' : '\\x1b[33m[timber]\\x1b[0m';\n process.stderr.write(`${prefix} ${message}\\n`);\n\n // Forward to browser console via Vite WebSocket\n if (_viteServer?.hot) {\n _viteServer.hot.send('timber:dev-warning', {\n warningId,\n level,\n message: `[timber] ${message}`,\n });\n }\n\n return true;\n}\n\n// ─── Warning Functions ──────────────────────────────────────────────────────\n\n/**\n * Warn when a layout wraps {children} in <Suspense>.\n *\n * This defers the page content — the primary resource — behind a fallback.\n * The page's data fetches won't affect the HTTP status code because they\n * resolve after onShellReady. If the page calls deny(404), the status code\n * is already committed as 200.\n *\n * @param layoutFile - Relative path to the layout file (e.g., \"app/(dashboard)/layout.tsx\")\n */\nexport function warnSuspenseWrappingChildren(layoutFile: string): void {\n emitOnce(\n WarningId.SUSPENSE_WRAPS_CHILDREN,\n layoutFile,\n 'warn',\n `Layout at ${layoutFile} wraps {children} in <Suspense>. ` +\n 'This prevents child pages from setting HTTP status codes. ' +\n 'Use useNavigationPending() for loading states instead.'\n );\n}\n\n/**\n * Warn when deny() is called inside a Suspense boundary.\n *\n * After the shell has flushed and the status code is committed, deny()\n * cannot change the HTTP response. The signal will be caught by the nearest\n * error boundary instead of producing a correct status code.\n *\n * @param file - Relative path to the file\n * @param line - Line number where deny() was called\n */\nexport function warnDenyInSuspense(file: string, line?: number): void {\n const location = line ? `${file}:${line}` : file;\n emitOnce(\n WarningId.DENY_IN_SUSPENSE,\n location,\n 'error',\n `deny() called inside <Suspense> at ${location}. ` +\n 'The HTTP status is already committed — this will trigger an error boundary with a 200 status. ' +\n 'Move deny() outside <Suspense> for correct HTTP semantics.'\n );\n}\n\n/**\n * Warn when redirect() is called inside a Suspense boundary.\n *\n * This will perform a client-side navigation instead of an HTTP redirect.\n *\n * @param file - Relative path to the file\n * @param line - Line number where redirect() was called\n */\nexport function warnRedirectInSuspense(file: string, line?: number): void {\n const location = line ? `${file}:${line}` : file;\n emitOnce(\n WarningId.REDIRECT_IN_SUSPENSE,\n location,\n 'error',\n `redirect() called inside <Suspense> at ${location}. ` +\n 'This will perform a client-side navigation instead of an HTTP redirect.'\n );\n}\n\n/**\n * Warn when redirect() is called in a slot's access.ts.\n *\n * Slots use deny() for graceful degradation. Redirecting from a slot would\n * redirect the entire page, breaking the contract that slot failure is\n * isolated to the slot.\n *\n * @param accessFile - Relative path to the access.ts file\n * @param line - Line number where redirect() was called\n */\nexport function warnRedirectInAccess(accessFile: string, line?: number): void {\n const location = line ? `${accessFile}:${line}` : accessFile;\n emitOnce(\n WarningId.REDIRECT_IN_ACCESS,\n location,\n 'error',\n `redirect() called in access.ts at ${location}. ` +\n 'Only deny() is valid in slot access checks. ' +\n 'Use deny() to block access or move redirect() to middleware.ts.'\n );\n}\n\n/**\n * Warn when cookies() or headers() is called during a static build.\n *\n * In output: 'static' mode, there is no per-request context — these APIs\n * read build-time values only. This is almost always a mistake.\n *\n * @param api - The dynamic API name (\"cookies\" or \"headers\")\n * @param file - Relative path to the file calling the API\n */\nexport function warnStaticRequestApi(api: 'cookies' | 'headers', file: string): void {\n emitOnce(\n WarningId.STATIC_REQUEST_API,\n `${api}:${file}`,\n 'error',\n `${api}() called during static generation of ${file}. ` +\n 'Dynamic request APIs are not available during prerendering.'\n );\n}\n\n/**\n * Warn when a \"use cache\" component receives request-specific props.\n *\n * Cached components should not depend on per-request data — a userId or\n * sessionId in the props means the cache will either be ineffective\n * (key per user) or dangerous (serve one user's data to another).\n *\n * @param componentName - Name of the cached component\n * @param propName - Name of the suspicious prop\n * @param file - Relative path to the component file\n * @param line - Line number\n */\nexport function warnCacheRequestProps(\n componentName: string,\n propName: string,\n file: string,\n line?: number\n): void {\n const location = line ? `${file}:${line}` : file;\n emitOnce(\n WarningId.CACHE_REQUEST_PROPS,\n `${componentName}:${propName}:${location}`,\n 'warn',\n `Cached component ${componentName} receives prop \"${propName}\" which appears request-specific. ` +\n 'Cached components should not depend on per-request data.'\n );\n}\n\n/**\n * Warn when a parallel slot resolves slowly without a <Suspense> wrapper.\n *\n * A slow slot without Suspense blocks onShellReady — and therefore the\n * status code commit — for the entire page. Wrapping it in <Suspense>\n * lets the shell flush without waiting for the slot.\n *\n * @param slotName - The slot name (e.g., \"@admin\")\n * @param durationMs - How long the slot took to resolve\n */\nexport function warnSlowSlotWithoutSuspense(slotName: string, durationMs: number): void {\n emitOnce(\n WarningId.SLOW_SLOT_NO_SUSPENSE,\n slotName,\n 'warn',\n `Slot ${slotName} resolved in ${durationMs}ms and is not wrapped in <Suspense>. ` +\n 'Consider wrapping to avoid blocking the flush.'\n );\n}\n\n// ─── Legacy aliases ─────────────────────────────────────────────────────────\n\n/** @deprecated Use warnStaticRequestApi instead */\nexport const warnDynamicApiInStaticBuild = warnStaticRequestApi;\n\n/** @deprecated Use warnRedirectInAccess instead */\nexport function warnRedirectInSlotAccess(slotName: string): void {\n warnRedirectInAccess(`${slotName}/access.ts`);\n}\n\n/** @deprecated Use warnDenyInSuspense / warnRedirectInSuspense instead */\nexport function warnDenyAfterFlush(signal: 'deny' | 'redirect'): void {\n if (signal === 'deny') {\n warnDenyInSuspense('unknown');\n } else {\n warnRedirectInSuspense('unknown');\n }\n}\n\n// ─── Testing ────────────────────────────────────────────────────────────────\n\n/**\n * Reset emitted warnings. For testing only.\n * @internal\n */\nexport function _resetWarnings(): void {\n _emitted.clear();\n}\n\n/**\n * Get the set of emitted dedup keys. For testing only.\n * @internal\n */\nexport function _getEmitted(): ReadonlySet<string> {\n return _emitted;\n}\n","/**\n * Shared formatting utilities.\n */\n\n/** Format a byte count as a human-readable string (e.g. \"1.50 kB\"). */\nexport function formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;\n return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n}\n"],"mappings":";AAoBA,IAAa,YAAY;CACvB,yBAAyB;CACzB,kBAAkB;CAClB,sBAAsB;CACtB,oBAAoB;CACpB,oBAAoB;CACpB,qBAAqB;CACrB,uBAAuB;CACxB;AAcD,IAAM,2BAAW,IAAI,KAAa;;AAGlC,IAAI,cAAoC;;;;;AAMxC,SAAgB,cAAc,QAAoC;AAChE,eAAc;;AAGhB,SAAS,QAAiB;AACxB,QAAA,QAAA,IAAA,aAAgC;;;;;;;;AASlC,SAAS,SACP,WACA,UACA,OACA,SACS;AACT,KAAI,CAAC,OAAO,CAAE,QAAO;CAErB,MAAM,WAAW,GAAG,UAAU,GAAG;AACjC,KAAI,SAAS,IAAI,SAAS,CAAE,QAAO;AACnC,UAAS,IAAI,SAAS;CAGtB,MAAM,SAAS,UAAU,UAAU,4BAA4B;AAC/D,SAAQ,OAAO,MAAM,GAAG,OAAO,GAAG,QAAQ,IAAI;AAG9C,KAAI,aAAa,IACf,aAAY,IAAI,KAAK,sBAAsB;EACzC;EACA;EACA,SAAS,YAAY;EACtB,CAAC;AAGJ,QAAO;;;;;;;;;;;;AAeT,SAAgB,6BAA6B,YAA0B;AACrE,UACE,UAAU,yBACV,YACA,QACA,aAAa,WAAW,mJAGzB;;;;;;;;;;;;AAaH,SAAgB,mBAAmB,MAAc,MAAqB;CACpE,MAAM,WAAW,OAAO,GAAG,KAAK,GAAG,SAAS;AAC5C,UACE,UAAU,kBACV,UACA,SACA,sCAAsC,SAAS,4JAGhD;;;;;;;;;;AAWH,SAAgB,uBAAuB,MAAc,MAAqB;CACxE,MAAM,WAAW,OAAO,GAAG,KAAK,GAAG,SAAS;AAC5C,UACE,UAAU,sBACV,UACA,SACA,0CAA0C,SAAS,2EAEpD;;;;;;;;;;;;AAaH,SAAgB,qBAAqB,YAAoB,MAAqB;CAC5E,MAAM,WAAW,OAAO,GAAG,WAAW,GAAG,SAAS;AAClD,UACE,UAAU,oBACV,UACA,SACA,qCAAqC,SAAS,+GAG/C;;;;;;;;;;;AAYH,SAAgB,qBAAqB,KAA4B,MAAoB;AACnF,UACE,UAAU,oBACV,GAAG,IAAI,GAAG,QACV,SACA,GAAG,IAAI,wCAAwC,KAAK,+DAErD;;;;;;;;;;;;;;AAeH,SAAgB,sBACd,eACA,UACA,MACA,MACM;CACN,MAAM,WAAW,OAAO,GAAG,KAAK,GAAG,SAAS;AAC5C,UACE,UAAU,qBACV,GAAG,cAAc,GAAG,SAAS,GAAG,YAChC,QACA,oBAAoB,cAAc,kBAAkB,SAAS,4FAE9D;;;;;;;;;;;;AAaH,SAAgB,4BAA4B,UAAkB,YAA0B;AACtF,UACE,UAAU,uBACV,UACA,QACA,QAAQ,SAAS,eAAe,WAAW,qFAE5C;;;AAMH,IAAa,8BAA8B;;AAG3C,SAAgB,yBAAyB,UAAwB;AAC/D,sBAAqB,GAAG,SAAS,YAAY;;;AAI/C,SAAgB,mBAAmB,QAAmC;AACpE,KAAI,WAAW,OACb,oBAAmB,UAAU;KAE7B,wBAAuB,UAAU;;;;;;;;AChQrC,SAAgB,WAAW,OAAuB;AAChD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAC7D,QAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC"}