@nifrajs/web 3.5.0 → 4.0.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 (390) hide show
  1. package/dist/backend-only.d.ts +15 -0
  2. package/dist/backend-only.d.ts.map +1 -0
  3. package/dist/backend-only.js +16 -0
  4. package/dist/backend-only.js.map +1 -0
  5. package/dist/boundary.d.ts +5 -0
  6. package/dist/boundary.d.ts.map +1 -1
  7. package/dist/boundary.js +11 -2
  8. package/dist/boundary.js.map +1 -1
  9. package/dist/build-plan.d.ts +18 -6
  10. package/dist/build-plan.d.ts.map +1 -1
  11. package/dist/build-plan.js +82 -34
  12. package/dist/build-plan.js.map +1 -1
  13. package/dist/build-vite.d.ts +4 -0
  14. package/dist/build-vite.d.ts.map +1 -1
  15. package/dist/build-vite.js +68 -13
  16. package/dist/build-vite.js.map +1 -1
  17. package/dist/build.d.ts +57 -23
  18. package/dist/build.d.ts.map +1 -1
  19. package/dist/build.js +356 -85
  20. package/dist/build.js.map +1 -1
  21. package/dist/bun-dev-entry.d.ts +1 -1
  22. package/dist/bun-dev-entry.js +1 -1
  23. package/dist/cdn.d.ts +74 -0
  24. package/dist/cdn.d.ts.map +1 -0
  25. package/dist/cdn.js +132 -0
  26. package/dist/cdn.js.map +1 -0
  27. package/dist/client.d.ts +3 -1
  28. package/dist/client.d.ts.map +1 -1
  29. package/dist/client.js +111 -15
  30. package/dist/client.js.map +1 -1
  31. package/dist/conformance.d.ts +4 -3
  32. package/dist/conformance.d.ts.map +1 -1
  33. package/dist/conformance.js +12 -3
  34. package/dist/conformance.js.map +1 -1
  35. package/dist/csp.d.ts +93 -0
  36. package/dist/csp.d.ts.map +1 -0
  37. package/dist/csp.js +122 -0
  38. package/dist/csp.js.map +1 -0
  39. package/dist/dev-client.d.ts +76 -0
  40. package/dist/dev-client.d.ts.map +1 -0
  41. package/dist/dev-client.js +280 -0
  42. package/dist/dev-client.js.map +1 -0
  43. package/dist/dev-diagnostics.d.ts +26 -2
  44. package/dist/dev-diagnostics.d.ts.map +1 -1
  45. package/dist/dev-diagnostics.js +38 -7
  46. package/dist/dev-diagnostics.js.map +1 -1
  47. package/dist/dev-error.d.ts +4 -13
  48. package/dist/dev-error.d.ts.map +1 -1
  49. package/dist/dev-error.js +46 -4
  50. package/dist/dev-error.js.map +1 -1
  51. package/dist/dev-feed.d.ts +298 -0
  52. package/dist/dev-feed.d.ts.map +1 -0
  53. package/dist/dev-feed.js +797 -0
  54. package/dist/dev-feed.js.map +1 -0
  55. package/dist/dev-indicator.d.ts +38 -0
  56. package/dist/dev-indicator.d.ts.map +1 -0
  57. package/dist/dev-indicator.js +93 -0
  58. package/dist/dev-indicator.js.map +1 -0
  59. package/dist/dev-session.d.ts +77 -0
  60. package/dist/dev-session.d.ts.map +1 -0
  61. package/dist/dev-session.js +580 -0
  62. package/dist/dev-session.js.map +1 -0
  63. package/dist/dev-sourcemap.d.ts +27 -0
  64. package/dist/dev-sourcemap.d.ts.map +1 -0
  65. package/dist/dev-sourcemap.js +235 -0
  66. package/dist/dev-sourcemap.js.map +1 -0
  67. package/dist/dev-ssr-graph.d.ts.map +1 -1
  68. package/dist/dev-ssr-graph.js +13 -5
  69. package/dist/dev-ssr-graph.js.map +1 -1
  70. package/dist/dev.d.ts +15 -2
  71. package/dist/dev.d.ts.map +1 -1
  72. package/dist/dev.js +69 -44
  73. package/dist/dev.js.map +1 -1
  74. package/dist/diagnostic-catalog.d.ts +35 -0
  75. package/dist/diagnostic-catalog.d.ts.map +1 -0
  76. package/dist/diagnostic-catalog.js +203 -0
  77. package/dist/diagnostic-catalog.js.map +1 -0
  78. package/dist/diagnostic-prompt.d.ts +49 -0
  79. package/dist/diagnostic-prompt.d.ts.map +1 -0
  80. package/dist/diagnostic-prompt.js +303 -0
  81. package/dist/diagnostic-prompt.js.map +1 -0
  82. package/dist/diagnostic.d.ts +17 -23
  83. package/dist/diagnostic.d.ts.map +1 -1
  84. package/dist/diagnostic.js +31 -39
  85. package/dist/diagnostic.js.map +1 -1
  86. package/dist/draft.d.ts.map +1 -1
  87. package/dist/draft.js +4 -1
  88. package/dist/draft.js.map +1 -1
  89. package/dist/fn.d.ts +5 -0
  90. package/dist/fn.d.ts.map +1 -1
  91. package/dist/fn.js +13 -3
  92. package/dist/fn.js.map +1 -1
  93. package/dist/fs.d.ts.map +1 -1
  94. package/dist/fs.js +4 -2
  95. package/dist/fs.js.map +1 -1
  96. package/dist/index.d.ts +13 -15
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +11 -12
  99. package/dist/index.js.map +1 -1
  100. package/dist/internal/cdn/cloudflare.d.ts +48 -0
  101. package/dist/internal/cdn/cloudflare.d.ts.map +1 -0
  102. package/dist/internal/cdn/cloudflare.js +94 -0
  103. package/dist/internal/cdn/cloudflare.js.map +1 -0
  104. package/dist/internal/cdn/core.d.ts +91 -0
  105. package/dist/internal/cdn/core.d.ts.map +1 -0
  106. package/dist/internal/cdn/core.js +220 -0
  107. package/dist/internal/cdn/core.js.map +1 -0
  108. package/dist/internal/cdn/fastly.d.ts +17 -0
  109. package/dist/internal/cdn/fastly.d.ts.map +1 -0
  110. package/dist/internal/cdn/fastly.js +43 -0
  111. package/dist/internal/cdn/fastly.js.map +1 -0
  112. package/dist/internal/cdn/vercel.d.ts +31 -0
  113. package/dist/internal/cdn/vercel.d.ts.map +1 -0
  114. package/dist/internal/cdn/vercel.js +56 -0
  115. package/dist/internal/cdn/vercel.js.map +1 -0
  116. package/dist/internal/code-unit-order.d.ts +4 -0
  117. package/dist/internal/code-unit-order.d.ts.map +1 -0
  118. package/dist/internal/code-unit-order.js +6 -0
  119. package/dist/internal/code-unit-order.js.map +1 -0
  120. package/dist/internal/codegen.d.ts.map +1 -1
  121. package/dist/internal/codegen.js +141 -25
  122. package/dist/internal/codegen.js.map +1 -1
  123. package/dist/internal/dev-csp.d.ts +24 -0
  124. package/dist/internal/dev-csp.d.ts.map +1 -0
  125. package/dist/internal/dev-csp.js +160 -0
  126. package/dist/internal/dev-csp.js.map +1 -0
  127. package/dist/internal/dev-reserved.d.ts +25 -0
  128. package/dist/internal/dev-reserved.d.ts.map +1 -0
  129. package/dist/internal/dev-reserved.js +39 -0
  130. package/dist/internal/dev-reserved.js.map +1 -0
  131. package/dist/internal/html-spans.d.ts +10 -0
  132. package/dist/internal/html-spans.d.ts.map +1 -0
  133. package/dist/internal/html-spans.js +46 -0
  134. package/dist/internal/html-spans.js.map +1 -0
  135. package/dist/internal/loading-runtime.d.ts +44 -0
  136. package/dist/internal/loading-runtime.d.ts.map +1 -0
  137. package/dist/internal/loading-runtime.js +206 -0
  138. package/dist/internal/loading-runtime.js.map +1 -0
  139. package/dist/internal/matches-runtime.d.ts +8 -0
  140. package/dist/internal/matches-runtime.d.ts.map +1 -0
  141. package/dist/internal/matches-runtime.js +61 -0
  142. package/dist/internal/matches-runtime.js.map +1 -0
  143. package/dist/internal/mount-shadow.d.ts +36 -0
  144. package/dist/internal/mount-shadow.d.ts.map +1 -0
  145. package/dist/internal/mount-shadow.js +65 -0
  146. package/dist/internal/mount-shadow.js.map +1 -0
  147. package/dist/internal/node-builtins.d.ts +3 -0
  148. package/dist/internal/node-builtins.d.ts.map +1 -0
  149. package/dist/internal/node-builtins.js +79 -0
  150. package/dist/internal/node-builtins.js.map +1 -0
  151. package/dist/internal/output-guard.d.ts +65 -0
  152. package/dist/internal/output-guard.d.ts.map +1 -0
  153. package/dist/internal/output-guard.js +630 -0
  154. package/dist/internal/output-guard.js.map +1 -0
  155. package/dist/internal/page-execution.d.ts +20 -8
  156. package/dist/internal/page-execution.d.ts.map +1 -1
  157. package/dist/internal/page-execution.js +571 -105
  158. package/dist/internal/page-execution.js.map +1 -1
  159. package/dist/internal/parity.d.ts +21 -0
  160. package/dist/internal/parity.d.ts.map +1 -1
  161. package/dist/internal/parity.js +104 -22
  162. package/dist/internal/parity.js.map +1 -1
  163. package/dist/internal/private-env.d.ts +12 -0
  164. package/dist/internal/private-env.d.ts.map +1 -0
  165. package/dist/internal/private-env.js +335 -0
  166. package/dist/internal/private-env.js.map +1 -0
  167. package/dist/internal/public-url.d.ts +3 -0
  168. package/dist/internal/public-url.d.ts.map +1 -0
  169. package/dist/internal/public-url.js +18 -0
  170. package/dist/internal/public-url.js.map +1 -0
  171. package/dist/internal/render-document.d.ts +25 -19
  172. package/dist/internal/render-document.d.ts.map +1 -1
  173. package/dist/internal/render-document.js +77 -61
  174. package/dist/internal/render-document.js.map +1 -1
  175. package/dist/internal/response-controls.d.ts +75 -0
  176. package/dist/internal/response-controls.d.ts.map +1 -0
  177. package/dist/internal/response-controls.js +256 -0
  178. package/dist/internal/response-controls.js.map +1 -0
  179. package/dist/internal/runtime-contract.d.ts +11 -16
  180. package/dist/internal/runtime-contract.d.ts.map +1 -1
  181. package/dist/internal/runtime-contract.js.map +1 -1
  182. package/dist/internal/secret-scan.d.ts +104 -0
  183. package/dist/internal/secret-scan.d.ts.map +1 -0
  184. package/dist/internal/secret-scan.js +485 -0
  185. package/dist/internal/secret-scan.js.map +1 -0
  186. package/dist/internal/server-boundary.d.ts +6 -29
  187. package/dist/internal/server-boundary.d.ts.map +1 -1
  188. package/dist/internal/server-boundary.js +6 -66
  189. package/dist/internal/server-boundary.js.map +1 -1
  190. package/dist/internal/source-map.d.ts +47 -0
  191. package/dist/internal/source-map.d.ts.map +1 -0
  192. package/dist/internal/source-map.js +225 -0
  193. package/dist/internal/source-map.js.map +1 -0
  194. package/dist/internal/target-compat.d.ts +27 -0
  195. package/dist/internal/target-compat.d.ts.map +1 -0
  196. package/dist/internal/target-compat.js +77 -0
  197. package/dist/internal/target-compat.js.map +1 -0
  198. package/dist/internal/timing-safe-equal.d.ts +6 -0
  199. package/dist/internal/timing-safe-equal.d.ts.map +1 -1
  200. package/dist/internal/timing-safe-equal.js +10 -0
  201. package/dist/internal/timing-safe-equal.js.map +1 -1
  202. package/dist/internal/vitals-runtime.d.ts +18 -0
  203. package/dist/internal/vitals-runtime.d.ts.map +1 -0
  204. package/dist/internal/vitals-runtime.js +38 -0
  205. package/dist/internal/vitals-runtime.js.map +1 -0
  206. package/dist/internal/web-app.d.ts +38 -9
  207. package/dist/internal/web-app.d.ts.map +1 -1
  208. package/dist/internal/web-app.js +199 -59
  209. package/dist/internal/web-app.js.map +1 -1
  210. package/dist/internal/zone-graph.d.ts +89 -0
  211. package/dist/internal/zone-graph.d.ts.map +1 -0
  212. package/dist/internal/zone-graph.js +492 -0
  213. package/dist/internal/zone-graph.js.map +1 -0
  214. package/dist/isr.d.ts +83 -6
  215. package/dist/isr.d.ts.map +1 -1
  216. package/dist/isr.js +263 -36
  217. package/dist/isr.js.map +1 -1
  218. package/dist/llms-txt.d.ts.map +1 -1
  219. package/dist/llms-txt.js +31 -6
  220. package/dist/llms-txt.js.map +1 -1
  221. package/dist/manifest.d.ts +220 -13
  222. package/dist/manifest.d.ts.map +1 -1
  223. package/dist/manifest.js +386 -9
  224. package/dist/manifest.js.map +1 -1
  225. package/dist/module-graph.d.ts +26 -5
  226. package/dist/module-graph.d.ts.map +1 -1
  227. package/dist/module-graph.js +17 -7
  228. package/dist/module-graph.js.map +1 -1
  229. package/dist/navigation.d.ts +17 -3
  230. package/dist/navigation.d.ts.map +1 -1
  231. package/dist/navigation.js +11 -5
  232. package/dist/navigation.js.map +1 -1
  233. package/dist/nonce.d.ts +47 -0
  234. package/dist/nonce.d.ts.map +1 -0
  235. package/dist/nonce.js +63 -0
  236. package/dist/nonce.js.map +1 -0
  237. package/dist/plugins/css-modules.d.ts.map +1 -1
  238. package/dist/plugins/css-modules.js +4 -3
  239. package/dist/plugins/css-modules.js.map +1 -1
  240. package/dist/plugins/kit.d.ts +9 -0
  241. package/dist/plugins/kit.d.ts.map +1 -1
  242. package/dist/plugins/kit.js +18 -0
  243. package/dist/plugins/kit.js.map +1 -1
  244. package/dist/plugins/svg.d.ts +22 -3
  245. package/dist/plugins/svg.d.ts.map +1 -1
  246. package/dist/plugins/svg.js +112 -1
  247. package/dist/plugins/svg.js.map +1 -1
  248. package/dist/plugins/vite-leak-guard.d.ts +107 -3
  249. package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
  250. package/dist/plugins/vite-leak-guard.js +378 -17
  251. package/dist/plugins/vite-leak-guard.js.map +1 -1
  252. package/dist/plugins/vite-zone-guard.d.ts +61 -0
  253. package/dist/plugins/vite-zone-guard.d.ts.map +1 -0
  254. package/dist/plugins/vite-zone-guard.js +208 -0
  255. package/dist/plugins/vite-zone-guard.js.map +1 -0
  256. package/dist/plugins/zone-guard.d.ts +27 -0
  257. package/dist/plugins/zone-guard.d.ts.map +1 -0
  258. package/dist/plugins/zone-guard.js +72 -0
  259. package/dist/plugins/zone-guard.js.map +1 -0
  260. package/dist/prerender.d.ts +10 -0
  261. package/dist/prerender.d.ts.map +1 -1
  262. package/dist/prerender.js +35 -3
  263. package/dist/prerender.js.map +1 -1
  264. package/dist/public-dir.d.ts +9 -0
  265. package/dist/public-dir.d.ts.map +1 -1
  266. package/dist/public-dir.js +67 -9
  267. package/dist/public-dir.js.map +1 -1
  268. package/dist/pwa-manifest.d.ts +68 -0
  269. package/dist/pwa-manifest.d.ts.map +1 -0
  270. package/dist/pwa-manifest.js +178 -0
  271. package/dist/pwa-manifest.js.map +1 -0
  272. package/dist/query.js +4 -4
  273. package/dist/query.js.map +1 -1
  274. package/dist/render-seam.d.ts +42 -2
  275. package/dist/render-seam.d.ts.map +1 -1
  276. package/dist/render-seam.js +6 -0
  277. package/dist/render-seam.js.map +1 -1
  278. package/dist/route-manifest.d.ts +3 -0
  279. package/dist/route-manifest.d.ts.map +1 -1
  280. package/dist/route-manifest.js +26 -3
  281. package/dist/route-manifest.js.map +1 -1
  282. package/dist/route-types.d.ts +24 -0
  283. package/dist/route-types.d.ts.map +1 -0
  284. package/dist/route-types.js +195 -0
  285. package/dist/route-types.js.map +1 -0
  286. package/dist/router.d.ts +28 -6
  287. package/dist/router.d.ts.map +1 -1
  288. package/dist/router.js +129 -40
  289. package/dist/router.js.map +1 -1
  290. package/dist/vitals.d.ts +33 -0
  291. package/dist/vitals.d.ts.map +1 -0
  292. package/dist/vitals.js +16 -0
  293. package/dist/vitals.js.map +1 -0
  294. package/dist/vite.d.ts +16 -1
  295. package/dist/vite.d.ts.map +1 -1
  296. package/dist/vite.js +187 -36
  297. package/dist/vite.js.map +1 -1
  298. package/dist/zones.d.ts +70 -0
  299. package/dist/zones.d.ts.map +1 -0
  300. package/dist/zones.js +365 -0
  301. package/dist/zones.js.map +1 -0
  302. package/package.json +67 -14
  303. package/src/backend-only.ts +16 -0
  304. package/src/boundary.ts +18 -5
  305. package/src/build-plan.ts +90 -35
  306. package/src/build-vite.ts +77 -11
  307. package/src/build.ts +466 -96
  308. package/src/bun-dev-entry.ts +1 -1
  309. package/src/cdn.ts +216 -0
  310. package/src/client.ts +111 -18
  311. package/src/conformance.ts +16 -3
  312. package/src/csp.ts +194 -0
  313. package/src/dev-client.ts +349 -0
  314. package/src/dev-diagnostics.ts +60 -7
  315. package/src/dev-error.ts +49 -5
  316. package/src/dev-feed.ts +1140 -0
  317. package/src/dev-indicator.ts +113 -0
  318. package/src/dev-session.ts +729 -0
  319. package/src/dev-sourcemap.ts +281 -0
  320. package/src/dev-ssr-graph.ts +16 -5
  321. package/src/dev.ts +86 -43
  322. package/src/diagnostic-catalog.ts +243 -0
  323. package/src/diagnostic-prompt.ts +355 -0
  324. package/src/diagnostic.ts +63 -66
  325. package/src/draft.ts +4 -1
  326. package/src/fn.ts +19 -3
  327. package/src/fs.ts +13 -2
  328. package/src/index.ts +42 -10
  329. package/src/internal/cdn/cloudflare.ts +146 -0
  330. package/src/internal/cdn/core.ts +316 -0
  331. package/src/internal/cdn/fastly.ts +62 -0
  332. package/src/internal/cdn/vercel.ts +95 -0
  333. package/src/internal/code-unit-order.ts +5 -0
  334. package/src/internal/codegen.ts +161 -24
  335. package/src/internal/dev-csp.ts +176 -0
  336. package/src/internal/dev-reserved.ts +52 -0
  337. package/src/internal/html-spans.ts +50 -0
  338. package/src/internal/loading-runtime.ts +244 -0
  339. package/src/internal/matches-runtime.ts +62 -0
  340. package/src/internal/mount-shadow.ts +88 -0
  341. package/src/internal/node-builtins.ts +79 -0
  342. package/src/internal/output-guard.ts +701 -0
  343. package/src/internal/page-execution.ts +795 -185
  344. package/src/internal/parity.ts +150 -36
  345. package/src/internal/private-env.ts +334 -0
  346. package/src/internal/public-url.ts +22 -0
  347. package/src/internal/render-document.ts +114 -67
  348. package/src/internal/response-controls.ts +284 -0
  349. package/src/internal/runtime-contract.ts +10 -15
  350. package/src/internal/secret-scan.ts +623 -0
  351. package/src/internal/server-boundary.ts +6 -69
  352. package/src/internal/source-map.ts +256 -0
  353. package/src/internal/target-compat.ts +92 -0
  354. package/src/internal/timing-safe-equal.ts +13 -0
  355. package/src/internal/vitals-runtime.ts +53 -0
  356. package/src/internal/web-app.ts +262 -84
  357. package/src/internal/zone-graph.ts +593 -0
  358. package/src/isr.ts +325 -37
  359. package/src/llms-txt.ts +28 -4
  360. package/src/manifest.ts +670 -16
  361. package/src/module-graph.ts +53 -9
  362. package/src/navigation.ts +29 -6
  363. package/src/nonce.ts +104 -0
  364. package/src/plugins/css-modules.ts +5 -3
  365. package/src/plugins/kit.ts +24 -0
  366. package/src/plugins/svg.ts +135 -4
  367. package/src/plugins/vite-leak-guard.ts +529 -16
  368. package/src/plugins/vite-zone-guard.ts +263 -0
  369. package/src/plugins/zone-guard.ts +110 -0
  370. package/src/prerender.ts +49 -3
  371. package/src/public-dir.ts +69 -8
  372. package/src/pwa-manifest.ts +226 -0
  373. package/src/query.ts +4 -4
  374. package/src/render-seam.ts +46 -1
  375. package/src/route-manifest.ts +15 -3
  376. package/src/route-types.ts +264 -0
  377. package/src/router.ts +163 -63
  378. package/src/vitals.ts +44 -0
  379. package/src/vite.ts +207 -36
  380. package/src/zones.ts +430 -0
  381. package/dist/plugins/vite-server-only.d.ts +0 -49
  382. package/dist/plugins/vite-server-only.d.ts.map +0 -1
  383. package/dist/plugins/vite-server-only.js +0 -57
  384. package/dist/plugins/vite-server-only.js.map +0 -1
  385. package/dist/server-only.d.ts +0 -21
  386. package/dist/server-only.d.ts.map +0 -1
  387. package/dist/server-only.js +0 -25
  388. package/dist/server-only.js.map +0 -1
  389. package/src/plugins/vite-server-only.ts +0 -75
  390. package/src/server-only.ts +0 -25
