skybridge 0.0.0-dev.f8da531 → 0.0.0-dev.f8ef758

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 (308) hide show
  1. package/README.md +123 -124
  2. package/dist/cli/build-helpers.d.ts +7 -0
  3. package/dist/cli/build-helpers.js +82 -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 +64 -0
  7. package/dist/cli/build-helpers.test.js.map +1 -0
  8. package/dist/cli/detect-port.d.ts +2 -2
  9. package/dist/cli/detect-port.js +9 -20
  10. package/dist/cli/detect-port.js.map +1 -1
  11. package/dist/cli/header.js.map +1 -1
  12. package/dist/cli/resolve-views-dir.d.ts +1 -0
  13. package/dist/cli/resolve-views-dir.js +17 -0
  14. package/dist/cli/resolve-views-dir.js.map +1 -0
  15. package/dist/cli/run-command.js.map +1 -1
  16. package/dist/cli/telemetry.js.map +1 -1
  17. package/dist/cli/tunnel-control-server.js.map +1 -1
  18. package/dist/cli/tunnel-control-server.test.js.map +1 -1
  19. package/dist/cli/tunnel-handler.js.map +1 -1
  20. package/dist/cli/tunnel-handler.test.js.map +1 -1
  21. package/dist/cli/tunnel.js +2 -2
  22. package/dist/cli/tunnel.js.map +1 -1
  23. package/dist/cli/tunnel.test.js.map +1 -1
  24. package/dist/cli/types.js.map +1 -1
  25. package/dist/cli/use-execute-steps.js.map +1 -1
  26. package/dist/cli/use-messages.js.map +1 -1
  27. package/dist/cli/use-nodemon.js +11 -2
  28. package/dist/cli/use-nodemon.js.map +1 -1
  29. package/dist/cli/use-open-browser.d.ts +1 -0
  30. package/dist/cli/use-open-browser.js +44 -0
  31. package/dist/cli/use-open-browser.js.map +1 -0
  32. package/dist/cli/use-tunnel.js.map +1 -1
  33. package/dist/cli/use-typescript-check.js +1 -1
  34. package/dist/cli/use-typescript-check.js.map +1 -1
  35. package/dist/commands/build.d.ts +0 -1
  36. package/dist/commands/build.js +41 -18
  37. package/dist/commands/build.js.map +1 -1
  38. package/dist/commands/create.d.ts +9 -0
  39. package/dist/commands/create.js +30 -0
  40. package/dist/commands/create.js.map +1 -0
  41. package/dist/commands/dev.d.ts +1 -0
  42. package/dist/commands/dev.js +23 -0
  43. package/dist/commands/dev.js.map +1 -1
  44. package/dist/commands/start.js +7 -1
  45. package/dist/commands/start.js.map +1 -1
  46. package/dist/commands/telemetry/disable.js.map +1 -1
  47. package/dist/commands/telemetry/enable.js.map +1 -1
  48. package/dist/commands/telemetry/status.js.map +1 -1
  49. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  50. package/dist/server/asset-base-url-transform-plugin.js +16 -1
  51. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  52. package/dist/server/asset-base-url-transform-plugin.test.js +51 -1
  53. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  54. package/dist/server/auth/discovery.d.ts +11 -0
  55. package/dist/server/auth/discovery.js +51 -0
  56. package/dist/server/auth/discovery.js.map +1 -0
  57. package/dist/server/auth/discovery.test.d.ts +1 -0
  58. package/dist/server/auth/discovery.test.js +93 -0
  59. package/dist/server/auth/discovery.test.js.map +1 -0
  60. package/dist/server/auth/index.d.ts +18 -0
  61. package/dist/server/auth/index.js +2 -0
  62. package/dist/server/auth/index.js.map +1 -0
  63. package/dist/server/auth/providers/auth0.d.ts +13 -0
  64. package/dist/server/auth/providers/auth0.js +18 -0
  65. package/dist/server/auth/providers/auth0.js.map +1 -0
  66. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  67. package/dist/server/auth/providers/auth0.test.js +33 -0
  68. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  69. package/dist/server/auth/providers/clerk.d.ts +14 -0
  70. package/dist/server/auth/providers/clerk.js +20 -0
  71. package/dist/server/auth/providers/clerk.js.map +1 -0
  72. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  73. package/dist/server/auth/providers/clerk.test.js +48 -0
  74. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  75. package/dist/server/auth/providers/custom.d.ts +17 -0
  76. package/dist/server/auth/providers/custom.js +28 -0
  77. package/dist/server/auth/providers/custom.js.map +1 -0
  78. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  79. package/dist/server/auth/providers/custom.test.js +91 -0
  80. package/dist/server/auth/providers/custom.test.js.map +1 -0
  81. package/dist/server/auth/providers/descope.d.ts +14 -0
  82. package/dist/server/auth/providers/descope.js +14 -0
  83. package/dist/server/auth/providers/descope.js.map +1 -0
  84. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  85. package/dist/server/auth/providers/descope.test.js +35 -0
  86. package/dist/server/auth/providers/descope.test.js.map +1 -0
  87. package/dist/server/auth/providers/stytch.d.ts +12 -0
  88. package/dist/server/auth/providers/stytch.js +17 -0
  89. package/dist/server/auth/providers/stytch.js.map +1 -0
  90. package/dist/server/auth/providers/stytch.test.d.ts +1 -0
  91. package/dist/server/auth/providers/stytch.test.js +33 -0
  92. package/dist/server/auth/providers/stytch.test.js.map +1 -0
  93. package/dist/server/auth/providers/workos.d.ts +11 -0
  94. package/dist/server/auth/providers/workos.js +16 -0
  95. package/dist/server/auth/providers/workos.js.map +1 -0
  96. package/dist/server/auth/providers/workos.test.d.ts +1 -0
  97. package/dist/server/auth/providers/workos.test.js +41 -0
  98. package/dist/server/auth/providers/workos.test.js.map +1 -0
  99. package/dist/server/auth/setup.d.ts +4 -0
  100. package/dist/server/auth/setup.js +51 -0
  101. package/dist/server/auth/setup.js.map +1 -0
  102. package/dist/server/auth/setup.test.d.ts +1 -0
  103. package/dist/server/auth/setup.test.js +185 -0
  104. package/dist/server/auth/setup.test.js.map +1 -0
  105. package/dist/server/auth/verify.d.ts +12 -0
  106. package/dist/server/auth/verify.js +38 -0
  107. package/dist/server/auth/verify.js.map +1 -0
  108. package/dist/server/auth/verify.test.d.ts +1 -0
  109. package/dist/server/auth/verify.test.js +100 -0
  110. package/dist/server/auth/verify.test.js.map +1 -0
  111. package/dist/server/auth.d.ts +20 -0
  112. package/dist/server/auth.js +28 -0
  113. package/dist/server/auth.js.map +1 -0
  114. package/dist/server/build-manifest.test.d.ts +1 -0
  115. package/dist/server/build-manifest.test.js +27 -0
  116. package/dist/server/build-manifest.test.js.map +1 -0
  117. package/dist/server/content-helpers.d.ts +40 -0
  118. package/dist/server/content-helpers.js +33 -0
  119. package/dist/server/content-helpers.js.map +1 -1
  120. package/dist/server/content-helpers.test.js.map +1 -1
  121. package/dist/server/express.d.ts +1 -5
  122. package/dist/server/express.js +13 -7
  123. package/dist/server/express.js.map +1 -1
  124. package/dist/server/express.test.js +214 -71
  125. package/dist/server/express.test.js.map +1 -1
  126. package/dist/server/file-ref.d.ts +28 -0
  127. package/dist/server/file-ref.js +27 -0
  128. package/dist/server/file-ref.js.map +1 -0
  129. package/dist/server/index.d.ts +11 -2
  130. package/dist/server/index.js +9 -1
  131. package/dist/server/index.js.map +1 -1
  132. package/dist/server/inferUtilityTypes.js.map +1 -1
  133. package/dist/server/metric.js.map +1 -1
  134. package/dist/server/middleware.d.ts +16 -3
  135. package/dist/server/middleware.js.map +1 -1
  136. package/dist/server/middleware.test-d.js.map +1 -1
  137. package/dist/server/middleware.test.js.map +1 -1
  138. package/dist/server/requestOrigin.d.ts +7 -0
  139. package/dist/server/requestOrigin.js +25 -0
  140. package/dist/server/requestOrigin.js.map +1 -0
  141. package/dist/server/server.d.ts +237 -7
  142. package/dist/server/server.js +278 -73
  143. package/dist/server/server.js.map +1 -1
  144. package/dist/server/templateHelper.d.ts +0 -2
  145. package/dist/server/templateHelper.js +3 -22
  146. package/dist/server/templateHelper.js.map +1 -1
  147. package/dist/server/templates.generated.d.ts +4 -0
  148. package/dist/server/templates.generated.js +47 -0
  149. package/dist/server/templates.generated.js.map +1 -0
  150. package/dist/server/tunnel-proxy-router.js.map +1 -1
  151. package/dist/server/tunnel-proxy-router.test.js.map +1 -1
  152. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  153. package/dist/server/view-resource-resolution.test.js +88 -0
  154. package/dist/server/view-resource-resolution.test.js.map +1 -0
  155. package/dist/server/viewsDevServer.js.map +1 -1
  156. package/dist/test/utils.js.map +1 -1
  157. package/dist/test/view.test.js +45 -0
  158. package/dist/test/view.test.js.map +1 -1
  159. package/dist/version.js +1 -3
  160. package/dist/version.js.map +1 -1
  161. package/dist/web/bridges/apps-sdk/adaptor.d.ts +7 -2
  162. package/dist/web/bridges/apps-sdk/adaptor.js +27 -3
  163. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
  164. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -0
  165. package/dist/web/bridges/apps-sdk/bridge.js +1 -0
  166. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  167. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  168. package/dist/web/bridges/apps-sdk/types.d.ts +8 -1
  169. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  170. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  171. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  172. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  173. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  174. package/dist/web/bridges/get-adaptor.js +7 -0
  175. package/dist/web/bridges/get-adaptor.js.map +1 -1
  176. package/dist/web/bridges/index.js.map +1 -1
  177. package/dist/web/bridges/mcp-app/adaptor.d.ts +7 -2
  178. package/dist/web/bridges/mcp-app/adaptor.js +21 -6
  179. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
  180. package/dist/web/bridges/mcp-app/bridge.d.ts +4 -2
  181. package/dist/web/bridges/mcp-app/bridge.js +23 -1
  182. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  183. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  184. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  185. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  186. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  187. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  188. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  189. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  190. package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
  191. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  192. package/dist/web/bridges/types.d.ts +98 -3
  193. package/dist/web/bridges/types.js.map +1 -1
  194. package/dist/web/bridges/use-host-context.d.ts +5 -0
  195. package/dist/web/bridges/use-host-context.js +5 -0
  196. package/dist/web/bridges/use-host-context.js.map +1 -1
  197. package/dist/web/components/modal-provider.js.map +1 -1
  198. package/dist/web/create-store.d.ts +26 -0
  199. package/dist/web/create-store.js +26 -0
  200. package/dist/web/create-store.js.map +1 -1
  201. package/dist/web/create-store.test.js.map +1 -1
  202. package/dist/web/data-llm.d.ts +33 -0
  203. package/dist/web/data-llm.js +28 -0
  204. package/dist/web/data-llm.js.map +1 -1
  205. package/dist/web/data-llm.test.js.map +1 -1
  206. package/dist/web/generate-helpers.d.ts +2 -0
  207. package/dist/web/generate-helpers.js +2 -0
  208. package/dist/web/generate-helpers.js.map +1 -1
  209. package/dist/web/generate-helpers.test-d.js +4 -2
  210. package/dist/web/generate-helpers.test-d.js.map +1 -1
  211. package/dist/web/generate-helpers.test.js.map +1 -1
  212. package/dist/web/helpers/state.js.map +1 -1
  213. package/dist/web/helpers/state.test.js.map +1 -1
  214. package/dist/web/hooks/index.d.ts +4 -0
  215. package/dist/web/hooks/index.js +4 -0
  216. package/dist/web/hooks/index.js.map +1 -1
  217. package/dist/web/hooks/test/utils.d.ts +6 -2
  218. package/dist/web/hooks/test/utils.js +13 -2
  219. package/dist/web/hooks/test/utils.js.map +1 -1
  220. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  221. package/dist/web/hooks/use-call-tool.js +28 -0
  222. package/dist/web/hooks/use-call-tool.js.map +1 -1
  223. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  224. package/dist/web/hooks/use-call-tool.test.js +27 -6
  225. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  226. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  227. package/dist/web/hooks/use-display-mode.js +20 -0
  228. package/dist/web/hooks/use-display-mode.js.map +1 -1
  229. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  230. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  231. package/dist/web/hooks/use-download.d.ts +5 -0
  232. package/dist/web/hooks/use-download.js +8 -0
  233. package/dist/web/hooks/use-download.js.map +1 -0
  234. package/dist/web/hooks/use-download.test.d.ts +1 -0
  235. package/dist/web/hooks/use-download.test.js +95 -0
  236. package/dist/web/hooks/use-download.test.js.map +1 -0
  237. package/dist/web/hooks/use-files.d.ts +32 -0
  238. package/dist/web/hooks/use-files.js +32 -0
  239. package/dist/web/hooks/use-files.js.map +1 -1
  240. package/dist/web/hooks/use-files.test.js.map +1 -1
  241. package/dist/web/hooks/use-layout.d.ts +2 -0
  242. package/dist/web/hooks/use-layout.js +2 -0
  243. package/dist/web/hooks/use-layout.js.map +1 -1
  244. package/dist/web/hooks/use-layout.test.js.map +1 -1
  245. package/dist/web/hooks/use-open-external.d.ts +17 -0
  246. package/dist/web/hooks/use-open-external.js +16 -0
  247. package/dist/web/hooks/use-open-external.js.map +1 -1
  248. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  249. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  250. package/dist/web/hooks/use-register-view-tool.js +50 -0
  251. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  252. package/dist/web/hooks/use-request-close.d.ts +16 -0
  253. package/dist/web/hooks/use-request-close.js +21 -0
  254. package/dist/web/hooks/use-request-close.js.map +1 -0
  255. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  256. package/dist/web/hooks/use-request-close.test.js +52 -0
  257. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  258. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  259. package/dist/web/hooks/use-request-modal.js +16 -1
  260. package/dist/web/hooks/use-request-modal.js.map +1 -1
  261. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  262. package/dist/web/hooks/use-request-size.d.ts +20 -0
  263. package/dist/web/hooks/use-request-size.js +24 -0
  264. package/dist/web/hooks/use-request-size.js.map +1 -0
  265. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  266. package/dist/web/hooks/use-request-size.test.js +65 -0
  267. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  268. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  269. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  270. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  271. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  272. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  273. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  274. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  275. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  276. package/dist/web/hooks/use-tool-info.js +30 -7
  277. package/dist/web/hooks/use-tool-info.js.map +1 -1
  278. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  279. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  280. package/dist/web/hooks/use-tool-info.test.js +5 -5
  281. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  282. package/dist/web/hooks/use-user.d.ts +2 -0
  283. package/dist/web/hooks/use-user.js +2 -0
  284. package/dist/web/hooks/use-user.js.map +1 -1
  285. package/dist/web/hooks/use-user.test.js.map +1 -1
  286. package/dist/web/hooks/use-view-state.d.ts +21 -0
  287. package/dist/web/hooks/use-view-state.js.map +1 -1
  288. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  289. package/dist/web/index.js.map +1 -1
  290. package/dist/web/mount-view.d.ts +19 -0
  291. package/dist/web/mount-view.js +19 -0
  292. package/dist/web/mount-view.js.map +1 -1
  293. package/dist/web/plugin/data-llm.test.js.map +1 -1
  294. package/dist/web/plugin/plugin.d.ts +28 -0
  295. package/dist/web/plugin/plugin.js +35 -9
  296. package/dist/web/plugin/plugin.js.map +1 -1
  297. package/dist/web/plugin/scan-views.js.map +1 -1
  298. package/dist/web/plugin/scan-views.test.js.map +1 -1
  299. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  300. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  301. package/dist/web/plugin/validate-view.js.map +1 -1
  302. package/dist/web/plugin/validate-view.test.js.map +1 -1
  303. package/dist/web/proxy.js.map +1 -1
  304. package/dist/web/types.d.ts +4 -0
  305. package/dist/web/types.js.map +1 -1
  306. package/package.json +28 -18
  307. package/dist/server/templates/development.hbs +0 -12
  308. package/dist/server/templates/production.hbs +0 -6
