skybridge 0.0.0-dev.ffe77e9 → 0.0.0-next.086b7ec

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 (297) hide show
  1. package/README.md +124 -124
  2. package/dist/cli/build-helpers.d.ts +10 -0
  3. package/dist/cli/build-helpers.js +93 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.d.ts +1 -0
  6. package/dist/cli/build-helpers.test.js +89 -0
  7. package/dist/cli/build-helpers.test.js.map +1 -0
  8. package/dist/cli/build-steps.d.ts +2 -0
  9. package/dist/cli/build-steps.js +68 -0
  10. package/dist/cli/build-steps.js.map +1 -0
  11. package/dist/cli/build-steps.test.d.ts +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 +2 -2
  15. package/dist/cli/detect-port.js +9 -20
  16. package/dist/cli/detect-port.js.map +1 -1
  17. package/dist/cli/header.d.ts +1 -1
  18. package/dist/cli/resolve-views-dir.d.ts +1 -0
  19. package/dist/cli/resolve-views-dir.js +17 -0
  20. package/dist/cli/resolve-views-dir.js.map +1 -0
  21. package/dist/cli/run-plain.d.ts +18 -0
  22. package/dist/cli/run-plain.js +89 -0
  23. package/dist/cli/run-plain.js.map +1 -0
  24. package/dist/cli/use-execute-steps.d.ts +1 -1
  25. package/dist/cli/use-nodemon.d.ts +14 -0
  26. package/dist/cli/use-nodemon.js +71 -60
  27. package/dist/cli/use-nodemon.js.map +1 -1
  28. package/dist/cli/use-typescript-check.d.ts +8 -2
  29. package/dist/cli/use-typescript-check.js +71 -68
  30. package/dist/cli/use-typescript-check.js.map +1 -1
  31. package/dist/commands/build.d.ts +0 -3
  32. package/dist/commands/build.js +2 -73
  33. package/dist/commands/build.js.map +1 -1
  34. package/dist/commands/create.d.ts +9 -0
  35. package/dist/commands/create.js +30 -0
  36. package/dist/commands/create.js.map +1 -0
  37. package/dist/commands/dev.d.ts +1 -0
  38. package/dist/commands/dev.js +48 -0
  39. package/dist/commands/dev.js.map +1 -1
  40. package/dist/commands/start.js +7 -1
  41. package/dist/commands/start.js.map +1 -1
  42. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  43. package/dist/server/asset-base-url-transform-plugin.js +16 -1
  44. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  45. package/dist/server/asset-base-url-transform-plugin.test.js +51 -1
  46. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  47. package/dist/server/auth/discovery.d.ts +32 -0
  48. package/dist/server/auth/discovery.js +56 -0
  49. package/dist/server/auth/discovery.js.map +1 -0
  50. package/dist/server/auth/discovery.test.d.ts +1 -0
  51. package/dist/server/auth/discovery.test.js +93 -0
  52. package/dist/server/auth/discovery.test.js.map +1 -0
  53. package/dist/server/auth/index.d.ts +18 -0
  54. package/dist/server/auth/index.js +2 -0
  55. package/dist/server/auth/index.js.map +1 -0
  56. package/dist/server/auth/providers/auth0.d.ts +18 -0
  57. package/dist/server/auth/providers/auth0.js +31 -0
  58. package/dist/server/auth/providers/auth0.js.map +1 -0
  59. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  60. package/dist/server/auth/providers/auth0.test.js +48 -0
  61. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  62. package/dist/server/auth/providers/clerk.d.ts +14 -0
  63. package/dist/server/auth/providers/clerk.js +16 -0
  64. package/dist/server/auth/providers/clerk.js.map +1 -0
  65. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  66. package/dist/server/auth/providers/clerk.test.js +28 -0
  67. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  68. package/dist/server/auth/providers/custom.d.ts +24 -0
  69. package/dist/server/auth/providers/custom.js +37 -0
  70. package/dist/server/auth/providers/custom.js.map +1 -0
  71. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  72. package/dist/server/auth/providers/custom.test.js +107 -0
  73. package/dist/server/auth/providers/custom.test.js.map +1 -0
  74. package/dist/server/auth/providers/descope.d.ts +15 -0
  75. package/dist/server/auth/providers/descope.js +33 -0
  76. package/dist/server/auth/providers/descope.js.map +1 -0
  77. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  78. package/dist/server/auth/providers/descope.test.js +37 -0
  79. package/dist/server/auth/providers/descope.test.js.map +1 -0
  80. package/dist/server/auth/providers/shared.d.ts +2 -0
  81. package/dist/server/auth/providers/shared.js +6 -0
  82. package/dist/server/auth/providers/shared.js.map +1 -0
  83. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  84. package/dist/server/auth/providers/shared.test.js +10 -0
  85. package/dist/server/auth/providers/shared.test.js.map +1 -0
  86. package/dist/server/auth/providers/stytch.d.ts +12 -0
  87. package/dist/server/auth/providers/stytch.js +13 -0
  88. package/dist/server/auth/providers/stytch.js.map +1 -0
  89. package/dist/server/auth/providers/workos.d.ts +11 -0
  90. package/dist/server/auth/providers/workos.js +12 -0
  91. package/dist/server/auth/providers/workos.js.map +1 -0
  92. package/dist/server/auth/setup.d.ts +4 -0
  93. package/dist/server/auth/setup.js +51 -0
  94. package/dist/server/auth/setup.js.map +1 -0
  95. package/dist/server/auth/setup.test.d.ts +1 -0
  96. package/dist/server/auth/setup.test.js +185 -0
  97. package/dist/server/auth/setup.test.js.map +1 -0
  98. package/dist/server/auth/verify.d.ts +12 -0
  99. package/dist/server/auth/verify.js +38 -0
  100. package/dist/server/auth/verify.js.map +1 -0
  101. package/dist/server/auth/verify.test.d.ts +1 -0
  102. package/dist/server/auth/verify.test.js +100 -0
  103. package/dist/server/auth/verify.test.js.map +1 -0
  104. package/dist/server/auth.d.ts +20 -0
  105. package/dist/server/auth.js +28 -0
  106. package/dist/server/auth.js.map +1 -0
  107. package/dist/server/build-manifest.test.d.ts +1 -0
  108. package/dist/server/build-manifest.test.js +27 -0
  109. package/dist/server/build-manifest.test.js.map +1 -0
  110. package/dist/server/content-helpers.d.ts +40 -0
  111. package/dist/server/content-helpers.js +33 -0
  112. package/dist/server/content-helpers.js.map +1 -1
  113. package/dist/server/express.test.js +61 -0
  114. package/dist/server/express.test.js.map +1 -1
  115. package/dist/server/file-ref.d.ts +28 -0
  116. package/dist/server/file-ref.js +27 -0
  117. package/dist/server/file-ref.js.map +1 -0
  118. package/dist/server/index.d.ts +11 -2
  119. package/dist/server/index.js +9 -1
  120. package/dist/server/index.js.map +1 -1
  121. package/dist/server/middleware.d.ts +16 -3
  122. package/dist/server/middleware.js.map +1 -1
  123. package/dist/server/requestOrigin.d.ts +7 -0
  124. package/dist/server/requestOrigin.js +25 -0
  125. package/dist/server/requestOrigin.js.map +1 -0
  126. package/dist/server/server.d.ts +230 -7
  127. package/dist/server/server.js +325 -161
  128. package/dist/server/server.js.map +1 -1
  129. package/dist/server/view-name.test-d.d.ts +1 -0
  130. package/dist/server/view-name.test-d.js +8 -0
  131. package/dist/server/view-name.test-d.js.map +1 -0
  132. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  133. package/dist/server/view-resource-resolution.test.js +171 -0
  134. package/dist/server/view-resource-resolution.test.js.map +1 -0
  135. package/dist/test/view.test.js +109 -96
  136. package/dist/test/view.test.js.map +1 -1
  137. package/dist/web/bridges/adaptor.d.ts +51 -0
  138. package/dist/web/bridges/adaptor.js +330 -0
  139. package/dist/web/bridges/adaptor.js.map +1 -0
  140. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  141. package/dist/web/bridges/adaptor.test.js +208 -0
  142. package/dist/web/bridges/adaptor.test.js.map +1 -0
  143. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -1
  144. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  145. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  146. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  147. package/dist/web/bridges/apps-sdk/index.js +0 -1
  148. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  149. package/dist/web/bridges/apps-sdk/types.d.ts +2 -0
  150. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  151. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  152. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  153. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  154. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  155. package/dist/web/bridges/get-adaptor.js +9 -7
  156. package/dist/web/bridges/get-adaptor.js.map +1 -1
  157. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  158. package/dist/web/bridges/get-adaptor.test.js +32 -0
  159. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  160. package/dist/web/bridges/mcp-app/bridge.d.ts +15 -2
  161. package/dist/web/bridges/mcp-app/bridge.js +68 -4
  162. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  163. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  164. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  165. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  166. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  167. package/dist/web/bridges/mcp-app/index.js +0 -1
  168. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  169. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  170. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  171. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  172. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  173. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  174. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  175. package/dist/web/bridges/types.d.ts +104 -1
  176. package/dist/web/bridges/types.js +14 -1
  177. package/dist/web/bridges/types.js.map +1 -1
  178. package/dist/web/bridges/types.test.d.ts +1 -0
  179. package/dist/web/bridges/types.test.js +19 -0
  180. package/dist/web/bridges/types.test.js.map +1 -0
  181. package/dist/web/bridges/use-host-context.d.ts +5 -0
  182. package/dist/web/bridges/use-host-context.js +5 -0
  183. package/dist/web/bridges/use-host-context.js.map +1 -1
  184. package/dist/web/components/modal-provider.d.ts +1 -1
  185. package/dist/web/components/modal-provider.js +4 -3
  186. package/dist/web/components/modal-provider.js.map +1 -1
  187. package/dist/web/create-store.d.ts +26 -0
  188. package/dist/web/create-store.js +26 -0
  189. package/dist/web/create-store.js.map +1 -1
  190. package/dist/web/create-store.test.js +8 -5
  191. package/dist/web/create-store.test.js.map +1 -1
  192. package/dist/web/data-llm.d.ts +34 -1
  193. package/dist/web/data-llm.js +28 -0
  194. package/dist/web/data-llm.js.map +1 -1
  195. package/dist/web/data-llm.test.js +17 -5
  196. package/dist/web/data-llm.test.js.map +1 -1
  197. package/dist/web/generate-helpers.d.ts +2 -0
  198. package/dist/web/generate-helpers.js +2 -0
  199. package/dist/web/generate-helpers.js.map +1 -1
  200. package/dist/web/generate-helpers.test-d.js +4 -2
  201. package/dist/web/generate-helpers.test-d.js.map +1 -1
  202. package/dist/web/hooks/index.d.ts +4 -0
  203. package/dist/web/hooks/index.js +4 -0
  204. package/dist/web/hooks/index.js.map +1 -1
  205. package/dist/web/hooks/test/utils.d.ts +6 -2
  206. package/dist/web/hooks/test/utils.js +13 -2
  207. package/dist/web/hooks/test/utils.js.map +1 -1
  208. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  209. package/dist/web/hooks/use-call-tool.js +28 -0
  210. package/dist/web/hooks/use-call-tool.js.map +1 -1
  211. package/dist/web/hooks/use-call-tool.test.js +62 -23
  212. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  213. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  214. package/dist/web/hooks/use-display-mode.js +20 -0
  215. package/dist/web/hooks/use-display-mode.js.map +1 -1
  216. package/dist/web/hooks/use-display-mode.test.js +56 -20
  217. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  218. package/dist/web/hooks/use-download.d.ts +5 -0
  219. package/dist/web/hooks/use-download.js +8 -0
  220. package/dist/web/hooks/use-download.js.map +1 -0
  221. package/dist/web/hooks/use-download.test.d.ts +1 -0
  222. package/dist/web/hooks/use-download.test.js +103 -0
  223. package/dist/web/hooks/use-download.test.js.map +1 -0
  224. package/dist/web/hooks/use-files.d.ts +32 -0
  225. package/dist/web/hooks/use-files.js +32 -0
  226. package/dist/web/hooks/use-files.js.map +1 -1
  227. package/dist/web/hooks/use-files.test.js +10 -2
  228. package/dist/web/hooks/use-files.test.js.map +1 -1
  229. package/dist/web/hooks/use-layout.d.ts +2 -0
  230. package/dist/web/hooks/use-layout.js +2 -0
  231. package/dist/web/hooks/use-layout.js.map +1 -1
  232. package/dist/web/hooks/use-layout.test.js +59 -26
  233. package/dist/web/hooks/use-layout.test.js.map +1 -1
  234. package/dist/web/hooks/use-open-external.d.ts +17 -0
  235. package/dist/web/hooks/use-open-external.js +16 -0
  236. package/dist/web/hooks/use-open-external.js.map +1 -1
  237. package/dist/web/hooks/use-open-external.test.js +13 -3
  238. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  239. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  240. package/dist/web/hooks/use-register-view-tool.js +50 -0
  241. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  242. package/dist/web/hooks/use-request-close.d.ts +16 -0
  243. package/dist/web/hooks/use-request-close.js +21 -0
  244. package/dist/web/hooks/use-request-close.js.map +1 -0
  245. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  246. package/dist/web/hooks/use-request-close.test.js +47 -0
  247. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  248. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  249. package/dist/web/hooks/use-request-modal.js +16 -1
  250. package/dist/web/hooks/use-request-modal.js.map +1 -1
  251. package/dist/web/hooks/use-request-modal.test.js +10 -0
  252. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  253. package/dist/web/hooks/use-request-size.d.ts +20 -0
  254. package/dist/web/hooks/use-request-size.js +24 -0
  255. package/dist/web/hooks/use-request-size.js.map +1 -0
  256. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  257. package/dist/web/hooks/use-request-size.test.js +47 -0
  258. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  259. package/dist/web/hooks/use-send-follow-up-message.d.ts +17 -0
  260. package/dist/web/hooks/use-send-follow-up-message.js +17 -0
  261. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  262. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  263. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  264. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  265. package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
  266. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  267. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  268. package/dist/web/hooks/use-tool-info.js +30 -7
  269. package/dist/web/hooks/use-tool-info.js.map +1 -1
  270. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  271. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  272. package/dist/web/hooks/use-tool-info.test.js +42 -32
  273. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  274. package/dist/web/hooks/use-user.d.ts +2 -0
  275. package/dist/web/hooks/use-user.js +2 -0
  276. package/dist/web/hooks/use-user.js.map +1 -1
  277. package/dist/web/hooks/use-user.test.js +81 -35
  278. package/dist/web/hooks/use-user.test.js.map +1 -1
  279. package/dist/web/hooks/use-view-state.d.ts +21 -0
  280. package/dist/web/hooks/use-view-state.js.map +1 -1
  281. package/dist/web/hooks/use-view-state.test.js +6 -2
  282. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  283. package/dist/web/mount-view.d.ts +19 -0
  284. package/dist/web/mount-view.js +19 -0
  285. package/dist/web/mount-view.js.map +1 -1
  286. package/dist/web/plugin/plugin.d.ts +28 -0
  287. package/dist/web/plugin/plugin.js +33 -0
  288. package/dist/web/plugin/plugin.js.map +1 -1
  289. package/dist/web/types.d.ts +4 -0
  290. package/dist/web/types.js.map +1 -1
  291. package/package.json +26 -19
  292. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -24
  293. package/dist/web/bridges/apps-sdk/adaptor.js +0 -96
  294. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  295. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -48
  296. package/dist/web/bridges/mcp-app/adaptor.js +0 -263
  297. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
