@nifrajs/web 4.0.2 → 5.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 (426) hide show
  1. package/README.md +19 -0
  2. package/dist/build-vite.d.ts +19 -0
  3. package/dist/build-vite.d.ts.map +1 -1
  4. package/dist/build-vite.js +31 -10
  5. package/dist/build-vite.js.map +1 -1
  6. package/dist/build.d.ts +8 -10
  7. package/dist/build.d.ts.map +1 -1
  8. package/dist/build.js +90 -31
  9. package/dist/build.js.map +1 -1
  10. package/dist/cdn.d.ts +8 -0
  11. package/dist/cdn.d.ts.map +1 -1
  12. package/dist/cdn.js +14 -15
  13. package/dist/cdn.js.map +1 -1
  14. package/dist/client.d.ts +6 -6
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +46 -18
  17. package/dist/client.js.map +1 -1
  18. package/dist/deferred.d.ts +2 -2
  19. package/dist/deferred.d.ts.map +1 -1
  20. package/dist/deferred.js +28 -7
  21. package/dist/deferred.js.map +1 -1
  22. package/dist/dev-feed.d.ts.map +1 -1
  23. package/dist/dev-feed.js +24 -5
  24. package/dist/dev-feed.js.map +1 -1
  25. package/dist/dev-port.d.ts +3 -2
  26. package/dist/dev-port.d.ts.map +1 -1
  27. package/dist/dev-port.js +2 -6
  28. package/dist/dev-port.js.map +1 -1
  29. package/dist/dev-session.d.ts.map +1 -1
  30. package/dist/dev-session.js +4 -14
  31. package/dist/dev-session.js.map +1 -1
  32. package/dist/dev.d.ts +7 -17
  33. package/dist/dev.d.ts.map +1 -1
  34. package/dist/dev.js +13 -1
  35. package/dist/dev.js.map +1 -1
  36. package/dist/draft.d.ts +8 -5
  37. package/dist/draft.d.ts.map +1 -1
  38. package/dist/draft.js +30 -13
  39. package/dist/draft.js.map +1 -1
  40. package/dist/fonts-google.d.ts.map +1 -1
  41. package/dist/fonts-google.js +7 -0
  42. package/dist/fonts-google.js.map +1 -1
  43. package/dist/index.d.ts +5 -4
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -3
  46. package/dist/index.js.map +1 -1
  47. package/dist/internal/codegen.d.ts +1 -0
  48. package/dist/internal/codegen.d.ts.map +1 -1
  49. package/dist/internal/codegen.js +56 -29
  50. package/dist/internal/codegen.js.map +1 -1
  51. package/dist/internal/disposable-dir.d.ts +8 -0
  52. package/dist/internal/disposable-dir.d.ts.map +1 -0
  53. package/dist/internal/disposable-dir.js +25 -0
  54. package/dist/internal/disposable-dir.js.map +1 -0
  55. package/dist/internal/entry-chunks.d.ts +9 -0
  56. package/dist/internal/entry-chunks.d.ts.map +1 -0
  57. package/dist/internal/entry-chunks.js +15 -0
  58. package/dist/internal/entry-chunks.js.map +1 -0
  59. package/dist/internal/evidence-traversal.d.ts +12 -0
  60. package/dist/internal/evidence-traversal.d.ts.map +1 -0
  61. package/dist/internal/evidence-traversal.js +48 -0
  62. package/dist/internal/evidence-traversal.js.map +1 -0
  63. package/dist/internal/head-merge.d.ts +6 -0
  64. package/dist/internal/head-merge.d.ts.map +1 -1
  65. package/dist/internal/head-merge.js +9 -0
  66. package/dist/internal/head-merge.js.map +1 -1
  67. package/dist/internal/js-string.d.ts +2 -0
  68. package/dist/internal/js-string.d.ts.map +1 -1
  69. package/dist/internal/js-string.js +5 -1
  70. package/dist/internal/js-string.js.map +1 -1
  71. package/dist/internal/mount-shadow.js +1 -1
  72. package/dist/internal/mount-shadow.js.map +1 -1
  73. package/dist/internal/output-guard.d.ts +7 -0
  74. package/dist/internal/output-guard.d.ts.map +1 -1
  75. package/dist/internal/output-guard.js +80 -8
  76. package/dist/internal/output-guard.js.map +1 -1
  77. package/dist/internal/package-entries.d.ts +34 -0
  78. package/dist/internal/package-entries.d.ts.map +1 -0
  79. package/dist/internal/package-entries.js +324 -0
  80. package/dist/internal/package-entries.js.map +1 -0
  81. package/dist/internal/page-execution.d.ts +6 -0
  82. package/dist/internal/page-execution.d.ts.map +1 -1
  83. package/dist/internal/page-execution.js +437 -114
  84. package/dist/internal/page-execution.js.map +1 -1
  85. package/dist/internal/parity.d.ts.map +1 -1
  86. package/dist/internal/parity.js +15 -2
  87. package/dist/internal/parity.js.map +1 -1
  88. package/dist/internal/private-env.d.ts +8 -0
  89. package/dist/internal/private-env.d.ts.map +1 -1
  90. package/dist/internal/private-env.js +25 -10
  91. package/dist/internal/private-env.js.map +1 -1
  92. package/dist/internal/progressive-cookies.d.ts +14 -0
  93. package/dist/internal/progressive-cookies.d.ts.map +1 -0
  94. package/dist/internal/progressive-cookies.js +43 -0
  95. package/dist/internal/progressive-cookies.js.map +1 -0
  96. package/dist/internal/public-env.d.ts +2 -0
  97. package/dist/internal/public-env.d.ts.map +1 -0
  98. package/dist/internal/public-env.js +13 -0
  99. package/dist/internal/public-env.js.map +1 -0
  100. package/dist/internal/render-document.d.ts +5 -44
  101. package/dist/internal/render-document.d.ts.map +1 -1
  102. package/dist/internal/render-document.js +51 -63
  103. package/dist/internal/render-document.js.map +1 -1
  104. package/dist/internal/response-controls.d.ts +2 -0
  105. package/dist/internal/response-controls.d.ts.map +1 -1
  106. package/dist/internal/response-controls.js +26 -16
  107. package/dist/internal/response-controls.js.map +1 -1
  108. package/dist/internal/revive-dates.d.ts +16 -0
  109. package/dist/internal/revive-dates.d.ts.map +1 -0
  110. package/dist/internal/revive-dates.js +32 -0
  111. package/dist/internal/revive-dates.js.map +1 -0
  112. package/dist/internal/route-path.d.ts +14 -0
  113. package/dist/internal/route-path.d.ts.map +1 -0
  114. package/dist/internal/route-path.js +19 -0
  115. package/dist/internal/route-path.js.map +1 -0
  116. package/dist/internal/secret-scan.d.ts.map +1 -1
  117. package/dist/internal/secret-scan.js +190 -20
  118. package/dist/internal/secret-scan.js.map +1 -1
  119. package/dist/internal/server-boundary.d.ts.map +1 -1
  120. package/dist/internal/server-boundary.js +33 -5
  121. package/dist/internal/server-boundary.js.map +1 -1
  122. package/dist/internal/web-app.d.ts +25 -18
  123. package/dist/internal/web-app.d.ts.map +1 -1
  124. package/dist/internal/web-app.js +81 -24
  125. package/dist/internal/web-app.js.map +1 -1
  126. package/dist/internal/wire-date.d.ts +3 -0
  127. package/dist/internal/wire-date.d.ts.map +1 -0
  128. package/dist/internal/wire-date.js +14 -0
  129. package/dist/internal/wire-date.js.map +1 -0
  130. package/dist/internal/without-query.d.ts +4 -0
  131. package/dist/internal/without-query.d.ts.map +1 -0
  132. package/dist/internal/without-query.js +9 -0
  133. package/dist/internal/without-query.js.map +1 -0
  134. package/dist/internal/zone-graph.d.ts +4 -0
  135. package/dist/internal/zone-graph.d.ts.map +1 -1
  136. package/dist/internal/zone-graph.js +71 -20
  137. package/dist/internal/zone-graph.js.map +1 -1
  138. package/dist/isr.d.ts +59 -3
  139. package/dist/isr.d.ts.map +1 -1
  140. package/dist/isr.js +311 -41
  141. package/dist/isr.js.map +1 -1
  142. package/dist/llms-txt.d.ts +2 -0
  143. package/dist/llms-txt.d.ts.map +1 -1
  144. package/dist/llms-txt.js +29 -3
  145. package/dist/llms-txt.js.map +1 -1
  146. package/dist/manifest.d.ts +37 -4
  147. package/dist/manifest.d.ts.map +1 -1
  148. package/dist/manifest.js +4 -0
  149. package/dist/manifest.js.map +1 -1
  150. package/dist/open-resolved.d.ts +18 -0
  151. package/dist/open-resolved.d.ts.map +1 -0
  152. package/dist/open-resolved.js +62 -0
  153. package/dist/open-resolved.js.map +1 -0
  154. package/dist/plugins/kit.d.ts +1 -0
  155. package/dist/plugins/kit.d.ts.map +1 -1
  156. package/dist/plugins/kit.js +26 -11
  157. package/dist/plugins/kit.js.map +1 -1
  158. package/dist/plugins/vite-leak-guard.d.ts +9 -1
  159. package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
  160. package/dist/plugins/vite-leak-guard.js +84 -7
  161. package/dist/plugins/vite-leak-guard.js.map +1 -1
  162. package/dist/plugins/vite-zone-guard.d.ts.map +1 -1
  163. package/dist/plugins/vite-zone-guard.js +17 -21
  164. package/dist/plugins/vite-zone-guard.js.map +1 -1
  165. package/dist/plugins/zone-guard.d.ts.map +1 -1
  166. package/dist/plugins/zone-guard.js +44 -3
  167. package/dist/plugins/zone-guard.js.map +1 -1
  168. package/dist/prerender.d.ts +5 -1
  169. package/dist/prerender.d.ts.map +1 -1
  170. package/dist/prerender.js +41 -19
  171. package/dist/prerender.js.map +1 -1
  172. package/dist/public-dir.d.ts +8 -1
  173. package/dist/public-dir.d.ts.map +1 -1
  174. package/dist/public-dir.js +17 -6
  175. package/dist/public-dir.js.map +1 -1
  176. package/dist/query.d.ts +13 -4
  177. package/dist/query.d.ts.map +1 -1
  178. package/dist/query.js +89 -26
  179. package/dist/query.js.map +1 -1
  180. package/dist/render-seam.d.ts +25 -2
  181. package/dist/render-seam.d.ts.map +1 -1
  182. package/dist/render-seam.js +1 -0
  183. package/dist/render-seam.js.map +1 -1
  184. package/dist/route-types.d.ts.map +1 -1
  185. package/dist/route-types.js +20 -9
  186. package/dist/route-types.js.map +1 -1
  187. package/dist/router.d.ts +9 -2
  188. package/dist/router.d.ts.map +1 -1
  189. package/dist/router.js +47 -50
  190. package/dist/router.js.map +1 -1
  191. package/dist/seo.d.ts +49 -0
  192. package/dist/seo.d.ts.map +1 -0
  193. package/dist/seo.js +48 -0
  194. package/dist/seo.js.map +1 -0
  195. package/dist/server-components/build-info.d.ts +3 -0
  196. package/dist/server-components/build-info.d.ts.map +1 -0
  197. package/dist/server-components/build-info.js +7 -0
  198. package/dist/server-components/build-info.js.map +1 -0
  199. package/dist/server-components/build-target.d.ts +12 -0
  200. package/dist/server-components/build-target.d.ts.map +1 -0
  201. package/dist/server-components/build-target.js +153 -0
  202. package/dist/server-components/build-target.js.map +1 -0
  203. package/dist/server-components/build.d.ts +24 -0
  204. package/dist/server-components/build.d.ts.map +1 -0
  205. package/dist/server-components/build.js +366 -0
  206. package/dist/server-components/build.js.map +1 -0
  207. package/dist/server-components/bundle-proof.d.ts +3 -0
  208. package/dist/server-components/bundle-proof.d.ts.map +1 -0
  209. package/dist/server-components/bundle-proof.js +23 -0
  210. package/dist/server-components/bundle-proof.js.map +1 -0
  211. package/dist/server-components/client.d.ts +46 -0
  212. package/dist/server-components/client.d.ts.map +1 -0
  213. package/dist/server-components/client.js +594 -0
  214. package/dist/server-components/client.js.map +1 -0
  215. package/dist/server-components/definition.d.ts +11 -0
  216. package/dist/server-components/definition.d.ts.map +1 -0
  217. package/dist/server-components/definition.js +94 -0
  218. package/dist/server-components/definition.js.map +1 -0
  219. package/dist/server-components/dev-http.d.ts +5 -0
  220. package/dist/server-components/dev-http.d.ts.map +1 -0
  221. package/dist/server-components/dev-http.js +71 -0
  222. package/dist/server-components/dev-http.js.map +1 -0
  223. package/dist/server-components/error.d.ts +9 -0
  224. package/dist/server-components/error.d.ts.map +1 -0
  225. package/dist/server-components/error.js +24 -0
  226. package/dist/server-components/error.js.map +1 -0
  227. package/dist/server-components/frames.d.ts +7 -0
  228. package/dist/server-components/frames.d.ts.map +1 -0
  229. package/dist/server-components/frames.js +169 -0
  230. package/dist/server-components/frames.js.map +1 -0
  231. package/dist/server-components/html-policy.d.ts +6 -0
  232. package/dist/server-components/html-policy.d.ts.map +1 -0
  233. package/dist/server-components/html-policy.js +75 -0
  234. package/dist/server-components/html-policy.js.map +1 -0
  235. package/dist/server-components/html.d.ts +4 -0
  236. package/dist/server-components/html.d.ts.map +1 -0
  237. package/dist/server-components/html.js +67 -0
  238. package/dist/server-components/html.js.map +1 -0
  239. package/dist/server-components/islands.d.ts +44 -0
  240. package/dist/server-components/islands.d.ts.map +1 -0
  241. package/dist/server-components/islands.js +42 -0
  242. package/dist/server-components/islands.js.map +1 -0
  243. package/dist/server-components/native.d.ts +4 -0
  244. package/dist/server-components/native.d.ts.map +1 -0
  245. package/dist/server-components/native.js +81 -0
  246. package/dist/server-components/native.js.map +1 -0
  247. package/dist/server-components/portal.d.ts +6 -0
  248. package/dist/server-components/portal.d.ts.map +1 -0
  249. package/dist/server-components/portal.js +35 -0
  250. package/dist/server-components/portal.js.map +1 -0
  251. package/dist/server-components/props.d.ts +3 -0
  252. package/dist/server-components/props.d.ts.map +1 -0
  253. package/dist/server-components/props.js +14 -0
  254. package/dist/server-components/props.js.map +1 -0
  255. package/dist/server-components/protocol.d.ts +44 -0
  256. package/dist/server-components/protocol.d.ts.map +1 -0
  257. package/dist/server-components/protocol.js +139 -0
  258. package/dist/server-components/protocol.js.map +1 -0
  259. package/dist/server-components/range.d.ts +24 -0
  260. package/dist/server-components/range.d.ts.map +1 -0
  261. package/dist/server-components/range.js +263 -0
  262. package/dist/server-components/range.js.map +1 -0
  263. package/dist/server-components/registry.d.ts +6 -0
  264. package/dist/server-components/registry.d.ts.map +1 -0
  265. package/dist/server-components/registry.js +30 -0
  266. package/dist/server-components/registry.js.map +1 -0
  267. package/dist/server-components/response.d.ts +4 -0
  268. package/dist/server-components/response.d.ts.map +1 -0
  269. package/dist/server-components/response.js +32 -0
  270. package/dist/server-components/response.js.map +1 -0
  271. package/dist/server-components/router-integration.d.ts +9 -0
  272. package/dist/server-components/router-integration.d.ts.map +1 -0
  273. package/dist/server-components/router-integration.js +29 -0
  274. package/dist/server-components/router-integration.js.map +1 -0
  275. package/dist/server-components/runtime.d.ts +14 -0
  276. package/dist/server-components/runtime.d.ts.map +1 -0
  277. package/dist/server-components/runtime.js +276 -0
  278. package/dist/server-components/runtime.js.map +1 -0
  279. package/dist/server-components/scheduler.d.ts +14 -0
  280. package/dist/server-components/scheduler.d.ts.map +1 -0
  281. package/dist/server-components/scheduler.js +74 -0
  282. package/dist/server-components/scheduler.js.map +1 -0
  283. package/dist/server-components/schema.d.ts +4 -0
  284. package/dist/server-components/schema.d.ts.map +1 -0
  285. package/dist/server-components/schema.js +77 -0
  286. package/dist/server-components/schema.js.map +1 -0
  287. package/dist/server-components/server-entry.d.ts +12 -0
  288. package/dist/server-components/server-entry.d.ts.map +1 -0
  289. package/dist/server-components/server-entry.js +90 -0
  290. package/dist/server-components/server-entry.js.map +1 -0
  291. package/dist/server-components/source.d.ts +15 -0
  292. package/dist/server-components/source.d.ts.map +1 -0
  293. package/dist/server-components/source.js +269 -0
  294. package/dist/server-components/source.js.map +1 -0
  295. package/dist/server-components/state.d.ts +4 -0
  296. package/dist/server-components/state.d.ts.map +1 -0
  297. package/dist/server-components/state.js +123 -0
  298. package/dist/server-components/state.js.map +1 -0
  299. package/dist/server-components/stream.d.ts +6 -0
  300. package/dist/server-components/stream.d.ts.map +1 -0
  301. package/dist/server-components/stream.js +70 -0
  302. package/dist/server-components/stream.js.map +1 -0
  303. package/dist/server-components/trusted-html.d.ts +3 -0
  304. package/dist/server-components/trusted-html.d.ts.map +1 -0
  305. package/dist/server-components/trusted-html.js +14 -0
  306. package/dist/server-components/trusted-html.js.map +1 -0
  307. package/dist/server-components/types.d.ts +107 -0
  308. package/dist/server-components/types.d.ts.map +1 -0
  309. package/dist/server-components/types.js +2 -0
  310. package/dist/server-components/types.js.map +1 -0
  311. package/dist/server-components/typescript.d.ts +11 -0
  312. package/dist/server-components/typescript.d.ts.map +1 -0
  313. package/dist/server-components/typescript.js +28 -0
  314. package/dist/server-components/typescript.js.map +1 -0
  315. package/dist/server-components/value.d.ts +5 -0
  316. package/dist/server-components/value.d.ts.map +1 -0
  317. package/dist/server-components/value.js +77 -0
  318. package/dist/server-components/value.js.map +1 -0
  319. package/dist/server-components/vite.d.ts +12 -0
  320. package/dist/server-components/vite.d.ts.map +1 -0
  321. package/dist/server-components/vite.js +197 -0
  322. package/dist/server-components/vite.js.map +1 -0
  323. package/dist/server-components.d.ts +5 -0
  324. package/dist/server-components.d.ts.map +1 -0
  325. package/dist/server-components.js +4 -0
  326. package/dist/server-components.js.map +1 -0
  327. package/dist/service-worker.d.ts +8 -1
  328. package/dist/service-worker.d.ts.map +1 -1
  329. package/dist/service-worker.js +20 -6
  330. package/dist/service-worker.js.map +1 -1
  331. package/dist/vite.d.ts +12 -0
  332. package/dist/vite.d.ts.map +1 -1
  333. package/dist/vite.js +7 -1
  334. package/dist/vite.js.map +1 -1
  335. package/dist/zones.d.ts +64 -2
  336. package/dist/zones.d.ts.map +1 -1
  337. package/dist/zones.js +331 -28
  338. package/dist/zones.js.map +1 -1
  339. package/package.json +102 -4
  340. package/src/build-vite.ts +31 -9
  341. package/src/build.ts +109 -31
  342. package/src/cdn.ts +18 -12
  343. package/src/client.ts +48 -17
  344. package/src/deferred.ts +27 -9
  345. package/src/dev-feed.ts +24 -5
  346. package/src/dev-port.ts +4 -10
  347. package/src/dev-session.ts +4 -13
  348. package/src/dev.ts +29 -1
  349. package/src/draft.ts +35 -14
  350. package/src/fonts-google.ts +10 -0
  351. package/src/index.ts +5 -6
  352. package/src/internal/codegen.ts +60 -29
  353. package/src/internal/disposable-dir.ts +24 -0
  354. package/src/internal/entry-chunks.ts +18 -0
  355. package/src/internal/evidence-traversal.ts +57 -0
  356. package/src/internal/head-merge.ts +16 -0
  357. package/src/internal/js-string.ts +6 -1
  358. package/src/internal/mount-shadow.ts +1 -1
  359. package/src/internal/output-guard.ts +88 -7
  360. package/src/internal/package-entries.ts +331 -0
  361. package/src/internal/page-execution.ts +573 -114
  362. package/src/internal/parity.ts +15 -2
  363. package/src/internal/private-env.ts +27 -13
  364. package/src/internal/progressive-cookies.ts +60 -0
  365. package/src/internal/public-env.ts +14 -0
  366. package/src/internal/render-document.ts +66 -89
  367. package/src/internal/response-controls.ts +31 -14
  368. package/src/internal/revive-dates.ts +35 -0
  369. package/src/internal/route-path.ts +24 -0
  370. package/src/internal/secret-scan.ts +190 -18
  371. package/src/internal/server-boundary.ts +29 -5
  372. package/src/internal/web-app.ts +126 -42
  373. package/src/internal/wire-date.ts +16 -0
  374. package/src/internal/without-query.ts +8 -0
  375. package/src/internal/zone-graph.ts +78 -25
  376. package/src/isr.ts +364 -45
  377. package/src/llms-txt.ts +32 -3
  378. package/src/manifest.ts +38 -4
  379. package/src/open-resolved.ts +64 -0
  380. package/src/plugins/kit.ts +31 -11
  381. package/src/plugins/vite-leak-guard.ts +104 -8
  382. package/src/plugins/vite-zone-guard.ts +21 -19
  383. package/src/plugins/zone-guard.ts +41 -2
  384. package/src/prerender.ts +39 -18
  385. package/src/public-dir.ts +27 -8
  386. package/src/query.ts +107 -26
  387. package/src/render-seam.ts +30 -2
  388. package/src/route-types.ts +34 -7
  389. package/src/router.ts +66 -59
  390. package/src/seo.ts +68 -0
  391. package/src/server-components/build-info.ts +11 -0
  392. package/src/server-components/build-target.ts +194 -0
  393. package/src/server-components/build.ts +419 -0
  394. package/src/server-components/bundle-proof.ts +33 -0
  395. package/src/server-components/client.ts +663 -0
  396. package/src/server-components/definition.ts +125 -0
  397. package/src/server-components/dev-http.ts +75 -0
  398. package/src/server-components/error.ts +24 -0
  399. package/src/server-components/frames.ts +181 -0
  400. package/src/server-components/html-policy.ts +94 -0
  401. package/src/server-components/html.ts +81 -0
  402. package/src/server-components/islands.ts +111 -0
  403. package/src/server-components/native.ts +101 -0
  404. package/src/server-components/portal.ts +42 -0
  405. package/src/server-components/props.ts +19 -0
  406. package/src/server-components/protocol.ts +167 -0
  407. package/src/server-components/range.ts +313 -0
  408. package/src/server-components/registry.ts +34 -0
  409. package/src/server-components/response.ts +44 -0
  410. package/src/server-components/router-integration.ts +40 -0
  411. package/src/server-components/runtime.ts +376 -0
  412. package/src/server-components/scheduler.ts +84 -0
  413. package/src/server-components/schema.ts +69 -0
  414. package/src/server-components/server-entry.ts +98 -0
  415. package/src/server-components/source.ts +324 -0
  416. package/src/server-components/state.ts +143 -0
  417. package/src/server-components/stream.ts +71 -0
  418. package/src/server-components/trusted-html.ts +21 -0
  419. package/src/server-components/types.ts +138 -0
  420. package/src/server-components/typescript.ts +39 -0
  421. package/src/server-components/value.ts +82 -0
  422. package/src/server-components/vite.ts +242 -0
  423. package/src/server-components.ts +32 -0
  424. package/src/service-worker.ts +24 -7
  425. package/src/vite.ts +8 -1
  426. package/src/zones.ts +418 -32
