@nifrajs/web 4.0.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/README.md +11 -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 +1 -1
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +25 -7
  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-session.d.ts.map +1 -1
  26. package/dist/dev-session.js +4 -14
  27. package/dist/dev-session.js.map +1 -1
  28. package/dist/dev.d.ts +7 -17
  29. package/dist/dev.d.ts.map +1 -1
  30. package/dist/dev.js +13 -1
  31. package/dist/dev.js.map +1 -1
  32. package/dist/draft.d.ts +8 -5
  33. package/dist/draft.d.ts.map +1 -1
  34. package/dist/draft.js +30 -13
  35. package/dist/draft.js.map +1 -1
  36. package/dist/fonts-google.d.ts.map +1 -1
  37. package/dist/fonts-google.js +7 -0
  38. package/dist/fonts-google.js.map +1 -1
  39. package/dist/index.d.ts +2 -2
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/internal/codegen.d.ts +1 -0
  44. package/dist/internal/codegen.d.ts.map +1 -1
  45. package/dist/internal/codegen.js +56 -29
  46. package/dist/internal/codegen.js.map +1 -1
  47. package/dist/internal/disposable-dir.d.ts +8 -0
  48. package/dist/internal/disposable-dir.d.ts.map +1 -0
  49. package/dist/internal/disposable-dir.js +25 -0
  50. package/dist/internal/disposable-dir.js.map +1 -0
  51. package/dist/internal/entry-chunks.d.ts +9 -0
  52. package/dist/internal/entry-chunks.d.ts.map +1 -0
  53. package/dist/internal/entry-chunks.js +15 -0
  54. package/dist/internal/entry-chunks.js.map +1 -0
  55. package/dist/internal/evidence-traversal.d.ts +12 -0
  56. package/dist/internal/evidence-traversal.d.ts.map +1 -0
  57. package/dist/internal/evidence-traversal.js +48 -0
  58. package/dist/internal/evidence-traversal.js.map +1 -0
  59. package/dist/internal/head-merge.d.ts +6 -0
  60. package/dist/internal/head-merge.d.ts.map +1 -1
  61. package/dist/internal/head-merge.js +9 -0
  62. package/dist/internal/head-merge.js.map +1 -1
  63. package/dist/internal/js-string.d.ts +2 -0
  64. package/dist/internal/js-string.d.ts.map +1 -1
  65. package/dist/internal/js-string.js +5 -1
  66. package/dist/internal/js-string.js.map +1 -1
  67. package/dist/internal/mount-shadow.js +1 -1
  68. package/dist/internal/mount-shadow.js.map +1 -1
  69. package/dist/internal/output-guard.d.ts +7 -0
  70. package/dist/internal/output-guard.d.ts.map +1 -1
  71. package/dist/internal/output-guard.js +80 -8
  72. package/dist/internal/output-guard.js.map +1 -1
  73. package/dist/internal/page-execution.d.ts +6 -0
  74. package/dist/internal/page-execution.d.ts.map +1 -1
  75. package/dist/internal/page-execution.js +377 -108
  76. package/dist/internal/page-execution.js.map +1 -1
  77. package/dist/internal/progressive-cookies.d.ts +14 -0
  78. package/dist/internal/progressive-cookies.d.ts.map +1 -0
  79. package/dist/internal/progressive-cookies.js +43 -0
  80. package/dist/internal/progressive-cookies.js.map +1 -0
  81. package/dist/internal/public-env.d.ts +2 -0
  82. package/dist/internal/public-env.d.ts.map +1 -0
  83. package/dist/internal/public-env.js +13 -0
  84. package/dist/internal/public-env.js.map +1 -0
  85. package/dist/internal/render-document.d.ts +1 -0
  86. package/dist/internal/render-document.d.ts.map +1 -1
  87. package/dist/internal/render-document.js +28 -5
  88. package/dist/internal/render-document.js.map +1 -1
  89. package/dist/internal/response-controls.d.ts +2 -0
  90. package/dist/internal/response-controls.d.ts.map +1 -1
  91. package/dist/internal/response-controls.js +26 -16
  92. package/dist/internal/response-controls.js.map +1 -1
  93. package/dist/internal/revive-dates.d.ts +16 -0
  94. package/dist/internal/revive-dates.d.ts.map +1 -0
  95. package/dist/internal/revive-dates.js +32 -0
  96. package/dist/internal/revive-dates.js.map +1 -0
  97. package/dist/internal/route-path.d.ts +8 -0
  98. package/dist/internal/route-path.d.ts.map +1 -0
  99. package/dist/internal/route-path.js +8 -0
  100. package/dist/internal/route-path.js.map +1 -0
  101. package/dist/internal/secret-scan.d.ts.map +1 -1
  102. package/dist/internal/secret-scan.js +88 -20
  103. package/dist/internal/secret-scan.js.map +1 -1
  104. package/dist/internal/server-boundary.d.ts.map +1 -1
  105. package/dist/internal/server-boundary.js +33 -5
  106. package/dist/internal/server-boundary.js.map +1 -1
  107. package/dist/internal/web-app.d.ts +21 -16
  108. package/dist/internal/web-app.d.ts.map +1 -1
  109. package/dist/internal/web-app.js +73 -21
  110. package/dist/internal/web-app.js.map +1 -1
  111. package/dist/internal/wire-date.d.ts +3 -0
  112. package/dist/internal/wire-date.d.ts.map +1 -0
  113. package/dist/internal/wire-date.js +14 -0
  114. package/dist/internal/wire-date.js.map +1 -0
  115. package/dist/internal/zone-graph.d.ts +4 -0
  116. package/dist/internal/zone-graph.d.ts.map +1 -1
  117. package/dist/internal/zone-graph.js +54 -14
  118. package/dist/internal/zone-graph.js.map +1 -1
  119. package/dist/isr.d.ts +58 -2
  120. package/dist/isr.d.ts.map +1 -1
  121. package/dist/isr.js +296 -39
  122. package/dist/isr.js.map +1 -1
  123. package/dist/llms-txt.d.ts +2 -0
  124. package/dist/llms-txt.d.ts.map +1 -1
  125. package/dist/llms-txt.js +29 -3
  126. package/dist/llms-txt.js.map +1 -1
  127. package/dist/manifest.d.ts +28 -4
  128. package/dist/manifest.d.ts.map +1 -1
  129. package/dist/manifest.js +3 -0
  130. package/dist/manifest.js.map +1 -1
  131. package/dist/open-resolved.d.ts +18 -0
  132. package/dist/open-resolved.d.ts.map +1 -0
  133. package/dist/open-resolved.js +62 -0
  134. package/dist/open-resolved.js.map +1 -0
  135. package/dist/plugins/kit.d.ts +1 -0
  136. package/dist/plugins/kit.d.ts.map +1 -1
  137. package/dist/plugins/kit.js +26 -11
  138. package/dist/plugins/kit.js.map +1 -1
  139. package/dist/plugins/vite-leak-guard.d.ts +3 -1
  140. package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
  141. package/dist/plugins/vite-leak-guard.js +4 -0
  142. package/dist/plugins/vite-leak-guard.js.map +1 -1
  143. package/dist/public-dir.d.ts +8 -1
  144. package/dist/public-dir.d.ts.map +1 -1
  145. package/dist/public-dir.js +17 -6
  146. package/dist/public-dir.js.map +1 -1
  147. package/dist/query.d.ts +13 -4
  148. package/dist/query.d.ts.map +1 -1
  149. package/dist/query.js +89 -26
  150. package/dist/query.js.map +1 -1
  151. package/dist/render-seam.d.ts +2 -0
  152. package/dist/render-seam.d.ts.map +1 -1
  153. package/dist/render-seam.js +1 -0
  154. package/dist/render-seam.js.map +1 -1
  155. package/dist/route-types.d.ts.map +1 -1
  156. package/dist/route-types.js +20 -9
  157. package/dist/route-types.js.map +1 -1
  158. package/dist/router.d.ts +9 -2
  159. package/dist/router.d.ts.map +1 -1
  160. package/dist/router.js +39 -46
  161. package/dist/router.js.map +1 -1
  162. package/dist/server-components/build-info.d.ts +3 -0
  163. package/dist/server-components/build-info.d.ts.map +1 -0
  164. package/dist/server-components/build-info.js +7 -0
  165. package/dist/server-components/build-info.js.map +1 -0
  166. package/dist/server-components/build-target.d.ts +12 -0
  167. package/dist/server-components/build-target.d.ts.map +1 -0
  168. package/dist/server-components/build-target.js +153 -0
  169. package/dist/server-components/build-target.js.map +1 -0
  170. package/dist/server-components/build.d.ts +24 -0
  171. package/dist/server-components/build.d.ts.map +1 -0
  172. package/dist/server-components/build.js +366 -0
  173. package/dist/server-components/build.js.map +1 -0
  174. package/dist/server-components/bundle-proof.d.ts +3 -0
  175. package/dist/server-components/bundle-proof.d.ts.map +1 -0
  176. package/dist/server-components/bundle-proof.js +23 -0
  177. package/dist/server-components/bundle-proof.js.map +1 -0
  178. package/dist/server-components/client.d.ts +46 -0
  179. package/dist/server-components/client.d.ts.map +1 -0
  180. package/dist/server-components/client.js +594 -0
  181. package/dist/server-components/client.js.map +1 -0
  182. package/dist/server-components/definition.d.ts +11 -0
  183. package/dist/server-components/definition.d.ts.map +1 -0
  184. package/dist/server-components/definition.js +94 -0
  185. package/dist/server-components/definition.js.map +1 -0
  186. package/dist/server-components/dev-http.d.ts +5 -0
  187. package/dist/server-components/dev-http.d.ts.map +1 -0
  188. package/dist/server-components/dev-http.js +71 -0
  189. package/dist/server-components/dev-http.js.map +1 -0
  190. package/dist/server-components/error.d.ts +9 -0
  191. package/dist/server-components/error.d.ts.map +1 -0
  192. package/dist/server-components/error.js +24 -0
  193. package/dist/server-components/error.js.map +1 -0
  194. package/dist/server-components/frames.d.ts +7 -0
  195. package/dist/server-components/frames.d.ts.map +1 -0
  196. package/dist/server-components/frames.js +169 -0
  197. package/dist/server-components/frames.js.map +1 -0
  198. package/dist/server-components/html-policy.d.ts +6 -0
  199. package/dist/server-components/html-policy.d.ts.map +1 -0
  200. package/dist/server-components/html-policy.js +75 -0
  201. package/dist/server-components/html-policy.js.map +1 -0
  202. package/dist/server-components/html.d.ts +4 -0
  203. package/dist/server-components/html.d.ts.map +1 -0
  204. package/dist/server-components/html.js +67 -0
  205. package/dist/server-components/html.js.map +1 -0
  206. package/dist/server-components/islands.d.ts +44 -0
  207. package/dist/server-components/islands.d.ts.map +1 -0
  208. package/dist/server-components/islands.js +42 -0
  209. package/dist/server-components/islands.js.map +1 -0
  210. package/dist/server-components/native.d.ts +4 -0
  211. package/dist/server-components/native.d.ts.map +1 -0
  212. package/dist/server-components/native.js +81 -0
  213. package/dist/server-components/native.js.map +1 -0
  214. package/dist/server-components/portal.d.ts +6 -0
  215. package/dist/server-components/portal.d.ts.map +1 -0
  216. package/dist/server-components/portal.js +35 -0
  217. package/dist/server-components/portal.js.map +1 -0
  218. package/dist/server-components/props.d.ts +3 -0
  219. package/dist/server-components/props.d.ts.map +1 -0
  220. package/dist/server-components/props.js +14 -0
  221. package/dist/server-components/props.js.map +1 -0
  222. package/dist/server-components/protocol.d.ts +44 -0
  223. package/dist/server-components/protocol.d.ts.map +1 -0
  224. package/dist/server-components/protocol.js +139 -0
  225. package/dist/server-components/protocol.js.map +1 -0
  226. package/dist/server-components/range.d.ts +24 -0
  227. package/dist/server-components/range.d.ts.map +1 -0
  228. package/dist/server-components/range.js +263 -0
  229. package/dist/server-components/range.js.map +1 -0
  230. package/dist/server-components/registry.d.ts +6 -0
  231. package/dist/server-components/registry.d.ts.map +1 -0
  232. package/dist/server-components/registry.js +30 -0
  233. package/dist/server-components/registry.js.map +1 -0
  234. package/dist/server-components/response.d.ts +4 -0
  235. package/dist/server-components/response.d.ts.map +1 -0
  236. package/dist/server-components/response.js +32 -0
  237. package/dist/server-components/response.js.map +1 -0
  238. package/dist/server-components/router-integration.d.ts +9 -0
  239. package/dist/server-components/router-integration.d.ts.map +1 -0
  240. package/dist/server-components/router-integration.js +29 -0
  241. package/dist/server-components/router-integration.js.map +1 -0
  242. package/dist/server-components/runtime.d.ts +14 -0
  243. package/dist/server-components/runtime.d.ts.map +1 -0
  244. package/dist/server-components/runtime.js +276 -0
  245. package/dist/server-components/runtime.js.map +1 -0
  246. package/dist/server-components/scheduler.d.ts +14 -0
  247. package/dist/server-components/scheduler.d.ts.map +1 -0
  248. package/dist/server-components/scheduler.js +74 -0
  249. package/dist/server-components/scheduler.js.map +1 -0
  250. package/dist/server-components/schema.d.ts +4 -0
  251. package/dist/server-components/schema.d.ts.map +1 -0
  252. package/dist/server-components/schema.js +77 -0
  253. package/dist/server-components/schema.js.map +1 -0
  254. package/dist/server-components/server-entry.d.ts +12 -0
  255. package/dist/server-components/server-entry.d.ts.map +1 -0
  256. package/dist/server-components/server-entry.js +90 -0
  257. package/dist/server-components/server-entry.js.map +1 -0
  258. package/dist/server-components/source.d.ts +15 -0
  259. package/dist/server-components/source.d.ts.map +1 -0
  260. package/dist/server-components/source.js +269 -0
  261. package/dist/server-components/source.js.map +1 -0
  262. package/dist/server-components/state.d.ts +4 -0
  263. package/dist/server-components/state.d.ts.map +1 -0
  264. package/dist/server-components/state.js +123 -0
  265. package/dist/server-components/state.js.map +1 -0
  266. package/dist/server-components/stream.d.ts +6 -0
  267. package/dist/server-components/stream.d.ts.map +1 -0
  268. package/dist/server-components/stream.js +70 -0
  269. package/dist/server-components/stream.js.map +1 -0
  270. package/dist/server-components/trusted-html.d.ts +3 -0
  271. package/dist/server-components/trusted-html.d.ts.map +1 -0
  272. package/dist/server-components/trusted-html.js +14 -0
  273. package/dist/server-components/trusted-html.js.map +1 -0
  274. package/dist/server-components/types.d.ts +107 -0
  275. package/dist/server-components/types.d.ts.map +1 -0
  276. package/dist/server-components/types.js +2 -0
  277. package/dist/server-components/types.js.map +1 -0
  278. package/dist/server-components/typescript.d.ts +11 -0
  279. package/dist/server-components/typescript.d.ts.map +1 -0
  280. package/dist/server-components/typescript.js +28 -0
  281. package/dist/server-components/typescript.js.map +1 -0
  282. package/dist/server-components/value.d.ts +5 -0
  283. package/dist/server-components/value.d.ts.map +1 -0
  284. package/dist/server-components/value.js +77 -0
  285. package/dist/server-components/value.js.map +1 -0
  286. package/dist/server-components/vite.d.ts +12 -0
  287. package/dist/server-components/vite.d.ts.map +1 -0
  288. package/dist/server-components/vite.js +197 -0
  289. package/dist/server-components/vite.js.map +1 -0
  290. package/dist/server-components.d.ts +5 -0
  291. package/dist/server-components.d.ts.map +1 -0
  292. package/dist/server-components.js +4 -0
  293. package/dist/server-components.js.map +1 -0
  294. package/dist/service-worker.d.ts +8 -1
  295. package/dist/service-worker.d.ts.map +1 -1
  296. package/dist/service-worker.js +20 -6
  297. package/dist/service-worker.js.map +1 -1
  298. package/dist/vite.d.ts +12 -0
  299. package/dist/vite.d.ts.map +1 -1
  300. package/dist/vite.js +7 -1
  301. package/dist/vite.js.map +1 -1
  302. package/dist/zones.d.ts +40 -0
  303. package/dist/zones.d.ts.map +1 -1
  304. package/dist/zones.js +170 -6
  305. package/dist/zones.js.map +1 -1
  306. package/package.json +97 -4
  307. package/src/build-vite.ts +31 -9
  308. package/src/build.ts +109 -31
  309. package/src/cdn.ts +18 -12
  310. package/src/client.ts +25 -6
  311. package/src/deferred.ts +27 -9
  312. package/src/dev-feed.ts +24 -5
  313. package/src/dev-session.ts +4 -13
  314. package/src/dev.ts +29 -1
  315. package/src/draft.ts +35 -14
  316. package/src/fonts-google.ts +10 -0
  317. package/src/index.ts +3 -2
  318. package/src/internal/codegen.ts +60 -29
  319. package/src/internal/disposable-dir.ts +24 -0
  320. package/src/internal/entry-chunks.ts +18 -0
  321. package/src/internal/evidence-traversal.ts +57 -0
  322. package/src/internal/head-merge.ts +16 -0
  323. package/src/internal/js-string.ts +6 -1
  324. package/src/internal/mount-shadow.ts +1 -1
  325. package/src/internal/output-guard.ts +88 -7
  326. package/src/internal/page-execution.ts +506 -108
  327. package/src/internal/progressive-cookies.ts +60 -0
  328. package/src/internal/public-env.ts +14 -0
  329. package/src/internal/render-document.ts +26 -11
  330. package/src/internal/response-controls.ts +31 -14
  331. package/src/internal/revive-dates.ts +35 -0
  332. package/src/internal/route-path.ts +8 -0
  333. package/src/internal/secret-scan.ts +90 -18
  334. package/src/internal/server-boundary.ts +29 -5
  335. package/src/internal/web-app.ts +116 -37
  336. package/src/internal/wire-date.ts +16 -0
  337. package/src/internal/zone-graph.ts +59 -19
  338. package/src/isr.ts +351 -43
  339. package/src/llms-txt.ts +32 -3
  340. package/src/manifest.ts +28 -4
  341. package/src/open-resolved.ts +64 -0
  342. package/src/plugins/kit.ts +31 -11
  343. package/src/plugins/vite-leak-guard.ts +5 -1
  344. package/src/public-dir.ts +27 -8
  345. package/src/query.ts +107 -26
  346. package/src/render-seam.ts +2 -0
  347. package/src/route-types.ts +34 -7
  348. package/src/router.ts +58 -55
  349. package/src/server-components/build-info.ts +11 -0
  350. package/src/server-components/build-target.ts +194 -0
  351. package/src/server-components/build.ts +419 -0
  352. package/src/server-components/bundle-proof.ts +33 -0
  353. package/src/server-components/client.ts +663 -0
  354. package/src/server-components/definition.ts +125 -0
  355. package/src/server-components/dev-http.ts +75 -0
  356. package/src/server-components/error.ts +24 -0
  357. package/src/server-components/frames.ts +181 -0
  358. package/src/server-components/html-policy.ts +94 -0
  359. package/src/server-components/html.ts +81 -0
  360. package/src/server-components/islands.ts +111 -0
  361. package/src/server-components/native.ts +101 -0
  362. package/src/server-components/portal.ts +42 -0
  363. package/src/server-components/props.ts +19 -0
  364. package/src/server-components/protocol.ts +167 -0
  365. package/src/server-components/range.ts +313 -0
  366. package/src/server-components/registry.ts +34 -0
  367. package/src/server-components/response.ts +44 -0
  368. package/src/server-components/router-integration.ts +40 -0
  369. package/src/server-components/runtime.ts +376 -0
  370. package/src/server-components/scheduler.ts +84 -0
  371. package/src/server-components/schema.ts +69 -0
  372. package/src/server-components/server-entry.ts +98 -0
  373. package/src/server-components/source.ts +324 -0
  374. package/src/server-components/state.ts +143 -0
  375. package/src/server-components/stream.ts +71 -0
  376. package/src/server-components/trusted-html.ts +21 -0
  377. package/src/server-components/types.ts +138 -0
  378. package/src/server-components/typescript.ts +39 -0
  379. package/src/server-components/value.ts +82 -0
  380. package/src/server-components/vite.ts +242 -0
  381. package/src/server-components.ts +32 -0
  382. package/src/service-worker.ts +24 -7
  383. package/src/vite.ts +8 -1
  384. package/src/zones.ts +208 -7