@@ -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"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ // @vitest-environment node
2
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync, } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { describe, expect, it } from "vitest";
6
+ import { getCommandSteps } from "./build-steps.js";
7
+ function mkTmp(prefix = "skybridge-build-steps-") {
8
+ return mkdtempSync(path.join(tmpdir(), prefix));
9
+ }
10
+ describe("getCommandSteps", () => {
11
+ it("omits the vite build step when no views are registered", async () => {
12
+ const root = mkTmp();
13
+ mkdirSync(path.join(root, "src"), { recursive: true });
14
+ writeFileSync(path.join(root, "vite.config.ts"), `import { defineConfig } from "vite";
15
+ import { skybridge } from "skybridge/vite";
16
+ export default defineConfig({ plugins: [skybridge()] });`);
17
+ writeFileSync(path.join(root, "tsconfig.json"), JSON.stringify({ compilerOptions: { strict: true } }));
18
+ const steps = await getCommandSteps(root);
19
+ const labels = steps.map((step) => step.label);
20
+ expect(labels).not.toContain("Building views");
21
+ expect(labels).toContain("Emitting manifest module");
22
+ expect(labels.at(-1)).toBe("Emitting Vercel build output");
23
+ });
24
+ it("includes the vite build step when views are present", async () => {
25
+ const root = mkTmp();
26
+ mkdirSync(path.join(root, "src", "views"), { recursive: true });
27
+ writeFileSync(path.join(root, "src", "views", "hello.tsx"), "export default function Hello() { return null; }\n");
28
+ writeFileSync(path.join(root, "vite.config.ts"), `import { defineConfig } from "vite";
29
+ import { skybridge } from "skybridge/vite";
30
+ export default defineConfig({ plugins: [skybridge()] });`);
31
+ writeFileSync(path.join(root, "tsconfig.json"), JSON.stringify({ compilerOptions: { strict: true } }));
32
+ const steps = await getCommandSteps(root);
33
+ const labels = steps.map((step) => step.label);
34
+ expect(labels).toContain("Building views");
35
+ });
36
+ it("emits an empty manifest module when there are no views", async () => {
37
+ const root = mkTmp();
38
+ mkdirSync(path.join(root, "src"), { recursive: true });
39
+ writeFileSync(path.join(root, "vite.config.ts"), `import { defineConfig } from "vite";
40
+ import { skybridge } from "skybridge/vite";
41
+ export default defineConfig({ plugins: [skybridge()] });`);
42
+ const steps = await getCommandSteps(root);
43
+ const emitManifest = steps.find((step) => step.label === "Emitting manifest module");
44
+ expect(emitManifest?.run).toBeDefined();
45
+ mkdirSync(path.join(root, "dist"), { recursive: true });
46
+ await emitManifest?.run?.();
47
+ const manifestOut = path.join(root, "dist", "vite-manifest.js");
48
+ expect(existsSync(manifestOut)).toBe(true);
49
+ expect(readFileSync(manifestOut, "utf-8")).toBe("export default {};\n");
50
+ });
51
+ });
52
+ //# sourceMappingURL=build-steps.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-steps.test.js","sourceRoot":"","sources":["../../src/cli/build-steps.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\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 { getCommandSteps } from \"./build-steps.js\";\n\nfunction mkTmp(prefix = \"skybridge-build-steps-\") {\n return mkdtempSync(path.join(tmpdir(), prefix));\n}\n\ndescribe(\"getCommandSteps\", () => {\n it(\"omits the vite build step when no views are registered\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"src\"), { recursive: true });\n writeFileSync(\n path.join(root, \"vite.config.ts\"),\n `import { defineConfig } from \"vite\";\nimport { skybridge } from \"skybridge/vite\";\nexport default defineConfig({ plugins: [skybridge()] });`,\n );\n writeFileSync(\n path.join(root, \"tsconfig.json\"),\n JSON.stringify({ compilerOptions: { strict: true } }),\n );\n\n const steps = await getCommandSteps(root);\n const labels = steps.map((step) => step.label);\n\n expect(labels).not.toContain(\"Building views\");\n expect(labels).toContain(\"Emitting manifest module\");\n expect(labels.at(-1)).toBe(\"Emitting Vercel build output\");\n });\n\n it(\"includes the vite build step when views are present\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"src\", \"views\"), { recursive: true });\n writeFileSync(\n path.join(root, \"src\", \"views\", \"hello.tsx\"),\n \"export default function Hello() { return null; }\\n\",\n );\n writeFileSync(\n path.join(root, \"vite.config.ts\"),\n `import { defineConfig } from \"vite\";\nimport { skybridge } from \"skybridge/vite\";\nexport default defineConfig({ plugins: [skybridge()] });`,\n );\n writeFileSync(\n path.join(root, \"tsconfig.json\"),\n JSON.stringify({ compilerOptions: { strict: true } }),\n );\n\n const steps = await getCommandSteps(root);\n const labels = steps.map((step) => step.label);\n\n expect(labels).toContain(\"Building views\");\n });\n\n it(\"emits an empty manifest module when there are no views\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"src\"), { recursive: true });\n writeFileSync(\n path.join(root, \"vite.config.ts\"),\n `import { defineConfig } from \"vite\";\nimport { skybridge } from \"skybridge/vite\";\nexport default defineConfig({ plugins: [skybridge()] });`,\n );\n\n const steps = await getCommandSteps(root);\n const emitManifest = steps.find(\n (step) => step.label === \"Emitting manifest module\",\n );\n expect(emitManifest?.run).toBeDefined();\n\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n await emitManifest?.run?.();\n\n const manifestOut = path.join(root, \"dist\", \"vite-manifest.js\");\n expect(existsSync(manifestOut)).toBe(true);\n expect(readFileSync(manifestOut, \"utf-8\")).toBe(\"export default {};\\n\");\n });\n});\n"]}
@@ -8,8 +8,8 @@ export declare function resolvePort(flagPort?: number): Promise<{
8
8
  envWarning: string;
9
9
  }>;
