enpilink 1.0.2

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 (477) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +289 -0
  3. package/bin/run.js +5 -0
  4. package/dist/cli/build-helpers.d.ts +8 -0
  5. package/dist/cli/build-helpers.js +105 -0
  6. package/dist/cli/build-helpers.js.map +1 -0
  7. package/dist/cli/build-helpers.test.d.ts +1 -0
  8. package/dist/cli/build-helpers.test.js +100 -0
  9. package/dist/cli/build-helpers.test.js.map +1 -0
  10. package/dist/cli/detect-port.d.ts +18 -0
  11. package/dist/cli/detect-port.js +50 -0
  12. package/dist/cli/detect-port.js.map +1 -0
  13. package/dist/cli/ensure-ssh-key.d.ts +17 -0
  14. package/dist/cli/ensure-ssh-key.js +45 -0
  15. package/dist/cli/ensure-ssh-key.js.map +1 -0
  16. package/dist/cli/ensure-ssh-key.test.d.ts +1 -0
  17. package/dist/cli/ensure-ssh-key.test.js +68 -0
  18. package/dist/cli/ensure-ssh-key.test.js.map +1 -0
  19. package/dist/cli/header.d.ts +4 -0
  20. package/dist/cli/header.js +6 -0
  21. package/dist/cli/header.js.map +1 -0
  22. package/dist/cli/resolve-views-dir.d.ts +1 -0
  23. package/dist/cli/resolve-views-dir.js +17 -0
  24. package/dist/cli/resolve-views-dir.js.map +1 -0
  25. package/dist/cli/run-command.d.ts +2 -0
  26. package/dist/cli/run-command.js +43 -0
  27. package/dist/cli/run-command.js.map +1 -0
  28. package/dist/cli/telemetry.d.ts +14 -0
  29. package/dist/cli/telemetry.js +24 -0
  30. package/dist/cli/telemetry.js.map +1 -0
  31. package/dist/cli/tunnel-control-server.d.ts +11 -0
  32. package/dist/cli/tunnel-control-server.js +35 -0
  33. package/dist/cli/tunnel-control-server.js.map +1 -0
  34. package/dist/cli/tunnel-control-server.test.d.ts +1 -0
  35. package/dist/cli/tunnel-control-server.test.js +39 -0
  36. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  37. package/dist/cli/tunnel-handler.d.ts +3 -0
  38. package/dist/cli/tunnel-handler.js +48 -0
  39. package/dist/cli/tunnel-handler.js.map +1 -0
  40. package/dist/cli/tunnel-handler.test.d.ts +1 -0
  41. package/dist/cli/tunnel-handler.test.js +107 -0
  42. package/dist/cli/tunnel-handler.test.js.map +1 -0
  43. package/dist/cli/tunnel-providers/index.d.ts +5 -0
  44. package/dist/cli/tunnel-providers/index.js +5 -0
  45. package/dist/cli/tunnel-providers/index.js.map +1 -0
  46. package/dist/cli/tunnel-providers/srv-us.d.ts +18 -0
  47. package/dist/cli/tunnel-providers/srv-us.js +66 -0
  48. package/dist/cli/tunnel-providers/srv-us.js.map +1 -0
  49. package/dist/cli/tunnel-providers/srv-us.test.d.ts +1 -0
  50. package/dist/cli/tunnel-providers/srv-us.test.js +74 -0
  51. package/dist/cli/tunnel-providers/srv-us.test.js.map +1 -0
  52. package/dist/cli/tunnel-providers/types.d.ts +49 -0
  53. package/dist/cli/tunnel-providers/types.js +2 -0
  54. package/dist/cli/tunnel-providers/types.js.map +1 -0
  55. package/dist/cli/tunnel.d.ts +75 -0
  56. package/dist/cli/tunnel.js +254 -0
  57. package/dist/cli/tunnel.js.map +1 -0
  58. package/dist/cli/tunnel.test.d.ts +1 -0
  59. package/dist/cli/tunnel.test.js +255 -0
  60. package/dist/cli/tunnel.test.js.map +1 -0
  61. package/dist/cli/types.d.ts +5 -0
  62. package/dist/cli/types.js +2 -0
  63. package/dist/cli/types.js.map +1 -0
  64. package/dist/cli/use-execute-steps.d.ts +11 -0
  65. package/dist/cli/use-execute-steps.js +36 -0
  66. package/dist/cli/use-execute-steps.js.map +1 -0
  67. package/dist/cli/use-messages.d.ts +3 -0
  68. package/dist/cli/use-messages.js +11 -0
  69. package/dist/cli/use-messages.js.map +1 -0
  70. package/dist/cli/use-nodemon.d.ts +2 -0
  71. package/dist/cli/use-nodemon.js +73 -0
  72. package/dist/cli/use-nodemon.js.map +1 -0
  73. package/dist/cli/use-open-browser.d.ts +1 -0
  74. package/dist/cli/use-open-browser.js +44 -0
  75. package/dist/cli/use-open-browser.js.map +1 -0
  76. package/dist/cli/use-open-tunnel-browser.d.ts +6 -0
  77. package/dist/cli/use-open-tunnel-browser.js +19 -0
  78. package/dist/cli/use-open-tunnel-browser.js.map +1 -0
  79. package/dist/cli/use-tunnel.d.ts +17 -0
  80. package/dist/cli/use-tunnel.js +131 -0
  81. package/dist/cli/use-tunnel.js.map +1 -0
  82. package/dist/cli/use-typescript-check.d.ts +9 -0
  83. package/dist/cli/use-typescript-check.js +94 -0
  84. package/dist/cli/use-typescript-check.js.map +1 -0
  85. package/dist/commands/build.d.ts +8 -0
  86. package/dist/commands/build.js +97 -0
  87. package/dist/commands/build.js.map +1 -0
  88. package/dist/commands/create.d.ts +9 -0
  89. package/dist/commands/create.js +30 -0
  90. package/dist/commands/create.js.map +1 -0
  91. package/dist/commands/dev.d.ts +13 -0
  92. package/dist/commands/dev.js +112 -0
  93. package/dist/commands/dev.js.map +1 -0
  94. package/dist/commands/start.d.ts +10 -0
  95. package/dist/commands/start.js +76 -0
  96. package/dist/commands/start.js.map +1 -0
  97. package/dist/commands/telemetry/disable.d.ts +5 -0
  98. package/dist/commands/telemetry/disable.js +12 -0
  99. package/dist/commands/telemetry/disable.js.map +1 -0
  100. package/dist/commands/telemetry/enable.d.ts +5 -0
  101. package/dist/commands/telemetry/enable.js +12 -0
  102. package/dist/commands/telemetry/enable.js.map +1 -0
  103. package/dist/commands/telemetry/status.d.ts +5 -0
  104. package/dist/commands/telemetry/status.js +12 -0
  105. package/dist/commands/telemetry/status.js.map +1 -0
  106. package/dist/server/admin.d.ts +79 -0
  107. package/dist/server/admin.js +239 -0
  108. package/dist/server/admin.js.map +1 -0
  109. package/dist/server/admin.test.d.ts +1 -0
  110. package/dist/server/admin.test.js +226 -0
  111. package/dist/server/admin.test.js.map +1 -0
  112. package/dist/server/analytics.d.ts +60 -0
  113. package/dist/server/analytics.js +168 -0
  114. package/dist/server/analytics.js.map +1 -0
  115. package/dist/server/analytics.test.d.ts +1 -0
  116. package/dist/server/analytics.test.js +179 -0
  117. package/dist/server/analytics.test.js.map +1 -0
  118. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  119. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  120. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  121. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  122. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  123. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  124. package/dist/server/auth.d.ts +20 -0
  125. package/dist/server/auth.js +28 -0
  126. package/dist/server/auth.js.map +1 -0
  127. package/dist/server/build-manifest.test.d.ts +1 -0
  128. package/dist/server/build-manifest.test.js +27 -0
  129. package/dist/server/build-manifest.test.js.map +1 -0
  130. package/dist/server/config/config.test.d.ts +1 -0
  131. package/dist/server/config/config.test.js +214 -0
  132. package/dist/server/config/config.test.js.map +1 -0
  133. package/dist/server/config/index.d.ts +3 -0
  134. package/dist/server/config/index.js +4 -0
  135. package/dist/server/config/index.js.map +1 -0
  136. package/dist/server/config/resolve.d.ts +73 -0
  137. package/dist/server/config/resolve.js +167 -0
  138. package/dist/server/config/resolve.js.map +1 -0
  139. package/dist/server/config/router.d.ts +23 -0
  140. package/dist/server/config/router.js +119 -0
  141. package/dist/server/config/router.js.map +1 -0
  142. package/dist/server/config/schema.d.ts +78 -0
  143. package/dist/server/config/schema.js +158 -0
  144. package/dist/server/config/schema.js.map +1 -0
  145. package/dist/server/content-helpers.d.ts +67 -0
  146. package/dist/server/content-helpers.js +79 -0
  147. package/dist/server/content-helpers.js.map +1 -0
  148. package/dist/server/content-helpers.test.d.ts +1 -0
  149. package/dist/server/content-helpers.test.js +70 -0
  150. package/dist/server/content-helpers.test.js.map +1 -0
  151. package/dist/server/express.d.ts +11 -0
  152. package/dist/server/express.js +129 -0
  153. package/dist/server/express.js.map +1 -0
  154. package/dist/server/express.test.d.ts +1 -0
  155. package/dist/server/express.test.js +464 -0
  156. package/dist/server/express.test.js.map +1 -0
  157. package/dist/server/file-ref.d.ts +28 -0
  158. package/dist/server/file-ref.js +27 -0
  159. package/dist/server/file-ref.js.map +1 -0
  160. package/dist/server/index.d.ts +17 -0
  161. package/dist/server/index.js +14 -0
  162. package/dist/server/index.js.map +1 -0
  163. package/dist/server/inferUtilityTypes.d.ts +64 -0
  164. package/dist/server/inferUtilityTypes.js +2 -0
  165. package/dist/server/inferUtilityTypes.js.map +1 -0
  166. package/dist/server/log-sink.d.ts +16 -0
  167. package/dist/server/log-sink.js +66 -0
  168. package/dist/server/log-sink.js.map +1 -0
  169. package/dist/server/metric.d.ts +12 -0
  170. package/dist/server/metric.js +13 -0
  171. package/dist/server/metric.js.map +1 -0
  172. package/dist/server/middleware.d.ts +137 -0
  173. package/dist/server/middleware.js +93 -0
  174. package/dist/server/middleware.js.map +1 -0
  175. package/dist/server/middleware.test-d.d.ts +1 -0
  176. package/dist/server/middleware.test-d.js +75 -0
  177. package/dist/server/middleware.test-d.js.map +1 -0
  178. package/dist/server/middleware.test.d.ts +1 -0
  179. package/dist/server/middleware.test.js +493 -0
  180. package/dist/server/middleware.test.js.map +1 -0
  181. package/dist/server/mock-seed.d.ts +62 -0
  182. package/dist/server/mock-seed.js +251 -0
  183. package/dist/server/mock-seed.js.map +1 -0
  184. package/dist/server/mock-seed.test.d.ts +1 -0
  185. package/dist/server/mock-seed.test.js +122 -0
  186. package/dist/server/mock-seed.test.js.map +1 -0
  187. package/dist/server/observability.d.ts +149 -0
  188. package/dist/server/observability.js +340 -0
  189. package/dist/server/observability.js.map +1 -0
  190. package/dist/server/observability.test.d.ts +1 -0
  191. package/dist/server/observability.test.js +251 -0
  192. package/dist/server/observability.test.js.map +1 -0
  193. package/dist/server/otel.d.ts +45 -0
  194. package/dist/server/otel.js +117 -0
  195. package/dist/server/otel.js.map +1 -0
  196. package/dist/server/otel.test.d.ts +1 -0
  197. package/dist/server/otel.test.js +122 -0
  198. package/dist/server/otel.test.js.map +1 -0
  199. package/dist/server/server.d.ts +422 -0
  200. package/dist/server/server.js +684 -0
  201. package/dist/server/server.js.map +1 -0
  202. package/dist/server/storage/index.d.ts +23 -0
  203. package/dist/server/storage/index.js +46 -0
  204. package/dist/server/storage/index.js.map +1 -0
  205. package/dist/server/storage/memory.d.ts +30 -0
  206. package/dist/server/storage/memory.js +98 -0
  207. package/dist/server/storage/memory.js.map +1 -0
  208. package/dist/server/storage/memory.test.d.ts +1 -0
  209. package/dist/server/storage/memory.test.js +81 -0
  210. package/dist/server/storage/memory.test.js.map +1 -0
  211. package/dist/server/storage/postgres.d.ts +65 -0
  212. package/dist/server/storage/postgres.js +242 -0
  213. package/dist/server/storage/postgres.js.map +1 -0
  214. package/dist/server/storage/postgres.test.d.ts +1 -0
  215. package/dist/server/storage/postgres.test.js +182 -0
  216. package/dist/server/storage/postgres.test.js.map +1 -0
  217. package/dist/server/storage/sqlite.d.ts +33 -0
  218. package/dist/server/storage/sqlite.js +250 -0
  219. package/dist/server/storage/sqlite.js.map +1 -0
  220. package/dist/server/storage/sqlite.test.d.ts +1 -0
  221. package/dist/server/storage/sqlite.test.js +133 -0
  222. package/dist/server/storage/sqlite.test.js.map +1 -0
  223. package/dist/server/storage/types.d.ts +119 -0
  224. package/dist/server/storage/types.js +11 -0
  225. package/dist/server/storage/types.js.map +1 -0
  226. package/dist/server/templateHelper.d.ts +16 -0
  227. package/dist/server/templateHelper.js +11 -0
  228. package/dist/server/templateHelper.js.map +1 -0
  229. package/dist/server/templates.generated.d.ts +4 -0
  230. package/dist/server/templates.generated.js +47 -0
  231. package/dist/server/templates.generated.js.map +1 -0
  232. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  233. package/dist/server/tunnel-proxy-router.js +110 -0
  234. package/dist/server/tunnel-proxy-router.js.map +1 -0
  235. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  236. package/dist/server/tunnel-proxy-router.test.js +229 -0
  237. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  238. package/dist/server/viewsDevServer.d.ts +14 -0
  239. package/dist/server/viewsDevServer.js +45 -0
  240. package/dist/server/viewsDevServer.js.map +1 -0
  241. package/dist/test/utils.d.ts +127 -0
  242. package/dist/test/utils.js +247 -0
  243. package/dist/test/utils.js.map +1 -0
  244. package/dist/test/view.test.d.ts +1 -0
  245. package/dist/test/view.test.js +568 -0
  246. package/dist/test/view.test.js.map +1 -0
  247. package/dist/version.d.ts +1 -0
  248. package/dist/version.js +3 -0
  249. package/dist/version.js.map +1 -0
  250. package/dist/web/bridges/apps-sdk/adaptor.d.ts +54 -0
  251. package/dist/web/bridges/apps-sdk/adaptor.js +164 -0
  252. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -0
  253. package/dist/web/bridges/apps-sdk/bridge.d.ts +11 -0
  254. package/dist/web/bridges/apps-sdk/bridge.js +47 -0
  255. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
  256. package/dist/web/bridges/apps-sdk/index.d.ts +5 -0
  257. package/dist/web/bridges/apps-sdk/index.js +5 -0
  258. package/dist/web/bridges/apps-sdk/index.js.map +1 -0
  259. package/dist/web/bridges/apps-sdk/types.d.ts +147 -0
  260. package/dist/web/bridges/apps-sdk/types.js +10 -0
  261. package/dist/web/bridges/apps-sdk/types.js.map +1 -0
  262. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
  263. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
  264. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
  265. package/dist/web/bridges/get-adaptor.d.ts +9 -0
  266. package/dist/web/bridges/get-adaptor.js +15 -0
  267. package/dist/web/bridges/get-adaptor.js.map +1 -0
  268. package/dist/web/bridges/index.d.ts +5 -0
  269. package/dist/web/bridges/index.js +6 -0
  270. package/dist/web/bridges/index.js.map +1 -0
  271. package/dist/web/bridges/mcp-app/adaptor.d.ts +81 -0
  272. package/dist/web/bridges/mcp-app/adaptor.js +346 -0
  273. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -0
  274. package/dist/web/bridges/mcp-app/bridge.d.ts +28 -0
  275. package/dist/web/bridges/mcp-app/bridge.js +124 -0
  276. package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
  277. package/dist/web/bridges/mcp-app/index.d.ts +4 -0
  278. package/dist/web/bridges/mcp-app/index.js +4 -0
  279. package/dist/web/bridges/mcp-app/index.js.map +1 -0
  280. package/dist/web/bridges/mcp-app/types.d.ts +8 -0
  281. package/dist/web/bridges/mcp-app/types.js +2 -0
  282. package/dist/web/bridges/mcp-app/types.js.map +1 -0
  283. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
  284. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
  285. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
  286. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
  287. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
  288. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
  289. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  290. package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
  291. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  292. package/dist/web/bridges/types.d.ts +243 -0
  293. package/dist/web/bridges/types.js +2 -0
  294. package/dist/web/bridges/types.js.map +1 -0
  295. package/dist/web/bridges/use-host-context.d.ts +7 -0
  296. package/dist/web/bridges/use-host-context.js +13 -0
  297. package/dist/web/bridges/use-host-context.js.map +1 -0
  298. package/dist/web/components/modal-provider.d.ts +4 -0
  299. package/dist/web/components/modal-provider.js +45 -0
  300. package/dist/web/components/modal-provider.js.map +1 -0
  301. package/dist/web/create-store.d.ts +29 -0
  302. package/dist/web/create-store.js +64 -0
  303. package/dist/web/create-store.js.map +1 -0
  304. package/dist/web/create-store.test.d.ts +1 -0
  305. package/dist/web/create-store.test.js +129 -0
  306. package/dist/web/create-store.test.js.map +1 -0
  307. package/dist/web/data-llm.d.ts +47 -0
  308. package/dist/web/data-llm.js +100 -0
  309. package/dist/web/data-llm.js.map +1 -0
  310. package/dist/web/data-llm.test.d.ts +1 -0
  311. package/dist/web/data-llm.test.js +142 -0
  312. package/dist/web/data-llm.test.js.map +1 -0
  313. package/dist/web/generate-helpers.d.ts +120 -0
  314. package/dist/web/generate-helpers.js +115 -0
  315. package/dist/web/generate-helpers.js.map +1 -0
  316. package/dist/web/generate-helpers.test-d.d.ts +1 -0
  317. package/dist/web/generate-helpers.test-d.js +211 -0
  318. package/dist/web/generate-helpers.test-d.js.map +1 -0
  319. package/dist/web/generate-helpers.test.d.ts +1 -0
  320. package/dist/web/generate-helpers.test.js +17 -0
  321. package/dist/web/generate-helpers.test.js.map +1 -0
  322. package/dist/web/helpers/state.d.ts +7 -0
  323. package/dist/web/helpers/state.js +45 -0
  324. package/dist/web/helpers/state.js.map +1 -0
  325. package/dist/web/helpers/state.test.d.ts +1 -0
  326. package/dist/web/helpers/state.test.js +53 -0
  327. package/dist/web/helpers/state.test.js.map +1 -0
  328. package/dist/web/hooks/index.d.ts +17 -0
  329. package/dist/web/hooks/index.js +18 -0
  330. package/dist/web/hooks/index.js.map +1 -0
  331. package/dist/web/hooks/test/utils.d.ts +20 -0
  332. package/dist/web/hooks/test/utils.js +75 -0
  333. package/dist/web/hooks/test/utils.js.map +1 -0
  334. package/dist/web/hooks/use-call-tool.d.ts +146 -0
  335. package/dist/web/hooks/use-call-tool.js +96 -0
  336. package/dist/web/hooks/use-call-tool.js.map +1 -0
  337. package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
  338. package/dist/web/hooks/use-call-tool.test-d.js +104 -0
  339. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
  340. package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
  341. package/dist/web/hooks/use-call-tool.test.js +211 -0
  342. package/dist/web/hooks/use-call-tool.test.js.map +1 -0
  343. package/dist/web/hooks/use-display-mode.d.ts +24 -0
  344. package/dist/web/hooks/use-display-mode.js +29 -0
  345. package/dist/web/hooks/use-display-mode.js.map +1 -0
  346. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  347. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  348. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  349. package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
  350. package/dist/web/hooks/use-display-mode.test.js +41 -0
  351. package/dist/web/hooks/use-display-mode.test.js.map +1 -0
  352. package/dist/web/hooks/use-download.d.ts +5 -0
  353. package/dist/web/hooks/use-download.js +8 -0
  354. package/dist/web/hooks/use-download.js.map +1 -0
  355. package/dist/web/hooks/use-download.test.d.ts +1 -0
  356. package/dist/web/hooks/use-download.test.js +95 -0
  357. package/dist/web/hooks/use-download.test.js.map +1 -0
  358. package/dist/web/hooks/use-files.d.ts +39 -0
  359. package/dist/web/hooks/use-files.js +42 -0
  360. package/dist/web/hooks/use-files.js.map +1 -0
  361. package/dist/web/hooks/use-files.test.d.ts +1 -0
  362. package/dist/web/hooks/use-files.test.js +54 -0
  363. package/dist/web/hooks/use-files.test.js.map +1 -0
  364. package/dist/web/hooks/use-intent.d.ts +30 -0
  365. package/dist/web/hooks/use-intent.js +34 -0
  366. package/dist/web/hooks/use-intent.js.map +1 -0
  367. package/dist/web/hooks/use-intent.test.d.ts +1 -0
  368. package/dist/web/hooks/use-intent.test.js +85 -0
  369. package/dist/web/hooks/use-intent.test.js.map +1 -0
  370. package/dist/web/hooks/use-layout.d.ts +24 -0
  371. package/dist/web/hooks/use-layout.js +25 -0
  372. package/dist/web/hooks/use-layout.js.map +1 -0
  373. package/dist/web/hooks/use-layout.test.d.ts +1 -0
  374. package/dist/web/hooks/use-layout.test.js +96 -0
  375. package/dist/web/hooks/use-layout.test.js.map +1 -0
  376. package/dist/web/hooks/use-notify.d.ts +29 -0
  377. package/dist/web/hooks/use-notify.js +33 -0
  378. package/dist/web/hooks/use-notify.js.map +1 -0
  379. package/dist/web/hooks/use-notify.test.d.ts +1 -0
  380. package/dist/web/hooks/use-notify.test.js +105 -0
  381. package/dist/web/hooks/use-notify.test.js.map +1 -0
  382. package/dist/web/hooks/use-open-external.d.ts +20 -0
  383. package/dist/web/hooks/use-open-external.js +24 -0
  384. package/dist/web/hooks/use-open-external.js.map +1 -0
  385. package/dist/web/hooks/use-open-external.test.d.ts +1 -0
  386. package/dist/web/hooks/use-open-external.test.js +65 -0
  387. package/dist/web/hooks/use-open-external.test.js.map +1 -0
  388. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  389. package/dist/web/hooks/use-register-view-tool.js +50 -0
  390. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  391. package/dist/web/hooks/use-request-close.d.ts +16 -0
  392. package/dist/web/hooks/use-request-close.js +21 -0
  393. package/dist/web/hooks/use-request-close.js.map +1 -0
  394. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  395. package/dist/web/hooks/use-request-close.test.js +52 -0
  396. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  397. package/dist/web/hooks/use-request-modal.d.ts +24 -0
  398. package/dist/web/hooks/use-request-modal.js +31 -0
  399. package/dist/web/hooks/use-request-modal.js.map +1 -0
  400. package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
  401. package/dist/web/hooks/use-request-modal.test.js +61 -0
  402. package/dist/web/hooks/use-request-modal.test.js.map +1 -0
  403. package/dist/web/hooks/use-request-size.d.ts +20 -0
  404. package/dist/web/hooks/use-request-size.js +24 -0
  405. package/dist/web/hooks/use-request-size.js.map +1 -0
  406. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  407. package/dist/web/hooks/use-request-size.test.js +65 -0
  408. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  409. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
  410. package/dist/web/hooks/use-send-follow-up-message.js +25 -0
  411. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
  412. package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
  413. package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
  414. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  415. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  416. package/dist/web/hooks/use-set-open-in-app-url.test.js +43 -0
  417. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  418. package/dist/web/hooks/use-tool-info.d.ts +87 -0
  419. package/dist/web/hooks/use-tool-info.js +49 -0
  420. package/dist/web/hooks/use-tool-info.js.map +1 -0
  421. package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
  422. package/dist/web/hooks/use-tool-info.test-d.js +91 -0
  423. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
  424. package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
  425. package/dist/web/hooks/use-tool-info.test.js +130 -0
  426. package/dist/web/hooks/use-tool-info.test.js.map +1 -0
  427. package/dist/web/hooks/use-user.d.ts +20 -0
  428. package/dist/web/hooks/use-user.js +37 -0
  429. package/dist/web/hooks/use-user.js.map +1 -0
  430. package/dist/web/hooks/use-user.test.d.ts +1 -0
  431. package/dist/web/hooks/use-user.test.js +122 -0
  432. package/dist/web/hooks/use-user.test.js.map +1 -0
  433. package/dist/web/hooks/use-view-state.d.ts +25 -0
  434. package/dist/web/hooks/use-view-state.js +32 -0
  435. package/dist/web/hooks/use-view-state.js.map +1 -0
  436. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  437. package/dist/web/hooks/use-view-state.test.js +177 -0
  438. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  439. package/dist/web/index.d.ts +7 -0
  440. package/dist/web/index.js +8 -0
  441. package/dist/web/index.js.map +1 -0
  442. package/dist/web/mount-view.d.ts +20 -0
  443. package/dist/web/mount-view.js +46 -0
  444. package/dist/web/mount-view.js.map +1 -0
  445. package/dist/web/plugin/data-llm.test.d.ts +1 -0
  446. package/dist/web/plugin/data-llm.test.js +81 -0
  447. package/dist/web/plugin/data-llm.test.js.map +1 -0
  448. package/dist/web/plugin/plugin.d.ts +33 -0
  449. package/dist/web/plugin/plugin.js +189 -0
  450. package/dist/web/plugin/plugin.js.map +1 -0
  451. package/dist/web/plugin/scan-views.d.ts +16 -0
  452. package/dist/web/plugin/scan-views.js +88 -0
  453. package/dist/web/plugin/scan-views.js.map +1 -0
  454. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  455. package/dist/web/plugin/scan-views.test.js +99 -0
  456. package/dist/web/plugin/scan-views.test.js.map +1 -0
  457. package/dist/web/plugin/transform-data-llm.d.ts +12 -0
  458. package/dist/web/plugin/transform-data-llm.js +96 -0
  459. package/dist/web/plugin/transform-data-llm.js.map +1 -0
  460. package/dist/web/plugin/transform-data-llm.test.d.ts +1 -0
  461. package/dist/web/plugin/transform-data-llm.test.js +81 -0
  462. package/dist/web/plugin/transform-data-llm.test.js.map +1 -0
  463. package/dist/web/plugin/validate-view.d.ts +1 -0
  464. package/dist/web/plugin/validate-view.js +9 -0
  465. package/dist/web/plugin/validate-view.js.map +1 -0
  466. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  467. package/dist/web/plugin/validate-view.test.js +24 -0
  468. package/dist/web/plugin/validate-view.test.js.map +1 -0
  469. package/dist/web/proxy.d.ts +1 -0
  470. package/dist/web/proxy.js +52 -0
  471. package/dist/web/proxy.js.map +1 -0
  472. package/dist/web/types.d.ts +20 -0
  473. package/dist/web/types.js +2 -0
  474. package/dist/web/types.js.map +1 -0
  475. package/package.json +125 -0
  476. package/scripts/postinstall.mjs +45 -0
  477. package/tsconfig.base.json +36 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Alpic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ <div align="center">