@@ -0,0 +1,256 @@
1
+ import { status as statusResult, } from "@nifrajs/core/server";
2
+ import { DATA_HEADER } from "../router.js";
3
+ import { isResponseResult } from "./render-document.js";
4
+ export const PRIVATE_NO_STORE = "private, no-store";
5
+ /**
6
+ * Headers of a navigation data response. It shares its URL with the document and differs only by a
7
+ * request header, so it must never be stored by a cache keyed on the URL alone: a stored data payload
8
+ * would be served in place of the page.
9
+ */
10
+ export const DATA_RESPONSE_HEADERS = Object.freeze({
11
+ "cache-control": PRIVATE_NO_STORE,
12
+ vary: DATA_HEADER,
13
+ });
14
+ /**
15
+ * Merge order of the header writers: middleware root to leaf (`MIDDLEWARE_SCOPE + i`), layouts root
16
+ * to leaf (`i`), then the page loader, then the action.
17
+ */
18
+ export const PAGE_SCOPE = 1e9;
19
+ export const ACTION_SCOPE = PAGE_SCOPE + 1;
20
+ export const MIDDLEWARE_SCOPE = -PAGE_SCOPE;
21
+ // RFC 9110 `token` and `field-value` (visible ASCII, space, tab, obs-text). A value outside this set
22
+ // could split the header block or be rejected by the transport after the loader already ran.
23
+ const TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
24
+ const FIELD_VALUE = /^[\t\x20-\x7e\x80-\xff]*$/;
25
+ const FRAMEWORK_PREFIX = "x-nifra-";
26
+ const TRANSPORT_OWNED = new Set([
27
+ "connection",
28
+ "content-encoding",
29
+ "content-length",
30
+ "keep-alive",
31
+ "te",
32
+ "trailer",
33
+ "transfer-encoding",
34
+ "upgrade",
35
+ ]);
36
+ const reservedReason = (name) => {
37
+ if (name === "set-cookie")
38
+ return "use ctx.set.cookie(), which applies the secure cookie defaults";
39
+ if (name === "location")
40
+ return "return redirect() instead";
41
+ if (name === "content-type")
42
+ return "the framework sets it for the representation it renders";
43
+ if (TRANSPORT_OWNED.has(name))
44
+ return "the transport owns it";
45
+ if (name.startsWith(FRAMEWORK_PREFIX))
46
+ return "the x-nifra- prefix is reserved for the framework";
47
+ return undefined;
48
+ };
49
+ /** `existing` with the data-request header added, so a cache keeps the document and its data apart. */
50
+ export function varyOnDataHeader(existing) {
51
+ if (existing === null || existing === undefined)
52
+ return DATA_HEADER;
53
+ let empty = true;
54
+ for (const part of existing.split(",")) {
55
+ const name = part.trim().toLowerCase();
56
+ if (name === "")
57
+ continue;
58
+ if (name === "*" || name === DATA_HEADER)
59
+ return existing;
60
+ empty = false;
61
+ }
62
+ return empty ? DATA_HEADER : `${existing}, ${DATA_HEADER}`;
63
+ }
64
+ const CACHE_CONTROL = "cache-control";
65
+ /** Headers of a rendered page that carries a cookie queued through `ctx.set`. */
66
+ export const PRIVATE_PAGE_HEADERS = Object.freeze({
67
+ [CACHE_CONTROL]: PRIVATE_NO_STORE,
68
+ });
69
+ /**
70
+ * `outcome` kept out of shared caches, for a request that queued a cookie through `ctx.set`.
71
+ *
72
+ * A rendered page is already private, and a plain render (`redirect()`, `status()`) inherits the
73
+ * serving app's header record. That leaves a hand-built `Response`, which inherits nothing, and a
74
+ * plain render that names its own `cache-control`, which would win over the inherited one.
75
+ */
76
+ export function privateOutcome(outcome) {
77
+ if (outcome instanceof Response)
78
+ return privateResponse(outcome);
79
+ if (!isResponseResult(outcome))
80
+ return outcome;
81
+ const plain = outcome.plain;
82
+ const own = plain?.headers;
83
+ if (plain === undefined || own === undefined)
84
+ return outcome;
85
+ let headers;
86
+ for (const name of Object.keys(own)) {
87
+ if (name.toLowerCase() !== CACHE_CONTROL)
88
+ continue;
89
+ headers ??= { ...own };
90
+ delete headers[name];
91
+ }
92
+ if (headers === undefined)
93
+ return outcome;
94
+ headers[CACHE_CONTROL] = PRIVATE_NO_STORE;
95
+ return statusResult(plain.status, plain.body, { headers });
96
+ }
97
+ function privateResponse(response) {
98
+ if (response.headers.get(CACHE_CONTROL) === PRIVATE_NO_STORE)
99
+ return response;
100
+ try {
101
+ response.headers.set(CACHE_CONTROL, PRIVATE_NO_STORE);
102
+ return response;
103
+ }
104
+ catch {
105
+ // Immutable headers (`Response.redirect()`, a `fetch()` result): answer with a copy.
106
+ const headers = new Headers(response.headers);
107
+ headers.set(CACHE_CONTROL, PRIVATE_NO_STORE);
108
+ return new Response(response.body, {
109
+ status: response.status,
110
+ statusText: response.statusText,
111
+ headers,
112
+ });
113
+ }
114
+ }
115
+ /**
116
+ * One page request's `ctx.set`: the response headers and cookies its loaders and action write.
117
+ *
118
+ * Every loader gets its own header record ({@link scope}), merged in a fixed order when the response
119
+ * is committed, so layout loaders that run in parallel with the page loader cannot race on a name.
120
+ * Cookies go straight to the serving app's own controls, which serialize them with the secure defaults
121
+ * and append them to whatever the request answers with.
122
+ */
123
+ export class PageResponseControls {
124
+ #c;
125
+ #written;
126
+ #sealed = false;
127
+ #personalized = false;
128
+ constructor(c) {
129
+ this.#c = c;
130
+ }
131
+ /** True once a cookie was queued through `ctx.set`: the response is specific to this visitor. */
132
+ get personalized() {
133
+ return this.#personalized;
134
+ }
135
+ /** The `ctx.set` of one loader or action. `order` fixes where its headers land in the merge. */
136
+ scope(order) {
137
+ return new ScopedResponseControls(this, order);
138
+ }
139
+ /** A scope's header record, created on first use. */
140
+ track(order) {
141
+ const headers = Object.create(null);
142
+ this.#written ??= [];
143
+ this.#written.push({ order, headers });
144
+ return headers;
145
+ }
146
+ /** The serving app's controls, marked as carrying per-visitor state. Throws once sealed. */
147
+ cookies(member) {
148
+ this.assertOpen(member);
149
+ this.personalize();
150
+ return this.#c.set;
151
+ }
152
+ /** Mark the response as one visitor's - a queued cookie, or a draft render - so no cache stores it. */
153
+ personalize() {
154
+ if (this.#personalized)
155
+ return;
156
+ this.#personalized = true;
157
+ // A redirect or status render merges the serving app's header record, so this keeps those
158
+ // outcomes out of shared caches too (a 301 is cacheable by default).
159
+ this.#c.set.headers["cache-control"] = PRIVATE_NO_STORE;
160
+ }
161
+ assertOpen(member) {
162
+ if (!this.#sealed)
163
+ return;
164
+ throw new Error(`[nifra/web] ctx.set.${member} was used after the response was committed. Write response headers and cookies before the loader or action returns - a deferred promise settles too late.`);
165
+ }
166
+ /**
167
+ * Close the controls: the response is decided. A later write - a deferred promise that settles after
168
+ * the loader returned - throws instead of being dropped without a trace.
169
+ */
170
+ seal() {
171
+ if (this.#sealed)
172
+ return;
173
+ this.#sealed = true;
174
+ if (this.#written === undefined)
175
+ return;
176
+ for (const entry of this.#written)
177
+ Object.freeze(entry.headers);
178
+ }
179
+ /**
180
+ * Seal, validate, and merge every written header. Returns `undefined` when none was written.
181
+ * Throws on a name or value that cannot be sent, and on a name the framework or transport owns.
182
+ */
183
+ commit() {
184
+ this.seal();
185
+ const written = this.#written;
186
+ if (written === undefined)
187
+ return undefined;
188
+ if (written.length > 1)
189
+ written.sort((a, b) => a.order - b.order);
190
+ let merged;
191
+ for (const entry of written) {
192
+ for (const rawName of Object.keys(entry.headers)) {
193
+ const name = validHeaderName(rawName);
194
+ merged ??= Object.create(null);
195
+ merged[name] = validHeaderValue(name, entry.headers[rawName]);
196
+ }
197
+ }
198
+ return merged;
199
+ }
200
+ /**
201
+ * The committed headers for the document. Written headers make the document vary on the
202
+ * data-request header; a queued cookie makes it private, whatever a loader asked for.
203
+ */
204
+ documentHeaders() {
205
+ const written = this.commit();
206
+ if (written !== undefined)
207
+ written.vary = varyOnDataHeader(written.vary);
208
+ if (!this.#personalized)
209
+ return written;
210
+ const headers = written ?? Object.create(null);
211
+ headers["cache-control"] = PRIVATE_NO_STORE;
212
+ return headers;
213
+ }
214
+ }
215
+ class ScopedResponseControls {
216
+ #owner;
217
+ #order;
218
+ #headers;
219
+ constructor(owner, order) {
220
+ this.#owner = owner;
221
+ this.#order = order;
222
+ }
223
+ get headers() {
224
+ this.#owner.assertOpen("headers");
225
+ this.#headers ??= this.#owner.track(this.#order);
226
+ return this.#headers;
227
+ }
228
+ cookie(name, value, options) {
229
+ this.#owner.cookies("cookie()").cookie(name, value, options);
230
+ }
231
+ deleteCookie(name, options) {
232
+ this.#owner.cookies("deleteCookie()").deleteCookie(name, options);
233
+ }
234
+ }
235
+ function validHeaderName(rawName) {
236
+ if (!TOKEN.test(rawName)) {
237
+ throw new Error(`[nifra/web] ctx.set.headers: ${JSON.stringify(rawName)} is not a valid header name`);
238
+ }
239
+ const name = rawName.toLowerCase();
240
+ const reason = reservedReason(name);
241
+ if (reason !== undefined) {
242
+ throw new Error(`[nifra/web] ctx.set.headers: "${name}" is reserved - ${reason}`);
243
+ }
244
+ return name;
245
+ }
246
+ // The message names the header only: a value can carry a token or a visitor's data.
247
+ function validHeaderValue(name, value) {
248
+ if (typeof value !== "string") {
249
+ throw new Error(`[nifra/web] ctx.set.headers: the value of "${name}" must be a string`);
250
+ }
251
+ if (!FIELD_VALUE.test(value)) {
252
+ throw new Error(`[nifra/web] ctx.set.headers: the value of "${name}" contains a character a header cannot carry (a line break, a control character, or one outside Latin-1)`);
253
+ }
254
+ return value;
255
+ }
256
+ //# sourceMappingURL=response-controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-controls.js","sourceRoot":"","sources":["../../src/internal/response-controls.ts"],"names":[],"mappings":"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"}
@@ -1,28 +1,23 @@
1
- /** Phantom brand key for {@link ServerOnly}. */
2
- declare const SERVER_ONLY_BRAND: unique symbol;
1
+ /** Phantom brand key for {@link BackendOnly}. */
2
+ declare const BACKEND_ONLY_BRAND: unique symbol;
3
3
  /**
4
4
  * Type-level intent marker for a value that must only exist on the server - a secret, a DB handle, a
5
- * server-only client. `ServerOnly<T>` is structurally `T` (the brand is an optional phantom field, so
5
+ * server-only client. `BackendOnly<T>` is structurally `T` (the brand is an optional phantom field, so
6
6
  * existing code keeps type-checking), but it advertises to readers + the compiler that the value is
7
7
  * not meant to cross to the browser. It is **purely type-level** and erases at build - it does NOT,
8
8
  * by itself, keep the value out of the client bundle.
9
9
  *
10
- * The enforcement is two runtime conventions:
11
- * - add the side-effect import `import "@nifrajs/web/server-only"` at the top of the module - the
12
- * client build ({@link buildClient}) fails loud, with the import chain, if it reaches a browser
13
- * chunk (the poison-import marker);
14
- * - or name the file `*.server.ts` - the `.server` convention empties it in the client build.
15
- *
16
- * Use this brand to express the intent in the types; pair it with one of those runtime markers so a
17
- * leak is caught at build time rather than shipping a secret to the client.
10
+ * The enforcement is the zone rules: code under `backend/` or in a `*.backend.ts` file never reaches a
11
+ * browser build, and a module that imports `@nifrajs/web/backend-only` fails every browser build that
12
+ * reaches it, wherever it lives.
18
13
  *
19
14
  * @example
20
- * import "@nifrajs/web/server-only"
21
- * import type { ServerOnly } from "@nifrajs/web"
22
- * export const apiKey: ServerOnly<string> = process.env.SECRET_API_KEY!
15
+ * import "@nifrajs/web/backend-only"
16
+ * import type { BackendOnly } from "@nifrajs/web"
17
+ * export const apiKey: BackendOnly<string> = process.env.SECRET_API_KEY!
23
18
  */
24
- export type ServerOnly<T> = T & {
25
- readonly [SERVER_ONLY_BRAND]?: never;
19
+ export type BackendOnly<T> = T & {
20
+ readonly [BACKEND_ONLY_BRAND]?: never;
26
21
  };
27
22
  /**
28
23
  * Pre-hydration form guard - a tiny inline script flushed in `<head>` (it runs in the window between
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-contract.d.ts","sourceRoot":"","sources":["../../src/internal/runtime-contract.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,CAAC,MAAM,iBAAiB,EAAE,OAAO,MAAM,CAAA;AAE9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAA;CAAE,CAAA;AAExE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,QAOjB,CAAA;AAEf;;;;;yCAKyC;AACzC,eAAO,MAAM,gBAAgB,OAAO,CAAA"}
1
+ {"version":3,"file":"runtime-contract.d.ts","sourceRoot":"","sources":["../../src/internal/runtime-contract.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,OAAO,CAAC,MAAM,kBAAkB,EAAE,OAAO,MAAM,CAAA;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,KAAK,CAAA;CAAE,CAAA;AAE1E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,QAOjB,CAAA;AAEf;;;;;yCAKyC;AACzC,eAAO,MAAM,gBAAgB,OAAO,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-contract.js","sourceRoot":"","sources":["../../src/internal/runtime-contract.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,mEAAmE;IACnE,kEAAkE;IAClE,yEAAyE;IACzE,6EAA6E;IAC7E,iCAAiC;IACjC,qFAAqF;IACrF,aAAa,CAAA;AAEf;;;;;yCAKyC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAA"}
1
+ {"version":3,"file":"runtime-contract.js","sourceRoot":"","sources":["../../src/internal/runtime-contract.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,mEAAmE;IACnE,kEAAkE;IAClE,yEAAyE;IACzE,6EAA6E;IAC7E,iCAAiC;IACjC,qFAAqF;IACrF,aAAa,CAAA;AAEf;;;;;yCAKyC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAA"}
@@ -0,0 +1,104 @@
1
+ import type { ClientModuleGraph } from "../module-graph.js";
2
+ import type { ZoneClassifier } from "../zones.js";
3
+ import type { ModuleSource } from "./zone-graph.js";
4
+ export type SecretRule =
5
+ /** A PEM private key block. */
6
+ "private-key"
7
+ /** A URL carrying a password: `postgres://user:password@host`. */
8
+ | "credential-url"
9
+ /** A known secret token format: AWS, Stripe secret keys, GitHub, Slack, OpenAI, Anthropic, ... */
10
+ | "key-format"
11
+ /** A high-entropy string literal assigned to a secret-like name. Source files only. */
12
+ | "assigned-secret"
13
+ /** The value of a non-public build environment variable, raw or URL, base64, JSON or HTML encoded. */
14
+ | "private-env-value";
15
+ /**
16
+ * One reviewed false positive. It names the rule, where the finding is and why it may ship: there is
17
+ * no exemption by value, so a credential that turns up somewhere else still fails the build.
18
+ */
19
+ export interface SecretExemption {
20
+ readonly rule: SecretRule;
21
+ /** The finding's file as reported: app-relative for a source or `public/` file, output-relative for
22
+ * an emitted file. */
23
+ readonly file?: string;
24
+ /** For `private-env-value`: the variable whose value may ship. */
25
+ readonly env?: string;
26
+ readonly reason: string;
27
+ }
28
+ export interface SecretFinding {
29
+ readonly rule: SecretRule;
30
+ /** The source module the match came from when it is known, else the published file. */
31
+ readonly file: string;
32
+ readonly line: number;
33
+ /** The published file the match is in, when {@link file} names the module it came from. */
34
+ readonly via?: string;
35
+ /** What matched, never the value: `"AWS access key id"`, `"value of DATABASE_URL (base64)"`. */
36
+ readonly what: string;
37
+ /** The first characters and the length, enough to recognize a key without publishing it. */
38
+ readonly preview: string;
39
+ }
40
+ /** A module bundled into a published file. */
41
+ export interface SecretOrigin {
42
+ /** As a finding names it: app-relative, or `node_modules/<package>/...`. */
43
+ readonly name: string;
44
+ readonly path: string;
45
+ }
46
+ export interface SecretScanFile {
47
+ /** Where the file is, as a finding should name it. */
48
+ readonly name: string;
49
+ readonly text: string;
50
+ /** A first-party source file: the assigned-secret rule applies. */
51
+ readonly firstParty?: boolean;
52
+ /** For an emitted bundle: the modules in it, so a finding names the one a match came from (a
53
+ * content-hashed file name is no place for an exemption). */
54
+ readonly origins?: readonly SecretOrigin[];
55
+ }
56
+ export interface SecretScanInput {
57
+ /** Source modules the browser build loaded, scanned before minification. */
58
+ readonly sources?: readonly SecretScanFile[];
59
+ /** Files that will be served: emitted bundles, maps, `public/` copies, prerendered pages. */
60
+ readonly artifacts?: readonly SecretScanFile[];
61
+ /** The build environment whose non-public values must not ship (default: none). */
62
+ readonly env?: Readonly<Record<string, string | undefined>>;
63
+ /** The public-env prefix (default `"PUBLIC_"`); prefixed variables are public by declaration. */
64
+ readonly publicEnvPrefix?: string;
65
+ readonly exemptions?: readonly SecretExemption[];
66
+ }
67
+ /** Refuse an exemption that does not name its rule, its location and its reason. */
68
+ export declare function assertSecretExemptions(exemptions: readonly SecretExemption[]): void;
69
+ /**
70
+ * Scan what a build publishes. Sources are scanned first: a match there is reported at its source
71
+ * location, and the same text in an emitted file (where names are hashed) is not reported again,
72
+ * exempted or not.
73
+ */
74
+ export declare function scanForSecrets(input: SecretScanInput): SecretFinding[];
75
+ /**
76
+ * A scrubber for text a dev tool hands to a person or an agent: logs, error messages, stacks,
77
+ * codeframes. Broader than the build scan because a log line is not a published artifact: every JWT
78
+ * (a session token is a credential), an `Authorization`/`Cookie` value, and every non-public env
79
+ * value in each encoding the build scan matches. Each hit becomes `[redacted:<what>]`.
80
+ */
81
+ export declare function createRedactor(env: Readonly<Record<string, string | undefined>>, publicEnvPrefix?: string): (text: string) => string;
82
+ /** The build environment: Bun's, else Node's. */
83
+ export declare const buildEnvironment: () => Readonly<Record<string, string | undefined>>;
84
+ /** Scan and throw the build-failing message on any finding. */
85
+ export declare function assertNoSecrets(input: SecretScanInput): void;
86
+ /** The build-failing message for secret findings, or `undefined` when there are none. */
87
+ export declare function formatSecretFindings(findings: readonly SecretFinding[]): string | undefined;
88
+ /** A published file's text, or `undefined` for a binary one (a NUL byte in its first 8 KB). */
89
+ export declare function textOf(bytes: Uint8Array): string | undefined;
90
+ /** An emitted bundle, plus its inline source map decoded: base64 would hide a key from every rule. */
91
+ export declare function emittedScanFiles(name: string, text: string, origins?: readonly SecretOrigin[]): SecretScanFile[];
92
+ /** How a finding names a module: app-relative inside the app, from `node_modules/` for a package. */
93
+ export declare function originName(appRoot: string, file: string): string;
94
+ /**
95
+ * The scan's view of a client graph: the first-party browser modules as sources, and for each emitted
96
+ * file (by basename) the modules bundled into it.
97
+ */
98
+ export declare function graphScanInput(graph: ClientModuleGraph, sourceOf: (id: string) => ModuleSource, classifier: ZoneClassifier): {
99
+ sources: SecretScanFile[];
100
+ originsOf: (outputName: string) => SecretOrigin[];
101
+ };
102
+ /** Every file under a `public/` directory, named as the app sees it (`public/robots.txt`). */
103
+ export declare function publicScanFiles(dir: string, label: string): SecretScanFile[];
104
+ //# sourceMappingURL=secret-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-scan.d.ts","sourceRoot":"","sources":["../../src/internal/secret-scan.ts"],"names":[],"mappings":"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"}