@nifrajs/web 5.5.1 → 5.6.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 (457) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/dist/boundary.d.ts +67 -7
  3. package/dist/boundary.d.ts.map +1 -1
  4. package/dist/boundary.js +6 -4
  5. package/dist/boundary.js.map +1 -1
  6. package/dist/build-plan.d.ts +3 -0
  7. package/dist/build-plan.d.ts.map +1 -1
  8. package/dist/build-plan.js.map +1 -1
  9. package/dist/build-vite.d.ts.map +1 -1
  10. package/dist/build-vite.js +2 -0
  11. package/dist/build-vite.js.map +1 -1
  12. package/dist/build.d.ts +9 -2
  13. package/dist/build.d.ts.map +1 -1
  14. package/dist/build.js +9 -0
  15. package/dist/build.js.map +1 -1
  16. package/dist/client.d.ts +2 -1
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +140 -12
  19. package/dist/client.js.map +1 -1
  20. package/dist/csp.d.ts +8 -0
  21. package/dist/csp.d.ts.map +1 -1
  22. package/dist/csp.js +11 -2
  23. package/dist/csp.js.map +1 -1
  24. package/dist/deferred.d.ts +6 -4
  25. package/dist/deferred.d.ts.map +1 -1
  26. package/dist/deferred.js +10 -6
  27. package/dist/deferred.js.map +1 -1
  28. package/dist/dev-feed.d.ts.map +1 -1
  29. package/dist/dev-feed.js +11 -2
  30. package/dist/dev-feed.js.map +1 -1
  31. package/dist/dev-session.d.ts.map +1 -1
  32. package/dist/dev-session.js +13 -6
  33. package/dist/dev-session.js.map +1 -1
  34. package/dist/dev.d.ts +4 -1
  35. package/dist/dev.d.ts.map +1 -1
  36. package/dist/dev.js +12 -5
  37. package/dist/dev.js.map +1 -1
  38. package/dist/diagnostic-catalog.d.ts +4 -0
  39. package/dist/diagnostic-catalog.d.ts.map +1 -1
  40. package/dist/diagnostic-catalog.js +48 -0
  41. package/dist/diagnostic-catalog.js.map +1 -1
  42. package/dist/diagnostic.d.ts +1 -1
  43. package/dist/diagnostic.d.ts.map +1 -1
  44. package/dist/diagnostic.js +1 -1
  45. package/dist/diagnostic.js.map +1 -1
  46. package/dist/fn.d.ts +5 -3
  47. package/dist/fn.d.ts.map +1 -1
  48. package/dist/fn.js +20 -5
  49. package/dist/fn.js.map +1 -1
  50. package/dist/fs.d.ts.map +1 -1
  51. package/dist/fs.js +13 -3
  52. package/dist/fs.js.map +1 -1
  53. package/dist/identity.d.ts +22 -0
  54. package/dist/identity.d.ts.map +1 -0
  55. package/dist/identity.js +60 -0
  56. package/dist/identity.js.map +1 -0
  57. package/dist/index.d.ts +7 -6
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +4 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/internal/cdn/cloudflare.d.ts +2 -1
  62. package/dist/internal/cdn/cloudflare.d.ts.map +1 -1
  63. package/dist/internal/cdn/cloudflare.js +2 -1
  64. package/dist/internal/cdn/cloudflare.js.map +1 -1
  65. package/dist/internal/certified-components.d.ts +1 -1
  66. package/dist/internal/certified-components.js +1 -1
  67. package/dist/internal/codegen.d.ts +11 -10
  68. package/dist/internal/codegen.d.ts.map +1 -1
  69. package/dist/internal/codegen.js +65 -8
  70. package/dist/internal/codegen.js.map +1 -1
  71. package/dist/internal/dev-websocket.d.ts +73 -0
  72. package/dist/internal/dev-websocket.d.ts.map +1 -0
  73. package/dist/internal/dev-websocket.js +145 -0
  74. package/dist/internal/dev-websocket.js.map +1 -0
  75. package/dist/internal/hole-runtime.d.ts +66 -0
  76. package/dist/internal/hole-runtime.d.ts.map +1 -0
  77. package/dist/internal/hole-runtime.js +211 -0
  78. package/dist/internal/hole-runtime.js.map +1 -0
  79. package/dist/internal/identity-epoch.d.ts +50 -0
  80. package/dist/internal/identity-epoch.d.ts.map +1 -0
  81. package/dist/internal/identity-epoch.js +179 -0
  82. package/dist/internal/identity-epoch.js.map +1 -0
  83. package/dist/internal/invalidation-contract.d.ts +23 -0
  84. package/dist/internal/invalidation-contract.d.ts.map +1 -0
  85. package/dist/internal/invalidation-contract.js +11 -0
  86. package/dist/internal/invalidation-contract.js.map +1 -0
  87. package/dist/internal/invalidation.d.ts +62 -0
  88. package/dist/internal/invalidation.d.ts.map +1 -0
  89. package/dist/internal/invalidation.js +149 -0
  90. package/dist/internal/invalidation.js.map +1 -0
  91. package/dist/internal/island-bindings.d.ts +51 -0
  92. package/dist/internal/island-bindings.d.ts.map +1 -0
  93. package/dist/internal/island-bindings.js +147 -0
  94. package/dist/internal/island-bindings.js.map +1 -0
  95. package/dist/internal/island-list.d.ts +26 -0
  96. package/dist/internal/island-list.d.ts.map +1 -0
  97. package/dist/internal/island-list.js +78 -0
  98. package/dist/internal/island-list.js.map +1 -0
  99. package/dist/internal/island-mount.d.ts +4 -0
  100. package/dist/internal/island-mount.d.ts.map +1 -0
  101. package/dist/internal/island-mount.js +66 -0
  102. package/dist/internal/island-mount.js.map +1 -0
  103. package/dist/internal/island-owner.d.ts +5 -0
  104. package/dist/internal/island-owner.d.ts.map +1 -0
  105. package/dist/internal/island-owner.js +20 -0
  106. package/dist/internal/island-owner.js.map +1 -0
  107. package/dist/internal/island-resource.d.ts +30 -0
  108. package/dist/internal/island-resource.d.ts.map +1 -0
  109. package/dist/internal/island-resource.js +57 -0
  110. package/dist/internal/island-resource.js.map +1 -0
  111. package/dist/internal/island-signals.d.ts +51 -0
  112. package/dist/internal/island-signals.d.ts.map +1 -0
  113. package/dist/internal/island-signals.js +220 -0
  114. package/dist/internal/island-signals.js.map +1 -0
  115. package/dist/internal/keep-alive-table.d.ts +23 -0
  116. package/dist/internal/keep-alive-table.d.ts.map +1 -0
  117. package/dist/internal/keep-alive-table.js +53 -0
  118. package/dist/internal/keep-alive-table.js.map +1 -0
  119. package/dist/internal/live-contract.d.ts +96 -0
  120. package/dist/internal/live-contract.d.ts.map +1 -0
  121. package/dist/internal/live-contract.js +5 -0
  122. package/dist/internal/live-contract.js.map +1 -0
  123. package/dist/internal/live-queries.d.ts +22 -0
  124. package/dist/internal/live-queries.d.ts.map +1 -0
  125. package/dist/internal/live-queries.js +54 -0
  126. package/dist/internal/live-queries.js.map +1 -0
  127. package/dist/internal/page-events.d.ts +10 -0
  128. package/dist/internal/page-events.d.ts.map +1 -0
  129. package/dist/internal/page-events.js +26 -0
  130. package/dist/internal/page-events.js.map +1 -0
  131. package/dist/internal/page-execution.d.ts +14 -1
  132. package/dist/internal/page-execution.d.ts.map +1 -1
  133. package/dist/internal/page-execution.js +415 -31
  134. package/dist/internal/page-execution.js.map +1 -1
  135. package/dist/internal/ppr/admission.d.ts +83 -0
  136. package/dist/internal/ppr/admission.d.ts.map +1 -0
  137. package/dist/internal/ppr/admission.js +221 -0
  138. package/dist/internal/ppr/admission.js.map +1 -0
  139. package/dist/internal/ppr/canary.d.ts +24 -0
  140. package/dist/internal/ppr/canary.d.ts.map +1 -0
  141. package/dist/internal/ppr/canary.js +102 -0
  142. package/dist/internal/ppr/canary.js.map +1 -0
  143. package/dist/internal/ppr/compile-shell.d.ts +39 -0
  144. package/dist/internal/ppr/compile-shell.d.ts.map +1 -0
  145. package/dist/internal/ppr/compile-shell.js +298 -0
  146. package/dist/internal/ppr/compile-shell.js.map +1 -0
  147. package/dist/internal/ppr/contract.d.ts +177 -0
  148. package/dist/internal/ppr/contract.d.ts.map +1 -0
  149. package/dist/internal/ppr/contract.js +80 -0
  150. package/dist/internal/ppr/contract.js.map +1 -0
  151. package/dist/internal/ppr/frames.d.ts +71 -0
  152. package/dist/internal/ppr/frames.d.ts.map +1 -0
  153. package/dist/internal/ppr/frames.js +119 -0
  154. package/dist/internal/ppr/frames.js.map +1 -0
  155. package/dist/internal/ppr/integration.d.ts +19 -0
  156. package/dist/internal/ppr/integration.d.ts.map +1 -0
  157. package/dist/internal/ppr/integration.js +106 -0
  158. package/dist/internal/ppr/integration.js.map +1 -0
  159. package/dist/internal/ppr/options.d.ts +96 -0
  160. package/dist/internal/ppr/options.d.ts.map +1 -0
  161. package/dist/internal/ppr/options.js +125 -0
  162. package/dist/internal/ppr/options.js.map +1 -0
  163. package/dist/internal/ppr/route-rules.d.ts +12 -0
  164. package/dist/internal/ppr/route-rules.d.ts.map +1 -0
  165. package/dist/internal/ppr/route-rules.js +53 -0
  166. package/dist/internal/ppr/route-rules.js.map +1 -0
  167. package/dist/internal/ppr/runtime.d.ts +29 -0
  168. package/dist/internal/ppr/runtime.d.ts.map +1 -0
  169. package/dist/internal/ppr/runtime.js +32 -0
  170. package/dist/internal/ppr/runtime.js.map +1 -0
  171. package/dist/internal/ppr/server.d.ts +29 -0
  172. package/dist/internal/ppr/server.d.ts.map +1 -0
  173. package/dist/internal/ppr/server.js +1407 -0
  174. package/dist/internal/ppr/server.js.map +1 -0
  175. package/dist/internal/ppr/shell-store.d.ts +38 -0
  176. package/dist/internal/ppr/shell-store.d.ts.map +1 -0
  177. package/dist/internal/ppr/shell-store.js +90 -0
  178. package/dist/internal/ppr/shell-store.js.map +1 -0
  179. package/dist/internal/prerendered-pages.d.ts +1 -1
  180. package/dist/internal/prerendered-pages.d.ts.map +1 -1
  181. package/dist/internal/prerendered-pages.js +7 -4
  182. package/dist/internal/prerendered-pages.js.map +1 -1
  183. package/dist/internal/query-digest.d.ts +9 -0
  184. package/dist/internal/query-digest.d.ts.map +1 -0
  185. package/dist/internal/query-digest.js +23 -0
  186. package/dist/internal/query-digest.js.map +1 -0
  187. package/dist/internal/query-runtime.d.ts +6 -1
  188. package/dist/internal/query-runtime.d.ts.map +1 -1
  189. package/dist/internal/query-runtime.js +9 -0
  190. package/dist/internal/query-runtime.js.map +1 -1
  191. package/dist/internal/query-seam.d.ts +29 -0
  192. package/dist/internal/query-seam.d.ts.map +1 -0
  193. package/dist/internal/query-seam.js +23 -0
  194. package/dist/internal/query-seam.js.map +1 -0
  195. package/dist/internal/render-document.d.ts +28 -1
  196. package/dist/internal/render-document.d.ts.map +1 -1
  197. package/dist/internal/render-document.js +83 -18
  198. package/dist/internal/render-document.js.map +1 -1
  199. package/dist/internal/request-abort.d.ts +8 -0
  200. package/dist/internal/request-abort.d.ts.map +1 -0
  201. package/dist/internal/request-abort.js +22 -0
  202. package/dist/internal/request-abort.js.map +1 -0
  203. package/dist/internal/server-boundary.d.ts +2 -0
  204. package/dist/internal/server-boundary.d.ts.map +1 -1
  205. package/dist/internal/server-boundary.js +8 -1
  206. package/dist/internal/server-boundary.js.map +1 -1
  207. package/dist/internal/share-data.d.ts +10 -0
  208. package/dist/internal/share-data.d.ts.map +1 -0
  209. package/dist/internal/share-data.js +135 -0
  210. package/dist/internal/share-data.js.map +1 -0
  211. package/dist/internal/store-signature.d.ts +15 -0
  212. package/dist/internal/store-signature.d.ts.map +1 -0
  213. package/dist/internal/store-signature.js +114 -0
  214. package/dist/internal/store-signature.js.map +1 -0
  215. package/dist/internal/vite-plugin-compat.d.ts +2 -2
  216. package/dist/internal/vite-plugin-compat.js +2 -2
  217. package/dist/internal/web-app.d.ts +25 -0
  218. package/dist/internal/web-app.d.ts.map +1 -1
  219. package/dist/internal/web-app.js +78 -3
  220. package/dist/internal/web-app.js.map +1 -1
  221. package/dist/islands-swap.d.ts +41 -0
  222. package/dist/islands-swap.d.ts.map +1 -0
  223. package/dist/islands-swap.js +270 -0
  224. package/dist/islands-swap.js.map +1 -0
  225. package/dist/islands.d.ts +86 -24
  226. package/dist/islands.d.ts.map +1 -1
  227. package/dist/islands.js +138 -78
  228. package/dist/islands.js.map +1 -1
  229. package/dist/isr.d.ts +67 -13
  230. package/dist/isr.d.ts.map +1 -1
  231. package/dist/isr.js +247 -99
  232. package/dist/isr.js.map +1 -1
  233. package/dist/keep-alive.d.ts +147 -0
  234. package/dist/keep-alive.d.ts.map +1 -0
  235. package/dist/keep-alive.js +1069 -0
  236. package/dist/keep-alive.js.map +1 -0
  237. package/dist/live/bus.d.ts +56 -0
  238. package/dist/live/bus.d.ts.map +1 -0
  239. package/dist/live/bus.js +32 -0
  240. package/dist/live/bus.js.map +1 -0
  241. package/dist/live/core.d.ts +25 -0
  242. package/dist/live/core.d.ts.map +1 -0
  243. package/dist/live/core.js +29 -0
  244. package/dist/live/core.js.map +1 -0
  245. package/dist/live/history.d.ts +38 -0
  246. package/dist/live/history.d.ts.map +1 -0
  247. package/dist/live/history.js +104 -0
  248. package/dist/live/history.js.map +1 -0
  249. package/dist/live/hub-protocol.d.ts +46 -0
  250. package/dist/live/hub-protocol.d.ts.map +1 -0
  251. package/dist/live/hub-protocol.js +108 -0
  252. package/dist/live/hub-protocol.js.map +1 -0
  253. package/dist/live/hub.d.ts +181 -0
  254. package/dist/live/hub.d.ts.map +1 -0
  255. package/dist/live/hub.js +539 -0
  256. package/dist/live/hub.js.map +1 -0
  257. package/dist/live/keyring.d.ts +87 -0
  258. package/dist/live/keyring.d.ts.map +1 -0
  259. package/dist/live/keyring.js +260 -0
  260. package/dist/live/keyring.js.map +1 -0
  261. package/dist/live/read-capped.d.ts +6 -0
  262. package/dist/live/read-capped.d.ts.map +1 -0
  263. package/dist/live/read-capped.js +42 -0
  264. package/dist/live/read-capped.js.map +1 -0
  265. package/dist/live/revocations.d.ts +52 -0
  266. package/dist/live/revocations.d.ts.map +1 -0
  267. package/dist/live/revocations.js +116 -0
  268. package/dist/live/revocations.js.map +1 -0
  269. package/dist/live/settings.d.ts +14 -0
  270. package/dist/live/settings.d.ts.map +1 -0
  271. package/dist/live/settings.js +38 -0
  272. package/dist/live/settings.js.map +1 -0
  273. package/dist/live-client.d.ts +34 -0
  274. package/dist/live-client.d.ts.map +1 -0
  275. package/dist/live-client.js +840 -0
  276. package/dist/live-client.js.map +1 -0
  277. package/dist/live-hub.d.ts +130 -0
  278. package/dist/live-hub.d.ts.map +1 -0
  279. package/dist/live-hub.js +507 -0
  280. package/dist/live-hub.js.map +1 -0
  281. package/dist/live-redis.d.ts +48 -0
  282. package/dist/live-redis.d.ts.map +1 -0
  283. package/dist/live-redis.js +201 -0
  284. package/dist/live-redis.js.map +1 -0
  285. package/dist/live.d.ts +94 -0
  286. package/dist/live.d.ts.map +1 -0
  287. package/dist/live.js +869 -0
  288. package/dist/live.js.map +1 -0
  289. package/dist/manifest.d.ts +113 -2
  290. package/dist/manifest.d.ts.map +1 -1
  291. package/dist/manifest.js +109 -5
  292. package/dist/manifest.js.map +1 -1
  293. package/dist/navigation.d.ts +9 -3
  294. package/dist/navigation.d.ts.map +1 -1
  295. package/dist/navigation.js +13 -3
  296. package/dist/navigation.js.map +1 -1
  297. package/dist/plugins/vite-zone-guard.d.ts +6 -0
  298. package/dist/plugins/vite-zone-guard.d.ts.map +1 -1
  299. package/dist/plugins/vite-zone-guard.js +8 -2
  300. package/dist/plugins/vite-zone-guard.js.map +1 -1
  301. package/dist/ppr.d.ts +73 -0
  302. package/dist/ppr.d.ts.map +1 -0
  303. package/dist/ppr.js +76 -0
  304. package/dist/ppr.js.map +1 -0
  305. package/dist/query.d.ts +8 -13
  306. package/dist/query.d.ts.map +1 -1
  307. package/dist/query.js +112 -18
  308. package/dist/query.js.map +1 -1
  309. package/dist/render-seam.d.ts +30 -0
  310. package/dist/render-seam.d.ts.map +1 -1
  311. package/dist/render-seam.js +5 -0
  312. package/dist/render-seam.js.map +1 -1
  313. package/dist/route-types.d.ts.map +1 -1
  314. package/dist/route-types.js +2 -2
  315. package/dist/route-types.js.map +1 -1
  316. package/dist/router.d.ts +72 -4
  317. package/dist/router.d.ts.map +1 -1
  318. package/dist/router.js +374 -99
  319. package/dist/router.js.map +1 -1
  320. package/dist/server-components/build.d.ts.map +1 -1
  321. package/dist/server-components/build.js +3 -3
  322. package/dist/server-components/build.js.map +1 -1
  323. package/dist/server-components/client.d.ts +23 -1
  324. package/dist/server-components/client.d.ts.map +1 -1
  325. package/dist/server-components/client.js +92 -5
  326. package/dist/server-components/client.js.map +1 -1
  327. package/dist/server-components/hole.d.ts +8 -0
  328. package/dist/server-components/hole.d.ts.map +1 -0
  329. package/dist/server-components/hole.js +20 -0
  330. package/dist/server-components/hole.js.map +1 -0
  331. package/dist/server-components/html-policy.d.ts.map +1 -1
  332. package/dist/server-components/html-policy.js +62 -4
  333. package/dist/server-components/html-policy.js.map +1 -1
  334. package/dist/server-components/html-scan.d.ts +17 -0
  335. package/dist/server-components/html-scan.d.ts.map +1 -0
  336. package/dist/server-components/html-scan.js +180 -0
  337. package/dist/server-components/html-scan.js.map +1 -0
  338. package/dist/server-components/html.d.ts.map +1 -1
  339. package/dist/server-components/html.js +19 -4
  340. package/dist/server-components/html.js.map +1 -1
  341. package/dist/server-components/router-integration.d.ts +4 -1
  342. package/dist/server-components/router-integration.d.ts.map +1 -1
  343. package/dist/server-components/router-integration.js +23 -2
  344. package/dist/server-components/router-integration.js.map +1 -1
  345. package/dist/server-components/runtime.d.ts +6 -1
  346. package/dist/server-components/runtime.d.ts.map +1 -1
  347. package/dist/server-components/runtime.js +86 -28
  348. package/dist/server-components/runtime.js.map +1 -1
  349. package/dist/server-components/state.d.ts +3 -1
  350. package/dist/server-components/state.d.ts.map +1 -1
  351. package/dist/server-components/state.js +50 -38
  352. package/dist/server-components/state.js.map +1 -1
  353. package/dist/server-components/types.d.ts +9 -0
  354. package/dist/server-components/types.d.ts.map +1 -1
  355. package/dist/vite.d.ts +5 -1
  356. package/dist/vite.d.ts.map +1 -1
  357. package/dist/vite.js +58 -4
  358. package/dist/vite.js.map +1 -1
  359. package/package.json +48 -8
  360. package/src/boundary.ts +77 -5
  361. package/src/build-plan.ts +3 -0
  362. package/src/build-vite.ts +2 -0
  363. package/src/build.ts +19 -1
  364. package/src/client.ts +147 -10
  365. package/src/csp.ts +16 -2
  366. package/src/deferred.ts +11 -5
  367. package/src/dev-feed.ts +11 -2
  368. package/src/dev-session.ts +22 -11
  369. package/src/dev.ts +29 -8
  370. package/src/diagnostic-catalog.ts +53 -0
  371. package/src/diagnostic.ts +1 -0
  372. package/src/fn.ts +24 -7
  373. package/src/fs.ts +22 -8
  374. package/src/identity.ts +61 -0
  375. package/src/index.ts +19 -0
  376. package/src/internal/cdn/cloudflare.ts +2 -1
  377. package/src/internal/certified-components.ts +1 -1
  378. package/src/internal/codegen.ts +87 -8
  379. package/src/internal/dev-websocket.ts +230 -0
  380. package/src/internal/hole-runtime.ts +286 -0
  381. package/src/internal/identity-epoch.ts +235 -0
  382. package/src/internal/invalidation-contract.ts +35 -0
  383. package/src/internal/invalidation.ts +213 -0
  384. package/src/internal/island-bindings.ts +191 -0
  385. package/src/internal/island-list.ts +92 -0
  386. package/src/internal/island-mount.ts +68 -0
  387. package/src/internal/island-owner.ts +20 -0
  388. package/src/internal/island-resource.ts +76 -0
  389. package/src/internal/island-signals.ts +249 -0
  390. package/src/internal/keep-alive-table.ts +72 -0
  391. package/src/internal/live-contract.ts +106 -0
  392. package/src/internal/live-queries.ts +60 -0
  393. package/src/internal/page-events.ts +27 -0
  394. package/src/internal/page-execution.ts +579 -40
  395. package/src/internal/ppr/admission.ts +300 -0
  396. package/src/internal/ppr/canary.ts +122 -0
  397. package/src/internal/ppr/compile-shell.ts +379 -0
  398. package/src/internal/ppr/contract.ts +265 -0
  399. package/src/internal/ppr/frames.ts +170 -0
  400. package/src/internal/ppr/integration.ts +137 -0
  401. package/src/internal/ppr/options.ts +221 -0
  402. package/src/internal/ppr/route-rules.ts +77 -0
  403. package/src/internal/ppr/runtime.ts +36 -0
  404. package/src/internal/ppr/server.ts +1764 -0
  405. package/src/internal/ppr/shell-store.ts +139 -0
  406. package/src/internal/prerendered-pages.ts +7 -4
  407. package/src/internal/query-digest.ts +34 -0
  408. package/src/internal/query-runtime.ts +14 -1
  409. package/src/internal/query-seam.ts +48 -0
  410. package/src/internal/render-document.ts +149 -22
  411. package/src/internal/request-abort.ts +26 -0
  412. package/src/internal/server-boundary.ts +10 -1
  413. package/src/internal/share-data.ts +136 -0
  414. package/src/internal/store-signature.ts +149 -0
  415. package/src/internal/vite-plugin-compat.ts +2 -2
  416. package/src/internal/web-app.ts +121 -3
  417. package/src/islands-swap.ts +283 -0
  418. package/src/islands.ts +169 -72
  419. package/src/isr.ts +348 -106
  420. package/src/keep-alive.ts +1315 -0
  421. package/src/live/bus.ts +77 -0
  422. package/src/live/core.ts +52 -0
  423. package/src/live/history.ts +109 -0
  424. package/src/live/hub-protocol.ts +133 -0
  425. package/src/live/hub.ts +615 -0
  426. package/src/live/keyring.ts +379 -0
  427. package/src/live/read-capped.ts +36 -0
  428. package/src/live/revocations.ts +155 -0
  429. package/src/live/settings.ts +46 -0
  430. package/src/live-client.ts +973 -0
  431. package/src/live-hub.ts +658 -0
  432. package/src/live-redis.ts +259 -0
  433. package/src/live.ts +1096 -0
  434. package/src/manifest.ts +274 -6
  435. package/src/navigation.ts +14 -2
  436. package/src/plugins/vite-zone-guard.ts +15 -2
  437. package/src/ppr.ts +153 -0
  438. package/src/query.ts +147 -20
  439. package/src/render-seam.ts +35 -0
  440. package/src/route-types.ts +3 -1
  441. package/src/router.ts +494 -101
  442. package/src/server-components/build.ts +9 -3
  443. package/src/server-components/client.ts +89 -5
  444. package/src/server-components/hole.ts +23 -0
  445. package/src/server-components/html-policy.ts +63 -4
  446. package/src/server-components/html-scan.ts +159 -0
  447. package/src/server-components/html.ts +18 -4
  448. package/src/server-components/router-integration.ts +21 -2
  449. package/src/server-components/runtime.ts +112 -30
  450. package/src/server-components/state.ts +66 -44
  451. package/src/server-components/types.ts +16 -0
  452. package/src/vite.ts +75 -6
  453. package/dist/nano.d.ts +0 -125
  454. package/dist/nano.d.ts.map +0 -1
  455. package/dist/nano.js +0 -190
  456. package/dist/nano.js.map +0 -1
  457. package/src/nano.ts +0 -246