2
+
3
+ # enpilink
4
+
5
+ **The open, account-free full-stack framework for [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) — and the ChatGPT Apps SDK.**
6
+
7
+ Build type-safe MCP servers whose tools render interactive **React views** inside
8
+ Claude, ChatGPT, VS Code, Goose, and any other MCP-Apps-compatible host.
9
+
10
+ <p>
11
+ <a href="https://github.com/enpitech/enpilink/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-8E2DE2.svg"></a>
12
+ <a href="https://github.com/modelcontextprotocol/ext-apps"><img alt="MCP Apps" src="https://img.shields.io/badge/MCP_Apps-compatible-4A00E0.svg"></a>
13
+ <img alt="Account-free" src="https://img.shields.io/badge/account-not_required-22c55e.svg">
14
+ <img alt="Tunnel: srv.us" src="https://img.shields.io/badge/tunnel-srv.us_(no_signup)-0ea5e9.svg">
15
+ <img alt="Interaction types" src="https://img.shields.io/badge/mcp--ui-tool_·_prompt_·_notify_·_intent-8E2DE2.svg">
16
+ <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-3178c6.svg?logo=typescript&logoColor=white">
17
+ <img alt="Node" src="https://img.shields.io/badge/node-%3E%3D22-339933.svg?logo=node.js&logoColor=white">
18
+ <a href="https://github.com/enpitech/enpilink/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/enpitech/enpilink/actions/workflows/ci.yml/badge.svg"></a>
19
+ <a href="https://github.com/enpitech/enpilink/pulls"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-FF941F.svg"></a>
20
+ </p>
21
+
22
+ <sub>a fork of <a href="https://github.com/alpic-ai/skybridge"><code>alpic-ai/skybridge</code></a> · powered by</sub>
23
+
24
+ <a href="https://enpitech.dev"><img src="docs/images/enpitech-logo.svg" alt="Enpitech" width="150"></a>
25
+
26
+ </div>
27
+
28
+ ---
29
+
30
+ ## Account-free by design
31
+
32
+ Local dev, public tunneling, and deploy all work with **no account, no token, and
33
+ no vendor lock-in**:
34
+
35
+ - **Account-free tunneling** via [srv.us](https://srv.us) — open and SSH-based, no
36
+ signup. `enpilink dev --tunnel` gives you a public `/mcp` URL in seconds and
37
+ auto-generates an SSH key at `~/.enpilink/id_ed25519` the first time.
38
+ - **No telemetry** — zero analytics, no network calls, no embedded keys.
39
+ - **Deploy anywhere** — `enpilink build` produces a standard Node server
40
+ (`node dist/__entry.js`); self-host on any platform or container.
41
+ - **All five mcp-ui interaction types** — `tool`, `prompt`, `link`, `intent`, and `notify`.
42
+
43
+ ## MCP Apps compliance
44
+
45
+ enpilink is a compliant **MCP Apps** framework, built on the official
46
+ [`@modelcontextprotocol/ext-apps`](https://github.com/modelcontextprotocol/ext-apps)
47
+ extension (stable spec `2026-01-26`). It serves view resources for both runtimes
48
+ so the same view runs in either host:
49
+
50
+ - `ui://views/ext-apps/*` — MCP Apps (Claude, Goose, VS Code, …)
51
+ - `ui://views/apps-sdk/*` — ChatGPT Apps SDK
52
+
53
+ ## The mcp-ui interaction types
54
+
55
+ An **interaction type** is one of the structured messages a view sends *back* to
56
+ its host. The [mcp-ui](https://mcpui.dev) standard defines **five**, and enpilink
57
+ supports all five (views send them through hooks, never raw `postMessage`):
58
+
59
+ | Type | Hook | Behavior |
60
+ |---|---|---|
61
+ | `tool` | `useCallTool` | real on both runtimes |
62
+ | `prompt` | `useSendFollowUpMessage` | real on both runtimes |
63
+ | `link` | `useOpenExternal` | real on both runtimes |
64
+ | `intent` | `useIntent` | no spec equivalent on either runtime; best-effort extension, may no-op on hosts that don't route it |
65
+ | `notify` | `useNotify` | real MCP `notifications/message` on MCP Apps; best-effort extension on the ChatGPT Apps SDK |
66
+
67
+ > These five are the standard's **view→host actions**. They're a subset of the
68
+ > full hook API below (the rest of the hooks *read* host context or *control*
69
+ > your own view). New to all this? See [`PRESENTATION.md`](PRESENTATION.md) for a
70
+ > plain-language, diagram-led tour.
71
+
72
+ `notify` and `intent` are guarded and additive: they never throw and degrade to
73
+ a no-op (or a log line) on hosts without support. See
74
+ [`docs/guides/interaction-types.mdx`](docs/guides/interaction-types.mdx) for the
75
+ full per-runtime matrix.
76
+
77
+ ## All view hooks
78
+
79
+ Everything a view can do from inside the iframe — import from `enpilink/web`.
80
+ Hooks never touch raw `postMessage`; the bridge picks the right runtime call.
81
+
82
+ | Hook | What it does | Runtime |
83
+ |---|---|---|
84
+ | **Interaction** | | |
85
+ | `useCallTool` | Call a server tool from the view; returns `{ callTool, callToolAsync, data, status, error }` with pending/success/error state. | both |
86
+ | `useSendFollowUpMessage` | Send a text message to the model as a user follow-up turn (`prompt`). | both |
87
+ | `useNotify` | Surface a notification/status to the host: `notify({ message, level?, title?, data? })`. | both — real `notifications/message` on MCP Apps, best-effort on Apps SDK |
88
+ | `useIntent` | Express a high-level intent for the host to route: `sendIntent({ name, params? })`. | both — best-effort extension, may no-op |
89
+ | **Navigation / links** | | |
90
+ | `useOpenExternal` | Open a URL outside the iframe via the host (use instead of `window.open`). | both |
91
+ | `useSetOpenInAppUrl` | Override the URL the host's fullscreen "Open in app" affordance points to. | Apps SDK only (throws on MCP Apps) |
92
+ | `useRequestClose` | Ask the host to dismiss/close the view. | both |
93
+ | **Layout / display** | | |
94
+ | `useDisplayMode` | Read and request the display mode — `inline` / `pip` / `fullscreen`. | both |
95
+ | `useRequestModal` | Open the view in a host modal overlay; returns `{ isOpen, params, open }`. | both |
96
+ | `useRequestSize` | Ask the host to resize the iframe to fit your content. | both |
97
+ | `useLayout` | Read the visual environment — max height, safe-area insets, theme. | both |
98
+ | **Context / data** | | |
99
+ | `useToolInfo` | Read the typed `input` / `output` / metadata of the tool call that rendered this view. | both |
100
+ | `useViewState` | `[state, setState]` persisted on the host across remounts of the view. | both |
101
+ | `useUser` | Session-stable user/environment info (device type, hover/touch capability). | both |
102
+ | **Files** | | |
103
+ | `useFiles` | Host file operations — `upload`, `getDownloadUrl`, `selectFiles` (native picker). | Apps SDK only (throws on MCP Apps) |
104
+ | `useDownload` | Download an MCP `EmbeddedResource` / `ResourceLink`'s contents via the host. | both |
105
+ | **Advanced** | | |
106
+ | `useRegisterViewTool` | Let the view expose its own tool to the host/model (app-provided tool). | MCP Apps only (no-op on Apps SDK) |
107
+
108
+ > "both" = works on MCP Apps (Claude, Goose, VS Code…) and the ChatGPT Apps SDK.
109
+ > Apps-SDK-only hooks throw on MCP Apps; MCP-Apps-only hooks no-op on the Apps SDK.
110
+
111
+ ---
112
+
113
+ ## Observability & Admin
114
+
115
+ enpilink ships an **opt-in** observability + admin layer — **off by default**,
116
+ with zero overhead and zero network when disabled (still no telemetry to us).
117
+
118
+ - **Observability** — set `ENPILINK_ANALYTICS=1` to record per-tool-call volume,
119
+ latency (p50/p95/p99), and error rate, viewable in the Console **Dashboard**
120
+ with a **live log stream**. Try it with demo data:
121
+ `enpilink dev --mock` (deterministic, in-memory, no real traffic). See
122
+ [`docs/guides/observability.mdx`](docs/guides/observability.mdx).
123
+ - **Configuration** — a typed config layer with **env > file > DB** precedence, a
124
+ **Configuration** admin tab for runtime settings, **env-only masked secrets**,
125
+ and a change **audit log**. See
126
+ [`docs/guides/configuration.mdx`](docs/guides/configuration.mdx).
127
+ - **Admin (production)** — expose the Dashboard + Configuration in prod with
128
+ `enpilink start --admin` + `ENPILINK_ADMIN_TOKEN` (refuses to start without a
129
+ token). Two-tier auth keeps `/mcp` and the SPA shell public while gating the
130
+ data APIs behind a static bearer token; for SSO, front it with a reverse proxy
131
+ (Cloudflare Access / oauth2-proxy / Tailscale) or self-hosted OIDC. See
132
+ [`docs/guides/admin.mdx`](docs/guides/admin.mdx).
133
+ - **Storage** — pluggable adapters: `memory` (dev), `sqlite` (prod default,
134
+ `ENPILINK_DB_PATH`), `postgres` (`ENPILINK_DB_URL`/`DATABASE_URL`/`PG*`), plus
135
+ `registerStorageAdapter` for custom backends, and optional **OpenTelemetry**
136
+ metrics export (`ENPILINK_OTEL=1` + `OTEL_EXPORTER_OTLP_ENDPOINT`). See
137
+ [`docs/guides/storage.mdx`](docs/guides/storage.mdx).
138
+
139
+ ---
140
+
141
+ ## Documentation
142
+
143
+ **New here?** Read [`PRESENTATION.md`](PRESENTATION.md) first — a plain-language,
144
+ diagram-led tour of the whole platform (what it solves, the standards, the
145
+ technology, and how interaction types relate to hooks). No prior knowledge needed.
146
+
147
+ There's **no hosted docs site yet** — the full docs run locally with
148
+ [Mintlify](https://mintlify.com):
149
+
150
+ ```bash
151
+ pnpm install
152
+ pnpm docs:dev # serves the docs at http://localhost:3000
153
+ ```
154
+
155
+ What's inside [`docs/`](docs):
156
+
157
+ - **API reference** ([`docs/api-reference/`](docs/api-reference)) — a page per
158
+ hook and core API (`useCallTool`, `useNotify`, `useViewState`, `registerTool`,
159
+ …), each with the signature, **a runnable example**, and runtime support. This
160
+ is the "what can I actually do with this hook" reference.
161
+ - **Guides** ([`docs/guides/`](docs/guides)) — task-oriented: communicating with
162
+ the model, managing state, host-environment context, fetching data, the
163
+ interaction types, and the observability / configuration / admin / storage
164
+ layer.
165
+ - **Concepts & fundamentals** — MCP Apps vs the Apps SDK, write-once-run-everywhere,
166
+ type safety, and data flow.
167
+ - **Quickstart** — create a new app, add to an existing server, deploy, migrate.
168
+
169
+ > Tip: you can also read any page directly as Markdown in [`docs/`](docs) on
170
+ > GitHub — e.g. [`docs/api-reference/use-notify.mdx`](docs/api-reference/use-notify.mdx).
171
+
172
+ ---
173
+
174
+ ## Quickstart
175
+
176
+ ### Prerequisites
177
+
178
+ - **Node.js ≥ 22**
179
+ - `ssh` (ships with macOS/Linux) — only needed for `--tunnel`
180
+
181
+ ### Run the built-in kitchen-sink demo
182
+
183
+ The fastest way to see everything is the bundled **kitchen-sink** showcase
184
+ (a fictional store, *Northwind*): 9 tools, 9 views, all 4 interaction types,
185
+ every host hook, deterministic mock data.
186
+
187
+ ```bash
188
+ git clone https://github.com/enpitech/enpilink
189
+ cd enpilink && pnpm install && pnpm run build
190
+
191
+ cd examples/kitchen-sink
192
+ pnpm dev # Console + HMR at http://localhost:3000/
193
+ pnpm dev:tunnel # opens an account-free srv.us tunnel and prints a public /mcp URL
194
+ ```
195
+
196
+ Then connect it to Claude:
197
+
198
+ 1. Copy the printed `https://<hash>.srv.us/mcp` URL.
199
+ 2. In Claude → **Settings → Connectors → Add custom connector**, paste that URL.
200
+ 3. Paste the contents of
201
+ [`examples/kitchen-sink/specs/SYSTEM_PROMPT.md`](examples/kitchen-sink/specs/SYSTEM_PROMPT.md)
202
+ into your Claude **project instructions** (MCP can't set a host system prompt,
203
+ so this tells the assistant which tools to call).
204
+
205
+ ### Scaffold a new app
206
+
207
+ ```bash
208
+ npm create enpilink@latest my-app
209
+ ```
210
+
211
+ > **POC distribution caveat.** `enpilink` and `@enpilink/console` are not yet
212
+ > published to npm, so a freshly scaffolded app's `npm install` will fail on the
213
+ > `workspace:*` ranges in the templates. For real distribution, publish both
214
+ > packages to npm and run `node scripts/bump.js <version>` to rewrite the
215
+ > templates' `workspace:*` ranges to `^<version>`. Until then, scaffold inside
216
+ > this monorepo (the templates resolve via the workspace) or use local
217
+ > `pnpm pack` tarballs. See [Status](#status) below.
218
+
219
+ The account-free tunnel under the hood is just one SSH command:
220
+
221
+ ```bash
222
+ ssh srv.us -R 1:localhost:<port>
223
+ ```
224
+
225
+ enpilink wraps this with auto key-gen (`~/.enpilink/id_ed25519`), URL parsing,
226
+ and auto-reconnect.
227
+
228
+ ---
229
+
230
+ ## CLI
231
+
232
+ ```bash
233
+ enpilink dev [--tunnel] [-p <port>] [--open] [--mock] # dev server + Console + HMR (alias: enpi)
234
+ enpilink build # compile server + views → dist/
235
+ enpilink start [--admin] # run the production build (node dist/__entry.js)
236
+ enpilink create [dir] # scaffold a new app (passthrough to create-enpilink)
237
+ ```
238
+
239
+ ### Production gotcha
240
+
241
+ The production entry reads the **`__PORT`** environment variable (NOT `PORT`),
242
+ defaulting to `3000`:
243
+
244
+ ```bash
245
+ __PORT=8080 node dist/__entry.js
246
+ ```
247
+
248
+ `enpilink start` sets `__PORT` for you. `enpilink build` also rewrites server
249
+ `@/…` path aliases automatically, so you do **not** need `tsc-alias` in your own
250
+ build scripts.
251
+
252
+ ---
253
+
254
+ ## Repo layout
255
+
256
+ ```
257
+ enpilink/
258
+ ├── packages/
259
+ │ ├── core/ → npm "enpilink": server framework + React hooks + Vite plugin + CLI (oclif + Ink)
260
+ │ ├── console/ → "@enpilink/console": dashboard / config / playground / docs web UI
261
+ │ └── create-enpilink/ → "create-enpilink": scaffolder (templates: blank, demo)
262
+ ├── examples/
263
+ │ ├── kitchen-sink/ → the all-features showcase ("Northwind"); basis of the demo template
264
+ │ └── manifest-ui/ → minimal single-view smoke-test example
265
+ ├── docs/ → Mintlify documentation
266
+ ├── skills/ → agent skill for building enpilink apps
267
+ └── scripts/ → version bump / overrides helpers
268
+ ```
269
+
270
+ ## Status
271
+
272
+ This is a POC fork. Today:
273
+
274
+ - ✅ Local dev, Console, HMR, build, and self-host all work account-free.
275
+ - ✅ The account-free **srv.us** tunnel is live-verified end-to-end (the printed
276
+ `/mcp` URL round-trips over a real public tunnel and survives reconnects).
277
+ - ⏳ **Real npm distribution** requires publishing `enpilink` + `@enpilink/console`
278
+ to npm, then running `node scripts/bump.js <version>`. Until then,
279
+ `npm create enpilink` is workspace-linked (works inside this repo / via local
280
+ tarballs, not from a bare `npm install`).
281
+
282
+ ## Attribution & license
283
+
284
+ enpilink is released under the [MIT License](LICENSE). It is forked from
285
+ [`alpic-ai/skybridge`](https://github.com/alpic-ai/skybridge) (MIT); the original
286
+ copyright is retained in `LICENSE`, and the fork's changes are summarized in
287
+ [`NOTICE`](NOTICE).
288
+
289
+ Built and maintained by the [Enpitech](https://enpitech.dev) team.
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execute } from "@oclif/core";
4
+
5
+ await execute({ dir: import.meta.url });
@@ -0,0 +1,8 @@
1
+ export declare const ENTRY_WRAPPER_CONTENT = "import { __setBuildManifest } from \"enpilink/server\";\nimport manifest from \"./vite-manifest.js\";\n\n__setBuildManifest(manifest);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n";
2
+ export declare function emitEntryWrapper(distDir: string): void;
3
+ export declare function emitManifestModule(manifestPath: string, outPath: string): void;
4
+ export declare function rewriteServerAliases(root: string): Promise<void>;
5
+ export declare const VERCEL_FUNCTION_NAME = "mcp";
6
+ export declare const VERCEL_CONFIG: unknown;
7
+ export declare const VERCEL_VC_CONFIG: unknown;
8
+ export declare function emitVercelBuildOutput(root: string): Promise<void>;
@@ -0,0 +1,105 @@
1
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
2
+ import path from "node:path";
3
+ // Primes the manifest in enpilink's module scope, then dynamically imports
4
+ // `./server.js` so user code runs *after* the side channel is set. The
5
+ // dynamic import is load-bearing: a static `export { default } from ...` is
6
+ // hoisted with the rest of the static graph and would evaluate `server.js`
7
+ // before `__setBuildManifest` runs.
8
+ export const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest } from "enpilink/server";
9
+ import manifest from "./vite-manifest.js";
10
+
11
+ __setBuildManifest(manifest);
12
+
13
+ const userMod = await import("./server.js");
14
+ export default userMod.default;
15
+ `;
16
+ export function emitEntryWrapper(distDir) {
17
+ writeFileSync(path.join(distDir, "__entry.js"), ENTRY_WRAPPER_CONTENT);
18
+ }
19
+ export function emitManifestModule(manifestPath, outPath) {
20
+ const manifest = readFileSync(manifestPath, "utf-8");
21
+ writeFileSync(outPath, `export default ${manifest};\n`);
22
+ }
23
+ // Rewrites TypeScript path aliases (e.g. `@/data` → `./data`) in the emitted
24
+ // server JS under `dist/`. `tsc` itself does NOT rewrite path aliases in the
25
+ // output, so a server that imports via `@/…` would throw ERR_MODULE_NOT_FOUND
26
+ // at `node dist/__entry.js`. We run tsc-alias programmatically against the
27
+ // project's tsconfig so `enpilink build` produces a runnable server regardless
28
+ // of whether the user uses path aliases — no `tsc-alias` in their own scripts.
29
+ //
30
+ // Safe to run unconditionally: tsc-alias uses TypeScript's own config parser
31
+ // and is a no-op when the project declares no `paths`. We only require a
32
+ // tsconfig.json to exist (it always does for an enpilink app).
33
+ export async function rewriteServerAliases(root) {
34
+ const configFile = path.join(root, "tsconfig.json");
35
+ if (!existsSync(configFile)) {
36
+ return;
37
+ }
38
+ const { replaceTscAliasPaths } = await import("tsc-alias");
39
+ await replaceTscAliasPaths({
40
+ configFile,
41
+ // The server's compiled JS lives in `dist/` (tsc `outDir`); rewrite aliases
42
+ // to relative imports there.
43
+ outDir: path.join(root, "dist"),
44
+ });
45
+ }
46
+ export const VERCEL_FUNCTION_NAME = "mcp";
47
+ export const VERCEL_CONFIG = {
48
+ version: 3,
49
+ routes: [
50
+ {
51
+ src: "/assets/(.*)",
52
+ headers: { "Access-Control-Allow-Origin": "*" },
53
+ continue: true,
54
+ },
55
+ { handle: "filesystem" },
56
+ { src: "/(.*)", dest: `/${VERCEL_FUNCTION_NAME}` },
57
+ ],
58
+ };
59
+ export const VERCEL_VC_CONFIG = {
60
+ runtime: "nodejs22.x",
61
+ handler: "index.js",
62
+ launcherType: "Nodejs",
63
+ shouldAddHelpers: true,
64
+ };
65
+ // Emit a Build Output API tree under `.vercel/output/`. Bundling the server
66
+ // with esbuild produces a self-contained function bundle, so we don't ship
67
+ // `node_modules` and don't touch tracked paths like `api/` or `public/`.
68
+ //
69
+ // Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via
70
+ // `__setBuildManifest` before importing user code. Bundling `dist/server.js`
71
+ // directly would skip that priming and 500 on view resource reads when the
72
+ // function falls back to `readFileSync('dist/assets/.vite/manifest.json')`
73
+ // (Vercel functions don't ship `dist/`).
74
+ export async function emitVercelBuildOutput(root) {
75
+ const outputDir = path.join(root, ".vercel", "output");
76
+ const funcDir = path.join(outputDir, "functions", `${VERCEL_FUNCTION_NAME}.func`);
77
+ const staticAssetsDir = path.join(outputDir, "static", "assets");
78
+ rmSync(outputDir, { recursive: true, force: true });
79
+ mkdirSync(funcDir, { recursive: true });
80
+ const { build } = await import("esbuild");
81
+ await build({
82
+ entryPoints: [path.join(root, "dist", "__entry.js")],
83
+ bundle: true,
84
+ platform: "node",
85
+ target: "node22",
86
+ format: "esm",
87
+ outfile: path.join(funcDir, "index.js"),
88
+ // Lets esbuild DCE dev-only branches that pull in vite/devtools.
89
+ define: { "process.env.NODE_ENV": '"production"' },
90
+ // Dev-only deps reachable from re-exports; safe to leave unresolved since
91
+ // the code paths that touch them are eliminated by the NODE_ENV define.
92
+ external: ["vite", "@enpilink/console"],
93
+ banner: {
94
+ // ESM bundles miss CJS interop globals that some deps reach for.
95
+ js: "import{createRequire}from'node:module';const require=createRequire(import.meta.url);",
96
+ },
97
+ });
98
+ writeFileSync(path.join(funcDir, ".vc-config.json"), `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\n`);
99
+ writeFileSync(path.join(funcDir, "package.json"), `${JSON.stringify({ type: "module" }, null, 2)}\n`);
100
+ cpSync(path.join(root, "dist", "assets"), staticAssetsDir, {
101
+ recursive: true,
102
+ });
103
+ writeFileSync(path.join(outputDir, "config.json"), `${JSON.stringify(VERCEL_CONFIG, null, 2)}\n`);
104
+ }
105
+ //# sourceMappingURL=build-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-helpers.js","sourceRoot":"","sources":["../../src/cli/build-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport path from \"node:path\";\n\n// Primes the manifest in enpilink's module scope, then dynamically imports\n// `./server.js` so user code runs *after* the side channel is set. The\n// dynamic import is load-bearing: a static `export { default } from ...` is\n// hoisted with the rest of the static graph and would evaluate `server.js`\n// before `__setBuildManifest` runs.\nexport const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest } from \"enpilink/server\";\nimport manifest from \"./vite-manifest.js\";\n\n__setBuildManifest(manifest);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n`;\n\nexport function emitEntryWrapper(distDir: string): void {\n writeFileSync(path.join(distDir, \"__entry.js\"), ENTRY_WRAPPER_CONTENT);\n}\n\nexport function emitManifestModule(\n manifestPath: string,\n outPath: string,\n): void {\n const manifest = readFileSync(manifestPath, \"utf-8\");\n writeFileSync(outPath, `export default ${manifest};\\n`);\n}\n\n// Rewrites TypeScript path aliases (e.g. `@/data` → `./data`) in the emitted\n// server JS under `dist/`. `tsc` itself does NOT rewrite path aliases in the\n// output, so a server that imports via `@/…` would throw ERR_MODULE_NOT_FOUND\n// at `node dist/__entry.js`. We run tsc-alias programmatically against the\n// project's tsconfig so `enpilink build` produces a runnable server regardless\n// of whether the user uses path aliases — no `tsc-alias` in their own scripts.\n//\n// Safe to run unconditionally: tsc-alias uses TypeScript's own config parser\n// and is a no-op when the project declares no `paths`. We only require a\n// tsconfig.json to exist (it always does for an enpilink app).\nexport async function rewriteServerAliases(root: string): Promise<void> {\n const configFile = path.join(root, \"tsconfig.json\");\n if (!existsSync(configFile)) {\n return;\n }\n const { replaceTscAliasPaths } = await import(\"tsc-alias\");\n await replaceTscAliasPaths({\n configFile,\n // The server's compiled JS lives in `dist/` (tsc `outDir`); rewrite aliases\n // to relative imports there.\n outDir: path.join(root, \"dist\"),\n });\n}\n\nexport const VERCEL_FUNCTION_NAME = \"mcp\";\n\nexport const VERCEL_CONFIG: unknown = {\n version: 3,\n routes: [\n {\n src: \"/assets/(.*)\",\n headers: { \"Access-Control-Allow-Origin\": \"*\" },\n continue: true,\n },\n { handle: \"filesystem\" },\n { src: \"/(.*)\", dest: `/${VERCEL_FUNCTION_NAME}` },\n ],\n};\n\nexport const VERCEL_VC_CONFIG: unknown = {\n runtime: \"nodejs22.x\",\n handler: \"index.js\",\n launcherType: \"Nodejs\",\n shouldAddHelpers: true,\n};\n\n// Emit a Build Output API tree under `.vercel/output/`. Bundling the server\n// with esbuild produces a self-contained function bundle, so we don't ship\n// `node_modules` and don't touch tracked paths like `api/` or `public/`.\n//\n// Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via\n// `__setBuildManifest` before importing user code. Bundling `dist/server.js`\n// directly would skip that priming and 500 on view resource reads when the\n// function falls back to `readFileSync('dist/assets/.vite/manifest.json')`\n// (Vercel functions don't ship `dist/`).\nexport async function emitVercelBuildOutput(root: string): Promise<void> {\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(\n outputDir,\n \"functions\",\n `${VERCEL_FUNCTION_NAME}.func`,\n );\n const staticAssetsDir = path.join(outputDir, \"static\", \"assets\");\n\n rmSync(outputDir, { recursive: true, force: true });\n mkdirSync(funcDir, { recursive: true });\n\n const { build } = await import(\"esbuild\");\n await build({\n entryPoints: [path.join(root, \"dist\", \"__entry.js\")],\n bundle: true,\n platform: \"node\",\n target: \"node22\",\n format: \"esm\",\n outfile: path.join(funcDir, \"index.js\"),\n // Lets esbuild DCE dev-only branches that pull in vite/devtools.\n define: { \"process.env.NODE_ENV\": '\"production\"' },\n // Dev-only deps reachable from re-exports; safe to leave unresolved since\n // the code paths that touch them are eliminated by the NODE_ENV define.\n external: [\"vite\", \"@enpilink/console\"],\n banner: {\n // ESM bundles miss CJS interop globals that some deps reach for.\n js: \"import{createRequire}from'node:module';const require=createRequire(import.meta.url);\",\n },\n });\n\n writeFileSync(\n path.join(funcDir, \".vc-config.json\"),\n `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\\n`,\n );\n writeFileSync(\n path.join(funcDir, \"package.json\"),\n `${JSON.stringify({ type: \"module\" }, null, 2)}\\n`,\n );\n\n cpSync(path.join(root, \"dist\", \"assets\"), staticAssetsDir, {\n recursive: true,\n });\n\n writeFileSync(\n path.join(outputDir, \"config.json\"),\n `${JSON.stringify(VERCEL_CONFIG, null, 2)}\\n`,\n );\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,100 @@
1
+ // @vitest-environment node
2
+ // esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.
3
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync, } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import path from "node:path";
6
+ import { describe, expect, it } from "vitest";
7
+ import { ENTRY_WRAPPER_CONTENT, emitEntryWrapper, emitManifestModule, emitVercelBuildOutput, rewriteServerAliases, VERCEL_CONFIG, VERCEL_VC_CONFIG, } from "./build-helpers.js";
8
+ function mkTmp(prefix = "enpilink-build-helpers-") {
9
+ return mkdtempSync(path.join(tmpdir(), prefix));
10
+ }
11
+ describe("emitEntryWrapper", () => {
12
+ it("writes dist/__entry.js that primes the manifest before importing user code", () => {
13
+ const dir = mkTmp();
14
+ emitEntryWrapper(dir);
15
+ const out = readFileSync(path.join(dir, "__entry.js"), "utf-8");
16
+ expect(out).toBe(ENTRY_WRAPPER_CONTENT);
17
+ expect(out).toContain('import { __setBuildManifest } from "enpilink/server"');
18
+ expect(out).toContain('import manifest from "./vite-manifest.js"');
19
+ expect(out).toContain("__setBuildManifest(manifest)");
20
+ // Dynamic import is load-bearing: `server.js` must evaluate after the
21
+ // setter runs, so a static re-export wouldn't work.
22
+ expect(out).toContain('await import("./server.js")');
23
+ expect(out).toContain("export default userMod.default");
24
+ });
25
+ });
26
+ describe("emitManifestModule", () => {
27
+ it("inlines the JSON manifest as an ESM default export", () => {
28
+ const dir = mkTmp();
29
+ const inPath = path.join(dir, "manifest.json");
30
+ const outPath = path.join(dir, "vite-manifest.js");
31
+ const manifest = { "src/views/foo.tsx": { file: "assets/foo-abc.js" } };
32
+ writeFileSync(inPath, JSON.stringify(manifest));
33
+ emitManifestModule(inPath, outPath);
34
+ const out = readFileSync(outPath, "utf-8");
35
+ expect(out.startsWith("export default ")).toBe(true);
36
+ const literal = out
37
+ .slice("export default ".length)
38
+ .trim()
39
+ .replace(/;$/, "");
40
+ expect(JSON.parse(literal)).toEqual(manifest);
41
+ });
42
+ });
43
+ describe("rewriteServerAliases", () => {
44
+ it("rewrites `@/` path aliases to relative imports in dist server JS", async () => {
45
+ const root = mkTmp();
46
+ mkdirSync(path.join(root, "src", "data"), { recursive: true });
47
+ mkdirSync(path.join(root, "dist", "data"), { recursive: true });
48
+ writeFileSync(path.join(root, "tsconfig.json"), JSON.stringify({
49
+ compilerOptions: {
50
+ outDir: "./dist",
51
+ rootDir: "./src",
52
+ paths: { "@/*": ["./src/*"] },
53
+ },
54
+ include: ["src"],
55
+ }));
56
+ // tsc-alias resolves aliases against the *output* tree, so the target must
57
+ // exist in dist/ (it normally does — tsc emits it).
58
+ writeFileSync(path.join(root, "dist", "data", "index.js"), "export {};\n");
59
+ writeFileSync(path.join(root, "dist", "server.js"), 'import { TODAY } from "@/data/index.js";\nexport default TODAY;\n');
60
+ await rewriteServerAliases(root);
61
+ const out = readFileSync(path.join(root, "dist", "server.js"), "utf-8");
62
+ expect(out).not.toContain("@/data");
63
+ expect(out).toContain("./data/index.js");
64
+ });
65
+ it("is a no-op when the project declares no `paths`", async () => {
66
+ const root = mkTmp();
67
+ mkdirSync(path.join(root, "dist"), { recursive: true });
68
+ writeFileSync(path.join(root, "tsconfig.json"), JSON.stringify({ compilerOptions: { outDir: "./dist" } }));
69
+ const original = 'import { x } from "./local.js";\n';
70
+ writeFileSync(path.join(root, "dist", "server.js"), original);
71
+ await expect(rewriteServerAliases(root)).resolves.toBeUndefined();
72
+ expect(readFileSync(path.join(root, "dist", "server.js"), "utf-8")).toBe(original);
73
+ });
74
+ it("does nothing when there is no tsconfig.json", async () => {
75
+ const root = mkTmp();
76
+ await expect(rewriteServerAliases(root)).resolves.toBeUndefined();
77
+ });
78
+ });
79
+ describe("emitVercelBuildOutput", () => {
80
+ it("emits a Build Output API tree with bundled function and static assets", async () => {
81
+ const root = mkTmp();
82
+ mkdirSync(path.join(root, "dist", "assets"), { recursive: true });
83
+ writeFileSync(path.join(root, "dist", "server.js"), "export default function handler(_req, res) { res.end('ok'); }\n");
84
+ // Minimal `dist/__entry.js` (the real wrapper imports `enpilink/server`,
85
+ // which isn't resolvable in this test's tmp dir — the function-bundling
86
+ // contract we care about here is just "bundle whatever `__entry.js`
87
+ // imports into a single function file").
88
+ writeFileSync(path.join(root, "dist", "__entry.js"), "const userMod = await import('./server.js');\nexport default userMod.default;\n");
89
+ writeFileSync(path.join(root, "dist", "assets", "view-abc.js"), "/* bundled view */\n");
90
+ await emitVercelBuildOutput(root);
91
+ const outputDir = path.join(root, ".vercel", "output");
92
+ const funcDir = path.join(outputDir, "functions", "mcp.func");
93
+ expect(existsSync(path.join(funcDir, "index.js"))).toBe(true);
94
+ expect(JSON.parse(readFileSync(path.join(funcDir, ".vc-config.json"), "utf-8"))).toEqual(VERCEL_VC_CONFIG);
95
+ expect(JSON.parse(readFileSync(path.join(funcDir, "package.json"), "utf-8"))).toEqual({ type: "module" });
96
+ expect(JSON.parse(readFileSync(path.join(outputDir, "config.json"), "utf-8"))).toEqual(VERCEL_CONFIG);
97
+ expect(readFileSync(path.join(outputDir, "static", "assets", "view-abc.js"), "utf-8")).toContain("bundled view");
98
+ });
99
+ });
100
+ //# sourceMappingURL=build-helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-helpers.test.js","sourceRoot":"","sources":["../../src/cli/build-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\n// esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport {\n ENTRY_WRAPPER_CONTENT,\n emitEntryWrapper,\n emitManifestModule,\n emitVercelBuildOutput,\n rewriteServerAliases,\n VERCEL_CONFIG,\n VERCEL_VC_CONFIG,\n} from \"./build-helpers.js\";\n\nfunction mkTmp(prefix = \"enpilink-build-helpers-\") {\n return mkdtempSync(path.join(tmpdir(), prefix));\n}\n\ndescribe(\"emitEntryWrapper\", () => {\n it(\"writes dist/__entry.js that primes the manifest before importing user code\", () => {\n const dir = mkTmp();\n emitEntryWrapper(dir);\n const out = readFileSync(path.join(dir, \"__entry.js\"), \"utf-8\");\n expect(out).toBe(ENTRY_WRAPPER_CONTENT);\n expect(out).toContain(\n 'import { __setBuildManifest } from \"enpilink/server\"',\n );\n expect(out).toContain('import manifest from \"./vite-manifest.js\"');\n expect(out).toContain(\"__setBuildManifest(manifest)\");\n // Dynamic import is load-bearing: `server.js` must evaluate after the\n // setter runs, so a static re-export wouldn't work.\n expect(out).toContain('await import(\"./server.js\")');\n expect(out).toContain(\"export default userMod.default\");\n });\n});\n\ndescribe(\"emitManifestModule\", () => {\n it(\"inlines the JSON manifest as an ESM default export\", () => {\n const dir = mkTmp();\n const inPath = path.join(dir, \"manifest.json\");\n const outPath = path.join(dir, \"vite-manifest.js\");\n const manifest = { \"src/views/foo.tsx\": { file: \"assets/foo-abc.js\" } };\n writeFileSync(inPath, JSON.stringify(manifest));\n emitManifestModule(inPath, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n expect(out.startsWith(\"export default \")).toBe(true);\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n expect(JSON.parse(literal)).toEqual(manifest);\n });\n});\n\ndescribe(\"rewriteServerAliases\", () => {\n it(\"rewrites `@/` path aliases to relative imports in dist server JS\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"src\", \"data\"), { recursive: true });\n mkdirSync(path.join(root, \"dist\", \"data\"), { recursive: true });\n writeFileSync(\n path.join(root, \"tsconfig.json\"),\n JSON.stringify({\n compilerOptions: {\n outDir: \"./dist\",\n rootDir: \"./src\",\n paths: { \"@/*\": [\"./src/*\"] },\n },\n include: [\"src\"],\n }),\n );\n // tsc-alias resolves aliases against the *output* tree, so the target must\n // exist in dist/ (it normally does — tsc emits it).\n writeFileSync(path.join(root, \"dist\", \"data\", \"index.js\"), \"export {};\\n\");\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n 'import { TODAY } from \"@/data/index.js\";\\nexport default TODAY;\\n',\n );\n\n await rewriteServerAliases(root);\n\n const out = readFileSync(path.join(root, \"dist\", \"server.js\"), \"utf-8\");\n expect(out).not.toContain(\"@/data\");\n expect(out).toContain(\"./data/index.js\");\n });\n\n it(\"is a no-op when the project declares no `paths`\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n writeFileSync(\n path.join(root, \"tsconfig.json\"),\n JSON.stringify({ compilerOptions: { outDir: \"./dist\" } }),\n );\n const original = 'import { x } from \"./local.js\";\\n';\n writeFileSync(path.join(root, \"dist\", \"server.js\"), original);\n\n await expect(rewriteServerAliases(root)).resolves.toBeUndefined();\n expect(readFileSync(path.join(root, \"dist\", \"server.js\"), \"utf-8\")).toBe(\n original,\n );\n });\n\n it(\"does nothing when there is no tsconfig.json\", async () => {\n const root = mkTmp();\n await expect(rewriteServerAliases(root)).resolves.toBeUndefined();\n });\n});\n\ndescribe(\"emitVercelBuildOutput\", () => {\n it(\"emits a Build Output API tree with bundled function and static assets\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\", \"assets\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n // Minimal `dist/__entry.js` (the real wrapper imports `enpilink/server`,\n // which isn't resolvable in this test's tmp dir — the function-bundling\n // contract we care about here is just \"bundle whatever `__entry.js`\n // imports into a single function file\").\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"view-abc.js\"),\n \"/* bundled view */\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(outputDir, \"functions\", \"mcp.func\");\n\n expect(existsSync(path.join(funcDir, \"index.js\"))).toBe(true);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \".vc-config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_VC_CONFIG);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \"package.json\"), \"utf-8\")),\n ).toEqual({ type: \"module\" });\n expect(\n JSON.parse(readFileSync(path.join(outputDir, \"config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_CONFIG);\n expect(\n readFileSync(\n path.join(outputDir, \"static\", \"assets\", \"view-abc.js\"),\n \"utf-8\",\n ),\n ).toContain(\"bundled view\");\n });\n});\n"]}
@@ -0,0 +1,18 @@
1
+ export declare function resolvePort(flagPort?: number): Promise<{
2
+ port: number;
3
+ fallback: boolean;
4
+ envWarning?: undefined;
5
+ } | {
6
+ port: number;
7
+ fallback: boolean;
8
+ envWarning: string;
9
+ }>;
10
+ /**
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
+ *
14
+ * @param host - Bind address for the check. Pass `"localhost"` for
15
+ * services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for
16
+ * services that bind to all interfaces (e.g. the HTTP server).
17
+ */
18
+ export declare function detectAvailablePort(startPort: number, host?: string): Promise<number>;