10
10
  /**
11
- * Returns the given port if available, otherwise lets the OS
12
- * pick a free port via `listen(0)`.
11
+ * Returns the first available port at or after `startPort`, incrementing
12
+ * by one until a free port is found or `MAX_PORT_INCREMENT` is reached.
13
13
  *
14
14
  * @param host - Bind address for the check. Pass `"localhost"` for
15
15
  * services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for
@@ -1,5 +1,6 @@
1
1
  import net from "node:net";
2
2
  const DEFAULT_PORT = 3000;
3
+ const MAX_PORT_INCREMENT = 100;
3
4
  export async function resolvePort(flagPort) {
4
5
  if (flagPort && flagPort > 1) {
5
6
  return { port: flagPort, fallback: false };
@@ -20,33 +21,21 @@ export async function resolvePort(flagPort) {
20
21
  return { port, fallback: port !== DEFAULT_PORT };
21
22
  }
22
23
  /**
23
- * Returns the given port if available, otherwise lets the OS
24
- * pick a free port via `listen(0)`.
24
+ * Returns the first available port at or after `startPort`, incrementing
25
+ * by one until a free port is found or `MAX_PORT_INCREMENT` is reached.
25
26
  *
26
27
  * @param host - Bind address for the check. Pass `"localhost"` for
27
28
  * services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for
28
29
  * services that bind to all interfaces (e.g. the HTTP server).
29
30
  */