@@ -20,9 +20,11 @@ import {
20
20
  import { BoundedComponentTasks, componentAbort } from "./scheduler.ts"
21
21
  import { componentValue } from "./schema.ts"
22
22
  import type {
23
+ ComponentHoles,
23
24
  ComponentInstance,
24
25
  ComponentOwner,
25
26
  ComponentRecord,
27
+ ComponentRender,
26
28
  ServerComponent,
27
29
  ServerComponentContext,
28
30
  ServerComponentHandle,
@@ -42,6 +44,11 @@ export interface ServerComponentsOptions {
42
44
  readonly build: string
43
45
  readonly adapter: ServerComponentRenderAdapter
44
46
  readonly owners: Readonly<Record<string, ComponentOwner>>
47
+ /**
48
+ * Experimental: route id to the server components its partially prerendered holes may show, each
49
+ * through `serverHole`. A route is an owner or hosts holes, never both.
50
+ */
51
+ readonly holes?: Readonly<Record<string, ComponentHoles>>
45
52
  readonly capabilities?: readonly CapabilityDefinition[]
46
53
  readonly assets?: readonly string[]
47
54
  }
@@ -103,20 +110,19 @@ export function createServerComponents(options: ServerComponentsOptions): Server
103
110
  )
104
111
  if (capabilities.size !== (options.capabilities?.length ?? 0))
105
112
  throw new ServerComponentError("component_contract")
106
- for (const [routeId, owner] of Object.entries(options.owners)) {
107
- if (
108
- typeof owner.instances !== "function" ||
109
- (owner.scope !== "anonymous" && typeof owner.scope !== "function")
110
- )
111
- throw new ServerComponentError("component_contract")
113
+ /** A route's component allowlist, by reference, each within the capabilities the route grants. */
114
+ const allowlist = (
115
+ list: readonly ServerComponentHandle[],
116
+ granted: readonly string[] = [],
117
+ ): ReadonlyMap<string, ServerComponentHandle> => {
112
118
  const components = new Map<string, ServerComponentHandle>()
113
- const allowed = new Set(owner.capabilities ?? [])
119
+ const allowed = new Set(granted)
114
120
  for (const capability of allowed) {
115
121
  const declared = capabilities.get(capability)
116
122
  if (declared === undefined || (declared.zone === "domain" && declared.access !== "read"))
117
123
  throw new ServerComponentError("component_contract")
118
124
  }
119
- for (const component of owner.components) {
125
+ for (const component of list) {
120
126
  if (
121
127
  !isServerComponent(component) ||
122
128
  component.reference === undefined ||
@@ -128,11 +134,106 @@ export function createServerComponents(options: ServerComponentsOptions): Server
128
134
  if (serverComponentCapabilities(component).some((capability) => !allowed.has(capability)))
129
135
  throw new ServerComponentError("component_contract")
130
136
  }
131
- owners.set(routeId, { owner, components })
137
+ return components
138
+ }
139
+ for (const [routeId, owner] of Object.entries(options.owners)) {
140
+ if (
141
+ typeof owner.instances !== "function" ||
142
+ (owner.scope !== "anonymous" && typeof owner.scope !== "function")
143
+ )
144
+ throw new ServerComponentError("component_contract")
145
+ owners.set(routeId, { owner, components: allowlist(owner.components, owner.capabilities) })
146
+ }
147
+ const holes = new Map<
148
+ string,
149
+ { capabilities: readonly string[]; components: ReadonlyMap<string, ServerComponentHandle> }
150
+ >()
151
+ for (const [routeId, entry] of Object.entries(options.holes ?? {})) {
152
+ // An owner route renders whole, so its holes never run.
153
+ if (owners.has(routeId) || !Array.isArray(entry.components))
154
+ throw new ServerComponentError("component_contract")
155
+ holes.set(routeId, {
156
+ capabilities: entry.capabilities ?? [],
157
+ components: allowlist(entry.components, entry.capabilities),
158
+ })
159
+ }
160
+ /** A rendered instance as a record: its range HTML checked, its payload and island props public. */
161
+ const recordOf = (
162
+ instance: {
163
+ readonly id: string
164
+ readonly reference: string
165
+ readonly key: ComponentRecord["key"]
166
+ readonly parent?: string | undefined
167
+ readonly input: ComponentRecord["input"]
168
+ },
169
+ rendered: ComponentRender,
170
+ ): ComponentRecord => {
171
+ const record: ComponentRecord = {
172
+ instance: instance.id,
173
+ reference: instance.reference,
174
+ key: instance.key,
175
+ parent: instance.parent ?? null,
176
+ input: instance.input,
177
+ html: componentRangeHTML(rendered.html, assets),
178
+ }
179
+ if (rendered.payload !== undefined)
180
+ Object.assign(record, {
181
+ payload: componentValue(rendered.payload, COMPONENT_LIMITS.outputBytes),
182
+ })
183
+ if (rendered.islands !== undefined)
184
+ Object.assign(record, {
185
+ islands: rendered.islands.map((island) => ({
186
+ ...island,
187
+ props: componentValue(island.props),
188
+ })),
189
+ })
190
+ return record
132
191
  }
133
192
  return {
134
193
  owns: (routeId) => owners.has(routeId),
135
- capabilities: (routeId) => owners.get(routeId)?.owner.capabilities ?? [],
194
+ capabilities: (routeId) =>
195
+ owners.get(routeId)?.owner.capabilities ?? holes.get(routeId)?.capabilities ?? [],
196
+ hosts: (routeId) => holes.has(routeId),
197
+ async hole(routeId, component, key, input, context) {
198
+ const reference = isServerComponent(component) ? component.reference : undefined
199
+ const handle =
200
+ reference === undefined ? undefined : holes.get(routeId)?.components.get(reference)
201
+ if (
202
+ reference === undefined ||
203
+ handle === undefined ||
204
+ handle !== component ||
205
+ !componentKey(key)
206
+ )
207
+ throw new ServerComponentError("component_contract")
208
+ const signal = AbortSignal.any([
209
+ context.signal,
210
+ AbortSignal.timeout(COMPONENT_LIMITS.executionMs),
211
+ ])
212
+ const ctx: ServerComponentContext = Object.create(context, {
213
+ signal: { value: signal, enumerable: true },
214
+ })
215
+ const value = componentValue(input, COMPONENT_LIMITS.inputBytes)
216
+ const id = await serverComponentIdentity(routeId, handle, key, null)
217
+ return admission.run(signal, async () => {
218
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The route's hole allowlist identifies this handle; authorization validates the input before any callback runs.
219
+ const authorized = await authorizeServerComponent(handle as ServerComponent, value, ctx)
220
+ const prepared = await prepareAuthorizedServerComponent(authorized)
221
+ const rendered = await options.adapter.render(prepared.view, prepared.props, {
222
+ reference,
223
+ instance: id,
224
+ signal,
225
+ children: [],
226
+ })
227
+ if (signal.aborted) throw componentAbort(signal)
228
+ if (typeof rendered.html !== "string") throw new ServerComponentError("component_contract")
229
+ if ((rendered.islands?.length ?? 0) > COMPONENT_LIMITS.instances)
230
+ throw new ServerComponentError("component_limit", 413)
231
+ const record = recordOf({ id, reference, key, input: value }, rendered)
232
+ if (encoder.encode(JSON.stringify(record)).length > COMPONENT_LIMITS.outputBytes)
233
+ throw new ServerComponentError("component_limit", 413)
234
+ return record
235
+ })
236
+ },
136
237
  classify(request, routeId) {
137
238
  const selection = readComponentRequest(request)
138
239
  if (selection === undefined) return undefined
@@ -275,29 +376,10 @@ export function createServerComponents(options: ServerComponentsOptions): Server
275
376
  if (signal.aborted) throw componentAbort(signal)
276
377
  if (typeof rendered.html !== "string")
277
378
  throw new ServerComponentError("component_contract")
278
- const html = componentRangeHTML(rendered.html, assets)
379
+ const record = recordOf({ ...instance, id }, rendered)
279
380
  count += rendered.islands?.length ?? 0
280
381
  if (count > COMPONENT_LIMITS.instances)
281
382
  throw new ServerComponentError("component_limit", 413)
282
- const record: ComponentRecord = {
283
- instance: id,
284
- reference: instance.reference,
285
- key: instance.key,
286
- parent: instance.parent ?? null,
287
- input: instance.input,
288
- html,
289
- }
290
- if (rendered.payload !== undefined)
291
- Object.assign(record, {
292
- payload: componentValue(rendered.payload, COMPONENT_LIMITS.outputBytes),
293
- })
294
- if (rendered.islands !== undefined)
295
- Object.assign(record, {
296
- islands: rendered.islands.map((island) => ({
297
- ...island,
298
- props: componentValue(island.props),
299
- })),
300
- })
301
383
  const size = encoder.encode(JSON.stringify(record)).length
302
384
  bytes += size
303
385
  if (
@@ -50,6 +50,69 @@ function island(value: unknown): ComponentIsland {
50
50
  if (item.slots !== undefined) Object.assign(result, { slots: item.slots })
51
51
  return result
52
52
  }
53
+ /** One record, checked as each of a state's is; `ids` and `islandIds` collect what must be unique. */
54
+ function componentRecord(
55
+ value: unknown,
56
+ ids: Set<string>,
57
+ islandIds: Set<string>,
58
+ ): ComponentRecord {
59
+ const record = object(
60
+ value,
61
+ ["instance", "reference", "key", "parent", "input", "html"],
62
+ ["payload", "islands"],
63
+ )
64
+ if (
65
+ !componentToken(record.instance) ||
66
+ ids.has(record.instance) ||
67
+ !componentToken(record.reference) ||
68
+ !componentKey(record.key) ||
69
+ (record.parent !== null && !componentToken(record.parent)) ||
70
+ typeof record.html !== "string"
71
+ )
72
+ throw new ServerComponentError("component_protocol", 400)
73
+ ids.add(record.instance)
74
+ validateComponentHTML(record.html)
75
+ if (
76
+ record.islands !== undefined &&
77
+ (!Array.isArray(record.islands) || record.islands.length > COMPONENT_LIMITS.instances)
78
+ )
79
+ throw new ServerComponentError("component_protocol", 400)
80
+ const islands =
81
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
82
+ record.islands === undefined ? undefined : (record.islands as unknown[]).map(island)
83
+ for (const island of islands ?? []) {
84
+ if (islandIds.has(island.renderId)) throw new ServerComponentError("component_protocol", 400)
85
+ islandIds.add(island.renderId)
86
+ }
87
+ const result: ComponentRecord = {
88
+ instance: record.instance,
89
+ reference: record.reference,
90
+ key: record.key,
91
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
92
+ parent: record.parent as string | null,
93
+ html: record.html,
94
+ input: componentValue(record.input, COMPONENT_LIMITS.inputBytes),
95
+ }
96
+ if (record.payload !== undefined)
97
+ Object.assign(result, {
98
+ payload: componentValue(record.payload, COMPONENT_LIMITS.outputBytes),
99
+ })
100
+ if (islands !== undefined) Object.assign(result, { islands })
101
+ return result
102
+ }
103
+
104
+ /** A record that arrives alone, as a partially prerendered hole's does, checked as a state's are. */
105
+ export function parseComponentRecord(value: unknown): ComponentRecord {
106
+ const record = componentRecord(
107
+ componentValue(value, COMPONENT_LIMITS.documentBytes),
108
+ new Set(),
109
+ new Set(),
110
+ )
111
+ if ((record.islands?.length ?? 0) >= COMPONENT_LIMITS.instances)
112
+ throw new ServerComponentError("component_limit", 413)
113
+ return record
114
+ }
115
+
53
116
  export function parseComponentState(
54
117
  value: unknown,
55
118
  maxBytes: number = COMPONENT_LIMITS.documentBytes,
@@ -72,52 +135,11 @@ export function parseComponentState(
72
135
  const islandIds = new Set<string>()
73
136
  let instances = state.records.length
74
137
  const records: ComponentRecord[] = state.records.map((value: unknown) => {
75
- const record = object(
76
- value,
77
- ["instance", "reference", "key", "parent", "input", "html"],
78
- ["payload", "islands"],
79
- )
80
- if (
81
- !componentToken(record.instance) ||
82
- ids.has(record.instance) ||
83
- !componentToken(record.reference) ||
84
- !componentKey(record.key) ||
85
- (record.parent !== null && !componentToken(record.parent)) ||
86
- typeof record.html !== "string"
87
- )
88
- throw new ServerComponentError("component_protocol", 400)
89
- ids.add(record.instance)
90
- validateComponentHTML(record.html)
91
- if (
92
- record.islands !== undefined &&
93
- (!Array.isArray(record.islands) || record.islands.length > COMPONENT_LIMITS.instances)
94
- )
95
- throw new ServerComponentError("component_protocol", 400)
96
- const islands =
97
- // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
98
- record.islands === undefined ? undefined : (record.islands as unknown[]).map(island)
99
- for (const island of islands ?? []) {
100
- if (islandIds.has(island.renderId)) throw new ServerComponentError("component_protocol", 400)
101
- islandIds.add(island.renderId)
102
- }
103
- instances += islands?.length ?? 0
138
+ const record = componentRecord(value, ids, islandIds)
139
+ instances += record.islands?.length ?? 0
104
140
  if (instances > COMPONENT_LIMITS.instances)
105
141
  throw new ServerComponentError("component_limit", 413)
106
- const result: ComponentRecord = {
107
- instance: record.instance,
108
- reference: record.reference,
109
- key: record.key,
110
- // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
111
- parent: record.parent as string | null,
112
- html: record.html,
113
- input: componentValue(record.input, COMPONENT_LIMITS.inputBytes),
114
- }
115
- if (record.payload !== undefined)
116
- Object.assign(result, {
117
- payload: componentValue(record.payload, COMPONENT_LIMITS.outputBytes),
118
- })
119
- if (islands !== undefined) Object.assign(result, { islands })
120
- return result
142
+ return record
121
143
  })
122
144
  // Refreshes contain a single child and may name its already mounted parent. Documents carry the full forest.
123
145
  for (const record of records) {
@@ -98,6 +98,12 @@ export interface ComponentOwner {
98
98
  readonly scope: "anonymous" | ((ctx: ServerComponentContext) => string | Promise<string>)
99
99
  }
100
100
 
101
+ /** Experimental: the server components a partially prerendered route's holes may show. */
102
+ export interface ComponentHoles {
103
+ readonly components: readonly ServerComponentHandle[]
104
+ readonly capabilities?: readonly string[]
105
+ }
106
+
101
107
  export interface ServerComponentHandle {
102
108
  readonly reference?: string
103
109
  readonly input: StandardSchemaV1
@@ -135,4 +141,14 @@ export interface ServerComponentRuntime {
135
141
  ): Promise<ComponentState>
136
142
  response(state: ComponentState, selection: import("./protocol.ts").ComponentRequest): Response
137
143
  failure(error: unknown): Response
144
+ /** Whether the route's partially prerendered holes may show server components. */
145
+ hosts?(routeId: string): boolean
146
+ /** Render `component` as the route's hole `key`, with the hole loader's output as its input. */
147
+ hole?(
148
+ routeId: string,
149
+ component: object,
150
+ key: string,
151
+ input: unknown,
152
+ context: ServerComponentContext,
153
+ ): Promise<ComponentRecord>
138
154
  }
package/src/vite.ts CHANGED
@@ -23,10 +23,21 @@ import { isHiddenPath } from "@nifrajs/core/static-file"
23
23
  import { CLIENT_BATCH_MAX_BYTES } from "./dev-client.ts"
24
24
  import { DEV_REQUEST_ID_HEADER, DEV_SERVER_FILES } from "./dev-feed.ts"
25
25
  import { listenOrExplain } from "./dev-port.ts"
26
- import { createDevSession, type DevAppHooks, isDevAgentPath } from "./dev-session.ts"
26
+ import {
27
+ createDevSession,
28
+ type DevAppHooks,
29
+ isDevAgentPath,
30
+ isLoopbackHost,
31
+ } from "./dev-session.ts"
27
32
  import { discoverRoutes } from "./fs.ts"
28
- import { DEFAULT_DEV_PORT, generateClientEntry, setSsrModuleLoader } from "./index.ts"
33
+ import {
34
+ DEFAULT_DEV_PORT,
35
+ generateClientEntry,
36
+ type LiveClientEntry,
37
+ setSsrModuleLoader,
38
+ } from "./index.ts"
29
39
  import { admitViteTags } from "./internal/dev-csp.ts"
40
+ import { type UpgradableApp, upgradeOnNode } from "./internal/dev-websocket.ts"
30
41
  import { viteDedupePackages } from "./internal/identity-policy.ts"
31
42
  import {
32
43
  assertIdentityParity,
@@ -49,7 +60,7 @@ import { viteServerFnStub } from "./plugins/vite-server-fn.ts"
49
60
  import { viteZoneGuard } from "./plugins/vite-zone-guard.ts"
50
61
 
51
62
  /** Minimal app surface - `createWebApp(...)` satisfies it. */
52
- interface FetchApp {
63
+ interface FetchApp extends UpgradableApp {
53
64
  fetch(request: Request): Response | Promise<Response>
54
65
  }
55
66
 
@@ -79,7 +90,10 @@ interface ViteLike {
79
90
  /** The module graph, used to invalidate a changed file AND its transitive importers before reload. */
80
91
  readonly moduleGraph?: ViteModuleGraph
81
92
  /** The resolved config: `publicDir` is absolute, or `""` when the public directory is off. */
82
- readonly config?: { readonly publicDir?: string }
93
+ readonly config?: {
94
+ readonly publicDir?: string
95
+ readonly server?: { readonly allowedHosts?: true | readonly string[] }
96
+ }
83
97
  readonly watcher: {
84
98
  on(event: "change" | "add" | "unlink", cb: (path: string) => void): void
85
99
  on(event: "ready", cb: () => void): void
@@ -163,6 +177,8 @@ export interface ViteDevServerOptions {
163
177
  * fix (default `true`). Off, the errors still reach the feed.
164
178
  */
165
179
  readonly indicator?: boolean
180
+ /** The app runs `createWebApp({ live })`: the same option as the build's (`BuildClientOptions.live`). */
181
+ readonly live?: LiveClientEntry | undefined
166
182
  }
167
183
 
168
184
  export interface ViteDevServer {
@@ -236,7 +252,7 @@ const readAgentBody = async (req: IncomingMessage, max: number): Promise<Buffer
236
252
  function toWebRequest(req: IncomingMessage, body: Buffer | undefined): Request {
237
253
  const headers = new Headers()
238
254
  for (const [key, value] of Object.entries(req.headers)) {
239
- if (typeof value === "string") headers.set(key, value)
255
+ if (typeof value === "string") appendJoined(headers, key, value)
240
256
  else if (Array.isArray(value)) for (const v of value) headers.append(key, v)
241
257
  }
242
258
  const url = `http://${req.headers.host ?? "localhost"}${req.url ?? "/"}`
@@ -252,6 +268,23 @@ function toWebRequest(req: IncomingMessage, body: Buffer | undefined): Request {
252
268
  return new Request(url, init as unknown as ConstructorParameters<typeof Request>[1])
253
269
  }
254
270
 
271
+ /**
272
+ * Node joins a repeated field into one string, and a trailing space there means the last member was
273
+ * empty (each field line is trimmed). `Headers` strips the whitespace around each value it is given,
274
+ * so the empty members are appended one by one to keep the "a, " production shows.
275
+ */
276
+ function appendJoined(headers: Headers, name: string, joined: string): void {
277
+ const delimiter = name === "cookie" ? "; " : ", "
278
+ let base = joined
279
+ let empty = 0
280
+ while (base.endsWith(delimiter)) {
281
+ base = base.slice(0, -delimiter.length)
282
+ empty++
283
+ }
284
+ headers.append(name, base)
285
+ for (; empty > 0; empty--) headers.append(name, "")
286
+ }
287
+
255
288
  /** The bits of a Node ServerResponse `pipeWebBodyToNode` touches - structural, to avoid a node:http dep here. */
256
289
  interface NodeResLike {
257
290
  /** Set once the socket is gone: `close` has fired, and a write returns `false` for good. */
@@ -395,7 +428,11 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
395
428
  const manifest = discoverRoutes(routesDir)
396
429
  writeFileSync(
397
430
  resolvePath(root, DEV_ENTRY),
398
- generateClientEntry(manifest, { clientModule: options.clientModule, resolve: toUrl }),
431
+ generateClientEntry(manifest, {
432
+ clientModule: options.clientModule,
433
+ resolve: toUrl,
434
+ live: options.live,
435
+ }),
399
436
  )
400
437
  }
401
438
  const usePolling = options.poll ?? process.env.CHOKIDAR_USEPOLLING === "1"
@@ -457,6 +494,38 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
457
494
  handleWithVite(req, res)
458
495
  })
459
496
 
497
+ // The app's own WebSocket routes. Vite's HMR socket rides this server with a listener of its own,
498
+ // so its handshakes, and any no app route takes, are left to the other listeners.
499
+ server.on("upgrade", (req, socket, head) => {
500
+ const protocol = req.headers["sec-websocket-protocol"] ?? ""
501
+ if (protocol.includes("vite-hmr") || protocol.includes("vite-ping")) return
502
+ if (!allowsHost(req.headers.host)) {
503
+ socket.on("error", () => {})
504
+ socket.end("HTTP/1.1 403 Forbidden\r\ncontent-length: 0\r\nconnection: close\r\n\r\n")
505
+ return
506
+ }
507
+ void upgradeOnNode(app, toWebRequest(req, undefined), req, socket, head)
508
+ })
509
+
510
+ /** Vite's own rule for a handshake's Host: a loopback name, or one `server.allowedHosts` lists. */
511
+ function allowsHost(host: string | undefined): boolean {
512
+ if (isLoopbackHost(host)) return true
513
+ const allowed = vite.config?.server?.allowedHosts
514
+ if (allowed === true) return true
515
+ if (allowed === undefined || host === undefined) return false
516
+ let name: string
517
+ try {
518
+ name = new URL(`http://${host}`).hostname
519
+ } catch {
520
+ return false
521
+ }
522
+ return allowed.some(
523
+ (entry) =>
524
+ entry === name ||
525
+ (entry.startsWith(".") && (name === entry.slice(1) || name.endsWith(entry))),
526
+ )
527
+ }
528
+
460
529
  // Vite's public middleware serves every file under the public directory, dotfiles included. A
461
530
  // build ships no hidden file and the Bun pipeline's `servePublicDir` refuses one, so a request for
462
531
  // `/.env` or `/.git/config` goes to the app here too, as it does in production.
package/dist/nano.d.ts DELETED
@@ -1,125 +0,0 @@
1
- /**
2
- * `@nifrajs/web/nano` - the smallest state layer that still lets an island drive a keyed list.
3
- *
4
- * The islands lane (`@nifrajs/web/islands`) is imperative and correct-by-construction, but it has no
5
- * state primitive: every DOM update is hand-written, and a list means rebuilding the whole container.
6
- * nano adds a small, closed set of primitives and stops:
7
- *
8
- * - `signal(v)` - a current-value cell you read with `.get()` and write with `.set()`.
9
- * - `computed(fn, [deps])` - a derived cell. Its dependencies are DECLARED, never auto-tracked.
10
- * - `resource(fetcher, [deps])` - an async cell with an explicit pending/error/ready value. This is
11
- * nano's answer to "suspense": no thrown promise, no magic boundary, just a value you can bind.
12
- * - `bind` / `bindList` / `bindResource` - explicit, one-directional DOM bindings that each return
13
- * their teardown.
14
- *
15
- * The design rule is the whole point: every reactive edge is a call you can see - a `bind(...)` or a
16
- * `computed(fn, [deps])`. There is no re-render scope, no VDOM, no template compiler, and no effect
17
- * that silently subscribes to whatever it happened to read. That is what removes the three failure
18
- * modes an AI (or a human) hits in a framework - stale closures, wrong effect deps, hydration
19
- * mismatch - and, just as importantly, it is what makes every remaining mistake STATICALLY
20
- * detectable: a missing dep is `[deps]` that doesn't list a signal the body reads; a leak is a `bind`
21
- * whose cleanup isn't returned. A framework's reactivity can't be linted like that; nano's can.
22
- *
23
- * Where nano stops: no client router and no nested/composable view state (a component tree that mounts
24
- * and unmounts its own children). When an app needs those, it has outgrown a vanilla page - reach for
25
- * a framework adapter (`@nifrajs/web-preact`), not more nano.
26
- *
27
- * Browser code: it touches the DOM and is meant to run in an island enhancer, never under SSR.
28
- */
29
- /** A value you can read now and be told about later. Both `signal` and `computed` are `Readable`, so
30
- * `bind`/`bindList` accept either. */
31
- export interface Readable<T> {
32
- get(): T;
33
- subscribe(listener: (value: T) => void): () => void;
34
- }
35
- /** A writable cell. `set` notifies subscribers only when the value actually changes (`Object.is`), so
36
- * a redundant write costs nothing. */
37
- export interface Signal<T> extends Readable<T> {
38
- set(value: T): void;
39
- }
40
- /** A current-value cell. `signal(0)` -> `.get()` reads, `.set(1)` writes and notifies. */
41
- export declare function signal<T>(initial: T): Signal<T>;
42
- /**
43
- * A derived cell. `computed(() => a.get() + b.get(), [a, b])` recomputes whenever a declared
44
- * dependency changes and notifies its own subscribers when the derived value changes.
45
- *
46
- * The `deps` array is mandatory and explicit ON PURPOSE - it is the contract a linter checks against
47
- * the signals the body reads (`NF-C023`). Auto-tracking would remove the array but reintroduce the
48
- * exact "why didn't this update" bug that makes framework reactivity hard to get right.
49
- */
50
- export declare function computed<T>(compute: () => T, deps: readonly Readable<unknown>[]): Readable<T>;
51
- /** The three states of an async cell. A discriminated union on `status` so a consumer must handle
52
- * every branch - there is no "value that might secretly be loading", the failure mode of ad-hoc
53
- * `isLoading` booleans. `value`/`error` are narrowed by `status`. */
54
- export type ResourceState<T> = {
55
- readonly status: "pending";
56
- readonly value: undefined;
57
- readonly error: undefined;
58
- } | {
59
- readonly status: "ready";
60
- readonly value: T;
61
- readonly error: undefined;
62
- } | {
63
- readonly status: "error";
64
- readonly value: undefined;
65
- readonly error: unknown;
66
- };
67
- /** An async cell: a `Readable` of `ResourceState<T>` plus `refetch()`. This is nano's answer to
68
- * "suspense" - an explicit pending/error/ready value, never a thrown promise or a magic boundary. */
69
- export interface Resource<T> extends Readable<ResourceState<T>> {
70
- refetch(): void;
71
- }
72
- /**
73
- * An async derived cell. `resource(fetcher, [deps])` runs `fetcher` immediately and again whenever a
74
- * declared dependency changes, exposing the result as an explicit `{ status, value, error }`.
75
- *
76
- * Two footguns are handled here so they cannot be got wrong by hand:
77
- * - Races: each run holds a generation; a stale run's resolution is dropped, and its `AbortSignal` is
78
- * aborted, so an earlier-started-later-finishing fetch never overwrites a newer one.
79
- * - Deps: like `computed`, dependencies are DECLARED (`NF-C023` checks the fetcher's `.get()` reads
80
- * against the array). A `resource` that reads a signal its deps omit won't refetch when it changes.
81
- */
82
- export declare function resource<T>(fetcher: (signal: AbortSignal) => Promise<T>, deps?: readonly Readable<unknown>[]): Resource<T>;
83
- /**
84
- * Bind one element to a source: `apply(el, value)` runs once immediately and again on every change.
85
- * Returns the unsubscribe - hand it back as the island's cleanup (or collect several).
86
- *
87
- * bind(count, remaining, (el, n) => { el.textContent = String(n) })
88
- */
89
- export declare function bind<T>(el: HTMLElement, source: Readable<T>, apply: (el: HTMLElement, value: T) => void): () => void;
90
- /** How a `bindList` turns items into keyed DOM. `key` MUST be stable and unique per item (never the
91
- * array index) - it is what lets add/remove/reorder touch only the changed rows. */
92
- export interface BindListOptions<T> {
93
- key(item: T): string | number;
94
- create(item: T): HTMLElement;
95
- update?(el: HTMLElement, item: T): void;
96
- }
97
- /**
98
- * Bind a list signal to a container with keyed reconciliation: new items are `create`d, surviving
99
- * items are `update`d in place (keeping focus, scroll, and selection), removed items are detached,
100
- * and the children are ordered to match the array. Returns the unsubscribe.
101
- *
102
- * This is the one imperative task too error-prone to hand-write each time - it is why nano exists on
103
- * top of islands rather than leaving you to rebuild the container on every change.
104
- */
105
- export declare function bindList<T>(source: Readable<readonly T[]>, container: HTMLElement, options: BindListOptions<T>): () => void;
106
- /** How a `bindResource` maps each async state to the DOM. `ready` is required (there is always a
107
- * success shape to render); `pending`/`error` are optional. Every branch is explicit - no hidden
108
- * "still loading" state can slip through as a rendered `undefined`. */
109
- export interface BindResourceHandlers<T> {
110
- ready(el: HTMLElement, value: T): void;
111
- pending?(el: HTMLElement): void;
112
- error?(el: HTMLElement, error: unknown): void;
113
- }
114
- /**
115
- * Bind an element to a `resource`, dispatching on `status`. Like `bind`, it applies immediately and
116
- * on every change and returns the unsubscribe - collect it (a discarded disposer is `NF-C021`).
117
- *
118
- * bindResource(el, user, {
119
- * pending: (n) => { n.textContent = "Loading…" },
120
- * ready: (n, u) => { n.textContent = u.name },
121
- * error: (n) => { n.textContent = "Failed to load" },
122
- * })
123
- */
124
- export declare function bindResource<T>(el: HTMLElement, source: Readable<ResourceState<T>>, handlers: BindResourceHandlers<T>): () => void;
125
- //# sourceMappingURL=nano.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nano.d.ts","sourceRoot":"","sources":["../src/nano.ts"],"names":[],"mappings":"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"}