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
@@ -0,0 +1,24 @@
1
+ import { type SafeArea, type Theme } from "../bridges/index.js";
2
+ export type LayoutState = {
3
+ theme: Theme;
4
+ maxHeight: number | undefined;
5
+ safeArea: SafeArea;
6
+ };
7
+ /**
8
+ * Hook for accessing layout and visual environment information.
9
+ * These values may change on resize or theme toggle.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const { theme, maxHeight, safeArea } = useLayout();
14
+ *
15
+ * // Apply theme-aware styling
16
+ * const backgroundColor = theme === "dark" ? "#1a1a1a" : "#ffffff";
17
+ *
18
+ * // Respect safe area insets
19
+ * const paddingTop = safeArea.insets.top;
20
+ * ```
21
+ *
22
+ * @see https://docs.enpitech.dev/api-reference/use-layout
23
+ */
24
+ export declare function useLayout(): LayoutState;
@@ -0,0 +1,25 @@
1
+ import { useHostContext } from "../bridges/index.js";
2
+ /**
3
+ * Hook for accessing layout and visual environment information.
4
+ * These values may change on resize or theme toggle.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * const { theme, maxHeight, safeArea } = useLayout();
9
+ *
10
+ * // Apply theme-aware styling
11
+ * const backgroundColor = theme === "dark" ? "#1a1a1a" : "#ffffff";
12
+ *
13
+ * // Respect safe area insets
14
+ * const paddingTop = safeArea.insets.top;
15
+ * ```
16
+ *
17
+ * @see https://docs.enpitech.dev/api-reference/use-layout
18
+ */
19
+ export function useLayout() {
20
+ const theme = useHostContext("theme");
21
+ const maxHeight = useHostContext("maxHeight");
22
+ const safeArea = useHostContext("safeArea");
23
+ return { theme, maxHeight, safeArea };
24
+ }
25
+ //# sourceMappingURL=use-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-layout.js","sourceRoot":"","sources":["../../../src/web/hooks/use-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAQhF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAE5C,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACxC,CAAC","sourcesContent":["import { type SafeArea, type Theme, useHostContext } from \"../bridges/index.js\";\n\nexport type LayoutState = {\n theme: Theme;\n maxHeight: number | undefined;\n safeArea: SafeArea;\n};\n\n/**\n * Hook for accessing layout and visual environment information.\n * These values may change on resize or theme toggle.\n *\n * @example\n * ```tsx\n * const { theme, maxHeight, safeArea } = useLayout();\n *\n * // Apply theme-aware styling\n * const backgroundColor = theme === \"dark\" ? \"#1a1a1a\" : \"#ffffff\";\n *\n * // Respect safe area insets\n * const paddingTop = safeArea.insets.top;\n * ```\n *\n * @see https://docs.enpitech.dev/api-reference/use-layout\n */\nexport function useLayout(): LayoutState {\n const theme = useHostContext(\"theme\");\n const maxHeight = useHostContext(\"maxHeight\");\n const safeArea = useHostContext(\"safeArea\");\n\n return { theme, maxHeight, safeArea };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,96 @@
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { McpAppAdaptor } from "../bridges/mcp-app/adaptor.js";
4
+ import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
5
+ import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
6
+ import { useLayout } from "./use-layout.js";
7
+ describe("useLayout", () => {
8
+ describe("apps-sdk host type", () => {
9
+ let OpenaiMock;
10
+ beforeEach(() => {
11
+ OpenaiMock = {
12
+ theme: "light",
13
+ maxHeight: 500,
14
+ safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
15
+ };
16
+ vi.stubGlobal("openai", OpenaiMock);
17
+ vi.stubGlobal("enpilink", { hostType: "apps-sdk" });
18
+ });
19
+ afterEach(() => {
20
+ vi.unstubAllGlobals();
21
+ vi.resetAllMocks();
22
+ });
23
+ it("should return theme, maxHeight, and safeArea from window.openai", () => {
24
+ const { result } = renderHook(() => useLayout());
25
+ expect(result.current.theme).toBe("light");
26
+ expect(result.current.maxHeight).toBe(500);
27
+ expect(result.current.safeArea).toEqual({
28
+ insets: { top: 0, bottom: 0, left: 0, right: 0 },
29
+ });
30
+ });
31
+ it("should return dark theme when set to dark", () => {
32
+ OpenaiMock.theme = "dark";
33
+ const { result } = renderHook(() => useLayout());
34
+ expect(result.current.theme).toBe("dark");
35
+ });
36
+ it("should return different maxHeight when set", () => {
37
+ OpenaiMock.maxHeight = 800;
38
+ const { result } = renderHook(() => useLayout());
39
+ expect(result.current.maxHeight).toBe(800);
40
+ });
41
+ it("should return safeArea with insets when set", () => {
42
+ OpenaiMock.safeArea = {
43
+ insets: { top: 44, bottom: 34, left: 0, right: 0 },
44
+ };
45
+ const { result } = renderHook(() => useLayout());
46
+ expect(result.current.safeArea.insets.top).toBe(44);
47
+ expect(result.current.safeArea.insets.bottom).toBe(34);
48
+ });
49
+ });
50
+ describe("mcp-app host type", () => {
51
+ beforeEach(() => {
52
+ vi.stubGlobal("enpilink", { hostType: "mcp-app" });
53
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
54
+ });
55
+ afterEach(async () => {
56
+ vi.unstubAllGlobals();
57
+ vi.resetAllMocks();
58
+ McpAppBridge.resetInstance();
59
+ McpAppAdaptor.resetInstance();
60
+ });
61
+ it("should return theme, maxHeight, and safeArea from mcp host context", async () => {
62
+ vi.stubGlobal("parent", {
63
+ postMessage: getMcpAppHostPostMessageMock({
64
+ theme: "dark",
65
+ containerDimensions: { maxHeight: 800, width: 400 },
66
+ safeAreaInsets: { top: 20, right: 0, bottom: 34, left: 0 },
67
+ }),
68
+ });
69
+ const { result } = renderHook(() => useLayout());
70
+ await waitFor(() => {
71
+ expect(result.current.theme).toBe("dark");
72
+ expect(result.current.maxHeight).toBe(800);
73
+ expect(result.current.safeArea).toEqual({
74
+ insets: { top: 20, right: 0, bottom: 34, left: 0 },
75
+ });
76
+ });
77
+ });
78
+ it("should maintain safeArea referential stability when data has not changed", async () => {
79
+ vi.stubGlobal("parent", {
80
+ postMessage: getMcpAppHostPostMessageMock({
81
+ theme: "light",
82
+ containerDimensions: { maxHeight: 500, width: 400 },
83
+ safeAreaInsets: { top: 44, right: 0, bottom: 34, left: 0 },
84
+ }),
85
+ });
86
+ const { result, rerender } = renderHook(() => useLayout());
87
+ await waitFor(() => {
88
+ expect(result.current.safeArea).toBeDefined();
89
+ });
90
+ const initialSafeArea = result.current.safeArea;
91
+ rerender();
92
+ expect(result.current.safeArea).toBe(initialSafeArea);
93
+ });
94
+ });
95
+ });
96
+ //# sourceMappingURL=use-layout.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-layout.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-layout.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { McpAppAdaptor } from \"../bridges/mcp-app/adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport type { SafeArea, Theme } from \"../bridges/types.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useLayout } from \"./use-layout.js\";\n\ndescribe(\"useLayout\", () => {\n describe(\"apps-sdk host type\", () => {\n let OpenaiMock: {\n theme: Theme;\n maxHeight: number;\n safeArea: SafeArea;\n };\n\n beforeEach(() => {\n OpenaiMock = {\n theme: \"light\",\n maxHeight: 500,\n safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },\n };\n vi.stubGlobal(\"openai\", OpenaiMock);\n vi.stubGlobal(\"enpilink\", { hostType: \"apps-sdk\" });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"should return theme, maxHeight, and safeArea from window.openai\", () => {\n const { result } = renderHook(() => useLayout());\n\n expect(result.current.theme).toBe(\"light\");\n expect(result.current.maxHeight).toBe(500);\n expect(result.current.safeArea).toEqual({\n insets: { top: 0, bottom: 0, left: 0, right: 0 },\n });\n });\n\n it(\"should return dark theme when set to dark\", () => {\n OpenaiMock.theme = \"dark\";\n const { result } = renderHook(() => useLayout());\n\n expect(result.current.theme).toBe(\"dark\");\n });\n\n it(\"should return different maxHeight when set\", () => {\n OpenaiMock.maxHeight = 800;\n const { result } = renderHook(() => useLayout());\n\n expect(result.current.maxHeight).toBe(800);\n });\n\n it(\"should return safeArea with insets when set\", () => {\n OpenaiMock.safeArea = {\n insets: { top: 44, bottom: 34, left: 0, right: 0 },\n };\n const { result } = renderHook(() => useLayout());\n\n expect(result.current.safeArea.insets.top).toBe(44);\n expect(result.current.safeArea.insets.bottom).toBe(34);\n });\n });\n\n describe(\"mcp-app host type\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"enpilink\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n });\n\n afterEach(async () => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n McpAppAdaptor.resetInstance();\n });\n\n it(\"should return theme, maxHeight, and safeArea from mcp host context\", async () => {\n vi.stubGlobal(\"parent\", {\n postMessage: getMcpAppHostPostMessageMock({\n theme: \"dark\",\n containerDimensions: { maxHeight: 800, width: 400 },\n safeAreaInsets: { top: 20, right: 0, bottom: 34, left: 0 },\n }),\n });\n const { result } = renderHook(() => useLayout());\n\n await waitFor(() => {\n expect(result.current.theme).toBe(\"dark\");\n expect(result.current.maxHeight).toBe(800);\n expect(result.current.safeArea).toEqual({\n insets: { top: 20, right: 0, bottom: 34, left: 0 },\n });\n });\n });\n\n it(\"should maintain safeArea referential stability when data has not changed\", async () => {\n vi.stubGlobal(\"parent\", {\n postMessage: getMcpAppHostPostMessageMock({\n theme: \"light\",\n containerDimensions: { maxHeight: 500, width: 400 },\n safeAreaInsets: { top: 44, right: 0, bottom: 34, left: 0 },\n }),\n });\n const { result, rerender } = renderHook(() => useLayout());\n\n await waitFor(() => {\n expect(result.current.safeArea).toBeDefined();\n });\n\n const initialSafeArea = result.current.safeArea;\n\n rerender();\n\n expect(result.current.safeArea).toBe(initialSafeArea);\n });\n });\n});\n"]}
@@ -0,0 +1,29 @@
1
+ import { type Notification } from "../bridges/index.js";
2
+ /** Function that surfaces a {@link Notification} to the host, returned by {@link useNotify}. */
3
+ export type NotifyFn = (notification: Notification) => Promise<void>;
4
+ /**
5
+ * Surface a status/notification to the host (toast, badge, or log entry) from
6
+ * a view — e.g. confirm an action succeeded.
7
+ *
8
+ * This is **best-effort**: how (and whether) the notification is shown is
9
+ * host-driven. Per-runtime behavior differs:
10
+ * - **MCP Apps** runtime: delivered via the real `notifications/message`
11
+ * protocol (`app.sendLog`). The `level: "success"` value has no MCP logging
12
+ * equivalent and is coerced to `"info"` (the original level is preserved in
13
+ * the structured payload).
14
+ * - **ChatGPT Apps SDK**: there is no native notification method, so this is an
15
+ * **enpilink extension** — it uses a `window.openai.notify` host method if
16
+ * present (the devtools emulator provides one), otherwise falls back to
17
+ * `window.parent.postMessage({ type: "notify", payload }, "*")`.
18
+ *
19
+ * A host that supports neither path simply no-ops; the call never throws.
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * const notify = useNotify();
24
+ * <button onClick={() => notify({ level: "success", message: "Saved!" })}>Save</button>
25
+ * ```
26
+ *
27
+ * @see https://docs.enpitech.dev/api-reference/use-notify
28
+ */
29
+ export declare function useNotify(): NotifyFn;
@@ -0,0 +1,33 @@
1
+ import { useCallback } from "react";
2
+ import { getAdaptor } from "../bridges/index.js";
3
+ /**
4
+ * Surface a status/notification to the host (toast, badge, or log entry) from
5
+ * a view — e.g. confirm an action succeeded.
6
+ *
7
+ * This is **best-effort**: how (and whether) the notification is shown is
8
+ * host-driven. Per-runtime behavior differs:
9
+ * - **MCP Apps** runtime: delivered via the real `notifications/message`
10
+ * protocol (`app.sendLog`). The `level: "success"` value has no MCP logging
11
+ * equivalent and is coerced to `"info"` (the original level is preserved in
12
+ * the structured payload).
13
+ * - **ChatGPT Apps SDK**: there is no native notification method, so this is an
14
+ * **enpilink extension** — it uses a `window.openai.notify` host method if
15
+ * present (the devtools emulator provides one), otherwise falls back to
16
+ * `window.parent.postMessage({ type: "notify", payload }, "*")`.
17
+ *
18
+ * A host that supports neither path simply no-ops; the call never throws.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const notify = useNotify();
23
+ * <button onClick={() => notify({ level: "success", message: "Saved!" })}>Save</button>
24
+ * ```
25
+ *
26
+ * @see https://docs.enpitech.dev/api-reference/use-notify
27
+ */
28
+ export function useNotify() {
29
+ const adaptor = getAdaptor();
30
+ const notify = useCallback((notification) => adaptor.notify(notification), [adaptor]);
31
+ return notify;
32
+ }
33
+ //# sourceMappingURL=use-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-notify.js","sourceRoot":"","sources":["../../../src/web/hooks/use-notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,UAAU,EAAqB,MAAM,qBAAqB,CAAC;AAKpE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,YAA0B,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,EAC5D,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { useCallback } from \"react\";\nimport { getAdaptor, type Notification } from \"../bridges/index.js\";\n\n/** Function that surfaces a {@link Notification} to the host, returned by {@link useNotify}. */\nexport type NotifyFn = (notification: Notification) => Promise<void>;\n\n/**\n * Surface a status/notification to the host (toast, badge, or log entry) from\n * a view — e.g. confirm an action succeeded.\n *\n * This is **best-effort**: how (and whether) the notification is shown is\n * host-driven. Per-runtime behavior differs:\n * - **MCP Apps** runtime: delivered via the real `notifications/message`\n * protocol (`app.sendLog`). The `level: \"success\"` value has no MCP logging\n * equivalent and is coerced to `\"info\"` (the original level is preserved in\n * the structured payload).\n * - **ChatGPT Apps SDK**: there is no native notification method, so this is an\n * **enpilink extension** — it uses a `window.openai.notify` host method if\n * present (the devtools emulator provides one), otherwise falls back to\n * `window.parent.postMessage({ type: \"notify\", payload }, \"*\")`.\n *\n * A host that supports neither path simply no-ops; the call never throws.\n *\n * @example\n * ```tsx\n * const notify = useNotify();\n * <button onClick={() => notify({ level: \"success\", message: \"Saved!\" })}>Save</button>\n * ```\n *\n * @see https://docs.enpitech.dev/api-reference/use-notify\n */\nexport function useNotify(): NotifyFn {\n const adaptor = getAdaptor();\n const notify = useCallback(\n (notification: Notification) => adaptor.notify(notification),\n [adaptor],\n );\n\n return notify;\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,105 @@
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { AppsSdkAdaptor } from "../bridges/apps-sdk/adaptor.js";
4
+ import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
5
+ import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
6
+ import { useNotify } from "./use-notify.js";
7
+ describe("useNotify", () => {
8
+ describe("apps-sdk host", () => {
9
+ let notifyMock;
10
+ beforeEach(() => {
11
+ AppsSdkAdaptor.resetInstance();
12
+ notifyMock = vi.fn(async () => { });
13
+ vi.stubGlobal("openai", { notify: notifyMock });
14
+ vi.stubGlobal("enpilink", { hostType: "apps-sdk" });
15
+ });
16
+ afterEach(() => {
17
+ AppsSdkAdaptor.resetInstance();
18
+ vi.unstubAllGlobals();
19
+ vi.resetAllMocks();
20
+ });
21
+ it("calls window.openai.notify with the notification payload", async () => {
22
+ const { result } = renderHook(() => useNotify());
23
+ await result.current({ level: "success", message: "Saved!" });
24
+ expect(notifyMock).toHaveBeenCalledTimes(1);
25
+ expect(notifyMock).toHaveBeenCalledWith({
26
+ level: "success",
27
+ message: "Saved!",
28
+ });
29
+ });
30
+ it("falls back to window.parent.postMessage when the host lacks notify", async () => {
31
+ AppsSdkAdaptor.resetInstance();
32
+ vi.unstubAllGlobals();
33
+ const postMessageMock = vi.fn();
34
+ vi.stubGlobal("openai", {});
35
+ vi.stubGlobal("enpilink", { hostType: "apps-sdk" });
36
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
37
+ const { result } = renderHook(() => useNotify());
38
+ await result.current({ message: "hello" });
39
+ expect(postMessageMock).toHaveBeenCalledWith({ type: "notify", payload: { message: "hello" } }, "*");
40
+ });
41
+ it("never throws when delivery fails", async () => {
42
+ AppsSdkAdaptor.resetInstance();
43
+ vi.unstubAllGlobals();
44
+ vi.stubGlobal("openai", {
45
+ notify: () => {
46
+ throw new Error("boom");
47
+ },
48
+ });
49
+ vi.stubGlobal("enpilink", { hostType: "apps-sdk" });
50
+ vi.spyOn(console, "warn").mockImplementation(() => { });
51
+ const { result } = renderHook(() => useNotify());
52
+ await expect(result.current({ message: "x" })).resolves.toBeUndefined();
53
+ });
54
+ });
55
+ describe("mcp-app host", () => {
56
+ let postMessageMock;
57
+ beforeEach(() => {
58
+ vi.stubGlobal("enpilink", { hostType: "mcp-app" });
59
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
60
+ postMessageMock = getMcpAppHostPostMessageMock();
61
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
62
+ });
63
+ afterEach(() => {
64
+ vi.unstubAllGlobals();
65
+ vi.resetAllMocks();
66
+ McpAppBridge.resetInstance();
67
+ });
68
+ it("sends a notifications/message log with the mapped level and payload", async () => {
69
+ const { result } = renderHook(() => useNotify());
70
+ await result.current({
71
+ level: "warning",
72
+ title: "Heads up",
73
+ message: "Low stock",
74
+ data: { sku: "ABC" },
75
+ });
76
+ await waitFor(() => {
77
+ expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({
78
+ jsonrpc: "2.0",
79
+ method: "notifications/message",
80
+ params: expect.objectContaining({
81
+ level: "warning",
82
+ logger: "enpilink",
83
+ data: {
84
+ title: "Heads up",
85
+ message: "Low stock",
86
+ level: "warning",
87
+ data: { sku: "ABC" },
88
+ },
89
+ }),
90
+ }), "*");
91
+ });
92
+ });
93
+ it("coerces level success to info on the MCP Apps runtime", async () => {
94
+ const { result } = renderHook(() => useNotify());
95
+ await result.current({ level: "success", message: "ok" });
96
+ await waitFor(() => {
97
+ expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({
98
+ method: "notifications/message",
99
+ params: expect.objectContaining({ level: "info" }),
100
+ }), "*");
101
+ });
102
+ });
103
+ });
104
+ });
105
+ //# sourceMappingURL=use-notify.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-notify.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-notify.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { AppsSdkAdaptor } from \"../bridges/apps-sdk/adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useNotify } from \"./use-notify.js\";\n\ndescribe(\"useNotify\", () => {\n describe(\"apps-sdk host\", () => {\n let notifyMock: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n AppsSdkAdaptor.resetInstance();\n notifyMock = vi.fn(async () => {});\n vi.stubGlobal(\"openai\", { notify: notifyMock });\n vi.stubGlobal(\"enpilink\", { hostType: \"apps-sdk\" });\n });\n\n afterEach(() => {\n AppsSdkAdaptor.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"calls window.openai.notify with the notification payload\", async () => {\n const { result } = renderHook(() => useNotify());\n\n await result.current({ level: \"success\", message: \"Saved!\" });\n\n expect(notifyMock).toHaveBeenCalledTimes(1);\n expect(notifyMock).toHaveBeenCalledWith({\n level: \"success\",\n message: \"Saved!\",\n });\n });\n\n it(\"falls back to window.parent.postMessage when the host lacks notify\", async () => {\n AppsSdkAdaptor.resetInstance();\n vi.unstubAllGlobals();\n const postMessageMock = vi.fn();\n vi.stubGlobal(\"openai\", {});\n vi.stubGlobal(\"enpilink\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n\n const { result } = renderHook(() => useNotify());\n await result.current({ message: \"hello\" });\n\n expect(postMessageMock).toHaveBeenCalledWith(\n { type: \"notify\", payload: { message: \"hello\" } },\n \"*\",\n );\n });\n\n it(\"never throws when delivery fails\", async () => {\n AppsSdkAdaptor.resetInstance();\n vi.unstubAllGlobals();\n vi.stubGlobal(\"openai\", {\n notify: () => {\n throw new Error(\"boom\");\n },\n });\n vi.stubGlobal(\"enpilink\", { hostType: \"apps-sdk\" });\n vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n const { result } = renderHook(() => useNotify());\n await expect(result.current({ message: \"x\" })).resolves.toBeUndefined();\n });\n });\n\n describe(\"mcp-app host\", () => {\n let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n vi.stubGlobal(\"enpilink\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n });\n\n it(\"sends a notifications/message log with the mapped level and payload\", async () => {\n const { result } = renderHook(() => useNotify());\n\n await result.current({\n level: \"warning\",\n title: \"Heads up\",\n message: \"Low stock\",\n data: { sku: \"ABC\" },\n });\n\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n jsonrpc: \"2.0\",\n method: \"notifications/message\",\n params: expect.objectContaining({\n level: \"warning\",\n logger: \"enpilink\",\n data: {\n title: \"Heads up\",\n message: \"Low stock\",\n level: \"warning\",\n data: { sku: \"ABC\" },\n },\n }),\n }),\n \"*\",\n );\n });\n });\n\n it(\"coerces level success to info on the MCP Apps runtime\", async () => {\n const { result } = renderHook(() => useNotify());\n\n await result.current({ level: \"success\", message: \"ok\" });\n\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n method: \"notifications/message\",\n params: expect.objectContaining({ level: \"info\" }),\n }),\n \"*\",\n );\n });\n });\n });\n});\n"]}
@@ -0,0 +1,20 @@
1
+ import type { OpenExternalOptions } from "../bridges/types.js";
2
+ /** Function that opens a URL outside the view's iframe, returned by {@link useOpenExternal}. */
3
+ export type OpenExternalFn = (href: string, options?: OpenExternalOptions) => void;
4
+ /**
5
+ * Open an external URL through the host (e.g. in the user's browser).
6
+ *
7
+ * Use this instead of `window.open` or anchor `target="_blank"`, which are
8
+ * unreliable inside a sandboxed iframe. Hosts may transform the URL (e.g.
9
+ * ChatGPT appends a `?redirectUrl=…` parameter for allowlisted targets — pass
10
+ * `redirectUrl: false` to suppress it).
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const openExternal = useOpenExternal();
15
+ * <button onClick={() => openExternal("https://example.com")}>Open docs</button>
16
+ * ```
17
+ *
18
+ * @see https://docs.enpitech.dev/api-reference/use-open-external
19
+ */
20
+ export declare function useOpenExternal(): OpenExternalFn;
@@ -0,0 +1,24 @@
1
+ import { useCallback } from "react";
2
+ import { getAdaptor } from "../bridges/index.js";
3
+ /**
4
+ * Open an external URL through the host (e.g. in the user's browser).
5
+ *
6
+ * Use this instead of `window.open` or anchor `target="_blank"`, which are
7
+ * unreliable inside a sandboxed iframe. Hosts may transform the URL (e.g.
8
+ * ChatGPT appends a `?redirectUrl=…` parameter for allowlisted targets — pass
9
+ * `redirectUrl: false` to suppress it).
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const openExternal = useOpenExternal();
14
+ * <button onClick={() => openExternal("https://example.com")}>Open docs</button>
15
+ * ```
16
+ *
17
+ * @see https://docs.enpitech.dev/api-reference/use-open-external
18
+ */
19
+ export function useOpenExternal() {
20
+ const adaptor = getAdaptor();
21
+ const openExternal = useCallback((href, options) => adaptor.openExternal(href, options), [adaptor]);
22
+ return openExternal;
23
+ }
24
+ //# sourceMappingURL=use-open-external.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-open-external.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AASjD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,IAAY,EAAE,OAA6B,EAAE,EAAE,CAC9C,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,EACrC,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import { useCallback } from \"react\";\nimport { getAdaptor } from \"../bridges/index.js\";\nimport type { OpenExternalOptions } from \"../bridges/types.js\";\n\n/** Function that opens a URL outside the view's iframe, returned by {@link useOpenExternal}. */\nexport type OpenExternalFn = (\n href: string,\n options?: OpenExternalOptions,\n) => void;\n\n/**\n * Open an external URL through the host (e.g. in the user's browser).\n *\n * Use this instead of `window.open` or anchor `target=\"_blank\"`, which are\n * unreliable inside a sandboxed iframe. Hosts may transform the URL (e.g.\n * ChatGPT appends a `?redirectUrl=…` parameter for allowlisted targets — pass\n * `redirectUrl: false` to suppress it).\n *\n * @example\n * ```tsx\n * const openExternal = useOpenExternal();\n * <button onClick={() => openExternal(\"https://example.com\")}>Open docs</button>\n * ```\n *\n * @see https://docs.enpitech.dev/api-reference/use-open-external\n */\nexport function useOpenExternal(): OpenExternalFn {\n const adaptor = getAdaptor();\n const openExternal = useCallback(\n (href: string, options?: OpenExternalOptions) =>\n adaptor.openExternal(href, options),\n [adaptor],\n );\n\n return openExternal;\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
4
+ import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
5
+ import { useOpenExternal } from "./use-open-external.js";
6
+ describe("useOpenExternal", () => {
7
+ describe("apps-sdk host", () => {
8
+ let openExternalMock;
9
+ beforeEach(() => {
10
+ openExternalMock = vi.fn();
11
+ vi.stubGlobal("openai", {
12
+ openExternal: openExternalMock,
13
+ });
14
+ vi.stubGlobal("enpilink", { hostType: "apps-sdk" });
15
+ });
16
+ afterEach(() => {
17
+ vi.unstubAllGlobals();
18
+ vi.resetAllMocks();
19
+ });
20
+ it("should return a function that calls window.openai.openExternal with the href", () => {
21
+ const { result } = renderHook(() => useOpenExternal());
22
+ const href = "https://example.com";
23
+ result.current(href);
24
+ expect(openExternalMock).toHaveBeenCalledTimes(1);
25
+ expect(openExternalMock).toHaveBeenCalledWith({ href });
26
+ });
27
+ it("should forward redirectUrl false option to window.openai.openExternal", () => {
28
+ const { result } = renderHook(() => useOpenExternal());
29
+ const href = "https://example.com";
30
+ result.current(href, { redirectUrl: false });
31
+ expect(openExternalMock).toHaveBeenCalledTimes(1);
32
+ expect(openExternalMock).toHaveBeenCalledWith({
33
+ href,
34
+ redirectUrl: false,
35
+ });
36
+ });
37
+ });
38
+ describe("mcp-app host", () => {
39
+ let postMessageMock;
40
+ beforeEach(() => {
41
+ vi.stubGlobal("enpilink", { hostType: "mcp-app" });
42
+ vi.stubGlobal("ResizeObserver", MockResizeObserver);
43
+ postMessageMock = getMcpAppHostPostMessageMock();
44
+ vi.stubGlobal("parent", { postMessage: postMessageMock });
45
+ });
46
+ afterEach(async () => {
47
+ vi.unstubAllGlobals();
48
+ vi.resetAllMocks();
49
+ McpAppBridge.resetInstance();
50
+ });
51
+ it("should return a function that sends ui/open-link request to the MCP host", async () => {
52
+ const { result } = renderHook(() => useOpenExternal());
53
+ const href = "https://example.com";
54
+ result.current(href, { redirectUrl: false });
55
+ await waitFor(() => {
56
+ expect(postMessageMock).toHaveBeenCalledWith(expect.objectContaining({
57
+ jsonrpc: "2.0",
58
+ method: "ui/open-link",
59
+ params: { url: href },
60
+ }), "*");
61
+ });
62
+ });
63
+ });
64
+ });
65
+ //# sourceMappingURL=use-open-external.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-open-external.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useOpenExternal } from \"./use-open-external.js\";\n\ndescribe(\"useOpenExternal\", () => {\n describe(\"apps-sdk host\", () => {\n let openExternalMock: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n openExternalMock = vi.fn();\n vi.stubGlobal(\"openai\", {\n openExternal: openExternalMock,\n });\n vi.stubGlobal(\"enpilink\", { hostType: \"apps-sdk\" });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"should return a function that calls window.openai.openExternal with the href\", () => {\n const { result } = renderHook(() => useOpenExternal());\n\n const href = \"https://example.com\";\n result.current(href);\n\n expect(openExternalMock).toHaveBeenCalledTimes(1);\n expect(openExternalMock).toHaveBeenCalledWith({ href });\n });\n\n it(\"should forward redirectUrl false option to window.openai.openExternal\", () => {\n const { result } = renderHook(() => useOpenExternal());\n\n const href = \"https://example.com\";\n result.current(href, { redirectUrl: false });\n\n expect(openExternalMock).toHaveBeenCalledTimes(1);\n expect(openExternalMock).toHaveBeenCalledWith({\n href,\n redirectUrl: false,\n });\n });\n });\n\n describe(\"mcp-app host\", () => {\n let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n vi.stubGlobal(\"enpilink\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(async () => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n McpAppBridge.resetInstance();\n });\n\n it(\"should return a function that sends ui/open-link request to the MCP host\", async () => {\n const { result } = renderHook(() => useOpenExternal());\n\n const href = \"https://example.com\";\n result.current(href, { redirectUrl: false });\n\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n jsonrpc: \"2.0\",\n method: \"ui/open-link\",\n params: { url: href },\n }),\n \"*\",\n );\n });\n });\n });\n});\n"]}
@@ -0,0 +1,38 @@
1
+ import type { ZodRawShapeCompat } from "@modelcontextprotocol/sdk/server/zod-compat.js";
2
+ import type { ViewToolConfig, ViewToolHandler } from "../bridges/types.js";
3
+ /**
4
+ * Register a tool the view exposes to the host and model — the MCP Apps
5
+ * "app-provided tools" feature. A view tool runs *inside the view*: the host
6
+ * discovers it via `tools/list` and invokes it via `tools/call`, and the
7
+ * handler executes against the view's live state. It is the inverse of
8
+ * {@link useCallTool} (which calls a server tool). Registered on mount, removed
9
+ * on unmount; re-registered when `config.name` changes.
10
+ *
11
+ * MCP Apps only — on the Apps SDK (`window.openai`) runtime it is a no-op.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * import * as z from "zod";
16
+ * import { useRegisterViewTool } from "enpilink/web";
17
+ *
18
+ * useRegisterViewTool(
19
+ * {
20
+ * name: "chess_make_move",
21
+ * description: "Play a move in algebraic notation, e.g. 'e4' or 'Nf3'.",
22
+ * inputSchema: { san: z.string() },
23
+ * annotations: { readOnlyHint: false },
24
+ * },
25
+ * ({ san }) => {
26
+ * const move = game.move(san);
27
+ * return {
28
+ * content: [{ type: "text", text: move ? `Played ${move.san}` : "Illegal move" }],
29
+ * structuredContent: { fen: game.fen() },
30
+ * isError: !move,
31
+ * };
32
+ * },
33
+ * );
34
+ * ```
35
+ *
36
+ * @see https://docs.enpitech.dev/api-reference/use-register-view-tool
37
+ */
38
+ export declare const useRegisterViewTool: <TInput extends ZodRawShapeCompat = ZodRawShapeCompat>(config: ViewToolConfig<TInput>, handler: ViewToolHandler<TInput>) => void;
@@ -0,0 +1,50 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { getAdaptor } from "../bridges/index.js";
3
+ /**
4
+ * Register a tool the view exposes to the host and model — the MCP Apps
5
+ * "app-provided tools" feature. A view tool runs *inside the view*: the host
6
+ * discovers it via `tools/list` and invokes it via `tools/call`, and the
7
+ * handler executes against the view's live state. It is the inverse of
8
+ * {@link useCallTool} (which calls a server tool). Registered on mount, removed
9
+ * on unmount; re-registered when `config.name` changes.
10
+ *
11
+ * MCP Apps only — on the Apps SDK (`window.openai`) runtime it is a no-op.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * import * as z from "zod";
16
+ * import { useRegisterViewTool } from "enpilink/web";
17
+ *
18
+ * useRegisterViewTool(
19
+ * {
20
+ * name: "chess_make_move",
21
+ * description: "Play a move in algebraic notation, e.g. 'e4' or 'Nf3'.",
22
+ * inputSchema: { san: z.string() },
23
+ * annotations: { readOnlyHint: false },
24
+ * },
25
+ * ({ san }) => {
26
+ * const move = game.move(san);
27
+ * return {
28
+ * content: [{ type: "text", text: move ? `Played ${move.san}` : "Illegal move" }],
29
+ * structuredContent: { fen: game.fen() },
30
+ * isError: !move,
31
+ * };
32
+ * },
33
+ * );
34
+ * ```
35
+ *
36
+ * @see https://docs.enpitech.dev/api-reference/use-register-view-tool
37
+ */
38
+ export const useRegisterViewTool = (config, handler) => {
39
+ const { name } = config;
40
+ const configRef = useRef(config);
41
+ configRef.current = config;
42
+ const handlerRef = useRef(handler);
43
+ handlerRef.current = handler;
44
+ useEffect(() => {
45
+ const adaptor = getAdaptor();
46
+ const wrappedHandler = (args) => handlerRef.current(args);
47
+ return adaptor.registerViewTool({ ...configRef.current, name }, wrappedHandler);
48
+ }, [name]);
49
+ };
50
+ //# sourceMappingURL=use-register-view-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-register-view-tool.js","sourceRoot":"","sources":["../../../src/web/hooks/use-register-view-tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAGjC,MAA8B,EAC9B,OAAgC,EAChC,EAAE;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;IACxB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAE7B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,MAAM,cAAc,GAAuB,CAAC,IAAI,EAAE,EAAE,CAClD,UAAU,CAAC,OAAO,CAAC,IAA8C,CAAC,CAAC;QAErE,OAAO,OAAO,CAAC,gBAAgB,CAC7B,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAC9B,cAAc,CACf,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACb,CAAC,CAAC","sourcesContent":["import type { ZodRawShapeCompat } from \"@modelcontextprotocol/sdk/server/zod-compat.js\";\nimport { useEffect, useRef } from \"react\";\nimport { getAdaptor } from \"../bridges/index.js\";\nimport type {\n AnyViewToolHandler,\n ViewToolConfig,\n ViewToolHandler,\n} from \"../bridges/types.js\";\n\n/**\n * Register a tool the view exposes to the host and model — the MCP Apps\n * \"app-provided tools\" feature. A view tool runs *inside the view*: the host\n * discovers it via `tools/list` and invokes it via `tools/call`, and the\n * handler executes against the view's live state. It is the inverse of\n * {@link useCallTool} (which calls a server tool). Registered on mount, removed\n * on unmount; re-registered when `config.name` changes.\n *\n * MCP Apps only — on the Apps SDK (`window.openai`) runtime it is a no-op.\n *\n * @example\n * ```tsx\n * import * as z from \"zod\";\n * import { useRegisterViewTool } from \"enpilink/web\";\n *\n * useRegisterViewTool(\n * {\n * name: \"chess_make_move\",\n * description: \"Play a move in algebraic notation, e.g. 'e4' or 'Nf3'.\",\n * inputSchema: { san: z.string() },\n * annotations: { readOnlyHint: false },\n * },\n * ({ san }) => {\n * const move = game.move(san);\n * return {\n * content: [{ type: \"text\", text: move ? `Played ${move.san}` : \"Illegal move\" }],\n * structuredContent: { fen: game.fen() },\n * isError: !move,\n * };\n * },\n * );\n * ```\n *\n * @see https://docs.enpitech.dev/api-reference/use-register-view-tool\n */\nexport const useRegisterViewTool = <\n TInput extends ZodRawShapeCompat = ZodRawShapeCompat,\n>(\n config: ViewToolConfig<TInput>,\n handler: ViewToolHandler<TInput>,\n) => {\n const { name } = config;\n const configRef = useRef(config);\n configRef.current = config;\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n const adaptor = getAdaptor();\n const wrappedHandler: AnyViewToolHandler = (args) =>\n handlerRef.current(args as Parameters<ViewToolHandler<TInput>>[0]);\n\n return adaptor.registerViewTool(\n { ...configRef.current, name },\n wrappedHandler,\n );\n }, [name]);\n};\n"]}
@@ -0,0 +1,16 @@
1
+ /** Function that asks the host to close the current view, returned by {@link useRequestClose}. */
2
+ export type RequestCloseFn = () => Promise<void>;
3
+ /**
4
+ * Ask the host to close (dismiss) the current view. The host decides whether
5
+ * to honor the request. Useful from modal views or after a terminal action
6
+ * like "Done".
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const close = useRequestClose();
11
+ * <button onClick={() => close()}>Done</button>
12
+ * ```
13
+ *
14
+ * @see https://docs.enpitech.dev/api-reference/use-request-close
15
+ */
16
+ export declare function useRequestClose(): RequestCloseFn;