@@ -0,0 +1,111 @@
1
+ import type { StandardSchemaV1 } from "@nifrajs/core/server"
2
+ import type { ComponentKey, ComponentRecord, ServerComponentHandle } from "./types.ts"
3
+
4
+ const contractBrand = Symbol.for("nifra.components.island")
5
+ const viewBrand = Symbol.for("nifra.components.view")
6
+ export interface ClientIsland<Props = unknown, Component = unknown> {
7
+ readonly reference?: string
8
+ readonly props: StandardSchemaV1<unknown, Props>
9
+ readonly component: Component
10
+ readonly slots: readonly string[]
11
+ readonly [contractBrand]: true
12
+ }
13
+ type NativeComponentProps<Component> = Component extends abstract new (
14
+ ...args: never[]
15
+ ) => { $props: infer Props }
16
+ ? Props
17
+ : Component extends abstract new (
18
+ ...args: never[]
19
+ ) => { props: infer Props }
20
+ ? Props
21
+ : Component extends (...args: infer Args) => unknown
22
+ ? Args extends []
23
+ ? object
24
+ : // Optional legacy context is not a public props alternative (Preact types it as any).
25
+ Args extends [unknown, infer Props, ...unknown[]]
26
+ ? Args[0] | Props
27
+ : Args[0]
28
+ : never
29
+ type CompatibleComponent<Props, Component> =
30
+ Props extends NativeComponentProps<Component>
31
+ ? unknown
32
+ : { readonly __nifraIslandPropsMustMatchComponent: never }
33
+
34
+ export function defineClientIsland<Props, Component>(
35
+ definition: {
36
+ readonly props: StandardSchemaV1<unknown, Props>
37
+ readonly component: Component
38
+ readonly slots?: readonly string[]
39
+ } & CompatibleComponent<NoInfer<Props>, NoInfer<Component>>,
40
+ reference?: string,
41
+ ): ClientIsland<Props, Component> {
42
+ const slots = definition.slots ?? []
43
+ if (
44
+ slots.length > 16 ||
45
+ new Set(slots).size !== slots.length ||
46
+ slots.some(
47
+ (name) =>
48
+ !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(name) || ["ref", "key", "constructor"].includes(name),
49
+ )
50
+ )
51
+ throw new Error("component_contract")
52
+ const contract: ClientIsland<Props, Component> = {
53
+ props: definition.props,
54
+ component: definition.component,
55
+ slots: Object.freeze([...slots]),
56
+ [contractBrand]: true,
57
+ }
58
+ if (reference !== undefined) Object.assign(contract, { reference })
59
+ return Object.freeze(contract)
60
+ }
61
+ export interface IslandInstance {
62
+ readonly contract: ClientIsland
63
+ readonly key: ComponentKey
64
+ readonly props: unknown
65
+ readonly slots: Readonly<Record<string, string>>
66
+ }
67
+ export function clientIsland<Props>(
68
+ contract: ClientIsland<Props>,
69
+ key: ComponentKey,
70
+ props: NoInfer<Props>,
71
+ slots: Readonly<Record<string, string>> = {},
72
+ ): IslandInstance {
73
+ return { contract, key, props, slots }
74
+ }
75
+ export interface NativeServerView {
76
+ readonly component: unknown
77
+ readonly islands: Readonly<Record<string, IslandInstance>>
78
+ readonly ranges: Readonly<Record<string, ComponentRecord>>
79
+ readonly [viewBrand]: true
80
+ }
81
+ /** Server-only native view rendered by the selected framework's own renderer. */
82
+ export function nativeServerView(
83
+ component: unknown,
84
+ islands: Readonly<Record<string, IslandInstance>> = {},
85
+ ranges: Readonly<Record<string, ComponentRecord>> = {},
86
+ ): NativeServerView {
87
+ return { component, islands, ranges, [viewBrand]: true }
88
+ }
89
+ export function serverComponentChild(
90
+ children: readonly ComponentRecord[],
91
+ component: Pick<ServerComponentHandle, "reference">,
92
+ key: ComponentKey,
93
+ ): ComponentRecord {
94
+ const matches = children.filter(
95
+ (record) => record.reference === component.reference && record.key === key,
96
+ )
97
+ if (matches.length !== 1) throw new Error("component_contract")
98
+ return matches[0]!
99
+ }
100
+ export function isNativeServerView(value: unknown): value is NativeServerView {
101
+ return (
102
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before inspecting the private symbol brand created by this module.
103
+ typeof value === "object" && value !== null && (value as NativeServerView)[viewBrand] === true
104
+ )
105
+ }
106
+ export function isClientIsland(value: unknown): value is ClientIsland {
107
+ return (
108
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before inspecting the private symbol brand created by this module.
109
+ typeof value === "object" && value !== null && (value as ClientIsland)[contractBrand] === true
110
+ )
111
+ }
@@ -0,0 +1,101 @@
1
+ import { isClientIsland, isNativeServerView } from "./islands.ts"
2
+ import { guardComponentProps } from "./props.ts"
3
+ import { COMPONENT_LIMITS, componentKey } from "./protocol.ts"
4
+ import { componentToken } from "./state.ts"
5
+ import type { ComponentIsland, ServerComponentRenderAdapter } from "./types.ts"
6
+
7
+ export type NativeRender = (
8
+ component: unknown,
9
+ props: Record<string, unknown>,
10
+ renderId: string,
11
+ ) => string | Promise<string>
12
+ export function nativeServerComponents(
13
+ name: "vue" | "svelte" | "solid" | "preact",
14
+ render: NativeRender,
15
+ ): ServerComponentRenderAdapter {
16
+ return {
17
+ name,
18
+ version: 1,
19
+ async render(view, props, context) {
20
+ if (typeof view !== "function") throw new Error("component_contract")
21
+ const value: unknown = await view({ props, children: context.children ?? [] })
22
+ if (!isNativeServerView(value)) throw new Error("component_contract")
23
+ const entries = Object.entries(value.islands)
24
+ if (entries.length > COMPONENT_LIMITS.instances) throw new Error("component_limit")
25
+ const seen = new Set<string>()
26
+ const islands: ComponentIsland[] = []
27
+ const markup: Record<string, { readonly html: string; readonly renderId: string }> =
28
+ Object.create(null)
29
+ for (const [slot, instance] of entries) {
30
+ if (
31
+ !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(slot) ||
32
+ !isClientIsland(instance.contract) ||
33
+ !componentToken(instance.contract.reference) ||
34
+ !componentKey(instance.key) ||
35
+ Object.keys(instance.slots).some((name) => !instance.contract.slots.includes(name))
36
+ )
37
+ throw new Error("component_contract")
38
+ const digest = await crypto.subtle.digest(
39
+ "SHA-256",
40
+ new TextEncoder().encode(
41
+ JSON.stringify([context.instance, instance.contract.reference, instance.key]),
42
+ ),
43
+ )
44
+ const renderId = `i_${[...new Uint8Array(digest)].map((n) => n.toString(16).padStart(2, "0")).join("")}`
45
+ if (seen.has(renderId)) throw new Error("component_contract")
46
+ seen.add(renderId)
47
+ const projected = await guardComponentProps(instance.contract.props, instance.props)
48
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The closed schema guard and bounded JSON validator produced this public props object before native rendering.
49
+ const guarded = projected as Record<string, unknown> // Closed schema guard and JSON check own this boundary.
50
+ const slots = Object.fromEntries(
51
+ instance.contract.slots.map((name) => {
52
+ const html = instance.slots[name] ?? ""
53
+ if (typeof html !== "string") throw new Error("component_contract")
54
+ return [name, `<nifra-slot data-nifra-slot="${name}">${html}</nifra-slot>`]
55
+ }),
56
+ )
57
+ const html = await render(instance.contract.component, { ...guarded, slots }, renderId)
58
+ if (context.signal.aborted) throw new Error("component_cancelled")
59
+ markup[slot] = {
60
+ html: `<nifra-island data-nifra-island="${renderId}">${html}</nifra-island>`,
61
+ renderId,
62
+ }
63
+ islands.push({
64
+ reference: instance.contract.reference,
65
+ key: instance.key,
66
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The closed schema guard and bounded JSON validator produced this public props object before native rendering.
67
+ props: projected as ComponentIsland["props"],
68
+ renderId,
69
+ slots: instance.slots,
70
+ })
71
+ }
72
+ const ranges: Record<string, { html: string; instance: string }> = Object.create(null)
73
+ const rangeIds = new Set<string>()
74
+ for (const [name, child] of Object.entries(value.ranges)) {
75
+ if (
76
+ !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(name) ||
77
+ child.parent !== context.instance ||
78
+ !(context.children ?? []).includes(child) ||
79
+ rangeIds.has(child.instance)
80
+ )
81
+ throw new Error("component_contract")
82
+ rangeIds.add(child.instance)
83
+ ranges[name] = {
84
+ instance: child.instance,
85
+ html:
86
+ '<nifra-component data-nifra-component="' +
87
+ child.instance +
88
+ '">' +
89
+ child.html +
90
+ "</nifra-component>",
91
+ }
92
+ }
93
+ const html = await render(
94
+ value.component,
95
+ { props, islands: markup, ranges },
96
+ `${context.instance}-view`,
97
+ )
98
+ return { html, islands }
99
+ },
100
+ }
101
+ }
@@ -0,0 +1,42 @@
1
+ /** Resolve only a declared target inside the island or component that owns the calling node. */
2
+ export function componentPortalTarget(source: Element, target: Element): Element {
3
+ const owner = source.closest("[data-nifra-island], [data-nifra-component]")
4
+ const name = target.getAttribute("data-nifra-portal")
5
+ if (
6
+ owner === null ||
7
+ name === null ||
8
+ !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(name) ||
9
+ !owner.contains(target) ||
10
+ target.closest("[data-nifra-island], [data-nifra-component]") !== owner
11
+ )
12
+ throw new Error("component_contract")
13
+ return target
14
+ }
15
+
16
+ const cleanups = new WeakMap<Element, Set<() => Promise<void>>>()
17
+
18
+ /** Native portal actions register cleanup with the island that owns their target. */
19
+ export function ownComponentPortal(
20
+ source: Element,
21
+ target: Element,
22
+ cleanup: () => void | Promise<void>,
23
+ ): () => Promise<void> {
24
+ componentPortalTarget(source, target)
25
+ const owner = source.closest("[data-nifra-island], [data-nifra-component]")!
26
+ const entries = cleanups.get(owner) ?? new Set<() => Promise<void>>()
27
+ let pending: Promise<void> | undefined
28
+ const dispose = () => {
29
+ entries.delete(dispose)
30
+ pending ??= Promise.resolve().then(cleanup)
31
+ return pending
32
+ }
33
+ entries.add(dispose)
34
+ cleanups.set(owner, entries)
35
+ return dispose
36
+ }
37
+
38
+ export async function disposeComponentPortals(owner: Element): Promise<void> {
39
+ const entries = cleanups.get(owner)
40
+ cleanups.delete(owner)
41
+ if (entries !== undefined) await Promise.all([...entries].map((cleanup) => cleanup()))
42
+ }
@@ -0,0 +1,19 @@
1
+ import type { StandardSchemaV1 } from "@nifrajs/core/schema"
2
+ import { outputGuard, runGuard } from "../internal/output-guard.ts"
3
+ import { assertComponentSchema } from "./schema.ts"
4
+ import { componentValue } from "./value.ts"
5
+
6
+ const guards = new WeakMap<object, ReturnType<typeof outputGuard>>()
7
+
8
+ export async function guardComponentProps(
9
+ schema: StandardSchemaV1,
10
+ value: unknown,
11
+ ): Promise<unknown> {
12
+ let guard = guards.get(schema)
13
+ if (guard === undefined) {
14
+ assertComponentSchema(schema)
15
+ guard = outputGuard(schema, "client component", "props")
16
+ guards.set(schema, guard)
17
+ }
18
+ return componentValue(await runGuard(guard, value, "client component props"))
19
+ }
@@ -0,0 +1,167 @@
1
+ import { ServerComponentError } from "./error.ts"
2
+ import type { ComponentKey, ComponentValue } from "./types.ts"
3
+ import { componentValue } from "./value.ts"
4
+
5
+ export const COMPONENT_HEADER = "x-nifra-component"
6
+ export const COMPONENT_MEDIA_TYPE = "application/vnd.nifra.component-v1"
7
+ export const COMPONENT_PROTOCOL = 1
8
+ export const COMPONENT_LIMITS = Object.freeze({
9
+ headerBytes: 2048,
10
+ encodedHeaderBytes: 2732,
11
+ inputBytes: 1024,
12
+ propsBytes: 65536,
13
+ outputBytes: 1048576,
14
+ documentBytes: 4194304,
15
+ frameBytes: 262144,
16
+ depth: 16,
17
+ instances: 128,
18
+ requestLoads: 8,
19
+ activeLoads: 64,
20
+ queuedLoads: 128,
21
+ executionMs: 10000,
22
+ idleMs: 5000,
23
+ operationMs: 15000,
24
+ })
25
+
26
+ export interface ComponentRequest {
27
+ readonly v: 1
28
+ readonly build: string
29
+ readonly reference: string
30
+ readonly key: ComponentKey
31
+ readonly parent: string | null
32
+ readonly generation: number
33
+ readonly routeEpoch: number
34
+ readonly authEpoch: number
35
+ readonly input: ComponentValue
36
+ }
37
+
38
+ const fields = [
39
+ "v",
40
+ "build",
41
+ "reference",
42
+ "key",
43
+ "parent",
44
+ "generation",
45
+ "routeEpoch",
46
+ "authEpoch",
47
+ "input",
48
+ ]
49
+ const token = /^[A-Za-z0-9_-]{1,128}$/
50
+ const encoder = new TextEncoder()
51
+ const decoder = new TextDecoder("utf-8", { fatal: true })
52
+
53
+ export function componentKey(value: unknown): value is ComponentKey {
54
+ return (
55
+ (typeof value === "string" &&
56
+ encoder.encode(value).length > 0 &&
57
+ encoder.encode(value).length <= 128) ||
58
+ (typeof value === "number" && Number.isSafeInteger(value))
59
+ )
60
+ }
61
+
62
+ export function parseComponentRequest(value: unknown): ComponentRequest {
63
+ if (typeof value !== "object" || value === null || Array.isArray(value))
64
+ throw new ServerComponentError("component_protocol", 400)
65
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; every field is validated before a request is returned.
66
+ const object = value as Record<string, unknown>
67
+ if (
68
+ Object.keys(object).length !== fields.length ||
69
+ fields.some((name) => !Object.hasOwn(object, name)) ||
70
+ object.v !== 1 ||
71
+ typeof object.build !== "string" ||
72
+ !token.test(object.build) ||
73
+ typeof object.reference !== "string" ||
74
+ !token.test(object.reference) ||
75
+ !componentKey(object.key) ||
76
+ (object.parent !== null && (typeof object.parent !== "string" || !token.test(object.parent)))
77
+ ) {
78
+ throw new ServerComponentError("component_protocol", 400)
79
+ }
80
+ const counter = (value: unknown): number => {
81
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
82
+ throw new ServerComponentError("component_protocol", 400)
83
+ return value
84
+ }
85
+ const input = componentValue(object.input, COMPONENT_LIMITS.inputBytes)
86
+ return {
87
+ v: 1,
88
+ build: object.build,
89
+ reference: object.reference,
90
+ key: object.key,
91
+ parent: object.parent,
92
+ generation: counter(object.generation),
93
+ routeEpoch: counter(object.routeEpoch),
94
+ authEpoch: counter(object.authEpoch),
95
+ input,
96
+ }
97
+ }
98
+
99
+ function base64url(bytes: Uint8Array): string {
100
+ let binary = ""
101
+ for (const byte of bytes) binary += String.fromCharCode(byte)
102
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "")
103
+ }
104
+
105
+ export function componentRequestHeader(value: ComponentRequest): string {
106
+ const request = parseComponentRequest(value)
107
+ const bytes = encoder.encode(JSON.stringify(request))
108
+ if (bytes.length > COMPONENT_LIMITS.headerBytes)
109
+ throw new ServerComponentError("component_limit", 431)
110
+ return base64url(bytes)
111
+ }
112
+
113
+ export function readComponentRequest(request: Request): ComponentRequest | undefined {
114
+ const encoded = request.headers.get(COMPONENT_HEADER)
115
+ if (encoded === null) return undefined
116
+ if (
117
+ request.method !== "GET" ||
118
+ request.headers.has("x-nifra-data") ||
119
+ request.headers.has("x-nifra-retain") ||
120
+ request.headers.has("x-nifra-revalidate") ||
121
+ request.headers.has("x-nifra-from")
122
+ )
123
+ throw new ServerComponentError("component_protocol", 400)
124
+ if (encoded.length > COMPONENT_LIMITS.encodedHeaderBytes)
125
+ throw new ServerComponentError("component_limit", 431)
126
+ if (!/^[A-Za-z0-9_-]+$/.test(encoded) || encoded.length % 4 === 1)
127
+ throw new ServerComponentError("component_protocol", 400)
128
+ const origin = new URL(request.url).origin
129
+ if (
130
+ request.headers.get("sec-fetch-site") !== "same-origin" ||
131
+ (request.headers.has("origin") && request.headers.get("origin") !== origin)
132
+ ) {
133
+ throw new ServerComponentError("component_denied", 403)
134
+ }
135
+ let decoded: unknown
136
+ try {
137
+ const binary = atob(encoded.replaceAll("-", "+").replaceAll("_", "/"))
138
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0))
139
+ if (bytes.length > COMPONENT_LIMITS.headerBytes)
140
+ throw new ServerComponentError("component_limit", 431)
141
+ if (base64url(bytes) !== encoded) throw new ServerComponentError("component_protocol", 400)
142
+ decoded = JSON.parse(decoder.decode(bytes))
143
+ } catch (error) {
144
+ if (error instanceof ServerComponentError) throw error
145
+ throw new ServerComponentError("component_protocol", 400)
146
+ }
147
+ return parseComponentRequest(decoded)
148
+ }
149
+
150
+ export const COMPONENT_RESPONSE_HEADERS = Object.freeze({
151
+ "content-type": COMPONENT_MEDIA_TYPE,
152
+ "cache-control": "private, no-store",
153
+ "x-content-type-options": "nosniff",
154
+ vary: "x-nifra-component, x-nifra-data",
155
+ })
156
+
157
+ export function componentFailure(error: unknown): Response {
158
+ const failure =
159
+ error instanceof ServerComponentError ? error : new ServerComponentError("component_failed")
160
+ return Response.json(
161
+ { v: 1, error: failure.code },
162
+ {
163
+ status: failure.status === 499 ? 409 : failure.status,
164
+ headers: { ...COMPONENT_RESPONSE_HEADERS, "content-type": "application/json" },
165
+ },
166
+ )
167
+ }