@@ -0,0 +1,324 @@
1
+ import { createHash } from "node:crypto"
2
+ import { relative } from "node:path"
3
+ import type * as TS from "typescript"
4
+ import { ts } from "./typescript.ts"
5
+
6
+ export interface CompiledComponentModule {
7
+ readonly code: string
8
+ readonly references: Readonly<Record<string, string>>
9
+ }
10
+
11
+ export function componentReference(file: string, root: string, name: string): string {
12
+ return (
13
+ "sc_" +
14
+ createHash("sha256")
15
+ .update(`${relative(root, file).replaceAll("\\", "/")}#${name}`)
16
+ .digest("hex")
17
+ .slice(0, 32)
18
+ )
19
+ }
20
+
21
+ export function sourceFile(source: string, file: string): TS.SourceFile {
22
+ return ts.createSourceFile(
23
+ file,
24
+ source,
25
+ ts.ScriptTarget.Latest,
26
+ true,
27
+ /\.[jt]sx$/.test(file) ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
28
+ )
29
+ }
30
+
31
+ function modifier(node: TS.Node, kind: TS.SyntaxKind): boolean {
32
+ return (
33
+ ts.canHaveModifiers(node) &&
34
+ (ts.getModifiers(node)?.some((item) => item.kind === kind) ?? false)
35
+ )
36
+ }
37
+
38
+ function literal(node: TS.Expression): unknown {
39
+ if (
40
+ ts.isAsExpression(node) ||
41
+ ts.isSatisfiesExpression(node) ||
42
+ ts.isParenthesizedExpression(node)
43
+ )
44
+ return literal(node.expression)
45
+ if (ts.isStringLiteral(node)) return node.text
46
+ if (!ts.isObjectLiteralExpression(node)) throw new Error("component_pipeline_literal")
47
+ const result: Record<string, unknown> = Object.create(null)
48
+ for (const member of node.properties) {
49
+ if (
50
+ !ts.isPropertyAssignment(member) ||
51
+ !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))
52
+ )
53
+ throw new Error("component_pipeline_literal")
54
+ if (
55
+ Object.hasOwn(result, member.name.text) ||
56
+ ["__proto__", "prototype", "constructor"].includes(member.name.text)
57
+ )
58
+ throw new Error("component_pipeline_literal")
59
+ result[member.name.text] = literal(member.initializer)
60
+ }
61
+ return result
62
+ }
63
+
64
+ /** The `componentPipeline` a config module exports as a plain literal, read without running the
65
+ * module, or `undefined` when it exports none or one that is not a literal. */
66
+ export function staticComponentPipeline(source: string, file: string): unknown {
67
+ let pipeline: unknown
68
+ for (const statement of sourceFile(source, file).statements) {
69
+ if (!ts.isVariableStatement(statement) || !modifier(statement, ts.SyntaxKind.ExportKeyword))
70
+ continue
71
+ for (const variable of statement.declarationList.declarations) {
72
+ if (
73
+ !ts.isIdentifier(variable.name) ||
74
+ variable.name.text !== "componentPipeline" ||
75
+ variable.initializer === undefined
76
+ )
77
+ continue
78
+ try {
79
+ pipeline = literal(variable.initializer)
80
+ } catch {
81
+ return undefined
82
+ }
83
+ }
84
+ }
85
+ return pipeline
86
+ }
87
+
88
+ export function directive(file: TS.SourceFile, value: string): boolean {
89
+ let found = false
90
+ const visit = (node: TS.Node): void => {
91
+ if (ts.isSourceFile(node) || ts.isBlock(node)) {
92
+ for (const statement of node.statements) {
93
+ if (!ts.isExpressionStatement(statement) || !ts.isStringLiteral(statement.expression)) break
94
+ if (statement.expression.text === value) found = true
95
+ }
96
+ }
97
+ ts.forEachChild(node, visit)
98
+ }
99
+ visit(file)
100
+ return found
101
+ }
102
+
103
+ export function exportedValues(file: TS.SourceFile): readonly string[] {
104
+ const names = new Set<string>()
105
+ for (const statement of file.statements) {
106
+ if (ts.isExportAssignment(statement)) {
107
+ names.add("default")
108
+ continue
109
+ }
110
+ if (ts.isExportDeclaration(statement)) {
111
+ if (statement.isTypeOnly) continue
112
+ if (statement.exportClause === undefined || !ts.isNamedExports(statement.exportClause))
113
+ throw new Error(
114
+ "[nifra/components] Native client modules require explicit, schema-registered component exports",
115
+ )
116
+ for (const element of statement.exportClause.elements)
117
+ if (!element.isTypeOnly) names.add(element.name.text)
118
+ }
119
+ if (!modifier(statement, ts.SyntaxKind.ExportKeyword)) continue
120
+ if (modifier(statement, ts.SyntaxKind.DefaultKeyword)) {
121
+ names.add("default")
122
+ continue
123
+ }
124
+ if (ts.isVariableStatement(statement)) {
125
+ for (const declaration of statement.declarationList.declarations) {
126
+ if (!ts.isIdentifier(declaration.name))
127
+ throw new Error("[nifra/components] Destructured component exports are unsupported")
128
+ names.add(declaration.name.text)
129
+ }
130
+ } else if (
131
+ ts.isFunctionDeclaration(statement) ||
132
+ ts.isClassDeclaration(statement) ||
133
+ ts.isEnumDeclaration(statement)
134
+ ) {
135
+ if (statement.name !== undefined) names.add(statement.name.text)
136
+ }
137
+ }
138
+ return [...names]
139
+ }
140
+
141
+ export function compileComponentModule(
142
+ source: string,
143
+ file: string,
144
+ root: string,
145
+ environment: string,
146
+ kind: "server" | "island" = "server",
147
+ ): CompiledComponentModule {
148
+ const ast = sourceFile(source, file)
149
+ if (directive(ast, "use server"))
150
+ throw new Error(
151
+ "[nifra/components] Native use-server actions are unsupported; use a validated serverFn in a *.fn.ts module",
152
+ )
153
+ const factories = new Set<string>()
154
+ const namespaces = new Set<string>()
155
+ for (const statement of ast.statements) {
156
+ if (
157
+ !ts.isImportDeclaration(statement) ||
158
+ !ts.isStringLiteral(statement.moduleSpecifier) ||
159
+ statement.moduleSpecifier.text !==
160
+ (kind === "server"
161
+ ? "@nifrajs/web/server-components"
162
+ : "@nifrajs/web/server-components/islands")
163
+ )
164
+ continue
165
+ const bindings = statement.importClause?.namedBindings
166
+ if (bindings !== undefined && ts.isNamedImports(bindings)) {
167
+ for (const element of bindings.elements)
168
+ if (
169
+ (element.propertyName ?? element.name).text ===
170
+ (kind === "server" ? "defineServerComponent" : "defineClientIsland")
171
+ )
172
+ factories.add(element.name.text)
173
+ } else if (bindings !== undefined && ts.isNamespaceImport(bindings))
174
+ namespaces.add(bindings.name.text)
175
+ }
176
+ const definitions = new Map<string, TS.CallExpression>()
177
+ for (const statement of ast.statements) {
178
+ if (!ts.isVariableStatement(statement)) continue
179
+ for (const declaration of statement.declarationList.declarations) {
180
+ let expression = declaration.initializer
181
+ while (
182
+ expression !== undefined &&
183
+ (ts.isAsExpression(expression) ||
184
+ ts.isSatisfiesExpression(expression) ||
185
+ ts.isParenthesizedExpression(expression))
186
+ )
187
+ expression = expression.expression
188
+ if (
189
+ !ts.isIdentifier(declaration.name) ||
190
+ expression === undefined ||
191
+ !ts.isCallExpression(expression)
192
+ )
193
+ continue
194
+ const callee = expression.expression
195
+ if (
196
+ (ts.isIdentifier(callee) && factories.has(callee.text)) ||
197
+ (ts.isPropertyAccessExpression(callee) &&
198
+ ts.isIdentifier(callee.expression) &&
199
+ namespaces.has(callee.expression.text) &&
200
+ callee.name.text === (kind === "server" ? "defineServerComponent" : "defineClientIsland"))
201
+ ) {
202
+ if (expression.arguments.length !== 1)
203
+ throw new Error(
204
+ "[nifra/components] Component references are generated by the compiler; remove the handwritten reference",
205
+ )
206
+ definitions.set(declaration.name.text, expression)
207
+ }
208
+ }
209
+ }
210
+ const references: Record<string, string> = Object.create(null)
211
+ for (const statement of ast.statements) {
212
+ if (ts.isVariableStatement(statement) && modifier(statement, ts.SyntaxKind.ExportKeyword)) {
213
+ for (const declaration of statement.declarationList.declarations) {
214
+ if (!ts.isIdentifier(declaration.name) || !definitions.has(declaration.name.text))
215
+ throw new Error(
216
+ "[nifra/components] Only named defineServerComponent handles may be exported from *.component.server modules",
217
+ )
218
+ references[declaration.name.text] = componentReference(file, root, declaration.name.text)
219
+ }
220
+ } else if (ts.isExportDeclaration(statement) && !statement.isTypeOnly) {
221
+ if (
222
+ statement.moduleSpecifier !== undefined ||
223
+ statement.exportClause === undefined ||
224
+ !ts.isNamedExports(statement.exportClause)
225
+ )
226
+ throw new Error("[nifra/components] Re-export component handles through a separate barrel")
227
+ for (const element of statement.exportClause.elements) {
228
+ if (element.isTypeOnly) continue
229
+ const local = (element.propertyName ?? element.name).text
230
+ if (!definitions.has(local))
231
+ throw new Error("[nifra/components] A component module exported an unregistered value")
232
+ references[element.name.text] = componentReference(file, root, local)
233
+ }
234
+ } else if (
235
+ ts.isExportAssignment(statement) ||
236
+ (modifier(statement, ts.SyntaxKind.ExportKeyword) &&
237
+ !ts.isInterfaceDeclaration(statement) &&
238
+ !ts.isTypeAliasDeclaration(statement))
239
+ ) {
240
+ throw new Error(
241
+ "[nifra/components] Export named defineServerComponent handles from *.component.server modules",
242
+ )
243
+ }
244
+ }
245
+ if (Object.keys(references).length === 0)
246
+ throw new Error("[nifra/components] A component module has no recognized server component")
247
+ if (environment === "client" && kind === "server") {
248
+ return {
249
+ references,
250
+ code: Object.entries(references)
251
+ .map(
252
+ ([name, reference]) =>
253
+ `export const ${name} = Object.freeze({ reference: ${JSON.stringify(reference)} });`,
254
+ )
255
+ .join("\n"),
256
+ }
257
+ }
258
+ let code = source
259
+ for (const [name, call] of [...definitions].sort((a, b) => b[1].end - a[1].end)) {
260
+ const argument = call.arguments[0]
261
+ if (argument === undefined)
262
+ throw new Error("[nifra/components] Missing server component definition")
263
+ const at = argument.end
264
+ code =
265
+ code.slice(0, at) +
266
+ ", " +
267
+ JSON.stringify(componentReference(file, root, name)) +
268
+ code.slice(at)
269
+ }
270
+ return { code, references }
271
+ }
272
+
273
+ export function guardCreateElementCalls(source: string, file: string): string {
274
+ const ast = sourceFile(source, file)
275
+ const namespaces = new Set<string>()
276
+ const factories = new Set<string>()
277
+ for (const statement of ast.statements) {
278
+ if (
279
+ !ts.isImportDeclaration(statement) ||
280
+ !ts.isStringLiteral(statement.moduleSpecifier) ||
281
+ statement.moduleSpecifier.text !== "react"
282
+ )
283
+ continue
284
+ if (statement.importClause?.name !== undefined) namespaces.add(statement.importClause.name.text)
285
+ const bindings = statement.importClause?.namedBindings
286
+ if (bindings !== undefined && ts.isNamespaceImport(bindings)) namespaces.add(bindings.name.text)
287
+ if (bindings !== undefined && ts.isNamedImports(bindings))
288
+ for (const element of bindings.elements) {
289
+ if ((element.propertyName ?? element.name).text === "createElement")
290
+ factories.add(element.name.text)
291
+ }
292
+ }
293
+ const changes: Array<{ start: number; end: number }> = []
294
+ const visit = (node: TS.Node): void => {
295
+ if (ts.isCallExpression(node)) {
296
+ const expression = node.expression
297
+ const named = ts.isIdentifier(expression) && factories.has(expression.text)
298
+ const member =
299
+ ts.isPropertyAccessExpression(expression) &&
300
+ ts.isIdentifier(expression.expression) &&
301
+ namespaces.has(expression.expression.text) &&
302
+ expression.name.text === "createElement"
303
+ const computed =
304
+ ts.isElementAccessExpression(expression) &&
305
+ ts.isIdentifier(expression.expression) &&
306
+ namespaces.has(expression.expression.text) &&
307
+ ts.isStringLiteral(expression.argumentExpression) &&
308
+ expression.argumentExpression.text === "createElement"
309
+ if (named || member || computed)
310
+ changes.push({ start: expression.getStart(ast), end: expression.end })
311
+ }
312
+ ts.forEachChild(node, visit)
313
+ }
314
+ visit(ast)
315
+ if (changes.length === 0) return source
316
+ const identifier = `__nifra_guardedCreateElement_${createHash("sha256").update(file).digest("hex").slice(0, 12)}`
317
+ let code = source
318
+ for (const change of changes.sort((a, b) => b.start - a.start))
319
+ code = code.slice(0, change.start) + identifier + code.slice(change.end)
320
+ return (
321
+ `import { guardedCreateElement as ${identifier} } from "@nifrajs/web-react/server-components/guard";\n` +
322
+ code
323
+ )
324
+ }
@@ -0,0 +1,143 @@
1
+ import { ServerComponentError } from "./error.ts"
2
+ import { validateComponentHTML } from "./html.ts"
3
+ import { COMPONENT_LIMITS, componentKey } from "./protocol.ts"
4
+ import type { ComponentIsland, ComponentRecord, ComponentState } from "./types.ts"
5
+ import { componentValue } from "./value.ts"
6
+
7
+ const token = /^[A-Za-z0-9_-]{1,128}$/
8
+ function object(
9
+ value: unknown,
10
+ fields: readonly string[],
11
+ optional: readonly string[] = [],
12
+ ): Record<string, unknown> {
13
+ if (
14
+ typeof value !== "object" ||
15
+ value === null ||
16
+ Array.isArray(value) ||
17
+ fields.some((field) => !Object.hasOwn(value, field)) ||
18
+ Object.keys(value).some((field) => !fields.includes(field) && !optional.includes(field))
19
+ )
20
+ throw new ServerComponentError("component_protocol", 400)
21
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
22
+ return value as Record<string, unknown>
23
+ }
24
+ export function componentToken(value: unknown): value is string {
25
+ return typeof value === "string" && token.test(value)
26
+ }
27
+ function island(value: unknown): ComponentIsland {
28
+ const item = object(value, ["reference", "key", "props", "renderId"], ["slots"])
29
+ if (!componentToken(item.reference) || !componentToken(item.renderId) || !componentKey(item.key))
30
+ throw new ServerComponentError("component_protocol", 400)
31
+ if (
32
+ item.slots !== undefined &&
33
+ (typeof item.slots !== "object" ||
34
+ item.slots === null ||
35
+ Array.isArray(item.slots) ||
36
+ Object.entries(item.slots).some(
37
+ ([key, html]) => !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(key) || typeof html !== "string",
38
+ ))
39
+ )
40
+ throw new ServerComponentError("component_protocol", 400)
41
+ if (item.slots !== undefined)
42
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
43
+ for (const html of Object.values(item.slots)) validateComponentHTML(html as string)
44
+ const result: ComponentIsland = {
45
+ reference: item.reference,
46
+ key: item.key,
47
+ renderId: item.renderId,
48
+ props: componentValue(item.props),
49
+ }
50
+ if (item.slots !== undefined) Object.assign(result, { slots: item.slots })
51
+ return result
52
+ }
53
+ export function parseComponentState(
54
+ value: unknown,
55
+ maxBytes: number = COMPONENT_LIMITS.documentBytes,
56
+ externalParent?: string | null,
57
+ ): ComponentState {
58
+ const bounded = componentValue(value, maxBytes)
59
+ const state = object(bounded, ["v", "build", "adapter", "owner", "scope", "records"])
60
+ if (
61
+ state.v !== 1 ||
62
+ !componentToken(state.build) ||
63
+ !componentToken(state.owner) ||
64
+ !componentToken(state.scope) ||
65
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
66
+ !["react", "vue", "svelte", "solid", "preact"].includes(state.adapter as string) ||
67
+ !Array.isArray(state.records) ||
68
+ state.records.length > COMPONENT_LIMITS.instances
69
+ )
70
+ throw new ServerComponentError("component_protocol", 400)
71
+ const ids = new Set<string>()
72
+ const islandIds = new Set<string>()
73
+ let instances = state.records.length
74
+ 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
104
+ if (instances > COMPONENT_LIMITS.instances)
105
+ 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
121
+ })
122
+ // Refreshes contain a single child and may name its already mounted parent. Documents carry the full forest.
123
+ for (const record of records) {
124
+ const chain = new Set([record.instance])
125
+ let parent = record.parent
126
+ while (parent !== null) {
127
+ if (!ids.has(parent) && parent === externalParent) break
128
+ if (chain.has(parent) || !ids.has(parent) || chain.size >= 16)
129
+ throw new ServerComponentError("component_protocol", 400)
130
+ chain.add(parent)
131
+ parent = records.find((item) => item.instance === parent)?.parent ?? null
132
+ }
133
+ }
134
+ return {
135
+ v: 1,
136
+ build: state.build,
137
+ owner: state.owner,
138
+ scope: state.scope,
139
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: Object shape is checked before field inspection; each typed field follows its closed vocabulary check.
140
+ adapter: state.adapter as ComponentState["adapter"],
141
+ records,
142
+ }
143
+ }
@@ -0,0 +1,71 @@
1
+ import { ServerComponentError } from "./error.ts"
2
+ import { COMPONENT_LIMITS } from "./protocol.ts"
3
+
4
+ export function bytesStream(bytes: Uint8Array): ReadableStream<Uint8Array> {
5
+ return new ReadableStream({
6
+ start(controller) {
7
+ controller.enqueue(bytes)
8
+ controller.close()
9
+ },
10
+ })
11
+ }
12
+
13
+ /** The bounded snapshot is shared by SSR and hydration; it never tees into an unread branch. */
14
+ export async function readComponentBytes(
15
+ stream: ReadableStream<Uint8Array>,
16
+ signal: AbortSignal,
17
+ limit: number = COMPONENT_LIMITS.outputBytes,
18
+ ): Promise<Uint8Array> {
19
+ const reader = stream.getReader()
20
+ const chunks: Uint8Array[] = []
21
+ let size = 0
22
+ const cancel = () => {
23
+ void reader.cancel().catch(() => {
24
+ /* Keep the primary read failure. */
25
+ })
26
+ }
27
+ signal.addEventListener("abort", cancel, { once: true })
28
+ try {
29
+ while (true) {
30
+ if (signal.aborted) throw new ServerComponentError("component_cancelled", 499)
31
+ const result = await reader.read()
32
+ if (result.done) break
33
+ if (result.value.length === 0) throw new ServerComponentError("component_protocol", 400)
34
+ size += result.value.length
35
+ if (size > limit) throw new ServerComponentError("component_limit", 413)
36
+ chunks.push(result.value)
37
+ }
38
+ if (signal.aborted) throw new ServerComponentError("component_cancelled", 499)
39
+ const bytes = new Uint8Array(size)
40
+ let offset = 0
41
+ for (const chunk of chunks) {
42
+ bytes.set(chunk, offset)
43
+ offset += chunk.length
44
+ }
45
+ return bytes
46
+ } catch (error) {
47
+ await reader.cancel().catch(() => {
48
+ /* Keep the primary read failure. */
49
+ })
50
+ throw error
51
+ } finally {
52
+ signal.removeEventListener("abort", cancel)
53
+ reader.releaseLock()
54
+ }
55
+ }
56
+
57
+ export function encodeComponentBytes(bytes: Uint8Array): string {
58
+ let binary = ""
59
+ for (const byte of bytes) binary += String.fromCharCode(byte)
60
+ return btoa(binary)
61
+ }
62
+
63
+ export function decodeComponentBytes(value: unknown): Uint8Array {
64
+ if (
65
+ typeof value !== "string" ||
66
+ value.length > Math.ceil(COMPONENT_LIMITS.outputBytes / 3) * 4 ||
67
+ !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)
68
+ )
69
+ throw new ServerComponentError("component_protocol", 400)
70
+ return Uint8Array.from(atob(value), (item) => item.charCodeAt(0))
71
+ }
@@ -0,0 +1,21 @@
1
+ import { validateComponentHTML } from "./html.ts"
2
+
3
+ interface TrustedHTMLFactory {
4
+ createPolicy(
5
+ name: string,
6
+ rules: { createHTML(html: string): string },
7
+ ): { createHTML(html: string): unknown }
8
+ }
9
+
10
+ /** Explicit opt-in for native framework HTML sinks. Every accepted string is tokenized first. */
11
+ export function installComponentTrustedTypesPolicy(): void {
12
+ // Trusted Types is not yet declared in all supported TypeScript DOM libraries.
13
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion lint/plugin/noChainedTypeAssertions: Trusted Types is optional on globalThis and absent from some DOM type libraries; the policy still validates HTML before insertion.
14
+ const factory = (globalThis as unknown as { trustedTypes?: TrustedHTMLFactory }).trustedTypes
15
+ factory?.createPolicy("default", {
16
+ createHTML(html) {
17
+ validateComponentHTML(html)
18
+ return html
19
+ },
20
+ })
21
+ }
@@ -0,0 +1,138 @@
1
+ import type { StandardSchemaV1 } from "@nifrajs/core/server"
2
+ import type { LoaderContext } from "../manifest.ts"
3
+
4
+ export type ComponentKey = string | number
5
+ export type ComponentValue =
6
+ | null
7
+ | boolean
8
+ | number
9
+ | string
10
+ | readonly ComponentValue[]
11
+ | {
12
+ readonly [key: string]: ComponentValue
13
+ }
14
+
15
+ export interface ServerComponentContext extends LoaderContext {
16
+ readonly signal: AbortSignal
17
+ readonly data: unknown
18
+ readonly layoutData: readonly unknown[]
19
+ }
20
+
21
+ export interface ServerComponentDefinition<Input, Props, View> {
22
+ readonly input: StandardSchemaV1<unknown, Input>
23
+ readonly props: StandardSchemaV1<unknown, Props>
24
+ readonly authorize: (ctx: ServerComponentContext, input: Input) => void | Promise<void>
25
+ readonly load: (ctx: ServerComponentContext, input: Input) => unknown | Promise<unknown>
26
+ readonly view: (args: {
27
+ readonly props: Props
28
+ readonly children?: readonly ComponentRecord[]
29
+ }) => View | Promise<View>
30
+ readonly capabilities?: readonly string[]
31
+ }
32
+
33
+ export interface ServerComponent<Input = unknown, Props = unknown, View = unknown> {
34
+ /** Compiler-generated opaque reference; application authors do not assign module URLs. */
35
+ readonly reference?: string
36
+ readonly view: (args: {
37
+ readonly props: Props
38
+ readonly children?: readonly ComponentRecord[]
39
+ }) => View | Promise<View>
40
+ readonly input: StandardSchemaV1<unknown, Input>
41
+ readonly props: StandardSchemaV1<unknown, Props>
42
+ }
43
+
44
+ export interface PreparedServerComponent<Props = unknown, View = unknown> {
45
+ readonly props: Props
46
+ readonly view: (args: {
47
+ readonly props: Props
48
+ readonly children?: readonly ComponentRecord[]
49
+ }) => View | Promise<View>
50
+ }
51
+
52
+ export interface ComponentRenderContext {
53
+ readonly reference: string
54
+ readonly instance: string
55
+ readonly signal: AbortSignal
56
+ readonly nonce?: string
57
+ readonly children?: readonly ComponentRecord[]
58
+ }
59
+
60
+ export interface ComponentRender {
61
+ readonly html: string
62
+ readonly payload?: ComponentValue
63
+ readonly islands?: readonly ComponentIsland[]
64
+ }
65
+
66
+ export interface ComponentIsland {
67
+ readonly reference: string
68
+ readonly key: ComponentKey
69
+ readonly props: ComponentValue
70
+ readonly renderId: string
71
+ readonly slots?: Readonly<Record<string, string>>
72
+ }
73
+
74
+ export interface ServerComponentRenderAdapter {
75
+ readonly name: "react" | "vue" | "svelte" | "solid" | "preact"
76
+ readonly version: 1
77
+ render(
78
+ view: unknown,
79
+ props: unknown,
80
+ context: ComponentRenderContext,
81
+ ): ComponentRender | Promise<ComponentRender>
82
+ }
83
+
84
+ export interface ComponentInstance {
85
+ readonly component: ServerComponentHandle
86
+ readonly key: ComponentKey
87
+ readonly input: unknown
88
+ readonly parent?: string
89
+ }
90
+
91
+ export interface ComponentOwner {
92
+ readonly components: readonly ServerComponentHandle[]
93
+ readonly capabilities?: readonly string[]
94
+ readonly instances: (
95
+ ctx: ServerComponentContext,
96
+ ) => readonly ComponentInstance[] | Promise<readonly ComponentInstance[]>
97
+ /** A public, non-secret token supplied by the application's auth integration. */
98
+ readonly scope: "anonymous" | ((ctx: ServerComponentContext) => string | Promise<string>)
99
+ }
100
+
101
+ export interface ServerComponentHandle {
102
+ readonly reference?: string
103
+ readonly input: StandardSchemaV1
104
+ readonly props: StandardSchemaV1
105
+ readonly view: (args: never) => unknown
106
+ }
107
+
108
+ export interface ComponentRecord extends ComponentRender {
109
+ readonly instance: string
110
+ readonly reference: string
111
+ readonly key: ComponentKey
112
+ readonly parent: string | null
113
+ readonly input: ComponentValue
114
+ }
115
+
116
+ export interface ComponentState {
117
+ readonly v: 1
118
+ readonly build: string
119
+ readonly adapter: "react" | "vue" | "svelte" | "solid" | "preact"
120
+ readonly owner: string
121
+ readonly scope: string
122
+ readonly records: readonly ComponentRecord[]
123
+ }
124
+
125
+ /** Optional seam passed to createWebApp; disabled applications have no runtime import of this feature. */
126
+ export interface ServerComponentRuntime {
127
+ owns(routeId: string): boolean
128
+ capabilities(routeId: string): readonly string[]
129
+ classify(request: Request, routeId: string): import("./protocol.ts").ComponentRequest | undefined
130
+ execute(
131
+ routeId: string,
132
+ context: ServerComponentContext,
133
+ selection?: import("./protocol.ts").ComponentRequest,
134
+ nonce?: string,
135
+ ): Promise<ComponentState>
136
+ response(state: ComponentState, selection: import("./protocol.ts").ComponentRequest): Response
137
+ failure(error: unknown): Response
138
+ }