30
31
  export async function detectAvailablePort(startPort, host) {
31
- const available = await isPortAvailable(startPort, host);
32
- if (available) {
33
- return startPort;
32
+ for (let port = startPort; port < startPort + MAX_PORT_INCREMENT; port++) {
33
+ if (await isPortAvailable(port, host)) {
34
+ return port;
35
+ }
36
+ console.log(`Port ${port} is in use, trying another one...`);
34
37
  }
35
- return new Promise((resolve, reject) => {
36
- const server = net.createServer();
37
- server.once("error", reject);
38
- server.once("listening", () => {
39
- const addr = server.address();
40
- if (addr && typeof addr === "object") {
41
- const { port } = addr;
42
- server.close(() => resolve(port));
43
- }
44
- else {
45
- server.close(() => reject(new Error("Failed to detect available port")));
46
- }
47
- });
48
- server.listen(0, host);
49
- });
38
+ throw new Error(`No available port found between ${startPort} and ${startPort + MAX_PORT_INCREMENT - 1}`);
50
39
  }
51
40
  function isPortAvailable(port, host) {
52
41
  return new Promise((resolve) => {
@@ -1 +1 @@
1
- {"version":3,"file":"detect-port.js","sourceRoot":"","sources":["../../src/cli/detect-port.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAiB;IACjD,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC3C,CAAC;QACD,OAAO;YACL,IAAI,EAAE,MAAM,mBAAmB,CAAC,YAAY,CAAC;YAC7C,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,iBAAiB,MAAM,+BAA+B;SACnE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,IAAa;IAEb,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAChB,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CACrD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,IAAa;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import net from \"node:net\";\n\nconst DEFAULT_PORT = 3000;\n\nexport async function resolvePort(flagPort?: number) {\n if (flagPort && flagPort > 1) {\n return { port: flagPort, fallback: false };\n }\n\n const rawEnv = process.env.PORT;\n if (rawEnv) {\n const parsed = Number(rawEnv);\n if (Number.isInteger(parsed) && parsed > 0) {\n return { port: parsed, fallback: false };\n }\n return {\n port: await detectAvailablePort(DEFAULT_PORT),\n fallback: false,\n envWarning: `Invalid PORT=\"${rawEnv}\", ignoring and using default`,\n };\n }\n\n const port = await detectAvailablePort(DEFAULT_PORT);\n return { port, fallback: port !== DEFAULT_PORT };\n}\n\n/**\n * Returns the given port if available, otherwise lets the OS\n * pick a free port via `listen(0)`.\n *\n * @param host - Bind address for the check. Pass `\"localhost\"` for\n * services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for\n * services that bind to all interfaces (e.g. the HTTP server).\n */\nexport async function detectAvailablePort(\n startPort: number,\n host?: string,\n): Promise<number> {\n const available = await isPortAvailable(startPort, host);\n if (available) {\n return startPort;\n }\n\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n\n server.once(\"error\", reject);\n server.once(\"listening\", () => {\n const addr = server.address();\n if (addr && typeof addr === \"object\") {\n const { port } = addr;\n server.close(() => resolve(port));\n } else {\n server.close(() =>\n reject(new Error(\"Failed to detect available port\")),\n );\n }\n });\n\n server.listen(0, host);\n });\n}\n\nfunction isPortAvailable(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", () => resolve(false));\n server.once(\"listening\", () => {\n server.close(() => resolve(true));\n });\n\n server.listen(port, host);\n });\n}\n"]}
1
+ {"version":3,"file":"detect-port.js","sourceRoot":"","sources":["../../src/cli/detect-port.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAiB;IACjD,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC3C,CAAC;QACD,OAAO;YACL,IAAI,EAAE,MAAM,mBAAmB,CAAC,YAAY,CAAC;YAC7C,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,iBAAiB,MAAM,+BAA+B;SACnE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,IAAa;IAEb,KAAK,IAAI,IAAI,GAAG,SAAS,EAAE,IAAI,GAAG,SAAS,GAAG,kBAAkB,EAAE,IAAI,EAAE,EAAE,CAAC;QACzE,IAAI,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,mCAAmC,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,IAAI,KAAK,CACb,mCAAmC,SAAS,QAAQ,SAAS,GAAG,kBAAkB,GAAG,CAAC,EAAE,CACzF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,IAAa;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import net from \"node:net\";\n\nconst DEFAULT_PORT = 3000;\nconst MAX_PORT_INCREMENT = 100;\n\nexport async function resolvePort(flagPort?: number) {\n if (flagPort && flagPort > 1) {\n return { port: flagPort, fallback: false };\n }\n\n const rawEnv = process.env.PORT;\n if (rawEnv) {\n const parsed = Number(rawEnv);\n if (Number.isInteger(parsed) && parsed > 0) {\n return { port: parsed, fallback: false };\n }\n return {\n port: await detectAvailablePort(DEFAULT_PORT),\n fallback: false,\n envWarning: `Invalid PORT=\"${rawEnv}\", ignoring and using default`,\n };\n }\n\n const port = await detectAvailablePort(DEFAULT_PORT);\n return { port, fallback: port !== DEFAULT_PORT };\n}\n\n/**\n * Returns the first available port at or after `startPort`, incrementing\n * by one until a free port is found or `MAX_PORT_INCREMENT` is reached.\n *\n * @param host - Bind address for the check. Pass `\"localhost\"` for\n * services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for\n * services that bind to all interfaces (e.g. the HTTP server).\n */\nexport async function detectAvailablePort(\n startPort: number,\n host?: string,\n): Promise<number> {\n for (let port = startPort; port < startPort + MAX_PORT_INCREMENT; port++) {\n if (await isPortAvailable(port, host)) {\n return port;\n }\n console.log(`Port ${port} is in use, trying another one...`);\n }\n throw new Error(\n `No available port found between ${startPort} and ${startPort + MAX_PORT_INCREMENT - 1}`,\n );\n}\n\nfunction isPortAvailable(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", () => resolve(false));\n server.once(\"listening\", () => {\n server.close(() => resolve(true));\n });\n\n server.listen(port, host);\n });\n}\n"]}
@@ -1,4 +1,4 @@
1
1
  export declare const Header: ({ version, children, }: {
2
2
  version: string;
3
3
  children?: React.ReactNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
4
+ }) => import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function resolveViewsDir(root: string): Promise<string | undefined>;
@@ -0,0 +1,17 @@
1
+ export async function resolveViewsDir(root) {
2
+ const { loadConfigFromFile } = await import("vite");
3
+ const loaded = await loadConfigFromFile({ command: "build", mode: "production" }, undefined, root);
4
+ const isPluginCandidate = (value) => typeof value === "object" && value !== null;
5
+ const plugins = [];
6
+ const walk = (value) => {
7
+ if (Array.isArray(value)) {
8
+ value.forEach(walk);
9
+ }
10
+ else if (isPluginCandidate(value)) {
11
+ plugins.push(value);
12
+ }
13
+ };
14
+ walk(loaded?.config.plugins ?? []);
15
+ return plugins.find((p) => p.name === "skybridge")?.api?.viewsDir;
16
+ }
17
+ //# sourceMappingURL=resolve-views-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-views-dir.js","sourceRoot":"","sources":["../../src/cli/resolve-views-dir.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY;IAEZ,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,EACxC,SAAS,EACT,IAAI,CACL,CAAC;IAEF,MAAM,iBAAiB,GAAG,CACxB,KAAc,EAC2C,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;IAE9C,MAAM,OAAO,GAA0D,EAAE,CAAC;IAC1E,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE;QAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC;AACpE,CAAC","sourcesContent":["export async function resolveViewsDir(\n root: string,\n): Promise<string | undefined> {\n const { loadConfigFromFile } = await import(\"vite\");\n const loaded = await loadConfigFromFile(\n { command: \"build\", mode: \"production\" },\n undefined,\n root,\n );\n\n const isPluginCandidate = (\n value: unknown,\n ): value is { name?: string; api?: { viewsDir?: string } } =>\n typeof value === \"object\" && value !== null;\n\n const plugins: Array<{ name?: string; api?: { viewsDir?: string } }> = [];\n const walk = (value: unknown) => {\n if (Array.isArray(value)) {\n value.forEach(walk);\n } else if (isPluginCandidate(value)) {\n plugins.push(value);\n }\n };\n walk(loaded?.config.plugins ?? []);\n return plugins.find((p) => p.name === \"skybridge\")?.api?.viewsDir;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { TunnelManager } from "./tunnel.js";
2
+ export interface RunPlainOptions {
3
+ env: NodeJS.ProcessEnv;
4
+ port: number;
5
+ fallback: boolean;
6
+ version: string;
7
+ tunnel: boolean;
8
+ tunnelManager: TunnelManager;
9
+ }
10
+ /**
11
+ * Run `skybridge dev` without the Ink UI. The server's stdout is forwarded
12
+ * verbatim to the real stdout so it can be piped through a formatter
13
+ * (`skybridge dev --plain | bunyan`); everything else (banner, URLs, tunnel
14
+ * state, TypeScript errors, restarts) is written to stderr.
15
+ *
16
+ * Returns a cleanup function that tears down nodemon and the tsc watcher.
17
+ */
18
+ export declare function runPlain(options: RunPlainOptions): () => void;
@@ -0,0 +1,89 @@
1
+ import { startNodemon } from "./use-nodemon.js";
2
+ import { startTypeScriptCheck } from "./use-typescript-check.js";
3
+ // Banner/URLs/diagnostics go to stderr so a downstream pipe (e.g.
4
+ // `skybridge dev --plain | bunyan`) only ever sees the server's own stdout.
5
+ function info(message) {
6
+ process.stderr.write(`${message}\n`);
7
+ }
8
+ function describeTunnel(state, port) {
9
+ switch (state.status) {
10
+ case "starting":
11
+ return `🌍 ${state.message}`;
12
+ case "connected":
13
+ return `🌍 Exposed on ${state.url}/mcp\n→ Test with an LLM on Playground: ${state.url}/try`;
14
+ case "error":
15
+ return `🌍 Cannot open tunnel: ${state.message}\n→ Try manually: npx alpic tunnel --port ${port}`;
16
+ default:
17
+ return "";
18
+ }
19
+ }
20
+ /**
21
+ * Run `skybridge dev` without the Ink UI. The server's stdout is forwarded
22
+ * verbatim to the real stdout so it can be piped through a formatter
23
+ * (`skybridge dev --plain | bunyan`); everything else (banner, URLs, tunnel
24
+ * state, TypeScript errors, restarts) is written to stderr.
25
+ *
26
+ * Returns a cleanup function that tears down nodemon and the tsc watcher.
27
+ */
28
+ export function runPlain(options) {
29
+ const { env, port, fallback, version, tunnel, tunnelManager } = options;
30
+ // If the downstream formatter (e.g. `| bunyan`) exits, the next write raises
31
+ // EPIPE. Swallow it so a closed pipe doesn't crash the dev server.
32
+ const ignoreEpipe = (err) => {
33
+ if (err.code !== "EPIPE") {
34
+ throw err;
35
+ }
36
+ };
37
+ process.stdout.on("error", ignoreEpipe);
38
+ process.stderr.on("error", ignoreEpipe);
39
+ info(`⛰ Skybridge v${version}`);
40
+ info(fallback
41
+ ? `🏠 3000 in use, running on http://localhost:${port}/mcp`
42
+ : `🏠 Running on http://localhost:${port}/mcp`);
43
+ info(`→ Test locally with DevTools: http://localhost:${port}/`);
44
+ if (!tunnel) {
45
+ info("🌍 Get a public URL and LLM Playground access with --tunnel.");
46
+ }
47
+ const stopNodemon = startNodemon(env, {
48
+ onStdout: (chunk) => process.stdout.write(chunk),
49
+ onStderr: (message) => info(message),
50
+ onRestart: (files) => info(`✓ Server restarted due to file changes: ${files.join(", ")}`),
51
+ });
52
+ let lastTsErrorKey = "";
53
+ const stopTypeScriptCheck = startTypeScriptCheck((errors) => {
54
+ // tsc re-emits on every save; only print when the error set actually changes.
55
+ const key = errors
56
+ .map((e) => `${e.file}:${e.line}:${e.col}:${e.message}`)
57
+ .join("|");
58
+ if (key === lastTsErrorKey) {
59
+ return;
60
+ }
61
+ lastTsErrorKey = key;
62
+ if (errors.length === 0) {
63
+ return;
64
+ }
65
+ info("⚠️ TypeScript errors found:");
66
+ for (const error of errors) {
67
+ info(` ${error.file}(${error.line},${error.col}): ${error.message}`);
68
+ }
69
+ });
70
+ const unsubscribeTunnel = tunnel
71
+ ? tunnelManager.subscribe((state) => {
72
+ const message = describeTunnel(state, port);
73
+ if (message) {
74
+ info(message);
75
+ }
76
+ })
77
+ : () => { };
78
+ if (tunnel) {
79
+ tunnelManager.start();
80
+ }
81
+ return () => {
82
+ unsubscribeTunnel();
83
+ stopNodemon();
84
+ stopTypeScriptCheck();
85
+ process.stdout.off("error", ignoreEpipe);
86
+ process.stderr.off("error", ignoreEpipe);
87
+ };
88
+ }
89
+ //# sourceMappingURL=run-plain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-plain.js","sourceRoot":"","sources":["../../src/cli/run-plain.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TunnelManager, TunnelState } from \"./tunnel.js\";\nimport { startNodemon } from \"./use-nodemon.js\";\nimport { startTypeScriptCheck, type TsError } from \"./use-typescript-check.js\";\n\nexport interface RunPlainOptions {\n env: NodeJS.ProcessEnv;\n port: number;\n fallback: boolean;\n version: string;\n tunnel: boolean;\n tunnelManager: TunnelManager;\n}\n\n// Banner/URLs/diagnostics go to stderr so a downstream pipe (e.g.\n// `skybridge dev --plain | bunyan`) only ever sees the server's own stdout.\nfunction info(message: string): void {\n process.stderr.write(`${message}\\n`);\n}\n\nfunction describeTunnel(state: TunnelState, port: number): string {\n switch (state.status) {\n case \"starting\":\n return `🌍 ${state.message}`;\n case \"connected\":\n return `🌍 Exposed on ${state.url}/mcp\\n→ Test with an LLM on Playground: ${state.url}/try`;\n case \"error\":\n return `🌍 Cannot open tunnel: ${state.message}\\n→ Try manually: npx alpic tunnel --port ${port}`;\n default:\n return \"\";\n }\n}\n\n/**\n * Run `skybridge dev` without the Ink UI. The server's stdout is forwarded\n * verbatim to the real stdout so it can be piped through a formatter\n * (`skybridge dev --plain | bunyan`); everything else (banner, URLs, tunnel\n * state, TypeScript errors, restarts) is written to stderr.\n *\n * Returns a cleanup function that tears down nodemon and the tsc watcher.\n */\nexport function runPlain(options: RunPlainOptions): () => void {\n const { env, port, fallback, version, tunnel, tunnelManager } = options;\n\n // If the downstream formatter (e.g. `| bunyan`) exits, the next write raises\n // EPIPE. Swallow it so a closed pipe doesn't crash the dev server.\n const ignoreEpipe = (err: NodeJS.ErrnoException) => {\n if (err.code !== \"EPIPE\") {\n throw err;\n }\n };\n process.stdout.on(\"error\", ignoreEpipe);\n process.stderr.on(\"error\", ignoreEpipe);\n\n info(`⛰ Skybridge v${version}`);\n info(\n fallback\n ? `🏠 3000 in use, running on http://localhost:${port}/mcp`\n : `🏠 Running on http://localhost:${port}/mcp`,\n );\n info(`→ Test locally with DevTools: http://localhost:${port}/`);\n if (!tunnel) {\n info(\"🌍 Get a public URL and LLM Playground access with --tunnel.\");\n }\n\n const stopNodemon = startNodemon(env, {\n onStdout: (chunk) => process.stdout.write(chunk),\n onStderr: (message) => info(message),\n onRestart: (files) =>\n info(`✓ Server restarted due to file changes: ${files.join(\", \")}`),\n });\n\n let lastTsErrorKey = \"\";\n const stopTypeScriptCheck = startTypeScriptCheck((errors: Array<TsError>) => {\n // tsc re-emits on every save; only print when the error set actually changes.\n const key = errors\n .map((e) => `${e.file}:${e.line}:${e.col}:${e.message}`)\n .join(\"|\");\n if (key === lastTsErrorKey) {\n return;\n }\n lastTsErrorKey = key;\n if (errors.length === 0) {\n return;\n }\n info(\"⚠️ TypeScript errors found:\");\n for (const error of errors) {\n info(` ${error.file}(${error.line},${error.col}): ${error.message}`);\n }\n });\n\n const unsubscribeTunnel = tunnel\n ? tunnelManager.subscribe((state) => {\n const message = describeTunnel(state, port);\n if (message) {\n info(message);\n }\n })\n : () => {};\n\n if (tunnel) {\n tunnelManager.start();\n }\n\n return () => {\n unsubscribeTunnel();\n stopNodemon();\n stopTypeScriptCheck();\n process.stdout.off(\"error\", ignoreEpipe);\n process.stderr.off(\"error\", ignoreEpipe);\n };\n}\n"]}
@@ -5,7 +5,7 @@ export interface CommandStep {
5
5
  }
6
6
  export declare const useExecuteSteps: (steps: CommandStep[]) => {
7
7
  currentStep: number;
8
- status: "error" | "success" | "running";
8
+ status: "error" | "running" | "success";
9
9
  error: string | null;
10
10
  execute: () => Promise<void>;
11
11
  };
@@ -1,2 +1,16 @@
1
1
  import type { PushMessage } from "./use-messages.js";
2
+ export interface NodemonHandlers {
3
+ /** A raw chunk of server stdout, forwarded untouched. */
4
+ onStdout: (chunk: Buffer) => void;
5
+ /** A (filtered) chunk of server stderr. */
6
+ onStderr: (message: string) => void;
7
+ /** The server restarted because the listed files changed. */
8
+ onRestart: (files: string[]) => void;
9
+ }
10
+ /**
11
+ * Boot nodemon and wire its stdout/stderr to the provided handlers. Returns a
12
+ * cleanup function that detaches the listeners and quits nodemon. Shared by the
13
+ * Ink-based dev UI (via {@link useNodemon}) and the `--plain` runner.
14
+ */
15
+ export declare function startNodemon(env: NodeJS.ProcessEnv, handlers: NodemonHandlers): () => void;
2
16
  export declare function useNodemon(env: NodeJS.ProcessEnv, pushMessage: PushMessage): void;
@@ -4,70 +4,81 @@ import nodemonOriginal from "nodemon";
4
4
  import { useEffect } from "react";
5
5
  const nodemon = nodemonOriginal;
6
6
  const SOURCEMAP_WARNING = /^Sourcemap for ".*" points to missing source files$/;
7
+ /**
8
+ * Boot nodemon and wire its stdout/stderr to the provided handlers. Returns a
9
+ * cleanup function that detaches the listeners and quits nodemon. Shared by the
10
+ * Ink-based dev UI (via {@link useNodemon}) and the `--plain` runner.
11
+ */
12
+ export function startNodemon(env, handlers) {
13
+ const configFile = resolve(process.cwd(), "nodemon.json");
14
+ const config = existsSync(configFile)
15
+ ? {
16
+ configFile,
17
+ }
18
+ : {
19
+ watch: ["src"],
20
+ ext: "ts,json",
21
+ exec: "tsx src/server.ts",
22
+ };
23
+ nodemon({ ...config, env, stdout: false });
24
+ const handleStdoutData = (chunk) => {
25
+ handlers.onStdout(chunk);
26
+ };
27
+ const handleStderrData = (chunk) => {
28
+ const message = chunk.toString().trim();
29
+ if (!message) {
30
+ return;
31
+ }
32
+ // Node's source-map warnings for third-party deps (superjson, @mcp/sdk, …) — not actionable.
33
+ const filtered = message
34
+ .split("\n")
35
+ .filter((line) => !SOURCEMAP_WARNING.test(line))
36
+ .join("\n");
37
+ if (filtered) {
38
+ handlers.onStderr(filtered);
39
+ }
40
+ };
41
+ const setupStdoutListener = () => {
42
+ if (nodemon.stdout) {
43
+ nodemon.stdout.off("data", handleStdoutData);
44
+ nodemon.stdout.on("data", handleStdoutData);
45
+ }
46
+ };
47
+ const setupStderrListener = () => {
48
+ if (nodemon.stderr) {
49
+ nodemon.stderr.off("data", handleStderrData);
50
+ nodemon.stderr.on("data", handleStderrData);
51
+ }
52
+ };
53
+ nodemon.on("readable", () => {
54
+ setupStdoutListener();
55
+ setupStderrListener();
56
+ });
57
+ nodemon.on("restart", (files) => {
58
+ handlers.onRestart(files);
59
+ setupStdoutListener();
60
+ setupStderrListener();
61
+ });
62
+ return () => {
63
+ if (nodemon.stdout) {
64
+ nodemon.stdout.off("data", handleStdoutData);
65
+ }
66
+ if (nodemon.stderr) {
67
+ nodemon.stderr.off("data", handleStderrData);
68
+ }
69
+ nodemon.emit("quit");
70
+ };
71
+ }
7
72
  export function useNodemon(env, pushMessage) {
8
- useEffect(() => {
9
- const configFile = resolve(process.cwd(), "nodemon.json");
10
- const config = existsSync(configFile)
11
- ? {
12
- configFile,
13
- }
14
- : {
15
- watch: ["src"],
16
- ext: "ts,json",
17
- exec: "tsx src/server.ts",
18
- };
19
- nodemon({ ...config, env, stdout: false });
20
- const handleStdoutData = (chunk) => {
73
+ useEffect(() => startNodemon(env, {
74
+ onStdout: (chunk) => {
21
75
  const message = chunk.toString().trim();
22
76
  if (message) {
23
77
  pushMessage(message, "log");
24
78
  }
25
- };
26
- const handleStderrData = (chunk) => {
27
- const message = chunk.toString().trim();
28
- if (!message) {
29
- return;
30
- }
31
- // Node's source-map warnings for third-party deps (superjson, @mcp/sdk, …) — not actionable.
32
- const filtered = message
33
- .split("\n")
34
- .filter((line) => !SOURCEMAP_WARNING.test(line))
35
- .join("\n");
36
- if (filtered) {
37
- pushMessage(filtered, "error");
38
- }
39
- };
40
- const setupStdoutListener = () => {
41
- if (nodemon.stdout) {
42
- nodemon.stdout.off("data", handleStdoutData);
43
- nodemon.stdout.on("data", handleStdoutData);
44
- }
45
- };
46
- const setupStderrListener = () => {
47
- if (nodemon.stderr) {
48
- nodemon.stderr.off("data", handleStderrData);
49
- nodemon.stderr.on("data", handleStderrData);
50
- }
51
- };
52
- nodemon.on("readable", () => {
53
- setupStdoutListener();
54
- setupStderrListener();
55
- });
56
- nodemon.on("restart", (files) => {
57
- const restartMessage = `Server restarted due to file changes: ${files.join(", ")}`;
58
- pushMessage(restartMessage, "restart");
59
- setupStdoutListener();
60
- setupStderrListener();
61
- });
62
- return () => {
63
- if (nodemon.stdout) {
64
- nodemon.stdout.off("data", handleStdoutData);
65
- }
66
- if (nodemon.stderr) {
67
- nodemon.stderr.off("data", handleStderrData);
68
- }
69
- nodemon.emit("quit");
70
- };
71
- }, [env, pushMessage]);
79
+ },
80
+ onStderr: (message) => pushMessage(message, "error"),
81
+ onRestart: (files) => pushMessage(`Server restarted due to file changes: ${files.join(", ")}`, "restart"),
82
+ }), [env, pushMessage]);
72
83
  }
73
84
  //# sourceMappingURL=use-nodemon.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-nodemon.js","sourceRoot":"","sources":["../../src/cli/use-nodemon.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport nodemonOriginal from \"nodemon\";\nimport { useEffect } from \"react\";\nimport type { ExtendedNodemon } from \"./nodemon.d.ts\";\nimport type { PushMessage } from \"./use-messages.js\";\n\nconst nodemon = nodemonOriginal as ExtendedNodemon;\n\nconst SOURCEMAP_WARNING = /^Sourcemap for \".*\" points to missing source files$/;\n\nexport function useNodemon(\n env: NodeJS.ProcessEnv,\n pushMessage: PushMessage,\n): void {\n useEffect(() => {\n const configFile = resolve(process.cwd(), \"nodemon.json\");\n\n const config = existsSync(configFile)\n ? {\n configFile,\n }\n : {\n watch: [\"src\"],\n ext: \"ts,json\",\n exec: \"tsx src/server.ts\",\n };\n\n nodemon({ ...config, env, stdout: false });\n\n const handleStdoutData = (chunk: Buffer) => {\n const message = chunk.toString().trim();\n if (message) {\n pushMessage(message, \"log\");\n }\n };\n\n const handleStderrData = (chunk: Buffer) => {\n const message = chunk.toString().trim();\n if (!message) {\n return;\n }\n // Node's source-map warnings for third-party deps (superjson, @mcp/sdk, …) — not actionable.\n const filtered = message\n .split(\"\\n\")\n .filter((line) => !SOURCEMAP_WARNING.test(line))\n .join(\"\\n\");\n if (filtered) {\n pushMessage(filtered, \"error\");\n }\n };\n\n const setupStdoutListener = () => {\n if (nodemon.stdout) {\n nodemon.stdout.off(\"data\", handleStdoutData);\n nodemon.stdout.on(\"data\", handleStdoutData);\n }\n };\n\n const setupStderrListener = () => {\n if (nodemon.stderr) {\n nodemon.stderr.off(\"data\", handleStderrData);\n nodemon.stderr.on(\"data\", handleStderrData);\n }\n };\n\n nodemon.on(\"readable\", () => {\n setupStdoutListener();\n setupStderrListener();\n });\n\n nodemon.on(\"restart\", (files: string[]) => {\n const restartMessage = `Server restarted due to file changes: ${files.join(\", \")}`;\n pushMessage(restartMessage, \"restart\");\n setupStdoutListener();\n setupStderrListener();\n });\n\n return () => {\n if (nodemon.stdout) {\n nodemon.stdout.off(\"data\", handleStdoutData);\n }\n if (nodemon.stderr) {\n nodemon.stderr.off(\"data\", handleStderrData);\n }\n nodemon.emit(\"quit\");\n };\n }, [env, pushMessage]);\n}\n"]}
1
+ {"version":3,"file":"use-nodemon.js","sourceRoot":"","sources":["../../src/cli/use-nodemon.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport nodemonOriginal from \"nodemon\";\nimport { useEffect } from \"react\";\nimport type { ExtendedNodemon } from \"./nodemon.d.ts\";\nimport type { PushMessage } from \"./use-messages.js\";\n\nconst nodemon = nodemonOriginal as ExtendedNodemon;\n\nconst SOURCEMAP_WARNING = /^Sourcemap for \".*\" points to missing source files$/;\n\nexport interface NodemonHandlers {\n /** A raw chunk of server stdout, forwarded untouched. */\n onStdout: (chunk: Buffer) => void;\n /** A (filtered) chunk of server stderr. */\n onStderr: (message: string) => void;\n /** The server restarted because the listed files changed. */\n onRestart: (files: string[]) => void;\n}\n\n/**\n * Boot nodemon and wire its stdout/stderr to the provided handlers. Returns a\n * cleanup function that detaches the listeners and quits nodemon. Shared by the\n * Ink-based dev UI (via {@link useNodemon}) and the `--plain` runner.\n */\nexport function startNodemon(\n env: NodeJS.ProcessEnv,\n handlers: NodemonHandlers,\n): () => void {\n const configFile = resolve(process.cwd(), \"nodemon.json\");\n\n const config = existsSync(configFile)\n ? {\n configFile,\n }\n : {\n watch: [\"src\"],\n ext: \"ts,json\",\n exec: \"tsx src/server.ts\",\n };\n\n nodemon({ ...config, env, stdout: false });\n\n const handleStdoutData = (chunk: Buffer) => {\n handlers.onStdout(chunk);\n };\n\n const handleStderrData = (chunk: Buffer) => {\n const message = chunk.toString().trim();\n if (!message) {\n return;\n }\n // Node's source-map warnings for third-party deps (superjson, @mcp/sdk, …) — not actionable.\n const filtered = message\n .split(\"\\n\")\n .filter((line) => !SOURCEMAP_WARNING.test(line))\n .join(\"\\n\");\n if (filtered) {\n handlers.onStderr(filtered);\n }\n };\n\n const setupStdoutListener = () => {\n if (nodemon.stdout) {\n nodemon.stdout.off(\"data\", handleStdoutData);\n nodemon.stdout.on(\"data\", handleStdoutData);\n }\n };\n\n const setupStderrListener = () => {\n if (nodemon.stderr) {\n nodemon.stderr.off(\"data\", handleStderrData);\n nodemon.stderr.on(\"data\", handleStderrData);\n }\n };\n\n nodemon.on(\"readable\", () => {\n setupStdoutListener();\n setupStderrListener();\n });\n\n nodemon.on(\"restart\", (files: string[]) => {\n handlers.onRestart(files);\n setupStdoutListener();\n setupStderrListener();\n });\n\n return () => {\n if (nodemon.stdout) {\n nodemon.stdout.off(\"data\", handleStdoutData);\n }\n if (nodemon.stderr) {\n nodemon.stderr.off(\"data\", handleStderrData);\n }\n nodemon.emit(\"quit\");\n };\n}\n\nexport function useNodemon(\n env: NodeJS.ProcessEnv,\n pushMessage: PushMessage,\n): void {\n useEffect(\n () =>\n startNodemon(env, {\n onStdout: (chunk) => {\n const message = chunk.toString().trim();\n if (message) {\n pushMessage(message, \"log\");\n }\n },\n onStderr: (message) => pushMessage(message, \"error\"),\n onRestart: (files) =>\n pushMessage(\n `Server restarted due to file changes: ${files.join(\", \")}`,\n \"restart\",\n ),\n }),\n [env, pushMessage],\n );\n}\n"]}
@@ -1,9 +1,15 @@
1
- type TsError = {
1
+ export type TsError = {
2
2
  file: string;
3
3
  line: number;
4
4
  col: number;
5
5
  code: string;
6
6
  message: string;
7
7
  };
8
+ /**
9
+ * Spawn `tsc --noEmit --watch` and report each completed check via `onErrors`
10
+ * (empty array when the check is clean). Returns a cleanup function that kills
11
+ * the watcher. Shared by the Ink-based dev UI (via {@link useTypeScriptCheck})
12
+ * and the `--plain` runner.
13
+ */
14
+ export declare function startTypeScriptCheck(onErrors: (errors: Array<TsError>) => void): () => void;
8
15
  export declare function useTypeScriptCheck(): Array<TsError>;
9
- export {};