@@ -0,0 +1,30 @@
1
+ import { Command, Help } from "@oclif/core";
2
+ import spawn from "cross-spawn";
3
+ function passthrough(args) {
4
+ const { status, error } = spawn.sync("npx", ["--yes", "create-skybridge@latest", ...args], { stdio: "inherit" });
5
+ if (error) {
6
+ console.error(error);
7
+ process.exit(1);
8
+ }
9
+ process.exit(status ?? 1);
10
+ }
11
+ export default class Create extends Command {
12
+ static description = "Scaffold a new Skybridge project";
13
+ static strict = false;
14
+ async run() {
15
+ passthrough(this.argv);
16
+ }
17
+ }
18
+ // Registered as `oclif.helpClass` so that `skybridge create --help` forwards
19
+ // to `create-skybridge --help` (single source of truth for the help text)
20
+ // instead of rendering oclif's auto-generated help. All other commands fall
21
+ // through to the default `Help` behaviour.
22
+ export class SkybridgeHelp extends Help {
23
+ async showCommandHelp(command) {
24
+ if (command.id === "create") {
25
+ passthrough(["--help"]);
26
+ }
27
+ return super.showCommandHelp(command);
28
+ }
29
+ }
30
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmC,IAAI,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,KAAK,MAAM,aAAa,CAAC;AAEhC,SAAS,WAAW,CAAC,IAAc;IACjC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,CAClC,KAAK,EACL,CAAC,OAAO,EAAE,yBAAyB,EAAE,GAAG,IAAI,CAAC,EAC7C,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;IACF,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IACzC,MAAM,CAAU,WAAW,GAAG,kCAAkC,CAAC;IACjE,MAAM,CAAU,MAAM,GAAG,KAAK,CAAC;IAExB,KAAK,CAAC,GAAG;QACd,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;;AAGH,6EAA6E;AAC7E,0EAA0E;AAC1E,4EAA4E;AAC5E,2CAA2C;AAC3C,MAAM,OAAO,aAAc,SAAQ,IAAI;IAC5B,KAAK,CAAC,eAAe,CAC5B,OAAiC;QAEjC,IAAI,OAAO,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC5B,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;CACF","sourcesContent":["import { Command, type Command as CommandLoadable, Help } from \"@oclif/core\";\nimport spawn from \"cross-spawn\";\n\nfunction passthrough(args: string[]): never {\n const { status, error } = spawn.sync(\n \"npx\",\n [\"--yes\", \"create-skybridge@latest\", ...args],\n { stdio: \"inherit\" },\n );\n if (error) {\n console.error(error);\n process.exit(1);\n }\n process.exit(status ?? 1);\n}\n\nexport default class Create extends Command {\n static override description = \"Scaffold a new Skybridge project\";\n static override strict = false;\n\n public async run(): Promise<void> {\n passthrough(this.argv);\n }\n}\n\n// Registered as `oclif.helpClass` so that `skybridge create --help` forwards\n// to `create-skybridge --help` (single source of truth for the help text)\n// instead of rendering oclif's auto-generated help. All other commands fall\n// through to the default `Help` behaviour.\nexport class SkybridgeHelp extends Help {\n override async showCommandHelp(\n command: CommandLoadable.Loadable,\n ): Promise<void> {\n if (command.id === \"create\") {\n passthrough([\"--help\"]);\n }\n return super.showCommandHelp(command);\n }\n}\n"]}
@@ -5,6 +5,7 @@ export default class Dev extends Command {
5
5
  static flags: {
6
6
  port: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
7
  tunnel: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ open: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
9
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
10
  };
10
11
  run(): Promise<void>;
@@ -3,11 +3,14 @@ import { Command, Flags } from "@oclif/core";
3
3
  import { Box, render, Text } from "ink";
4
4
  import { resolvePort } from "../cli/detect-port.js";
5
5
  import { Header } from "../cli/header.js";
6
+ import { resolveViewsDir } from "../cli/resolve-views-dir.js";
6
7
  import { startTunnelControlServer } from "../cli/tunnel-control-server.js";
7
8
  import { useMessages } from "../cli/use-messages.js";
8
9
  import { useNodemon } from "../cli/use-nodemon.js";
10
+ import { useOpenBrowser } from "../cli/use-open-browser.js";
9
11
  import { useTunnel } from "../cli/use-tunnel.js";
10
12
  import { useTypeScriptCheck } from "../cli/use-typescript-check.js";
13
+ import { scanAndWriteViewsDts } from "../web/plugin/scan-views.js";
11
14
  export default class Dev extends Command {
12
15
  static description = "Start development server";
13
16
  static examples = ["skybridge"];
@@ -21,6 +24,11 @@ export default class Dev extends Command {
21
24
  description: "Open an Alpic tunnel for remote testing",
22
25
  default: false,
23
26
  }),
27
+ open: Flags.boolean({
28
+ description: "Open DevTools in the browser when the server is ready",
29
+ default: process.env.SKYBRIDGE_OPEN !== "false",
30
+ allowNo: true,
31
+ }),
24
32
  verbose: Flags.boolean({
25
33
  char: "v",
26
34
  description: "Show tunnel logs",
@@ -29,6 +37,20 @@ export default class Dev extends Command {
29
37
  };
30
38
  async run() {
31
39
  const { flags } = await this.parse(Dev);
40
+ // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit
41
+ // --watch`. Vite's plugin config hook writes the same file when nodemon
42
+ // boots the server, but tsc starts in parallel — if .skybridge/ doesn't
43
+ // exist at tsc startup, its watcher never picks up the late-created file
44
+ // and the dev UI reports phantom TS errors forever.
45
+ const root = process.cwd();
46
+ try {
47
+ scanAndWriteViewsDts(root, await resolveViewsDir(root));
48
+ }
49
+ catch {
50
+ // Best-effort: if the scan fails (e.g. broken vite config, duplicate
51
+ // view names) tsc may show phantom errors, but the dev server should
52
+ // still start so the developer can fix the underlying issue.
53
+ }
32
54
  const { port, fallback, envWarning } = await resolvePort(flags.port);
33
55
  if (envWarning) {
34
56
  this.warn(envWarning);
@@ -43,6 +65,7 @@ export default class Dev extends Command {
43
65
  const tsErrors = useTypeScriptCheck();
44
66
  const [messages, pushMessage] = useMessages();
45
67
  useNodemon(env, pushMessage);
68
+ useOpenBrowser(port, flags.open);
46
69
  const tunnelState = useTunnel(port, pushMessage, flags.verbose, flags.tunnel);
47
70
  return (_jsxs(Box, { flexDirection: "column", padding: 1, marginLeft: 1, children: [_jsx(Header, { version: this.config.version }), _jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDFE0", " "] }), fallback ? (_jsx(Text, { color: "yellow", children: "3000 in use, running on " })) : (_jsx(Text, { children: "Running on " })), _jsx(Text, { color: "green", children: `http://localhost:${port}/mcp` })] }), _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: "#20a832", children: ["\u2192", " "] }), _jsxs(Text, { color: "white", bold: true, children: ["Test locally with DevTools:", " "] }), _jsx(Text, { color: "green", children: `http://localhost:${port}/` })] }), tunnelState.status === "idle" && (_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsx(Text, { children: "Get a public URL and LLM Playground access with " }), _jsx(Text, { color: "cyan", bold: true, children: "--tunnel" }), _jsx(Text, { children: "." })] })), tunnelState.status === "starting" && (_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsx(Text, { color: "yellow", children: tunnelState.message })] })), tunnelState.status === "connected" && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsx(Text, { children: "Exposed on " }), _jsx(Text, { color: "green", children: `${tunnelState.url}/mcp` })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "#20a832", children: ["\u2192", " "] }), _jsxs(Text, { color: "white", bold: true, children: ["Test with an LLM on Playground:", " "] }), _jsx(Text, { color: "green", children: `${tunnelState.url}/try` })] })] })), tunnelState.status === "error" && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83C\uDF0D", " "] }), _jsxs(Text, { color: "red", children: ["Cannot open tunnel: ", tunnelState.message] })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "#20a832", children: ["\u2192", " "] }), _jsx(Text, { color: "red", children: `Try manually: npx alpic tunnel --port ${port}` })] })] })), _jsxs(Box, { children: [_jsxs(Text, { children: ["\uD83D\uDEDF", " "] }), _jsx(Text, { children: "Need help? Reach us on " }), _jsx(Text, { color: "white", underline: true, children: "https://discord.alpic.ai" })] }), tsErrors.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "\u26A0\uFE0F TypeScript errors found:" }), tsErrors.map((error) => (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "white", children: error.file }), _jsxs(Text, { color: "grey", children: ["(", error.line, ",", error.col, "):", " "] })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "red", children: error.message }) })] }, `${error.file}:${error.line}:${error.col}`)))] })), messages.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "white", bold: true, children: "Logs:" }), messages.map((message) => (_jsx(Box, { marginLeft: 2, children: message.type === "restart" ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", children: ["\u2713", " "] }), _jsx(Text, { color: "white", children: message.text })] })) : message.type === "error" ? (_jsx(Text, { color: "red", children: message.text })) : (_jsx(Text, { children: message.text })) }, message.id)))] }))] }));
48
71
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { resolveViewsDir } from \"../cli/resolve-views-dir.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit\n // --watch`. Vite's plugin config hook writes the same file when nodemon\n // boots the server, but tsc starts in parallel — if .skybridge/ doesn't\n // exist at tsc startup, its watcher never picks up the late-created file\n // and the dev UI reports phantom TS errors forever.\n const root = process.cwd();\n try {\n scanAndWriteViewsDts(root, await resolveViewsDir(root));\n } catch {\n // Best-effort: if the scan fails (e.g. broken vite config, duplicate\n // view names) tsc may show phantom errors, but the dev server should\n // still start so the developer can fix the underlying issue.\n }\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
@@ -20,7 +20,13 @@ export default class Start extends Command {
20
20
  this.warn(envWarning);
21
21
  }
22
22
  console.clear();
23
- const indexPath = resolve(process.cwd(), "dist/server.js");
23
+ // `dist/server.js` is the natural entry (the user's `await server.run()`
24
+ // binds the port). Prefer `dist/__entry.js` when present because it
25
+ // primes the Vite manifest first — without it, hashed asset URLs in
26
+ // views won't resolve.
27
+ const entryPath = resolve(process.cwd(), "dist/__entry.js");
28
+ const fallbackPath = resolve(process.cwd(), "dist/server.js");
29
+ const indexPath = existsSync(entryPath) ? entryPath : fallbackPath;
24
30
  if (!existsSync(indexPath)) {
25
31
  console.error("❌ Error: No build output found");
26
32
  console.error("");
@@ -1 +1 @@
1
- {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,OAAO;IACxC,MAAM,CAAU,WAAW,GAAG,yBAAyB,CAAC;IACxD,MAAM,CAAU,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC/C,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,2BAA2B;YACxC,GAAG,EAAE,CAAC;SACP,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;QAEhB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAE3D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;YAChD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CACT,8CAA8C,IAAI,CAAC,MAAM,CAAC,OAAO,SAAS,CAC3E,CAAC;QACF,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CACT,mEAAmE,IAAI,aAAa,CACrF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,aAAa,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,UAAU,CAAC,QAAQ,SAAS,EAAE,EAAE;YACpC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;YACvC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,QAAQ,EAAE,YAAY;gBACtB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;aACrB;SACF,CAAC,CAAC;IACL,CAAC"}
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,OAAO;IACxC,MAAM,CAAU,WAAW,GAAG,yBAAyB,CAAC;IACxD,MAAM,CAAU,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC/C,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,2BAA2B;YACxC,GAAG,EAAE,CAAC;SACP,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;QAEhB,yEAAyE;QACzE,oEAAoE;QACpE,oEAAoE;QACpE,uBAAuB;QACvB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAC5D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;QAEnE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;YAChD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CACT,8CAA8C,IAAI,CAAC,MAAM,CAAC,OAAO,SAAS,CAC3E,CAAC;QACF,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CACT,mEAAmE,IAAI,aAAa,CACrF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,aAAa,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,UAAU,CAAC,QAAQ,SAAS,EAAE,EAAE;YACpC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;YACvC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,QAAQ,EAAE,YAAY;gBACtB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;aACrB;SACF,CAAC,CAAC;IACL,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { Command, Flags } from \"@oclif/core\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { runCommand } from \"../cli/run-command.js\";\n\nexport default class Start extends Command {\n static override description = \"Start production server\";\n static override examples = [\"skybridge start\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Start);\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n console.clear();\n\n // `dist/server.js` is the natural entry (the user's `await server.run()`\n // binds the port). Prefer `dist/__entry.js` when present because it\n // primes the Vite manifest first — without it, hashed asset URLs in\n // views won't resolve.\n const entryPath = resolve(process.cwd(), \"dist/__entry.js\");\n const fallbackPath = resolve(process.cwd(), \"dist/server.js\");\n const indexPath = existsSync(entryPath) ? entryPath : fallbackPath;\n\n if (!existsSync(indexPath)) {\n console.error(\"❌ Error: No build output found\");\n console.error(\"\");\n console.error(\"Please build your project first:\");\n console.error(\" skybridge build\");\n console.error(\"\");\n process.exit(1);\n }\n\n console.log(\n `\\x1b[36m\\x1b[1m⛰ Skybridge\\x1b[0m \\x1b[36mv${this.config.version}\\x1b[0m`,\n );\n if (fallback) {\n console.log(\n `\\x1b[33m3000 in use, running on\\x1b[0m \\x1b[32mhttp://localhost:${port}/mcp\\x1b[0m`,\n );\n } else {\n console.log(`Running on \\x1b[32mhttp://localhost:${port}/mcp\\x1b[0m`);\n }\n\n await runCommand(`node ${indexPath}`, {\n stdio: [\"ignore\", \"inherit\", \"inherit\"],\n env: {\n ...process.env,\n NODE_ENV: \"production\",\n __PORT: String(port),\n },\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../src/commands/telemetry/disable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,OAAO;IACnD,MAAM,CAAU,WAAW,GAAG,6CAA6C,CAAC;IAErE,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACnC,UAAU,CAAC,KAAK,CAAC,CAAC;QAElB,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAChB,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,uBAAS,EAC7B,KAAC,IAAI,uCAA4B,EACjC,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,+BAElB,IACH,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,yDAAgD,GAC9D,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,gOAKX,GACH,IACF,CACP,CAAC;QAEF,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IAClB,CAAC"}
1
+ {"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../src/commands/telemetry/disable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,OAAO;IACnD,MAAM,CAAU,WAAW,GAAG,6CAA6C,CAAC;IAErE,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACnC,UAAU,CAAC,KAAK,CAAC,CAAC;QAElB,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAChB,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,uBAAS,EAC7B,KAAC,IAAI,uCAA4B,EACjC,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,+BAElB,IACH,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,yDAAgD,GAC9D,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,gOAKX,GACH,IACF,CACP,CAAC;QAEF,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IAClB,CAAC","sourcesContent":["import { Command } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { setEnabled } from \"../../cli/telemetry.js\";\n\nexport default class TelemetryDisable extends Command {\n static override description = \"Disable Skybridge telemetry on this machine\";\n\n public async run(): Promise<void> {\n await this.parse(TelemetryDisable);\n setEnabled(false);\n\n const App = () => (\n <Box flexDirection=\"column\" padding={1}>\n <Box>\n <Text color=\"yellow\">✓</Text>\n <Text> Telemetry has been </Text>\n <Text color=\"yellow\" bold>\n disabled\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\">Config saved to ~/.skybridge/config.json</Text>\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\">\n Skybridge never collects Personally Identifiable Information (PII).\n If you'd like to help us improve Skybridge by allowing anonymous CLI\n usage data, please reenable telemetry with: skybridge telemetry\n enable\n </Text>\n </Box>\n </Box>\n );\n\n render(<App />);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"enable.js","sourceRoot":"","sources":["../../../src/commands/telemetry/enable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,OAAO;IAClD,MAAM,CAAU,WAAW,GAAG,4CAA4C,CAAC;IAEpE,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClC,UAAU,CAAC,IAAI,CAAC,CAAC;QAEjB,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAChB,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,uBAAS,EAC5B,KAAC,IAAI,uCAA4B,EACjC,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,8BAEjB,IACH,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,yDAAgD,GAC9D,IACF,CACP,CAAC;QAEF,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IAClB,CAAC"}
1
+ {"version":3,"file":"enable.js","sourceRoot":"","sources":["../../../src/commands/telemetry/enable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,OAAO;IAClD,MAAM,CAAU,WAAW,GAAG,4CAA4C,CAAC;IAEpE,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClC,UAAU,CAAC,IAAI,CAAC,CAAC;QAEjB,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAChB,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,uBAAS,EAC5B,KAAC,IAAI,uCAA4B,EACjC,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,8BAEjB,IACH,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,yDAAgD,GAC9D,IACF,CACP,CAAC;QAEF,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IAClB,CAAC","sourcesContent":["import { Command } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { setEnabled } from \"../../cli/telemetry.js\";\n\nexport default class TelemetryEnable extends Command {\n static override description = \"Enable Skybridge telemetry on this machine\";\n\n public async run(): Promise<void> {\n await this.parse(TelemetryEnable);\n setEnabled(true);\n\n const App = () => (\n <Box flexDirection=\"column\" padding={1}>\n <Box>\n <Text color=\"green\">✓</Text>\n <Text> Telemetry has been </Text>\n <Text color=\"green\" bold>\n enabled\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\">Config saved to ~/.skybridge/config.json</Text>\n </Box>\n </Box>\n );\n\n render(<App />);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/telemetry/status.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,OAAO;IAClD,MAAM,CAAU,WAAW,GACzB,2DAA2D,CAAC;IAEvD,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;QAE5B,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAChB,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,KAAC,IAAI,IAAC,IAAI,QAAC,SAAS,0CAEb,EAEP,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,MAAC,GAAG,eACF,KAAC,IAAI,2BAAgB,EACpB,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,8BAEjB,CACR,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,+BAElB,CACR,IACG,EAEN,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,6BAAoB,EACtC,KAAC,IAAI,cAAE,YAAY,EAAE,GAAQ,IACzB,IACF,EAEN,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,6DAAoD,EACtE,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,uDAA8C,EAChE,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,wDAA+C,IAC7D,IACF,CACP,CAAC;QAEF,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IAClB,CAAC"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/telemetry/status.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,OAAO;IAClD,MAAM,CAAU,WAAW,GACzB,2DAA2D,CAAC;IAEvD,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;QAE5B,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAChB,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,KAAC,IAAI,IAAC,IAAI,QAAC,SAAS,0CAEb,EAEP,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,MAAC,GAAG,eACF,KAAC,IAAI,2BAAgB,EACpB,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,8BAEjB,CACR,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,+BAElB,CACR,IACG,EAEN,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,6BAAoB,EACtC,KAAC,IAAI,cAAE,YAAY,EAAE,GAAQ,IACzB,IACF,EAEN,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,6DAAoD,EACtE,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,uDAA8C,EAChE,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,wDAA+C,IAC7D,IACF,CACP,CAAC;QAEF,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IAClB,CAAC","sourcesContent":["import { Command } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { getMachineId, isEnabled } from \"../../cli/telemetry.js\";\n\nexport default class TelemetryStatus extends Command {\n static override description =\n \"Get Skybridge current telemetry settings for this machine\";\n\n public async run(): Promise<void> {\n await this.parse(TelemetryStatus);\n const enabled = isEnabled();\n\n const App = () => (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold underline>\n Skybridge Telemetry\n </Text>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Box>\n <Text>Status: </Text>\n {enabled ? (\n <Text color=\"green\" bold>\n Enabled\n </Text>\n ) : (\n <Text color=\"yellow\" bold>\n Disabled\n </Text>\n )}\n </Box>\n\n <Box marginTop={1}>\n <Text color=\"gray\">Machine ID: </Text>\n <Text>{getMachineId()}</Text>\n </Box>\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"gray\">To opt out, run: skybridge telemetry disable</Text>\n <Text color=\"gray\">Or set: SKYBRIDGE_TELEMETRY_DISABLED=1</Text>\n <Text color=\"gray\">Debug mode: SKYBRIDGE_TELEMETRY_DEBUG=1</Text>\n </Box>\n </Box>\n );\n\n render(<App />);\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { Plugin } from "vite";
2
+ export declare function isCssRequest(id: string): boolean;
2
3
  /**
3
4
  * Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,
4
5
  * so they work both locally and behind tunnels.
@@ -1,3 +1,10 @@
1
+ // Mirrors Vite's own `isCSSRequest`: matches the css family of extensions
2
+ // either at the end of the id or right before the query string. Catches both
3
+ // plain `.css` requests and SFC style blocks (e.g. `Foo.vue?vue&type=style&lang.css`).
4
+ const CSS_LANGS_RE = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
5
+ export function isCssRequest(id) {
6
+ return CSS_LANGS_RE.test(id);
7
+ }
1
8
  /**
2
9
  * Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,
3
10
  * so they work both locally and behind tunnels.
@@ -15,10 +22,18 @@ export function assetBaseUrlTransform(code) {
15
22
  export function assetBaseUrlTransformPlugin() {
16
23
  return {
17
24
  name: "asset-base-url-transform",
18
- transform(code) {
25
+ transform(code, id) {
19
26
  if (!code) {
20
27
  return null;
21
28
  }
29
+ // Vite serves CSS modules as JS that embeds the stylesheet as a string
30
+ // literal. Rewriting `url("/foo.woff2")` inside that string to a JS
31
+ // concatenation expression produces invalid CSS once it lands in a
32
+ // <style> tag. CSS asset URLs are already handled at build time by
33
+ // `experimental.renderBuiltUrl`, so skip CSS requests here.
34
+ if (isCssRequest(id)) {
35
+ return null;
36
+ }
22
37
  const transformedCode = assetBaseUrlTransform(code);
23
38
  if (transformedCode === code) {
24
39
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"asset-base-url-transform-plugin.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,kBAAkB,GACtB,4GAA4G,CAAC;IAE/G,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;QACpE,OAAO,0CAA0C,SAAS,GAAG,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,SAAS,CAAC,IAAI;YACZ,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,eAAe;gBACrB,GAAG,EAAE,IAAI;aACV,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"asset-base-url-transform-plugin.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,6EAA6E;AAC7E,uFAAuF;AACvF,MAAM,YAAY,GAChB,6DAA6D,CAAC;AAEhE,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,kBAAkB,GACtB,4GAA4G,CAAC;IAE/G,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;QACpE,OAAO,0CAA0C,SAAS,GAAG,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,SAAS,CAAC,IAAI,EAAE,EAAE;YAChB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,uEAAuE;YACvE,oEAAoE;YACpE,mEAAmE;YACnE,mEAAmE;YACnE,4DAA4D;YAC5D,IAAI,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,eAAe;gBACrB,GAAG,EAAE,IAAI;aACV,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Plugin } from \"vite\";\n\n// Mirrors Vite's own `isCSSRequest`: matches the css family of extensions\n// either at the end of the id or right before the query string. Catches both\n// plain `.css` requests and SFC style blocks (e.g. `Foo.vue?vue&type=style&lang.css`).\nconst CSS_LANGS_RE =\n /\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\\?)/;\n\nexport function isCssRequest(id: string): boolean {\n return CSS_LANGS_RE.test(id);\n}\n\n/**\n * Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,\n * so they work both locally and behind tunnels.\n */\nexport function assetBaseUrlTransform(code: string): string {\n const assetStringPattern =\n /(?<!\\bfrom\\s)(?<!https?:\\/\\/)([\"'`])(\\/[^\"'`]+\\.(svg|png|jpeg|jpg|gif|webp|mp3|mp4|woff|woff2|ttf|eot))\\1/g;\n\n code = code.replace(assetStringPattern, (_match, _quote, assetPath) => {\n return `(window.skybridge?.serverUrl ?? \"\") + \"${assetPath}\"`;\n });\n\n return code;\n}\n\n/**\n * Vite plugin that transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`.\n */\nexport function assetBaseUrlTransformPlugin(): Plugin {\n return {\n name: \"asset-base-url-transform\",\n transform(code, id) {\n if (!code) {\n return null;\n }\n\n // Vite serves CSS modules as JS that embeds the stylesheet as a string\n // literal. Rewriting `url(\"/foo.woff2\")` inside that string to a JS\n // concatenation expression produces invalid CSS once it lands in a\n // <style> tag. CSS asset URLs are already handled at build time by\n // `experimental.renderBuiltUrl`, so skip CSS requests here.\n if (isCssRequest(id)) {\n return null;\n }\n\n const transformedCode = assetBaseUrlTransform(code);\n\n if (transformedCode === code) {\n return null;\n }\n\n return {\n code: transformedCode,\n map: null,\n };\n },\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { assetBaseUrlTransform } from "./asset-base-url-transform-plugin.js";
2
+ import { assetBaseUrlTransform, assetBaseUrlTransformPlugin, isCssRequest, } from "./asset-base-url-transform-plugin.js";
3
3
  describe("assetBaseUrlTransform", () => {
4
4
  it("should transform asset paths to use window.skybridge.serverUrl", () => {
5
5
  const cases = [
@@ -81,4 +81,54 @@ describe("assetBaseUrlTransform", () => {
81
81
  expect(result).toContain(`const logo = (window.skybridge?.serverUrl ?? "") + "/assets/logo.png";`);
82
82
  });
83
83
  });
84
+ describe("isCssRequest", () => {
85
+ it("returns true for CSS-family extensions", () => {
86
+ expect(isCssRequest("/src/styles.css")).toBe(true);
87
+ expect(isCssRequest("/src/styles.module.css")).toBe(true);
88
+ expect(isCssRequest("/src/styles.scss")).toBe(true);
89
+ expect(isCssRequest("/src/styles.sass")).toBe(true);
90
+ expect(isCssRequest("/src/styles.less")).toBe(true);
91
+ expect(isCssRequest("/src/styles.styl")).toBe(true);
92
+ });
93
+ it("returns true for CSS modules with Vite query strings", () => {
94
+ expect(isCssRequest("/src/styles.css?direct")).toBe(true);
95
+ expect(isCssRequest("/src/styles.css?inline")).toBe(true);
96
+ expect(isCssRequest("/src/styles.css?used")).toBe(true);
97
+ expect(isCssRequest("/src/Foo.vue?vue&type=style&lang.css")).toBe(true);
98
+ });
99
+ it("returns false for non-CSS modules", () => {
100
+ expect(isCssRequest("/src/index.tsx")).toBe(false);
101
+ expect(isCssRequest("/src/utils.ts")).toBe(false);
102
+ expect(isCssRequest("/src/Logo.svg")).toBe(false);
103
+ expect(isCssRequest("/src/notes.cssx")).toBe(false);
104
+ });
105
+ });
106
+ describe("assetBaseUrlTransformPlugin", () => {
107
+ function runTransform(id, code) {
108
+ const plugin = assetBaseUrlTransformPlugin();
109
+ const hook = plugin.transform;
110
+ if (!hook) {
111
+ throw new Error("plugin.transform is not defined");
112
+ }
113
+ const handler = typeof hook === "function" ? hook : hook.handler;
114
+ return handler.call(
115
+ // biome-ignore lint/suspicious/noExplicitAny: vitest harness for plugin hook
116
+ {}, code, id, { moduleType: "js" });
117
+ }
118
+ it("rewrites asset paths in JS modules", () => {
119
+ const result = runTransform("/src/widget.tsx", `const logo = "/assets/logo.png";`);
120
+ expect(result?.code).toContain(`(window.skybridge?.serverUrl ?? "") + "/assets/logo.png"`);
121
+ });
122
+ // Reproducer for #697: CSS imports are served as JS modules with the
123
+ // stylesheet embedded as a string. Rewriting url("/foo.woff2") inside that
124
+ // string would produce invalid CSS once the styles are injected.
125
+ it("does not rewrite asset paths when transforming a CSS module", () => {
126
+ const cssCode = `__vite__updateStyle("style-id", "@font-face { src: url(\\"/fonts/Brand.woff2\\") format(\\"woff2\\"); }");`;
127
+ expect(runTransform("/src/fonts.css", cssCode)).toBeNull();
128
+ expect(runTransform("/src/fonts.css?direct", cssCode)).toBeNull();
129
+ expect(runTransform("/src/fonts.css?inline", cssCode)).toBeNull();
130
+ expect(runTransform("/src/styles.scss", cssCode)).toBeNull();
131
+ expect(runTransform("/src/Foo.vue?vue&type=style&lang.css", cssCode)).toBeNull();
132
+ });
133
+ });
84
134
  //# sourceMappingURL=asset-base-url-transform-plugin.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset-base-url-transform-plugin.test.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-base-url-transform-plugin.test.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n assetBaseUrlTransform,\n assetBaseUrlTransformPlugin,\n isCssRequest,\n} from \"./asset-base-url-transform-plugin.js\";\n\ndescribe(\"assetBaseUrlTransform\", () => {\n it(\"should transform asset paths to use window.skybridge.serverUrl\", () => {\n const cases = [\n {\n desc: \"single-quoted\",\n code: `const image = '/assets/logo.png';`,\n expected: `const image = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n },\n {\n desc: \"double-quoted\",\n code: `const image = \"/assets/logo.png\";`,\n expected: `const image = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n },\n {\n desc: \"backtick-quoted\",\n code: \"const image = `/assets/logo.png`;\",\n expected: `const image = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n },\n ];\n\n for (const { code, expected } of cases) {\n const result = assetBaseUrlTransform(code);\n expect(result).toBe(expected);\n }\n });\n\n it(\"should transform multiple asset paths\", () => {\n const code = `\n const logo = '/assets/logo.png';\n const icon = '/assets/icon.svg';\n const font = '/assets/font.woff2';\n `;\n const result = assetBaseUrlTransform(code);\n\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\"`,\n );\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/icon.svg\"`,\n );\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/font.woff2\"`,\n );\n });\n\n it(\"should not transform already absolute URLs\", () => {\n const code = `\n const local = '/assets/logo.png';\n const http = 'http://example.com/image.png';\n const https = 'https://example.com/image.png';\n `;\n const result = assetBaseUrlTransform(code);\n\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\"`,\n );\n expect(result).toContain(\"http://example.com/image.png\");\n expect(result).toContain(\"https://example.com/image.png\");\n });\n\n it(\"should not transform code without asset paths\", () => {\n const code = `const text = \"Hello World\";`;\n const result = assetBaseUrlTransform(code);\n\n expect(result).toBe(code);\n });\n\n it(\"should not transform asset paths inside static `import ... from` clauses\", () => {\n // Reproducer for #713: a dep does `import * as sprite from './icons.svg'`,\n // Vite resolves the relative path to absolute, then this transform used\n // to rewrite the resolved string — producing invalid JS like\n // `import * as sprite from (expr) + \"...\"` that crashes vite:import-analysis.\n const cases = [\n `import * as sprite from \"/Users/me/proj/node_modules/pkg/icons.svg\";`,\n `import sprite from '/assets/icons.svg';`,\n `import sprite from \"/assets/icons.svg\";`,\n `export { default } from \"/assets/icons.svg\";`,\n `export * from '/assets/sprites.svg';`,\n ];\n\n for (const code of cases) {\n expect(assetBaseUrlTransform(code)).toBe(code);\n }\n });\n\n it(\"should still transform value-position asset paths in files that also have unrelated imports\", () => {\n const code = [\n `import { foo } from \"./foo.js\";`,\n `import * as sprite from \"/assets/sprite.svg\";`,\n `const logo = \"/assets/logo.png\";`,\n ].join(\"\\n\");\n const result = assetBaseUrlTransform(code);\n\n // Imports untouched\n expect(result).toContain(`from \"./foo.js\"`);\n expect(result).toContain(`from \"/assets/sprite.svg\"`);\n // Value-position rewritten\n expect(result).toContain(\n `const logo = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n );\n });\n});\n\ndescribe(\"isCssRequest\", () => {\n it(\"returns true for CSS-family extensions\", () => {\n expect(isCssRequest(\"/src/styles.css\")).toBe(true);\n expect(isCssRequest(\"/src/styles.module.css\")).toBe(true);\n expect(isCssRequest(\"/src/styles.scss\")).toBe(true);\n expect(isCssRequest(\"/src/styles.sass\")).toBe(true);\n expect(isCssRequest(\"/src/styles.less\")).toBe(true);\n expect(isCssRequest(\"/src/styles.styl\")).toBe(true);\n });\n\n it(\"returns true for CSS modules with Vite query strings\", () => {\n expect(isCssRequest(\"/src/styles.css?direct\")).toBe(true);\n expect(isCssRequest(\"/src/styles.css?inline\")).toBe(true);\n expect(isCssRequest(\"/src/styles.css?used\")).toBe(true);\n expect(isCssRequest(\"/src/Foo.vue?vue&type=style&lang.css\")).toBe(true);\n });\n\n it(\"returns false for non-CSS modules\", () => {\n expect(isCssRequest(\"/src/index.tsx\")).toBe(false);\n expect(isCssRequest(\"/src/utils.ts\")).toBe(false);\n expect(isCssRequest(\"/src/Logo.svg\")).toBe(false);\n expect(isCssRequest(\"/src/notes.cssx\")).toBe(false);\n });\n});\n\ndescribe(\"assetBaseUrlTransformPlugin\", () => {\n type TransformResult = { code: string; map: null } | null;\n\n function runTransform(id: string, code: string): TransformResult {\n const plugin = assetBaseUrlTransformPlugin();\n const hook = plugin.transform;\n if (!hook) {\n throw new Error(\"plugin.transform is not defined\");\n }\n const handler = typeof hook === \"function\" ? hook : hook.handler;\n return handler.call(\n // biome-ignore lint/suspicious/noExplicitAny: vitest harness for plugin hook\n {} as any,\n code,\n id,\n { moduleType: \"js\" },\n ) as TransformResult;\n }\n\n it(\"rewrites asset paths in JS modules\", () => {\n const result = runTransform(\n \"/src/widget.tsx\",\n `const logo = \"/assets/logo.png\";`,\n );\n expect(result?.code).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\"`,\n );\n });\n\n // Reproducer for #697: CSS imports are served as JS modules with the\n // stylesheet embedded as a string. Rewriting url(\"/foo.woff2\") inside that\n // string would produce invalid CSS once the styles are injected.\n it(\"does not rewrite asset paths when transforming a CSS module\", () => {\n const cssCode = `__vite__updateStyle(\"style-id\", \"@font-face { src: url(\\\\\"/fonts/Brand.woff2\\\\\") format(\\\\\"woff2\\\\\"); }\");`;\n\n expect(runTransform(\"/src/fonts.css\", cssCode)).toBeNull();\n expect(runTransform(\"/src/fonts.css?direct\", cssCode)).toBeNull();\n expect(runTransform(\"/src/fonts.css?inline\", cssCode)).toBeNull();\n expect(runTransform(\"/src/styles.scss\", cssCode)).toBeNull();\n expect(\n runTransform(\"/src/Foo.vue?vue&type=style&lang.css\", cssCode),\n ).toBeNull();\n });\n});\n"]}
@@ -0,0 +1,11 @@
1
+ import { type OAuthMetadata } from "@modelcontextprotocol/sdk/shared/auth.js";
2
+ /**
3
+ * Discovered AS metadata + `jwks_uri` — the SDK's `OAuthMetadata` omits it (its
4
+ * OAuth client never verifies tokens), but we need it to verify token signatures
5
+ * via JWKS, so we re-type the field for typed access.
6
+ */
7
+ export type DiscoveredMetadata = OAuthMetadata & {
8
+ jwks_uri?: string;
9
+ };
10
+ /** Fetches and validates an authorization server's discovery document. */
11
+ export declare function discoverAuthorizationServer(issuer: string): Promise<DiscoveredMetadata>;
@@ -0,0 +1,51 @@
1
+ import { OAuthMetadataSchema, } from "@modelcontextprotocol/sdk/shared/auth.js";
2
+ const WELL_KNOWN = [
3
+ "/.well-known/openid-configuration",
4
+ "/.well-known/oauth-authorization-server",
5
+ ];
6
+ const DISCOVERY_TIMEOUT_MS = 5000;
7
+ /** Fetches and validates an authorization server's discovery document. */
8
+ export async function discoverAuthorizationServer(issuer) {
9
+ const base = issuer.replace(/\/$/, "");
10
+ const errors = [];
11
+ // First valid doc lacking a registration_endpoint, kept as a fallback so a
12
+ // genuinely non-DCR IdP still resolves (and is rejected later by the caller).
13
+ let fallback;
14
+ for (const path of WELL_KNOWN) {
15
+ const url = `${base}${path}`;
16
+ // Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer
17
+ // mismatch) records a per-URL reason and falls through to the next path.
18
+ try {
19
+ const res = await fetch(url, {
20
+ signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),
21
+ });
22
+ if (!res.ok) {
23
+ throw new Error(`HTTP ${res.status}`);
24
+ }
25
+ const parsed = OAuthMetadataSchema.safeParse(await res.json());
26
+ if (!parsed.success) {
27
+ throw new Error(`invalid metadata (${parsed.error.message})`);
28
+ }
29
+ // RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).
30
+ if (parsed.data.issuer.replace(/\/$/, "") !== base) {
31
+ throw new Error(`issuer mismatch: ${parsed.data.issuer}`);
32
+ }
33
+ const metadata = parsed.data;
34
+ // Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a
35
+ // valid openid-configuration without `registration_endpoint` yet expose
36
+ // it at oauth-authorization-server. Keep looking past a doc that omits it.
37
+ if (metadata.registration_endpoint) {
38
+ return metadata;
39
+ }
40
+ fallback ??= metadata;
41
+ }
42
+ catch (err) {
43
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
44
+ }
45
+ }
46
+ if (fallback) {
47
+ return fallback;
48
+ }
49
+ throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join("; ")}`);
50
+ }
51
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,GACpB,MAAM,0CAA0C,CAAC;AASlD,MAAM,UAAU,GAAG;IACjB,mCAAmC;IACnC,yCAAyC;CAC1C,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,QAAwC,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,yEAAyE;QACzE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC3B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC;aAClD,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC;YACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YAC/D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YAChE,CAAC;YACD,yEAAyE;YACzE,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;gBACnD,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5D,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAA0B,CAAC;YACnD,0EAA0E;YAC1E,wEAAwE;YACxE,2EAA2E;YAC3E,IAAI,QAAQ,CAAC,qBAAqB,EAAE,CAAC;gBACnC,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,QAAQ,KAAK,QAAQ,CAAC;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CACT,GAAG,GAAG,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC","sourcesContent":["import {\n type OAuthMetadata,\n OAuthMetadataSchema,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\n\n/**\n * Discovered AS metadata + `jwks_uri` — the SDK's `OAuthMetadata` omits it (its\n * OAuth client never verifies tokens), but we need it to verify token signatures\n * via JWKS, so we re-type the field for typed access.\n */\nexport type DiscoveredMetadata = OAuthMetadata & { jwks_uri?: string };\n\nconst WELL_KNOWN = [\n \"/.well-known/openid-configuration\",\n \"/.well-known/oauth-authorization-server\",\n];\n\nconst DISCOVERY_TIMEOUT_MS = 5000;\n\n/** Fetches and validates an authorization server's discovery document. */\nexport async function discoverAuthorizationServer(\n issuer: string,\n): Promise<DiscoveredMetadata> {\n const base = issuer.replace(/\\/$/, \"\");\n const errors: string[] = [];\n // First valid doc lacking a registration_endpoint, kept as a fallback so a\n // genuinely non-DCR IdP still resolves (and is rejected later by the caller).\n let fallback: DiscoveredMetadata | undefined;\n\n for (const path of WELL_KNOWN) {\n const url = `${base}${path}`;\n // Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer\n // mismatch) records a per-URL reason and falls through to the next path.\n try {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n const parsed = OAuthMetadataSchema.safeParse(await res.json());\n if (!parsed.success) {\n throw new Error(`invalid metadata (${parsed.error.message})`);\n }\n // RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).\n if (parsed.data.issuer.replace(/\\/$/, \"\") !== base) {\n throw new Error(`issuer mismatch: ${parsed.data.issuer}`);\n }\n const metadata = parsed.data as DiscoveredMetadata;\n // Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a\n // valid openid-configuration without `registration_endpoint` yet expose\n // it at oauth-authorization-server. Keep looking past a doc that omits it.\n if (metadata.registration_endpoint) {\n return metadata;\n }\n fallback ??= metadata;\n } catch (err) {\n errors.push(\n `${url}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (fallback) {\n return fallback;\n }\n throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join(\"; \")}`);\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,93 @@
1
+ // @vitest-environment node
2
+ import http from "node:http";
3
+ import { afterEach, describe, expect, it } from "vitest";
4
+ import { discoverAuthorizationServer } from "./discovery.js";
5
+ let server;
6
+ afterEach(() => server?.close());
7
+ function doc(origin, extra = {}) {
8
+ return {
9
+ issuer: origin,
10
+ authorization_endpoint: `${origin}/authorize`,
11
+ token_endpoint: `${origin}/token`,
12
+ registration_endpoint: `${origin}/register`,
13
+ response_types_supported: ["code"],
14
+ scopes_supported: ["openid", "email"],
15
+ jwks_uri: `${origin}/jwks`,
16
+ ...extra,
17
+ };
18
+ }
19
+ // Serves JSON bodies built from the live origin at their well-known paths;
20
+ // returns the origin URL.
21
+ async function serve(build) {
22
+ let origin = "";
23
+ const srv = http.createServer((req, res) => {
24
+ const body = build(origin)[req.url ?? ""];
25
+ if (body === undefined) {
26
+ res.writeHead(404).end();
27
+ return;
28
+ }
29
+ res.setHeader("content-type", "application/json");
30
+ res.end(JSON.stringify(body));
31
+ });
32
+ await new Promise((resolve) => srv.listen(0, resolve));
33
+ server = srv;
34
+ origin = `http://localhost:${srv.address().port}`;
35
+ return origin;
36
+ }
37
+ describe("discoverAuthorizationServer", () => {
38
+ it("fetches and validates openid-configuration", async () => {
39
+ const base = await serve((o) => ({
40
+ "/.well-known/openid-configuration": doc(o),
41
+ }));
42
+ const meta = await discoverAuthorizationServer(base);
43
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
44
+ expect(meta.jwks_uri).toBe(`${base}/jwks`);
45
+ });
46
+ it("accepts a canonically slash-terminated issuer", async () => {
47
+ const base = await serve((o) => ({
48
+ "/.well-known/openid-configuration": doc(o, { issuer: `${o}/` }),
49
+ }));
50
+ const meta = await discoverAuthorizationServer(base);
51
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
52
+ });
53
+ it("falls back to oauth-authorization-server when oidc is 404", async () => {
54
+ const base = await serve((o) => ({
55
+ "/.well-known/oauth-authorization-server": doc(o),
56
+ }));
57
+ const meta = await discoverAuthorizationServer(base);
58
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
59
+ });
60
+ it("throws when no well-known doc is reachable", async () => {
61
+ const base = await serve(() => ({}));
62
+ await expect(discoverAuthorizationServer(base)).rejects.toThrow(/discovery failed/i);
63
+ });
64
+ it("falls through to oauth-authorization-server when oidc doc is schema-invalid", async () => {
65
+ const base = await serve((o) => ({
66
+ "/.well-known/openid-configuration": doc(o, {
67
+ response_types_supported: undefined,
68
+ }),
69
+ "/.well-known/oauth-authorization-server": doc(o),
70
+ }));
71
+ const meta = await discoverAuthorizationServer(base);
72
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
73
+ });
74
+ it("prefers the doc advertising DCR when oidc omits registration_endpoint", async () => {
75
+ // Clerk-shaped: valid openid-configuration without a registration_endpoint,
76
+ // DCR exposed only at oauth-authorization-server.
77
+ const base = await serve((o) => ({
78
+ "/.well-known/openid-configuration": doc(o, {
79
+ registration_endpoint: undefined,
80
+ }),
81
+ "/.well-known/oauth-authorization-server": doc(o),
82
+ }));
83
+ const meta = await discoverAuthorizationServer(base);
84
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
85
+ });
86
+ it("rejects a doc whose issuer does not match the fetch origin", async () => {
87
+ const base = await serve(() => ({
88
+ "/.well-known/openid-configuration": doc("https://evil.test"),
89
+ }));
90
+ await expect(discoverAuthorizationServer(base)).rejects.toThrow(/discovery failed/i);
91
+ });
92
+ });
93
+ //# sourceMappingURL=discovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\nimport http from \"node:http\";\nimport { afterEach, describe, expect, it } from \"vitest\";\nimport { discoverAuthorizationServer } from \"./discovery.js\";\n\nlet server: http.Server | undefined;\nafterEach(() => server?.close());\n\nfunction doc(origin: string, extra: Record<string, unknown> = {}) {\n return {\n issuer: origin,\n authorization_endpoint: `${origin}/authorize`,\n token_endpoint: `${origin}/token`,\n registration_endpoint: `${origin}/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\", \"email\"],\n jwks_uri: `${origin}/jwks`,\n ...extra,\n };\n}\n\n// Serves JSON bodies built from the live origin at their well-known paths;\n// returns the origin URL.\nasync function serve(build: (origin: string) => Record<string, unknown>) {\n let origin = \"\";\n const srv = http.createServer((req, res) => {\n const body = build(origin)[req.url ?? \"\"];\n if (body === undefined) {\n res.writeHead(404).end();\n return;\n }\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify(body));\n });\n await new Promise<void>((resolve) => srv.listen(0, resolve));\n server = srv;\n origin = `http://localhost:${(srv.address() as { port: number }).port}`;\n return origin;\n}\n\ndescribe(\"discoverAuthorizationServer\", () => {\n it(\"fetches and validates openid-configuration\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n expect(meta.jwks_uri).toBe(`${base}/jwks`);\n });\n\n it(\"accepts a canonically slash-terminated issuer\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, { issuer: `${o}/` }),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"falls back to oauth-authorization-server when oidc is 404\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"throws when no well-known doc is reachable\", async () => {\n const base = await serve(() => ({}));\n await expect(discoverAuthorizationServer(base)).rejects.toThrow(\n /discovery failed/i,\n );\n });\n\n it(\"falls through to oauth-authorization-server when oidc doc is schema-invalid\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, {\n response_types_supported: undefined,\n }),\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"prefers the doc advertising DCR when oidc omits registration_endpoint\", async () => {\n // Clerk-shaped: valid openid-configuration without a registration_endpoint,\n // DCR exposed only at oauth-authorization-server.\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, {\n registration_endpoint: undefined,\n }),\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"rejects a doc whose issuer does not match the fetch origin\", async () => {\n const base = await serve(() => ({\n \"/.well-known/openid-configuration\": doc(\"https://evil.test\"),\n }));\n await expect(discoverAuthorizationServer(base)).rejects.toThrow(\n /discovery failed/i,\n );\n });\n});\n"]}
@@ -0,0 +1,18 @@
1
+ import type { OAuthMetadata } from "@modelcontextprotocol/sdk/shared/auth.js";
2
+ import type { JwksVerifyConfig } from "./verify.js";
3
+ /** Resource-server OAuth config for `SkybridgeServerOptions.oauth`. */
4
+ export type OAuthConfig = {
5
+ /**
6
+ * Public URL of this server; sets `resourceServerUrl` and the
7
+ * `resource_metadata` URL. When omitted, it is inferred per request from
8
+ * `x-forwarded-host`/`origin`/`host` headers.
9
+ */
10
+ baseUrl?: string;
11
+ /** AS metadata served at `/.well-known/oauth-authorization-server`. */
12
+ oauthMetadata: OAuthMetadata;
13
+ verify: JwksVerifyConfig;
14
+ /** Scopes advertised in protected-resource metadata. */
15
+ scopesSupported?: string[];
16
+ /** Server-wide required-scope floor. */
17
+ requiredScopes?: string[];
18
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/auth/index.ts"],"names":[],"mappings":"","sourcesContent":["import type { OAuthMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport type { JwksVerifyConfig } from \"./verify.js\";\n\n/** Resource-server OAuth config for `SkybridgeServerOptions.oauth`. */\nexport type OAuthConfig = {\n /**\n * Public URL of this server; sets `resourceServerUrl` and the\n * `resource_metadata` URL. When omitted, it is inferred per request from\n * `x-forwarded-host`/`origin`/`host` headers.\n */\n baseUrl?: string;\n /** AS metadata served at `/.well-known/oauth-authorization-server`. */\n oauthMetadata: OAuthMetadata;\n verify: JwksVerifyConfig;\n /** Scopes advertised in protected-resource metadata. */\n scopesSupported?: string[];\n /** Server-wide required-scope floor. */\n requiredScopes?: string[];\n};\n"]}