skybridge 0.0.0-dev.feb36b5 → 0.0.0-dev.febcf34

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 (495) hide show
  1. package/LICENSE +21 -674
  2. package/README.md +124 -97
  3. package/bin/run.js +5 -0
  4. package/dist/cli/build-helpers.d.ts +10 -0
  5. package/dist/cli/build-helpers.js +93 -0
  6. package/dist/cli/build-helpers.js.map +1 -0
  7. package/dist/cli/build-helpers.test.js +89 -0
  8. package/dist/cli/build-helpers.test.js.map +1 -0
  9. package/dist/cli/build-steps.d.ts +2 -0
  10. package/dist/cli/build-steps.js +68 -0
  11. package/dist/cli/build-steps.js.map +1 -0
  12. package/dist/cli/build-steps.test.js +52 -0
  13. package/dist/cli/build-steps.test.js.map +1 -0
  14. package/dist/cli/detect-port.d.ts +18 -0
  15. package/dist/cli/detect-port.js +50 -0
  16. package/dist/cli/detect-port.js.map +1 -0
  17. package/dist/cli/header.d.ts +4 -0
  18. package/dist/cli/header.js +6 -0
  19. package/dist/cli/header.js.map +1 -0
  20. package/dist/cli/resolve-views-dir.d.ts +1 -0
  21. package/dist/cli/resolve-views-dir.js +17 -0
  22. package/dist/cli/resolve-views-dir.js.map +1 -0
  23. package/dist/cli/run-command.d.ts +2 -0
  24. package/dist/cli/run-command.js +43 -0
  25. package/dist/cli/run-command.js.map +1 -0
  26. package/dist/cli/run-plain.d.ts +18 -0
  27. package/dist/cli/run-plain.js +89 -0
  28. package/dist/cli/run-plain.js.map +1 -0
  29. package/dist/cli/telemetry.d.ts +7 -0
  30. package/dist/cli/telemetry.js +123 -0
  31. package/dist/cli/telemetry.js.map +1 -0
  32. package/dist/cli/tunnel-control-server.d.ts +9 -0
  33. package/dist/cli/tunnel-control-server.js +31 -0
  34. package/dist/cli/tunnel-control-server.js.map +1 -0
  35. package/dist/cli/tunnel-control-server.test.d.ts +1 -0
  36. package/dist/cli/tunnel-control-server.test.js +39 -0
  37. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  38. package/dist/cli/tunnel-handler.d.ts +3 -0
  39. package/dist/cli/tunnel-handler.js +48 -0
  40. package/dist/cli/tunnel-handler.js.map +1 -0
  41. package/dist/cli/tunnel-handler.test.d.ts +1 -0
  42. package/dist/cli/tunnel-handler.test.js +105 -0
  43. package/dist/cli/tunnel-handler.test.js.map +1 -0
  44. package/dist/cli/tunnel.d.ts +57 -0
  45. package/dist/cli/tunnel.js +154 -0
  46. package/dist/cli/tunnel.js.map +1 -0
  47. package/dist/cli/tunnel.test.d.ts +1 -0
  48. package/dist/cli/tunnel.test.js +190 -0
  49. package/dist/cli/tunnel.test.js.map +1 -0
  50. package/dist/cli/types.d.ts +5 -0
  51. package/dist/cli/types.js +2 -0
  52. package/dist/cli/types.js.map +1 -0
  53. package/dist/cli/use-execute-steps.d.ts +11 -0
  54. package/dist/cli/use-execute-steps.js +36 -0
  55. package/dist/cli/use-execute-steps.js.map +1 -0
  56. package/dist/cli/use-messages.d.ts +3 -0
  57. package/dist/cli/use-messages.js +11 -0
  58. package/dist/cli/use-messages.js.map +1 -0
  59. package/dist/cli/use-nodemon.d.ts +16 -0
  60. package/dist/cli/use-nodemon.js +84 -0
  61. package/dist/cli/use-nodemon.js.map +1 -0
  62. package/dist/cli/use-open-browser.d.ts +1 -0
  63. package/dist/cli/use-open-browser.js +44 -0
  64. package/dist/cli/use-open-browser.js.map +1 -0
  65. package/dist/cli/use-tunnel.d.ts +14 -0
  66. package/dist/cli/use-tunnel.js +131 -0
  67. package/dist/cli/use-tunnel.js.map +1 -0
  68. package/dist/cli/use-typescript-check.d.ts +15 -0
  69. package/dist/cli/use-typescript-check.js +97 -0
  70. package/dist/cli/use-typescript-check.js.map +1 -0
  71. package/dist/commands/build.d.ts +6 -0
  72. package/dist/commands/build.js +31 -0
  73. package/dist/commands/build.js.map +1 -0
  74. package/dist/commands/create.d.ts +9 -0
  75. package/dist/commands/create.js +30 -0
  76. package/dist/commands/create.js.map +1 -0
  77. package/dist/commands/dev.d.ts +13 -0
  78. package/dist/commands/dev.js +128 -0
  79. package/dist/commands/dev.js.map +1 -0
  80. package/dist/commands/start.d.ts +9 -0
  81. package/dist/commands/start.js +55 -0
  82. package/dist/commands/start.js.map +1 -0
  83. package/dist/commands/telemetry/disable.d.ts +5 -0
  84. package/dist/commands/telemetry/disable.js +14 -0
  85. package/dist/commands/telemetry/disable.js.map +1 -0
  86. package/dist/commands/telemetry/enable.d.ts +5 -0
  87. package/dist/commands/telemetry/enable.js +14 -0
  88. package/dist/commands/telemetry/enable.js.map +1 -0
  89. package/dist/commands/telemetry/status.d.ts +5 -0
  90. package/dist/commands/telemetry/status.js +14 -0
  91. package/dist/commands/telemetry/status.js.map +1 -0
  92. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  93. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  94. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  95. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  96. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  97. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  98. package/dist/server/auth/discovery.d.ts +32 -0
  99. package/dist/server/auth/discovery.js +56 -0
  100. package/dist/server/auth/discovery.js.map +1 -0
  101. package/dist/server/auth/discovery.test.d.ts +1 -0
  102. package/dist/server/auth/discovery.test.js +93 -0
  103. package/dist/server/auth/discovery.test.js.map +1 -0
  104. package/dist/server/auth/index.d.ts +18 -0
  105. package/dist/server/auth/index.js +2 -0
  106. package/dist/server/auth/index.js.map +1 -0
  107. package/dist/server/auth/providers/auth0.d.ts +18 -0
  108. package/dist/server/auth/providers/auth0.js +31 -0
  109. package/dist/server/auth/providers/auth0.js.map +1 -0
  110. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  111. package/dist/server/auth/providers/auth0.test.js +48 -0
  112. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  113. package/dist/server/auth/providers/clerk.d.ts +14 -0
  114. package/dist/server/auth/providers/clerk.js +16 -0
  115. package/dist/server/auth/providers/clerk.js.map +1 -0
  116. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  117. package/dist/server/auth/providers/clerk.test.js +28 -0
  118. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  119. package/dist/server/auth/providers/custom.d.ts +24 -0
  120. package/dist/server/auth/providers/custom.js +37 -0
  121. package/dist/server/auth/providers/custom.js.map +1 -0
  122. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  123. package/dist/server/auth/providers/custom.test.js +107 -0
  124. package/dist/server/auth/providers/custom.test.js.map +1 -0
  125. package/dist/server/auth/providers/descope.d.ts +15 -0
  126. package/dist/server/auth/providers/descope.js +34 -0
  127. package/dist/server/auth/providers/descope.js.map +1 -0
  128. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  129. package/dist/server/auth/providers/descope.test.js +38 -0
  130. package/dist/server/auth/providers/descope.test.js.map +1 -0
  131. package/dist/server/auth/providers/shared.d.ts +2 -0
  132. package/dist/server/auth/providers/shared.js +6 -0
  133. package/dist/server/auth/providers/shared.js.map +1 -0
  134. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  135. package/dist/server/auth/providers/shared.test.js +10 -0
  136. package/dist/server/auth/providers/shared.test.js.map +1 -0
  137. package/dist/server/auth/providers/stytch.d.ts +12 -0
  138. package/dist/server/auth/providers/stytch.js +13 -0
  139. package/dist/server/auth/providers/stytch.js.map +1 -0
  140. package/dist/server/auth/providers/workos.d.ts +11 -0
  141. package/dist/server/auth/providers/workos.js +12 -0
  142. package/dist/server/auth/providers/workos.js.map +1 -0
  143. package/dist/server/auth/setup.d.ts +4 -0
  144. package/dist/server/auth/setup.js +51 -0
  145. package/dist/server/auth/setup.js.map +1 -0
  146. package/dist/server/auth/setup.test.d.ts +1 -0
  147. package/dist/server/auth/setup.test.js +185 -0
  148. package/dist/server/auth/setup.test.js.map +1 -0
  149. package/dist/server/auth/verify.d.ts +12 -0
  150. package/dist/server/auth/verify.js +38 -0
  151. package/dist/server/auth/verify.js.map +1 -0
  152. package/dist/server/auth/verify.test.d.ts +1 -0
  153. package/dist/server/auth/verify.test.js +100 -0
  154. package/dist/server/auth/verify.test.js.map +1 -0
  155. package/dist/server/auth.d.ts +20 -0
  156. package/dist/server/auth.js +28 -0
  157. package/dist/server/auth.js.map +1 -0
  158. package/dist/server/build-manifest.test.d.ts +1 -0
  159. package/dist/server/build-manifest.test.js +27 -0
  160. package/dist/server/build-manifest.test.js.map +1 -0
  161. package/dist/server/content-helpers.d.ts +67 -0
  162. package/dist/server/content-helpers.js +79 -0
  163. package/dist/server/content-helpers.js.map +1 -0
  164. package/dist/server/content-helpers.test.d.ts +1 -0
  165. package/dist/server/content-helpers.test.js +70 -0
  166. package/dist/server/content-helpers.test.js.map +1 -0
  167. package/dist/server/express.d.ts +11 -0
  168. package/dist/server/express.js +101 -0
  169. package/dist/server/express.js.map +1 -0
  170. package/dist/server/express.test.d.ts +1 -0
  171. package/dist/server/express.test.js +491 -0
  172. package/dist/server/express.test.js.map +1 -0
  173. package/dist/server/file-ref.d.ts +28 -0
  174. package/dist/server/file-ref.js +27 -0
  175. package/dist/server/file-ref.js.map +1 -0
  176. package/dist/server/index.d.ts +15 -0
  177. package/dist/server/index.js +12 -0
  178. package/dist/server/index.js.map +1 -0
  179. package/dist/server/inferUtilityTypes.d.ts +64 -0
  180. package/dist/server/inferUtilityTypes.js +2 -0
  181. package/dist/server/inferUtilityTypes.js.map +1 -0
  182. package/dist/server/metric.d.ts +14 -0
  183. package/dist/server/metric.js +62 -0
  184. package/dist/server/metric.js.map +1 -0
  185. package/dist/server/middleware.d.ts +137 -0
  186. package/dist/server/middleware.js +93 -0
  187. package/dist/server/middleware.js.map +1 -0
  188. package/dist/server/middleware.test-d.d.ts +1 -0
  189. package/dist/server/middleware.test-d.js +75 -0
  190. package/dist/server/middleware.test-d.js.map +1 -0
  191. package/dist/server/middleware.test.d.ts +1 -0
  192. package/dist/server/middleware.test.js +493 -0
  193. package/dist/server/middleware.test.js.map +1 -0
  194. package/dist/server/requestOrigin.d.ts +7 -0
  195. package/dist/server/requestOrigin.js +25 -0
  196. package/dist/server/requestOrigin.js.map +1 -0
  197. package/dist/server/server.d.ts +419 -0
  198. package/dist/server/server.js +632 -0
  199. package/dist/server/server.js.map +1 -0
  200. package/dist/{src/server → server}/templateHelper.d.ts +5 -4
  201. package/dist/server/templateHelper.js +11 -0
  202. package/dist/server/templateHelper.js.map +1 -0
  203. package/dist/server/templates.generated.d.ts +4 -0
  204. package/dist/server/templates.generated.js +47 -0
  205. package/dist/server/templates.generated.js.map +1 -0
  206. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  207. package/dist/server/tunnel-proxy-router.js +110 -0
  208. package/dist/server/tunnel-proxy-router.js.map +1 -0
  209. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  210. package/dist/server/tunnel-proxy-router.test.js +229 -0
  211. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  212. package/dist/server/view-name.test-d.d.ts +1 -0
  213. package/dist/server/view-name.test-d.js +8 -0
  214. package/dist/server/view-name.test-d.js.map +1 -0
  215. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  216. package/dist/server/view-resource-resolution.test.js +171 -0
  217. package/dist/server/view-resource-resolution.test.js.map +1 -0
  218. package/dist/server/viewsDevServer.d.ts +14 -0
  219. package/dist/server/viewsDevServer.js +45 -0
  220. package/dist/server/viewsDevServer.js.map +1 -0
  221. package/dist/test/utils.d.ts +127 -0
  222. package/dist/test/utils.js +247 -0
  223. package/dist/test/utils.js.map +1 -0
  224. package/dist/test/view.test.d.ts +1 -0
  225. package/dist/test/view.test.js +536 -0
  226. package/dist/test/view.test.js.map +1 -0
  227. package/dist/version.d.ts +1 -0
  228. package/dist/version.js +3 -0
  229. package/dist/version.js.map +1 -0
  230. package/dist/web/bridges/adaptor.d.ts +51 -0
  231. package/dist/web/bridges/adaptor.js +330 -0
  232. package/dist/web/bridges/adaptor.js.map +1 -0
  233. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  234. package/dist/web/bridges/adaptor.test.js +208 -0
  235. package/dist/web/bridges/adaptor.test.js.map +1 -0
  236. package/dist/web/bridges/apps-sdk/bridge.d.ts +15 -0
  237. package/dist/web/bridges/apps-sdk/bridge.js +58 -0
  238. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
  239. package/dist/web/bridges/apps-sdk/index.d.ts +4 -0
  240. package/dist/web/bridges/apps-sdk/index.js +4 -0
  241. package/dist/web/bridges/apps-sdk/index.js.map +1 -0
  242. package/dist/web/bridges/apps-sdk/types.d.ts +133 -0
  243. package/dist/web/bridges/apps-sdk/types.js.map +1 -0
  244. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
  245. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
  246. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
  247. package/dist/web/bridges/get-adaptor.d.ts +9 -0
  248. package/dist/web/bridges/get-adaptor.js +10 -0
  249. package/dist/web/bridges/get-adaptor.js.map +1 -0
  250. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  251. package/dist/web/bridges/get-adaptor.test.js +32 -0
  252. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  253. package/dist/web/bridges/index.d.ts +5 -0
  254. package/dist/web/bridges/index.js +6 -0
  255. package/dist/web/bridges/index.js.map +1 -0
  256. package/dist/web/bridges/mcp-app/bridge.d.ts +39 -0
  257. package/dist/web/bridges/mcp-app/bridge.js +166 -0
  258. package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
  259. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  260. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  261. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  262. package/dist/web/bridges/mcp-app/index.d.ts +3 -0
  263. package/dist/web/bridges/mcp-app/index.js +3 -0
  264. package/dist/web/bridges/mcp-app/index.js.map +1 -0
  265. package/dist/web/bridges/mcp-app/types.d.ts +8 -0
  266. package/dist/web/bridges/mcp-app/types.js +2 -0
  267. package/dist/web/bridges/mcp-app/types.js.map +1 -0
  268. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
  269. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
  270. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
  271. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
  272. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
  273. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
  274. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  275. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  276. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  277. package/dist/web/bridges/types.d.ts +214 -0
  278. package/dist/web/bridges/types.js +15 -0
  279. package/dist/web/bridges/types.js.map +1 -0
  280. package/dist/web/bridges/types.test.d.ts +1 -0
  281. package/dist/web/bridges/types.test.js +19 -0
  282. package/dist/web/bridges/types.test.js.map +1 -0
  283. package/dist/web/bridges/use-host-context.d.ts +7 -0
  284. package/dist/web/bridges/use-host-context.js +13 -0
  285. package/dist/web/bridges/use-host-context.js.map +1 -0
  286. package/dist/web/components/modal-provider.d.ts +4 -0
  287. package/dist/web/components/modal-provider.js +46 -0
  288. package/dist/web/components/modal-provider.js.map +1 -0
  289. package/dist/web/create-store.d.ts +29 -0
  290. package/dist/web/create-store.js +64 -0
  291. package/dist/web/create-store.js.map +1 -0
  292. package/dist/web/create-store.test.d.ts +1 -0
  293. package/dist/web/create-store.test.js +132 -0
  294. package/dist/web/create-store.test.js.map +1 -0
  295. package/dist/web/data-llm.d.ts +47 -0
  296. package/dist/web/data-llm.js +100 -0
  297. package/dist/web/data-llm.js.map +1 -0
  298. package/dist/web/data-llm.test.d.ts +1 -0
  299. package/dist/web/data-llm.test.js +154 -0
  300. package/dist/web/data-llm.test.js.map +1 -0
  301. package/dist/web/generate-helpers.d.ts +120 -0
  302. package/dist/web/generate-helpers.js +115 -0
  303. package/dist/web/generate-helpers.js.map +1 -0
  304. package/dist/web/generate-helpers.test-d.d.ts +1 -0
  305. package/dist/web/generate-helpers.test-d.js +211 -0
  306. package/dist/web/generate-helpers.test-d.js.map +1 -0
  307. package/dist/web/generate-helpers.test.d.ts +1 -0
  308. package/dist/web/generate-helpers.test.js +17 -0
  309. package/dist/web/generate-helpers.test.js.map +1 -0
  310. package/dist/web/helpers/state.d.ts +7 -0
  311. package/dist/web/helpers/state.js +45 -0
  312. package/dist/web/helpers/state.js.map +1 -0
  313. package/dist/web/helpers/state.test.d.ts +1 -0
  314. package/dist/web/helpers/state.test.js +53 -0
  315. package/dist/web/helpers/state.test.js.map +1 -0
  316. package/dist/web/hooks/index.d.ts +15 -0
  317. package/dist/web/hooks/index.js +16 -0
  318. package/dist/web/hooks/index.js.map +1 -0
  319. package/dist/web/hooks/test/utils.d.ts +20 -0
  320. package/dist/web/hooks/test/utils.js +75 -0
  321. package/dist/web/hooks/test/utils.js.map +1 -0
  322. package/dist/web/hooks/use-call-tool.d.ts +146 -0
  323. package/dist/web/hooks/use-call-tool.js +96 -0
  324. package/dist/web/hooks/use-call-tool.js.map +1 -0
  325. package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
  326. package/dist/web/hooks/use-call-tool.test-d.js +104 -0
  327. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
  328. package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
  329. package/dist/web/hooks/use-call-tool.test.js +225 -0
  330. package/dist/web/hooks/use-call-tool.test.js.map +1 -0
  331. package/dist/web/hooks/use-display-mode.d.ts +24 -0
  332. package/dist/web/hooks/use-display-mode.js +29 -0
  333. package/dist/web/hooks/use-display-mode.js.map +1 -0
  334. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  335. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  336. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  337. package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
  338. package/dist/web/hooks/use-display-mode.test.js +77 -0
  339. package/dist/web/hooks/use-display-mode.test.js.map +1 -0
  340. package/dist/web/hooks/use-download.d.ts +5 -0
  341. package/dist/web/hooks/use-download.js +8 -0
  342. package/dist/web/hooks/use-download.js.map +1 -0
  343. package/dist/web/hooks/use-download.test.d.ts +1 -0
  344. package/dist/web/hooks/use-download.test.js +103 -0
  345. package/dist/web/hooks/use-download.test.js.map +1 -0
  346. package/dist/web/hooks/use-files.d.ts +39 -0
  347. package/dist/web/hooks/use-files.js +42 -0
  348. package/dist/web/hooks/use-files.js.map +1 -0
  349. package/dist/web/hooks/use-files.test.d.ts +1 -0
  350. package/dist/web/hooks/use-files.test.js +62 -0
  351. package/dist/web/hooks/use-files.test.js.map +1 -0
  352. package/dist/web/hooks/use-layout.d.ts +24 -0
  353. package/dist/web/hooks/use-layout.js +25 -0
  354. package/dist/web/hooks/use-layout.js.map +1 -0
  355. package/dist/web/hooks/use-layout.test.d.ts +1 -0
  356. package/dist/web/hooks/use-layout.test.js +129 -0
  357. package/dist/web/hooks/use-layout.test.js.map +1 -0
  358. package/dist/web/hooks/use-open-external.d.ts +20 -0
  359. package/dist/web/hooks/use-open-external.js +24 -0
  360. package/dist/web/hooks/use-open-external.js.map +1 -0
  361. package/dist/web/hooks/use-open-external.test.d.ts +1 -0
  362. package/dist/web/hooks/use-open-external.test.js +75 -0
  363. package/dist/web/hooks/use-open-external.test.js.map +1 -0
  364. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  365. package/dist/web/hooks/use-register-view-tool.js +50 -0
  366. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  367. package/dist/web/hooks/use-request-close.d.ts +16 -0
  368. package/dist/web/hooks/use-request-close.js +21 -0
  369. package/dist/web/hooks/use-request-close.js.map +1 -0
  370. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  371. package/dist/web/hooks/use-request-close.test.js +47 -0
  372. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  373. package/dist/web/hooks/use-request-modal.d.ts +24 -0
  374. package/dist/web/hooks/use-request-modal.js +31 -0
  375. package/dist/web/hooks/use-request-modal.js.map +1 -0
  376. package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
  377. package/dist/web/hooks/use-request-modal.test.js +71 -0
  378. package/dist/web/hooks/use-request-modal.test.js.map +1 -0
  379. package/dist/web/hooks/use-request-size.d.ts +20 -0
  380. package/dist/web/hooks/use-request-size.js +24 -0
  381. package/dist/web/hooks/use-request-size.js.map +1 -0
  382. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  383. package/dist/web/hooks/use-request-size.test.js +47 -0
  384. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  385. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
  386. package/dist/web/hooks/use-send-follow-up-message.js +25 -0
  387. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
  388. package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
  389. package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
  390. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  391. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  392. package/dist/web/hooks/use-set-open-in-app-url.test.js +63 -0
  393. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  394. package/dist/web/hooks/use-tool-info.d.ts +87 -0
  395. package/dist/web/hooks/use-tool-info.js +49 -0
  396. package/dist/web/hooks/use-tool-info.js.map +1 -0
  397. package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
  398. package/dist/web/hooks/use-tool-info.test-d.js +91 -0
  399. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
  400. package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
  401. package/dist/web/hooks/use-tool-info.test.js +140 -0
  402. package/dist/web/hooks/use-tool-info.test.js.map +1 -0
  403. package/dist/web/hooks/use-user.d.ts +20 -0
  404. package/dist/web/hooks/use-user.js +37 -0
  405. package/dist/web/hooks/use-user.js.map +1 -0
  406. package/dist/web/hooks/use-user.test.d.ts +1 -0
  407. package/dist/web/hooks/use-user.test.js +168 -0
  408. package/dist/web/hooks/use-user.test.js.map +1 -0
  409. package/dist/web/hooks/use-view-state.d.ts +25 -0
  410. package/dist/web/hooks/use-view-state.js +32 -0
  411. package/dist/web/hooks/use-view-state.js.map +1 -0
  412. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  413. package/dist/web/hooks/use-view-state.test.js +181 -0
  414. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  415. package/dist/web/index.d.ts +7 -0
  416. package/dist/web/index.js +8 -0
  417. package/dist/web/index.js.map +1 -0
  418. package/dist/web/mount-view.d.ts +20 -0
  419. package/dist/web/mount-view.js +46 -0
  420. package/dist/web/mount-view.js.map +1 -0
  421. package/dist/web/plugin/data-llm.test.d.ts +1 -0
  422. package/dist/web/plugin/data-llm.test.js +81 -0
  423. package/dist/web/plugin/data-llm.test.js.map +1 -0
  424. package/dist/web/plugin/plugin.d.ts +33 -0
  425. package/dist/web/plugin/plugin.js +188 -0
  426. package/dist/web/plugin/plugin.js.map +1 -0
  427. package/dist/web/plugin/scan-views.d.ts +16 -0
  428. package/dist/web/plugin/scan-views.js +88 -0
  429. package/dist/web/plugin/scan-views.js.map +1 -0
  430. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  431. package/dist/web/plugin/scan-views.test.js +99 -0
  432. package/dist/web/plugin/scan-views.test.js.map +1 -0
  433. package/dist/web/plugin/transform-data-llm.d.ts +12 -0
  434. package/dist/web/plugin/transform-data-llm.js +96 -0
  435. package/dist/web/plugin/transform-data-llm.js.map +1 -0
  436. package/dist/web/plugin/transform-data-llm.test.d.ts +1 -0
  437. package/dist/web/plugin/transform-data-llm.test.js +81 -0
  438. package/dist/web/plugin/transform-data-llm.test.js.map +1 -0
  439. package/dist/web/plugin/validate-view.d.ts +1 -0
  440. package/dist/web/plugin/validate-view.js +9 -0
  441. package/dist/web/plugin/validate-view.js.map +1 -0
  442. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  443. package/dist/web/plugin/validate-view.test.js +24 -0
  444. package/dist/web/plugin/validate-view.test.js.map +1 -0
  445. package/dist/web/proxy.d.ts +1 -0
  446. package/dist/web/proxy.js +52 -0
  447. package/dist/web/proxy.js.map +1 -0
  448. package/dist/web/types.d.ts +20 -0
  449. package/dist/web/types.js +2 -0
  450. package/dist/web/types.js.map +1 -0
  451. package/package.json +90 -31
  452. package/tsconfig.base.json +33 -0
  453. package/dist/src/server/index.d.ts +0 -2
  454. package/dist/src/server/index.js +0 -3
  455. package/dist/src/server/index.js.map +0 -1
  456. package/dist/src/server/server.d.ts +0 -13
  457. package/dist/src/server/server.js +0 -54
  458. package/dist/src/server/server.js.map +0 -1
  459. package/dist/src/server/templateHelper.js +0 -29
  460. package/dist/src/server/templateHelper.js.map +0 -1
  461. package/dist/src/server/templates/development.hbs +0 -12
  462. package/dist/src/server/templates/production.hbs +0 -6
  463. package/dist/src/server/widgetsDevServer.d.ts +0 -12
  464. package/dist/src/server/widgetsDevServer.js +0 -39
  465. package/dist/src/server/widgetsDevServer.js.map +0 -1
  466. package/dist/src/test/setup.js +0 -9
  467. package/dist/src/test/setup.js.map +0 -1
  468. package/dist/src/test/utils.d.ts +0 -28
  469. package/dist/src/test/utils.js +0 -43
  470. package/dist/src/test/utils.js.map +0 -1
  471. package/dist/src/test/widget.test.js +0 -76
  472. package/dist/src/test/widget.test.js.map +0 -1
  473. package/dist/src/web/index.d.ts +0 -5
  474. package/dist/src/web/index.js +0 -6
  475. package/dist/src/web/index.js.map +0 -1
  476. package/dist/src/web/mount-widget.d.ts +0 -1
  477. package/dist/src/web/mount-widget.js +0 -14
  478. package/dist/src/web/mount-widget.js.map +0 -1
  479. package/dist/src/web/plugin.d.ts +0 -2
  480. package/dist/src/web/plugin.js +0 -28
  481. package/dist/src/web/plugin.js.map +0 -1
  482. package/dist/src/web/types.d.ts +0 -95
  483. package/dist/src/web/types.js.map +0 -1
  484. package/dist/src/web/use-openai-global.d.ts +0 -2
  485. package/dist/src/web/use-openai-global.js +0 -21
  486. package/dist/src/web/use-openai-global.js.map +0 -1
  487. package/dist/src/web/use-tool-output.d.ts +0 -3
  488. package/dist/src/web/use-tool-output.js +0 -5
  489. package/dist/src/web/use-tool-output.js.map +0 -1
  490. package/dist/vitest.config.d.ts +0 -2
  491. package/dist/vitest.config.js +0 -9
  492. package/dist/vitest.config.js.map +0 -1
  493. /package/dist/{src/test/setup.d.ts → cli/build-helpers.test.d.ts} +0 -0
  494. /package/dist/{src/test/widget.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  495. /package/dist/{src/web → web/bridges/apps-sdk}/types.js +0 -0
package/README.md CHANGED
@@ -1,126 +1,153 @@
1
- <div align="center">
2
-
3
- # Skybridge
4
-
5
- **Skybridge is the TypeScript framework for building ChatGPT apps**
6
-
7
- [![By Alpic](https://img.shields.io/badge/Made%20by%20Alpic-f6ffed?logo=alpic)](https://alpic.ai)
8
-
9
- ![NPM Downloads](https://img.shields.io/npm/dm/skybridge?color=e90060)
10
- ![NPM Version](https://img.shields.io/npm/v/skybridge?color=e90060)
11
- ![GitHub License](https://img.shields.io/github/license/alpic-ai/skybridge?color=e90060)
12
-
13
- </div>
14
-
15
- Skybridge comes with 2 packages:
16
-
17
- - `skybridge/server`: A drop-in replacement of the `@modelcontextprotocol/sdk` official `McpServer` class with extra features for widget development.
18
- - `skybridge/web`: A react library with hooks and components to build widgets on the underlying _OpenAI iFrame skybridge_ runtime.
19
-
20
- ## Quick start
21
-
22
- To get started in less than a minute, you can [create a new repository](https://github.com/new?template_name=apps-sdk-template&template_owner=alpic-ai) using our [ChatGPT SDK template](https://github.com/alpic-ai/apps-sdk-template). This template includes a basic setup for both the server and the widgets.
23
-
24
- ## Installation
25
-
1
+ # Skybridge - the MCP Apps framework
2
+
3
+ <p align="center">
4
+ <a href="https://docs.skybridge.tech">
5
+ <picture>
6
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/skybridge-readme-banner-dark.png" />
7
+ <img alt="Skybridge, the full-stack React framework for MCP apps and MCP servers" src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/skybridge-readme-banner-light.png" width="100%" />
8
+ </picture>
9
+ </a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <strong>The full-stack React framework for MCP Apps and MCP Servers.</strong>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://docs.skybridge.tech">Documentation</a> ·
18
+ <a href="https://docs.skybridge.tech/quickstart/create-new-app">Quickstart</a> ·
19
+ <a href="https://github.com/alpic-ai/skybridge/tree/main/examples">Examples</a>
20
+ </p>
21
+
22
+ <p align="center">
23
+ <a href="https://www.npmjs.com/package/skybridge"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/skybridge?color=77F5EE&amp;labelColor=161B22&amp;style=for-the-badge"><img alt="npm version" src="https://img.shields.io/npm/v/skybridge?color=E3FAF7&amp;labelColor=F6F8FA&amp;style=for-the-badge"></picture></a>
24
+ <a href="https://www.npmjs.com/package/skybridge"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/skybridge?color=D7FFC8&amp;labelColor=161B22&amp;style=for-the-badge"><img alt="npm downloads" src="https://img.shields.io/npm/dm/skybridge?color=E8FBD9&amp;labelColor=F6F8FA&amp;style=for-the-badge"></picture></a>
25
+ <a href="https://discord.com/invite/gNAazGueab"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/Discord-community-77F5EE?style=for-the-badge&amp;logo=discord&amp;logoColor=77F5EE&amp;labelColor=161B22"><img alt="Discord community" src="https://img.shields.io/badge/Discord-community-E3FAF7?style=for-the-badge&amp;logo=discord&amp;logoColor=5865F2&amp;labelColor=F6F8FA"></picture></a>
26
+ <a href="https://github.com/alpic-ai/skybridge/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/license/alpic-ai/skybridge?color=D7FFC8&amp;labelColor=161B22&amp;style=for-the-badge"><img alt="License: MIT" src="https://img.shields.io/github/license/alpic-ai/skybridge?color=E8FBD9&amp;labelColor=F6F8FA&amp;style=for-the-badge"></picture></a>
27
+ </p>
28
+
29
+ ## About Skybridge
30
+
31
+ Skybridge helps developers build type-safe MCP apps for Claude, ChatGPT and other UI-enabled MCP clients, with a complete set of tooling designed for both humans and agents.
32
+
33
+ Why? MCP apps extend the [Model Context Protocol](https://modelcontextprotocol.io/docs/getting-started/intro) with **rich, interactive UI views** rendered from MCP servers. Conversational apps need seamless interaction between the user, the UI, and the model. This means new UX patterns, developer tooling, and abstractions.
34
+ Plus, the raw SDKs are low-level: no hooks, type safety, HMR, etc.
35
+
36
+ That's why we built *Skybridge*.
37
+
38
+ Features include:
39
+
40
+ - **Delightful dev environment**: Skybridge provides a dev server with a local emulator, hot module reload, and a permanent tunnel to connect your local app to Claude and ChatGPT.
41
+ - **Write once, run everywhere**: the framework abstracts implementation differences between MCP clients, so your app runs seamlessly in Claude, ChatGPT, VSCode, and any other MCP apps compatible client.
42
+ - **Agent-ready**: powerful skills, CLI, and programmatic dev tool APIs, everything your coding agent needs to build MCP apps end-to-end.
43
+ - **Type-safe end-to-end**: tRPC-style inference from MCP server tool definition to React view for type safety from server to frontend.
44
+ - **React-first**: Intuitive React Query-style hooks, with advanced state management.
45
+ - **Example library**: get started quickly with ChatGPT- and Claude-ready app examples for ecommerce, travel, SaaS, and more.
46
+
47
+ They chose to build their MCP apps with Skybridge:
48
+
49
+ <p align="center">
50
+ <a href="https://www.datadoghq.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/datadog-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/datadog-light.svg" alt="Datadog" height="24"></picture></a>
51
+ &nbsp;&nbsp;
52
+ <a href="https://bitmovin.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/bitmovin-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/bitmovin-light.svg" alt="Bitmovin" height="22"></picture></a>
53
+ &nbsp;&nbsp;
54
+ <a href="https://www.evaneos.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/evaneos-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/evaneos-light.svg" alt="Evaneos" height="18"></picture></a>
55
+ &nbsp;&nbsp;
56
+ <a href="https://www.touchstream.media"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/touchstream-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/touchstream-light.svg" alt="Touchstream" height="24"></picture></a>
57
+ &nbsp;&nbsp;
58
+ <a href="https://www.cottages.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/cottages-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/cottages-light.svg" alt="Cottages.com" height="24"></picture></a>
59
+ </p>
60
+
61
+ ## Get started
62
+
63
+ **For agents**
64
+
65
+ Install our [skill](https://docs.skybridge.tech/devtools/skills) for building MCP apps and ChatGPT apps:
26
66
  ```bash
27
- pnpm add skybridge
67
+ npx skills add alpic-ai/skybridge -s skybridge
28
68
  ```
69
+ Once installed, ask your agent "What skills do you have?" to confirm, then try:
29
70
 
30
- ## Concepts
31
-
32
- ### Widgets
33
-
34
- > A widget is a UI component that turns structured tool results into a human-friendly UI. Those are built using React components. They are rendered inside an iframe inline with the conversation on ChatGPT.
71
+ - _Create a new MCP app_
72
+ - _Migrate my MCP server to the Skybridge framework_
73
+ - _Add a new view to my MCP app_
35
74
 
36
- Each widget in your app must have a unique name. The name is used to bridge the tool invocation result with the widget React component.
75
+ **For humans**
37
76
 
38
- For example, in order to register a new widget named `pokemon` on your ChatGPT app. You should have the following file structure and file contents:
39
-
40
- _Project structure_
41
-
42
- ```
43
- server/
44
- └── src/
45
- └── index.ts // Register the widget with McpServer.widget()
46
- web/
47
- └── src/
48
- └── widgets/
49
- └── pokemon.tsx // Use the same widget name as the file name
77
+ Bootstrap a new project with:
78
+ ```bash
79
+ npm create skybridge@latest my-app
50
80
  ```
81
+ For full install instructions, read our [**Quickstart guide**](https://docs.skybridge.tech/quickstart/create-new-app).
51
82
 
52
- _server/src/index.ts_
53
-
54
- ```ts
55
- import { McpServer } from "skybridge/server";
56
-
57
- const server = new McpServer();
83
+ ## Documentation
58
84
 
59
- server.widget(
60
- "pokemon"
61
- // Remaining arguments...
62
- );
63
- ```
64
-
65
- _web/src/widgets/pokemon.tsx_
85
+ The [Skybridge documentation](https://docs.skybridge.tech) covers the full lifecycle of building MCP Apps:
66
86
 
67
- ```ts
68
- import { mountWidget } from "skybridge/web";
87
+ - [Fundamentals](https://docs.skybridge.tech/fundamentals): understand MCP Apps, ChatGPT Apps, and how Skybridge bridges both runtimes.
88
+ - [Core concepts](https://docs.skybridge.tech/concepts): learn about server <> model <> UI data flows, LLM context sync, type safety, and instant local iteration with our devtools.
89
+ - [Guides](https://docs.skybridge.tech/guides/fetching-data): build real app behavior with tools, views, state, and model communication.
90
+ - [API Reference](https://docs.skybridge.tech/api-reference): browse our MCP server APIs, React hooks, CLI commands, and runtime compatibility.
69
91
 
70
- const Pokemon: React.FunctionComponent = () => {
71
- // Your React component code goes here...
72
- };
92
+ ## Deploy
73
93
 
74
- mountWidget(<Pokemon />);
75
- ```
94
+ Deploy Skybridge apps instantly on [Alpic](https://alpic.ai) for scalable hosting, MCP-specific analytics, permanent tunneling, app store compliance auditing and submission help. You can also self-host on any Node.js-compatible platform.
76
95
 
77
- ## Packages
96
+ See our [deployment guide](https://docs.skybridge.tech/quickstart/deploy) for the full production path.
78
97
 
79
- ### skybridge/server
98
+ ## Community & Contributing
80
99
 
81
- The `skybridge/server` package is a drop-in replacement of the `@modelcontextprotocol/sdk` official `McpServer` class with extra features for widget development. If you're already using the `@modelcontextprotocol/sdk`, you can simply replace your `McpServer` import with `skybridge/server` and you're good to go.
100
+ We'd love your help improving Skybridge. Here are a few ways to get involved:
82
101
 
83
- ### skybridge/web
102
+ - **Bugs**: If you run into a bug or unexpected behavior, open a [GitHub Issue](https://github.com/alpic-ai/skybridge/issues) with a clear reproduction.
103
+ - **Questions and ideas**: Need help building with Skybridge or have ideas to improve the framework, docs, examples, or developer experience? [Open an issue](https://github.com/alpic-ai/skybridge/issues) or share them on our [Discord](https://discord.com/invite/gNAazGueab).
104
+ - **Pull requests**: For code or documentation changes, read the [Contributing Guide](https://github.com/alpic-ai/skybridge/blob/main/CONTRIBUTING.md) before opening a PR.
84
105
 
85
- The `skybridge/web` package is a react library with hooks and components to build widgets on the underlying _OpenAI iFrame skybridge_ runtime.
106
+ Skybridge is released under the [MIT License](https://github.com/alpic-ai/skybridge/blob/main/LICENSE).
86
107
 
87
- **Vite plugin**
108
+ ### Contributors
88
109
 
89
- The `skybridge/web` package comes with a Vite plugin that allows you to build your widgets as regular Vite apps.
110
+ Built and maintained with ❤️ by [Harijoe](https://github.com/harijoe), [Fred Barthelet](https://github.com/fredericbarthelet), and the [Alpic](https://alpic.ai) team.
90
111
 
91
- ```ts
92
- import { defineConfig } from "vite";
93
- import { skybridge } from "skybridge/web";
112
+ <a href="https://github.com/alpic-ai/skybridge/graphs/contributors">
113
+ <img src="https://contrib.rocks/image?repo=alpic-ai/skybridge" alt="Skybridge contributors">
114
+ </a>
94
115
 
95
- export default defineConfig({
96
- plugins: [skybridge()],
97
- });
98
- ```
116
+ ## Example templates
99
117
 
100
- **Hooks**
118
+ Explore all our example templates in the [Examples](https://docs.skybridge.tech/examples) section of the documentation.
101
119
 
102
- The `skybridge/web` package comes with a set of hooks to help you build your widgets.
120
+ ### Basic
103
121
 
104
- ```ts
105
- import { useToolOutput } from "skybridge/web";
122
+ | Preview | App | Description | Demo | Code |
123
+ | --- | --- | --- | --- | --- |
124
+ | <img src="docs/images/showcase-example.png" alt="Everything" width="160" /> | Everything | Comprehensive playground app showcasing all Skybridge hooks and features. | [Try Demo](https://everything.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/everything) |
106
125
 
107
- // Initial data returned by the tool invocation on structuredOutput
108
- const toolOutput = useToolOutput();
109
- ```
126
+ ### Use cases
110
127
 
111
- ## Migrate your existing MCP server to a ChatGPT app
128
+ | Preview | App | Description | Demo | Code |
129
+ | --- | --- | --- | --- | --- |
130
+ | <img src="docs/images/showcase-capitals.png" alt="Capitals Explorer" width="160" /> | Capitals Explorer | Interactive world map with geolocation, country information, and dynamic capital exploration. | [Try Demo](https://capitals.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/capitals) |
131
+ | <img src="docs/images/showcase-flight-booking.png" alt="Flight Booking" width="160" /> | Flight Booking | Flight search carousel with route details, pricing comparison, and external booking. | [Try Demo](https://flight-booking.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/flight-booking) |
132
+ | <img src="docs/images/showcase-ecommerce.png" alt="Ecommerce Carousel" width="160" /> | Ecommerce Carousel | Product carousel with persistent cart, localization, theme switching, and modal dialogs. | [Try Demo](https://ecommerce.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/ecom-carousel) |
133
+ | <img src="docs/images/showcase-investigation-game.png" alt="Investigation Game" width="160" /> | Investigation Game | Multi-screen mystery game with fullscreen mode, dynamic story progression and context asynchronicity demonstration | [Try Demo](https://investigation-game.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/investigation-game) |
134
+ | <img src="docs/images/showcase-productivity.png" alt="Productivity" width="160" /> | Productivity | Interactive analytics dashboard with charts, theme adaptation, localization, fullscreen mode, and bidirectional tool calls. | [Try Demo](https://productivity.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/productivity) |
135
+ | <img src="docs/images/showcase-times-up.png" alt="Time's Up" width="160" /> | Time's Up | Word-guessing party game where the user gives hints and the AI tries to guess. | [Try Demo](https://times-up.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/times-up) |
136
+ | <img src="docs/images/showcase-lumo.png" alt="Lumo Interactive AI Tutor" width="160" /> | Lumo — Interactive AI Tutor | Adaptive tutor with Mermaid diagrams, mind maps, quizzes, and fill-in-the-blank exercises. | [Try Demo](https://lumo-mcp-app-39519fdd.alpic.live/try) | [View code](https://github.com/connorads/lumo-mcp-app) |
112
137
 
113
- If you're already using the `@modelcontextprotocol/sdk` to build a MCP server, you can migrate to a ChatGPT app by following these steps:
138
+ ### Auth
114
139
 
115
- 1. Replace your `McpServer` import from `@modelcontextprotocol/sdk` with the same import from `skybridge/server`
116
- 2. Create a new vite project in a folder named `web` and install the `skybridge` package
117
- 3. Replace the `vite.config.ts` file with the following:
140
+ | Preview | Provider | Description | Code |
141
+ | --- | --- | --- | --- |
142
+ | <img src="docs/images/descope.webp" alt="Auth Descope" width="160" /> | Descope | Full OAuth authentication with Descope and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-descope) |
143
+ | <img src="docs/images/showcase-clerk.png" alt="Auth Clerk" width="160" /> | Clerk | Full OAuth authentication with Clerk and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-clerk) |
144
+ | <img src="docs/images/showcase-workos.png" alt="Auth WorkOS AuthKit" width="160" /> | WorkOS AuthKit | Full OAuth authentication with WorkOS AuthKit and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-workos) |
145
+ | <img src="docs/images/showcase-stytch.png" alt="Auth Stytch" width="160" /> | Stytch | Full OAuth authentication with Stytch and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-stytch) |
146
+ | <img src="docs/images/showcase-auth0.png" alt="Auth Auth0" width="160" /> | Auth0 | Full OAuth authentication with Auth0 and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-auth0) |
118
147
 
119
- ```ts
120
- import { defineConfig } from "vite";
121
- import { skybridge } from "skybridge/web";
148
+ ### UI and component libraries
122
149
 
123
- export default defineConfig({
124
- plugins: [skybridge()],
125
- });
126
- ```
150
+ | Preview | App | Description | Demo | Code |
151
+ | --- | --- | --- | --- | --- |
152
+ | <img src="docs/images/showcase-manifest-ui.png" alt="Manifest UI" width="160" /> | Manifest UI | Agentic component library example for rich AI-powered experiences. | [Try Demo](https://manifest-ui.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/manifest-ui) |
153
+ | <img src="docs/images/showcase-generative-ui.png" alt="Generative UI" width="160" /> | Generative UI | LLM-generated dynamic UIs with json-render and 36 pre-built shadcn/ui components. | [Try Demo](https://generative-ui.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/generative-ui) |
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execute } from "@oclif/core";
4
+
5
+ await execute({ dir: import.meta.url });
@@ -0,0 +1,10 @@
1
+ export declare const ENTRY_WRAPPER_CONTENT = "import { __setBuildManifest } from \"skybridge/server\";\nimport manifest from \"./vite-manifest.js\";\n\n__setBuildManifest(manifest);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n";
2
+ export declare function emitEntryWrapper(distDir: string): void;
3
+ export declare function emitManifestModule(manifestPath: string, outPath: string): void;
4
+ /** Emit an empty Vite manifest for view-less (headless) servers. */
5
+ export declare function emitEmptyManifestModule(outPath: string): void;
6
+ export declare function ensureAssetsDir(assetsDir: string): void;
7
+ export declare const VERCEL_FUNCTION_NAME = "mcp";
8
+ export declare const VERCEL_CONFIG: unknown;
9
+ export declare const VERCEL_VC_CONFIG: unknown;
10
+ export declare function emitVercelBuildOutput(root: string): Promise<void>;
@@ -0,0 +1,93 @@
1
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
2
+ import path from "node:path";
3
+ // Primes the manifest in skybridge's module scope, then dynamically imports
4
+ // `./server.js` so user code runs *after* the side channel is set. The
5
+ // dynamic import is load-bearing: a static `export { default } from ...` is
6
+ // hoisted with the rest of the static graph and would evaluate `server.js`
7
+ // before `__setBuildManifest` runs.
8
+ export const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest } from "skybridge/server";
9
+ import manifest from "./vite-manifest.js";
10
+
11
+ __setBuildManifest(manifest);
12
+
13
+ const userMod = await import("./server.js");
14
+ export default userMod.default;
15
+ `;
16
+ export function emitEntryWrapper(distDir) {
17
+ writeFileSync(path.join(distDir, "__entry.js"), ENTRY_WRAPPER_CONTENT);
18
+ }
19
+ export function emitManifestModule(manifestPath, outPath) {
20
+ const manifest = readFileSync(manifestPath, "utf-8");
21
+ writeFileSync(outPath, `export default ${manifest};\n`);
22
+ }
23
+ /** Emit an empty Vite manifest for view-less (headless) servers. */
24
+ export function emitEmptyManifestModule(outPath) {
25
+ writeFileSync(outPath, "export default {};\n");
26
+ }
27
+ export function ensureAssetsDir(assetsDir) {
28
+ mkdirSync(assetsDir, { recursive: true });
29
+ }
30
+ export const VERCEL_FUNCTION_NAME = "mcp";
31
+ export const VERCEL_CONFIG = {
32
+ version: 3,
33
+ routes: [
34
+ {
35
+ src: "/assets/(.*)",
36
+ headers: { "Access-Control-Allow-Origin": "*" },
37
+ continue: true,
38
+ },
39
+ { handle: "filesystem" },
40
+ { src: "/(.*)", dest: `/${VERCEL_FUNCTION_NAME}` },
41
+ ],
42
+ };
43
+ export const VERCEL_VC_CONFIG = {
44
+ runtime: "nodejs22.x",
45
+ handler: "index.js",
46
+ launcherType: "Nodejs",
47
+ shouldAddHelpers: true,
48
+ };
49
+ // Emit a Build Output API tree under `.vercel/output/`. Bundling the server
50
+ // with esbuild produces a self-contained function bundle, so we don't ship
51
+ // `node_modules` and don't touch tracked paths like `api/` or `public/`.
52
+ //
53
+ // Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via
54
+ // `__setBuildManifest` before importing user code. Bundling `dist/server.js`
55
+ // directly would skip that priming and 500 on view resource reads when the
56
+ // function falls back to `readFileSync('dist/assets/.vite/manifest.json')`
57
+ // (Vercel functions don't ship `dist/`).
58
+ export async function emitVercelBuildOutput(root) {
59
+ const outputDir = path.join(root, ".vercel", "output");
60
+ const funcDir = path.join(outputDir, "functions", `${VERCEL_FUNCTION_NAME}.func`);
61
+ const staticAssetsDir = path.join(outputDir, "static", "assets");
62
+ rmSync(outputDir, { recursive: true, force: true });
63
+ mkdirSync(funcDir, { recursive: true });
64
+ const { build } = await import("esbuild");
65
+ await build({
66
+ entryPoints: [path.join(root, "dist", "__entry.js")],
67
+ bundle: true,
68
+ platform: "node",
69
+ target: "node22",
70
+ format: "esm",
71
+ outfile: path.join(funcDir, "index.js"),
72
+ // Lets esbuild DCE dev-only branches that pull in vite/devtools.
73
+ define: { "process.env.NODE_ENV": '"production"' },
74
+ // Dev-only deps reachable from re-exports; safe to leave unresolved since
75
+ // the code paths that touch them are eliminated by the NODE_ENV define.
76
+ external: ["vite", "@skybridge/devtools"],
77
+ banner: {
78
+ // ESM bundles miss CJS interop globals that some deps reach for.
79
+ js: "import{createRequire}from'node:module';const require=createRequire(import.meta.url);",
80
+ },
81
+ });
82
+ writeFileSync(path.join(funcDir, ".vc-config.json"), `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\n`);
83
+ writeFileSync(path.join(funcDir, "package.json"), `${JSON.stringify({ type: "module" }, null, 2)}\n`);
84
+ const assetsSrc = path.join(root, "dist", "assets");
85
+ if (existsSync(assetsSrc)) {
86
+ cpSync(assetsSrc, staticAssetsDir, { recursive: true });
87
+ }
88
+ else {
89
+ mkdirSync(staticAssetsDir, { recursive: true });
90
+ }
91
+ writeFileSync(path.join(outputDir, "config.json"), `${JSON.stringify(VERCEL_CONFIG, null, 2)}\n`);
92
+ }
93
+ //# sourceMappingURL=build-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-helpers.js","sourceRoot":"","sources":["../../src/cli/build-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport path from \"node:path\";\n\n// Primes the manifest in skybridge's module scope, then dynamically imports\n// `./server.js` so user code runs *after* the side channel is set. The\n// dynamic import is load-bearing: a static `export { default } from ...` is\n// hoisted with the rest of the static graph and would evaluate `server.js`\n// before `__setBuildManifest` runs.\nexport const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest } from \"skybridge/server\";\nimport manifest from \"./vite-manifest.js\";\n\n__setBuildManifest(manifest);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n`;\n\nexport function emitEntryWrapper(distDir: string): void {\n writeFileSync(path.join(distDir, \"__entry.js\"), ENTRY_WRAPPER_CONTENT);\n}\n\nexport function emitManifestModule(\n manifestPath: string,\n outPath: string,\n): void {\n const manifest = readFileSync(manifestPath, \"utf-8\");\n writeFileSync(outPath, `export default ${manifest};\\n`);\n}\n\n/** Emit an empty Vite manifest for view-less (headless) servers. */\nexport function emitEmptyManifestModule(outPath: string): void {\n writeFileSync(outPath, \"export default {};\\n\");\n}\n\nexport function ensureAssetsDir(assetsDir: string): void {\n mkdirSync(assetsDir, { recursive: true });\n}\n\nexport const VERCEL_FUNCTION_NAME = \"mcp\";\n\nexport const VERCEL_CONFIG: unknown = {\n version: 3,\n routes: [\n {\n src: \"/assets/(.*)\",\n headers: { \"Access-Control-Allow-Origin\": \"*\" },\n continue: true,\n },\n { handle: \"filesystem\" },\n { src: \"/(.*)\", dest: `/${VERCEL_FUNCTION_NAME}` },\n ],\n};\n\nexport const VERCEL_VC_CONFIG: unknown = {\n runtime: \"nodejs22.x\",\n handler: \"index.js\",\n launcherType: \"Nodejs\",\n shouldAddHelpers: true,\n};\n\n// Emit a Build Output API tree under `.vercel/output/`. Bundling the server\n// with esbuild produces a self-contained function bundle, so we don't ship\n// `node_modules` and don't touch tracked paths like `api/` or `public/`.\n//\n// Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via\n// `__setBuildManifest` before importing user code. Bundling `dist/server.js`\n// directly would skip that priming and 500 on view resource reads when the\n// function falls back to `readFileSync('dist/assets/.vite/manifest.json')`\n// (Vercel functions don't ship `dist/`).\nexport async function emitVercelBuildOutput(root: string): Promise<void> {\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(\n outputDir,\n \"functions\",\n `${VERCEL_FUNCTION_NAME}.func`,\n );\n const staticAssetsDir = path.join(outputDir, \"static\", \"assets\");\n\n rmSync(outputDir, { recursive: true, force: true });\n mkdirSync(funcDir, { recursive: true });\n\n const { build } = await import(\"esbuild\");\n await build({\n entryPoints: [path.join(root, \"dist\", \"__entry.js\")],\n bundle: true,\n platform: \"node\",\n target: \"node22\",\n format: \"esm\",\n outfile: path.join(funcDir, \"index.js\"),\n // Lets esbuild DCE dev-only branches that pull in vite/devtools.\n define: { \"process.env.NODE_ENV\": '\"production\"' },\n // Dev-only deps reachable from re-exports; safe to leave unresolved since\n // the code paths that touch them are eliminated by the NODE_ENV define.\n external: [\"vite\", \"@skybridge/devtools\"],\n banner: {\n // ESM bundles miss CJS interop globals that some deps reach for.\n js: \"import{createRequire}from'node:module';const require=createRequire(import.meta.url);\",\n },\n });\n\n writeFileSync(\n path.join(funcDir, \".vc-config.json\"),\n `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\\n`,\n );\n writeFileSync(\n path.join(funcDir, \"package.json\"),\n `${JSON.stringify({ type: \"module\" }, null, 2)}\\n`,\n );\n\n const assetsSrc = path.join(root, \"dist\", \"assets\");\n if (existsSync(assetsSrc)) {\n cpSync(assetsSrc, staticAssetsDir, { recursive: true });\n } else {\n mkdirSync(staticAssetsDir, { recursive: true });\n }\n\n writeFileSync(\n path.join(outputDir, \"config.json\"),\n `${JSON.stringify(VERCEL_CONFIG, null, 2)}\\n`,\n );\n}\n"]}
@@ -0,0 +1,89 @@
1
+ // @vitest-environment node
2
+ // esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.
3
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync, } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import path from "node:path";
6
+ import { describe, expect, it } from "vitest";
7
+ import { ENTRY_WRAPPER_CONTENT, emitEmptyManifestModule, emitEntryWrapper, emitManifestModule, emitVercelBuildOutput, ensureAssetsDir, VERCEL_CONFIG, VERCEL_VC_CONFIG, } from "./build-helpers.js";
8
+ function mkTmp(prefix = "skybridge-build-helpers-") {
9
+ return mkdtempSync(path.join(tmpdir(), prefix));
10
+ }
11
+ describe("emitEntryWrapper", () => {
12
+ it("writes dist/__entry.js that primes the manifest before importing user code", () => {
13
+ const dir = mkTmp();
14
+ emitEntryWrapper(dir);
15
+ const out = readFileSync(path.join(dir, "__entry.js"), "utf-8");
16
+ expect(out).toBe(ENTRY_WRAPPER_CONTENT);
17
+ expect(out).toContain('import { __setBuildManifest } from "skybridge/server"');
18
+ expect(out).toContain('import manifest from "./vite-manifest.js"');
19
+ expect(out).toContain("__setBuildManifest(manifest)");
20
+ // Dynamic import is load-bearing: `server.js` must evaluate after the
21
+ // setter runs, so a static re-export wouldn't work.
22
+ expect(out).toContain('await import("./server.js")');
23
+ expect(out).toContain("export default userMod.default");
24
+ });
25
+ });
26
+ describe("emitManifestModule", () => {
27
+ it("inlines the JSON manifest as an ESM default export", () => {
28
+ const dir = mkTmp();
29
+ const inPath = path.join(dir, "manifest.json");
30
+ const outPath = path.join(dir, "vite-manifest.js");
31
+ const manifest = { "src/views/foo.tsx": { file: "assets/foo-abc.js" } };
32
+ writeFileSync(inPath, JSON.stringify(manifest));
33
+ emitManifestModule(inPath, outPath);
34
+ const out = readFileSync(outPath, "utf-8");
35
+ expect(out.startsWith("export default ")).toBe(true);
36
+ const literal = out
37
+ .slice("export default ".length)
38
+ .trim()
39
+ .replace(/;$/, "");
40
+ expect(JSON.parse(literal)).toEqual(manifest);
41
+ });
42
+ });
43
+ describe("emitEmptyManifestModule", () => {
44
+ it("writes an empty object default export", () => {
45
+ const dir = mkTmp();
46
+ const outPath = path.join(dir, "vite-manifest.js");
47
+ emitEmptyManifestModule(outPath);
48
+ expect(readFileSync(outPath, "utf-8")).toBe("export default {};\n");
49
+ });
50
+ });
51
+ describe("ensureAssetsDir", () => {
52
+ it("creates the assets directory when missing", () => {
53
+ const dir = mkTmp();
54
+ const assetsDir = path.join(dir, "dist", "assets");
55
+ ensureAssetsDir(assetsDir);
56
+ expect(existsSync(assetsDir)).toBe(true);
57
+ });
58
+ });
59
+ describe("emitVercelBuildOutput", () => {
60
+ it("emits a Build Output API tree with bundled function and static assets", async () => {
61
+ const root = mkTmp();
62
+ mkdirSync(path.join(root, "dist", "assets"), { recursive: true });
63
+ writeFileSync(path.join(root, "dist", "server.js"), "export default function handler(_req, res) { res.end('ok'); }\n");
64
+ // Minimal `dist/__entry.js` (the real wrapper imports `skybridge/server`,
65
+ // which isn't resolvable in this test's tmp dir — the function-bundling
66
+ // contract we care about here is just "bundle whatever `__entry.js`
67
+ // imports into a single function file").
68
+ writeFileSync(path.join(root, "dist", "__entry.js"), "const userMod = await import('./server.js');\nexport default userMod.default;\n");
69
+ writeFileSync(path.join(root, "dist", "assets", "view-abc.js"), "/* bundled view */\n");
70
+ await emitVercelBuildOutput(root);
71
+ const outputDir = path.join(root, ".vercel", "output");
72
+ const funcDir = path.join(outputDir, "functions", "mcp.func");
73
+ expect(existsSync(path.join(funcDir, "index.js"))).toBe(true);
74
+ expect(JSON.parse(readFileSync(path.join(funcDir, ".vc-config.json"), "utf-8"))).toEqual(VERCEL_VC_CONFIG);
75
+ expect(JSON.parse(readFileSync(path.join(funcDir, "package.json"), "utf-8"))).toEqual({ type: "module" });
76
+ expect(JSON.parse(readFileSync(path.join(outputDir, "config.json"), "utf-8"))).toEqual(VERCEL_CONFIG);
77
+ expect(readFileSync(path.join(outputDir, "static", "assets", "view-abc.js"), "utf-8")).toContain("bundled view");
78
+ });
79
+ it("emits static assets directory when dist/assets is missing", async () => {
80
+ const root = mkTmp();
81
+ mkdirSync(path.join(root, "dist"), { recursive: true });
82
+ writeFileSync(path.join(root, "dist", "__entry.js"), "const userMod = await import('./server.js');\nexport default userMod.default;\n");
83
+ writeFileSync(path.join(root, "dist", "server.js"), "export default function handler(_req, res) { res.end('ok'); }\n");
84
+ await emitVercelBuildOutput(root);
85
+ expect(existsSync(path.join(root, ".vercel", "output", "static", "assets"))).toBe(true);
86
+ expect(existsSync(path.join(root, ".vercel", "output", "functions", "mcp.func", "index.js"))).toBe(true);
87
+ });
88
+ });
89
+ //# sourceMappingURL=build-helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-helpers.test.js","sourceRoot":"","sources":["../../src/cli/build-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\n// esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport {\n ENTRY_WRAPPER_CONTENT,\n emitEmptyManifestModule,\n emitEntryWrapper,\n emitManifestModule,\n emitVercelBuildOutput,\n ensureAssetsDir,\n VERCEL_CONFIG,\n VERCEL_VC_CONFIG,\n} from \"./build-helpers.js\";\n\nfunction mkTmp(prefix = \"skybridge-build-helpers-\") {\n return mkdtempSync(path.join(tmpdir(), prefix));\n}\n\ndescribe(\"emitEntryWrapper\", () => {\n it(\"writes dist/__entry.js that primes the manifest before importing user code\", () => {\n const dir = mkTmp();\n emitEntryWrapper(dir);\n const out = readFileSync(path.join(dir, \"__entry.js\"), \"utf-8\");\n expect(out).toBe(ENTRY_WRAPPER_CONTENT);\n expect(out).toContain(\n 'import { __setBuildManifest } from \"skybridge/server\"',\n );\n expect(out).toContain('import manifest from \"./vite-manifest.js\"');\n expect(out).toContain(\"__setBuildManifest(manifest)\");\n // Dynamic import is load-bearing: `server.js` must evaluate after the\n // setter runs, so a static re-export wouldn't work.\n expect(out).toContain('await import(\"./server.js\")');\n expect(out).toContain(\"export default userMod.default\");\n });\n});\n\ndescribe(\"emitManifestModule\", () => {\n it(\"inlines the JSON manifest as an ESM default export\", () => {\n const dir = mkTmp();\n const inPath = path.join(dir, \"manifest.json\");\n const outPath = path.join(dir, \"vite-manifest.js\");\n const manifest = { \"src/views/foo.tsx\": { file: \"assets/foo-abc.js\" } };\n writeFileSync(inPath, JSON.stringify(manifest));\n emitManifestModule(inPath, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n expect(out.startsWith(\"export default \")).toBe(true);\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n expect(JSON.parse(literal)).toEqual(manifest);\n });\n});\n\ndescribe(\"emitEmptyManifestModule\", () => {\n it(\"writes an empty object default export\", () => {\n const dir = mkTmp();\n const outPath = path.join(dir, \"vite-manifest.js\");\n emitEmptyManifestModule(outPath);\n expect(readFileSync(outPath, \"utf-8\")).toBe(\"export default {};\\n\");\n });\n});\n\ndescribe(\"ensureAssetsDir\", () => {\n it(\"creates the assets directory when missing\", () => {\n const dir = mkTmp();\n const assetsDir = path.join(dir, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n expect(existsSync(assetsDir)).toBe(true);\n });\n});\n\ndescribe(\"emitVercelBuildOutput\", () => {\n it(\"emits a Build Output API tree with bundled function and static assets\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\", \"assets\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n // Minimal `dist/__entry.js` (the real wrapper imports `skybridge/server`,\n // which isn't resolvable in this test's tmp dir — the function-bundling\n // contract we care about here is just \"bundle whatever `__entry.js`\n // imports into a single function file\").\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"view-abc.js\"),\n \"/* bundled view */\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(outputDir, \"functions\", \"mcp.func\");\n\n expect(existsSync(path.join(funcDir, \"index.js\"))).toBe(true);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \".vc-config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_VC_CONFIG);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \"package.json\"), \"utf-8\")),\n ).toEqual({ type: \"module\" });\n expect(\n JSON.parse(readFileSync(path.join(outputDir, \"config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_CONFIG);\n expect(\n readFileSync(\n path.join(outputDir, \"static\", \"assets\", \"view-abc.js\"),\n \"utf-8\",\n ),\n ).toContain(\"bundled view\");\n });\n\n it(\"emits static assets directory when dist/assets is missing\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n expect(\n existsSync(path.join(root, \".vercel\", \"output\", \"static\", \"assets\")),\n ).toBe(true);\n expect(\n existsSync(\n path.join(\n root,\n \".vercel\",\n \"output\",\n \"functions\",\n \"mcp.func\",\n \"index.js\",\n ),\n ),\n ).toBe(true);\n });\n});\n"]}
@@ -0,0 +1,2 @@
1
+ import type { CommandStep } from "./use-execute-steps.js";
2
+ export declare function getCommandSteps(root?: string): Promise<CommandStep[]>;
@@ -0,0 +1,68 @@
1
+ import { rmSync, writeFileSync } from "node:fs";
2
+ import path, { isAbsolute, resolve } from "node:path";
3
+ import { scanAndWriteViewsDts, scanViewsSync, } from "../web/plugin/scan-views.js";
4
+ import { emitEmptyManifestModule, emitEntryWrapper, emitManifestModule, emitVercelBuildOutput, ensureAssetsDir, } from "./build-helpers.js";
5
+ import { resolveViewsDir } from "./resolve-views-dir.js";
6
+ export async function getCommandSteps(root = process.cwd()) {
7
+ const viewsDir = await resolveViewsDir(root);
8
+ const rawDir = viewsDir ?? "src/views";
9
+ const resolvedDir = isAbsolute(rawDir) ? rawDir : resolve(root, rawDir);
10
+ // Non-throwing pre-check: duplicate view names are validated in the
11
+ // "Scanning views" step so useExecuteSteps can render a styled error.
12
+ const hasViews = scanViewsSync(resolvedDir).valid.length > 0;
13
+ const steps = [
14
+ {
15
+ label: "Scanning views",
16
+ run: async () => {
17
+ scanAndWriteViewsDts(root, viewsDir);
18
+ },
19
+ },
20
+ {
21
+ label: "Compiling server",
22
+ run: () => rmSync(path.join(root, "dist"), { recursive: true, force: true }),
23
+ command: "tsc -b --force",
24
+ },
25
+ ];
26
+ if (hasViews) {
27
+ steps.push({
28
+ label: "Building views",
29
+ command: "vite build",
30
+ });
31
+ }
32
+ steps.push({
33
+ label: "Emitting manifest module",
34
+ run: () => {
35
+ const manifestOut = path.join(root, "dist", "vite-manifest.js");
36
+ if (hasViews) {
37
+ emitManifestModule(path.join(root, "dist", "assets", ".vite", "manifest.json"), manifestOut);
38
+ }
39
+ else {
40
+ emitEmptyManifestModule(manifestOut);
41
+ }
42
+ },
43
+ }, {
44
+ label: "Emitting entry wrapper",
45
+ run: () => {
46
+ emitEntryWrapper(path.join(root, "dist"));
47
+ },
48
+ }, {
49
+ label: "Emitting Cloudflare redirects",
50
+ run: () => {
51
+ const assetsDir = path.join(root, "dist", "assets");
52
+ ensureAssetsDir(assetsDir);
53
+ writeFileSync(path.join(assetsDir, "_redirects"), "/assets/assets/* /assets/:splat 200\n");
54
+ },
55
+ }, {
56
+ label: "Emitting Cloudflare headers",
57
+ run: () => {
58
+ const assetsDir = path.join(root, "dist", "assets");
59
+ ensureAssetsDir(assetsDir);
60
+ writeFileSync(path.join(assetsDir, "_headers"), "/assets/*\n Access-Control-Allow-Origin: *\n");
61
+ },
62
+ }, {
63
+ label: "Emitting Vercel build output",
64
+ run: () => emitVercelBuildOutput(root),
65
+ });
66
+ return steps;
67
+ }
68
+ //# sourceMappingURL=build-steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-steps.js","sourceRoot":"","sources":["../../src/cli/build-steps.ts"],"names":[],"mappings":"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","sourcesContent":["import { rmSync, writeFileSync } from \"node:fs\";\nimport path, { isAbsolute, resolve } from \"node:path\";\nimport {\n scanAndWriteViewsDts,\n scanViewsSync,\n} from \"../web/plugin/scan-views.js\";\nimport {\n emitEmptyManifestModule,\n emitEntryWrapper,\n emitManifestModule,\n emitVercelBuildOutput,\n ensureAssetsDir,\n} from \"./build-helpers.js\";\nimport { resolveViewsDir } from \"./resolve-views-dir.js\";\nimport type { CommandStep } from \"./use-execute-steps.js\";\n\nexport async function getCommandSteps(\n root = process.cwd(),\n): Promise<CommandStep[]> {\n const viewsDir = await resolveViewsDir(root);\n const rawDir = viewsDir ?? \"src/views\";\n const resolvedDir = isAbsolute(rawDir) ? rawDir : resolve(root, rawDir);\n // Non-throwing pre-check: duplicate view names are validated in the\n // \"Scanning views\" step so useExecuteSteps can render a styled error.\n const hasViews = scanViewsSync(resolvedDir).valid.length > 0;\n\n const steps: CommandStep[] = [\n {\n label: \"Scanning views\",\n run: async () => {\n scanAndWriteViewsDts(root, viewsDir);\n },\n },\n {\n label: \"Compiling server\",\n run: () =>\n rmSync(path.join(root, \"dist\"), { recursive: true, force: true }),\n command: \"tsc -b --force\",\n },\n ];\n\n if (hasViews) {\n steps.push({\n label: \"Building views\",\n command: \"vite build\",\n });\n }\n\n steps.push(\n {\n label: \"Emitting manifest module\",\n run: () => {\n const manifestOut = path.join(root, \"dist\", \"vite-manifest.js\");\n if (hasViews) {\n emitManifestModule(\n path.join(root, \"dist\", \"assets\", \".vite\", \"manifest.json\"),\n manifestOut,\n );\n } else {\n emitEmptyManifestModule(manifestOut);\n }\n },\n },\n {\n label: \"Emitting entry wrapper\",\n run: () => {\n emitEntryWrapper(path.join(root, \"dist\"));\n },\n },\n {\n label: \"Emitting Cloudflare redirects\",\n run: () => {\n const assetsDir = path.join(root, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n writeFileSync(\n path.join(assetsDir, \"_redirects\"),\n \"/assets/assets/* /assets/:splat 200\\n\",\n );\n },\n },\n {\n label: \"Emitting Cloudflare headers\",\n run: () => {\n const assetsDir = path.join(root, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n writeFileSync(\n path.join(assetsDir, \"_headers\"),\n \"/assets/*\\n Access-Control-Allow-Origin: *\\n\",\n );\n },\n },\n {\n label: \"Emitting Vercel build output\",\n run: () => emitVercelBuildOutput(root),\n },\n );\n\n return steps;\n}\n"]}