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.
- package/LICENSE +21 -0
- package/README.md +289 -0
- package/bin/run.js +5 -0
- package/dist/cli/build-helpers.d.ts +8 -0
- package/dist/cli/build-helpers.js +105 -0
- package/dist/cli/build-helpers.js.map +1 -0
- package/dist/cli/build-helpers.test.d.ts +1 -0
- package/dist/cli/build-helpers.test.js +100 -0
- package/dist/cli/build-helpers.test.js.map +1 -0
- package/dist/cli/detect-port.d.ts +18 -0
- package/dist/cli/detect-port.js +50 -0
- package/dist/cli/detect-port.js.map +1 -0
- package/dist/cli/ensure-ssh-key.d.ts +17 -0
- package/dist/cli/ensure-ssh-key.js +45 -0
- package/dist/cli/ensure-ssh-key.js.map +1 -0
- package/dist/cli/ensure-ssh-key.test.d.ts +1 -0
- package/dist/cli/ensure-ssh-key.test.js +68 -0
- package/dist/cli/ensure-ssh-key.test.js.map +1 -0
- package/dist/cli/header.d.ts +4 -0
- package/dist/cli/header.js +6 -0
- package/dist/cli/header.js.map +1 -0
- package/dist/cli/resolve-views-dir.d.ts +1 -0
- package/dist/cli/resolve-views-dir.js +17 -0
- package/dist/cli/resolve-views-dir.js.map +1 -0
- package/dist/cli/run-command.d.ts +2 -0
- package/dist/cli/run-command.js +43 -0
- package/dist/cli/run-command.js.map +1 -0
- package/dist/cli/telemetry.d.ts +14 -0
- package/dist/cli/telemetry.js +24 -0
- package/dist/cli/telemetry.js.map +1 -0
- package/dist/cli/tunnel-control-server.d.ts +11 -0
- package/dist/cli/tunnel-control-server.js +35 -0
- package/dist/cli/tunnel-control-server.js.map +1 -0
- package/dist/cli/tunnel-control-server.test.d.ts +1 -0
- package/dist/cli/tunnel-control-server.test.js +39 -0
- package/dist/cli/tunnel-control-server.test.js.map +1 -0
- package/dist/cli/tunnel-handler.d.ts +3 -0
- package/dist/cli/tunnel-handler.js +48 -0
- package/dist/cli/tunnel-handler.js.map +1 -0
- package/dist/cli/tunnel-handler.test.d.ts +1 -0
- package/dist/cli/tunnel-handler.test.js +107 -0
- package/dist/cli/tunnel-handler.test.js.map +1 -0
- package/dist/cli/tunnel-providers/index.d.ts +5 -0
- package/dist/cli/tunnel-providers/index.js +5 -0
- package/dist/cli/tunnel-providers/index.js.map +1 -0
- package/dist/cli/tunnel-providers/srv-us.d.ts +18 -0
- package/dist/cli/tunnel-providers/srv-us.js +66 -0
- package/dist/cli/tunnel-providers/srv-us.js.map +1 -0
- package/dist/cli/tunnel-providers/srv-us.test.d.ts +1 -0
- package/dist/cli/tunnel-providers/srv-us.test.js +74 -0
- package/dist/cli/tunnel-providers/srv-us.test.js.map +1 -0
- package/dist/cli/tunnel-providers/types.d.ts +49 -0
- package/dist/cli/tunnel-providers/types.js +2 -0
- package/dist/cli/tunnel-providers/types.js.map +1 -0
- package/dist/cli/tunnel.d.ts +75 -0
- package/dist/cli/tunnel.js +254 -0
- package/dist/cli/tunnel.js.map +1 -0
- package/dist/cli/tunnel.test.d.ts +1 -0
- package/dist/cli/tunnel.test.js +255 -0
- package/dist/cli/tunnel.test.js.map +1 -0
- package/dist/cli/types.d.ts +5 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/use-execute-steps.d.ts +11 -0
- package/dist/cli/use-execute-steps.js +36 -0
- package/dist/cli/use-execute-steps.js.map +1 -0
- package/dist/cli/use-messages.d.ts +3 -0
- package/dist/cli/use-messages.js +11 -0
- package/dist/cli/use-messages.js.map +1 -0
- package/dist/cli/use-nodemon.d.ts +2 -0
- package/dist/cli/use-nodemon.js +73 -0
- package/dist/cli/use-nodemon.js.map +1 -0
- package/dist/cli/use-open-browser.d.ts +1 -0
- package/dist/cli/use-open-browser.js +44 -0
- package/dist/cli/use-open-browser.js.map +1 -0
- package/dist/cli/use-open-tunnel-browser.d.ts +6 -0
- package/dist/cli/use-open-tunnel-browser.js +19 -0
- package/dist/cli/use-open-tunnel-browser.js.map +1 -0
- package/dist/cli/use-tunnel.d.ts +17 -0
- package/dist/cli/use-tunnel.js +131 -0
- package/dist/cli/use-tunnel.js.map +1 -0
- package/dist/cli/use-typescript-check.d.ts +9 -0
- package/dist/cli/use-typescript-check.js +94 -0
- package/dist/cli/use-typescript-check.js.map +1 -0
- package/dist/commands/build.d.ts +8 -0
- package/dist/commands/build.js +97 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create.d.ts +9 -0
- package/dist/commands/create.js +30 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +13 -0
- package/dist/commands/dev.js +112 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/start.js +76 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/telemetry/disable.d.ts +5 -0
- package/dist/commands/telemetry/disable.js +12 -0
- package/dist/commands/telemetry/disable.js.map +1 -0
- package/dist/commands/telemetry/enable.d.ts +5 -0
- package/dist/commands/telemetry/enable.js +12 -0
- package/dist/commands/telemetry/enable.js.map +1 -0
- package/dist/commands/telemetry/status.d.ts +5 -0
- package/dist/commands/telemetry/status.js +12 -0
- package/dist/commands/telemetry/status.js.map +1 -0
- package/dist/server/admin.d.ts +79 -0
- package/dist/server/admin.js +239 -0
- package/dist/server/admin.js.map +1 -0
- package/dist/server/admin.test.d.ts +1 -0
- package/dist/server/admin.test.js +226 -0
- package/dist/server/admin.test.js.map +1 -0
- package/dist/server/analytics.d.ts +60 -0
- package/dist/server/analytics.js +168 -0
- package/dist/server/analytics.js.map +1 -0
- package/dist/server/analytics.test.d.ts +1 -0
- package/dist/server/analytics.test.js +179 -0
- package/dist/server/analytics.test.js.map +1 -0
- package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
- package/dist/server/asset-base-url-transform-plugin.js +48 -0
- package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
- package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
- package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
- package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
- package/dist/server/auth.d.ts +20 -0
- package/dist/server/auth.js +28 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/build-manifest.test.d.ts +1 -0
- package/dist/server/build-manifest.test.js +27 -0
- package/dist/server/build-manifest.test.js.map +1 -0
- package/dist/server/config/config.test.d.ts +1 -0
- package/dist/server/config/config.test.js +214 -0
- package/dist/server/config/config.test.js.map +1 -0
- package/dist/server/config/index.d.ts +3 -0
- package/dist/server/config/index.js +4 -0
- package/dist/server/config/index.js.map +1 -0
- package/dist/server/config/resolve.d.ts +73 -0
- package/dist/server/config/resolve.js +167 -0
- package/dist/server/config/resolve.js.map +1 -0
- package/dist/server/config/router.d.ts +23 -0
- package/dist/server/config/router.js +119 -0
- package/dist/server/config/router.js.map +1 -0
- package/dist/server/config/schema.d.ts +78 -0
- package/dist/server/config/schema.js +158 -0
- package/dist/server/config/schema.js.map +1 -0
- package/dist/server/content-helpers.d.ts +67 -0
- package/dist/server/content-helpers.js +79 -0
- package/dist/server/content-helpers.js.map +1 -0
- package/dist/server/content-helpers.test.d.ts +1 -0
- package/dist/server/content-helpers.test.js +70 -0
- package/dist/server/content-helpers.test.js.map +1 -0
- package/dist/server/express.d.ts +11 -0
- package/dist/server/express.js +129 -0
- package/dist/server/express.js.map +1 -0
- package/dist/server/express.test.d.ts +1 -0
- package/dist/server/express.test.js +464 -0
- package/dist/server/express.test.js.map +1 -0
- package/dist/server/file-ref.d.ts +28 -0
- package/dist/server/file-ref.js +27 -0
- package/dist/server/file-ref.js.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.js +14 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/inferUtilityTypes.d.ts +64 -0
- package/dist/server/inferUtilityTypes.js +2 -0
- package/dist/server/inferUtilityTypes.js.map +1 -0
- package/dist/server/log-sink.d.ts +16 -0
- package/dist/server/log-sink.js +66 -0
- package/dist/server/log-sink.js.map +1 -0
- package/dist/server/metric.d.ts +12 -0
- package/dist/server/metric.js +13 -0
- package/dist/server/metric.js.map +1 -0
- package/dist/server/middleware.d.ts +137 -0
- package/dist/server/middleware.js +93 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/middleware.test-d.d.ts +1 -0
- package/dist/server/middleware.test-d.js +75 -0
- package/dist/server/middleware.test-d.js.map +1 -0
- package/dist/server/middleware.test.d.ts +1 -0
- package/dist/server/middleware.test.js +493 -0
- package/dist/server/middleware.test.js.map +1 -0
- package/dist/server/mock-seed.d.ts +62 -0
- package/dist/server/mock-seed.js +251 -0
- package/dist/server/mock-seed.js.map +1 -0
- package/dist/server/mock-seed.test.d.ts +1 -0
- package/dist/server/mock-seed.test.js +122 -0
- package/dist/server/mock-seed.test.js.map +1 -0
- package/dist/server/observability.d.ts +149 -0
- package/dist/server/observability.js +340 -0
- package/dist/server/observability.js.map +1 -0
- package/dist/server/observability.test.d.ts +1 -0
- package/dist/server/observability.test.js +251 -0
- package/dist/server/observability.test.js.map +1 -0
- package/dist/server/otel.d.ts +45 -0
- package/dist/server/otel.js +117 -0
- package/dist/server/otel.js.map +1 -0
- package/dist/server/otel.test.d.ts +1 -0
- package/dist/server/otel.test.js +122 -0
- package/dist/server/otel.test.js.map +1 -0
- package/dist/server/server.d.ts +422 -0
- package/dist/server/server.js +684 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/storage/index.d.ts +23 -0
- package/dist/server/storage/index.js +46 -0
- package/dist/server/storage/index.js.map +1 -0
- package/dist/server/storage/memory.d.ts +30 -0
- package/dist/server/storage/memory.js +98 -0
- package/dist/server/storage/memory.js.map +1 -0
- package/dist/server/storage/memory.test.d.ts +1 -0
- package/dist/server/storage/memory.test.js +81 -0
- package/dist/server/storage/memory.test.js.map +1 -0
- package/dist/server/storage/postgres.d.ts +65 -0
- package/dist/server/storage/postgres.js +242 -0
- package/dist/server/storage/postgres.js.map +1 -0
- package/dist/server/storage/postgres.test.d.ts +1 -0
- package/dist/server/storage/postgres.test.js +182 -0
- package/dist/server/storage/postgres.test.js.map +1 -0
- package/dist/server/storage/sqlite.d.ts +33 -0
- package/dist/server/storage/sqlite.js +250 -0
- package/dist/server/storage/sqlite.js.map +1 -0
- package/dist/server/storage/sqlite.test.d.ts +1 -0
- package/dist/server/storage/sqlite.test.js +133 -0
- package/dist/server/storage/sqlite.test.js.map +1 -0
- package/dist/server/storage/types.d.ts +119 -0
- package/dist/server/storage/types.js +11 -0
- package/dist/server/storage/types.js.map +1 -0
- package/dist/server/templateHelper.d.ts +16 -0
- package/dist/server/templateHelper.js +11 -0
- package/dist/server/templateHelper.js.map +1 -0
- package/dist/server/templates.generated.d.ts +4 -0
- package/dist/server/templates.generated.js +47 -0
- package/dist/server/templates.generated.js.map +1 -0
- package/dist/server/tunnel-proxy-router.d.ts +7 -0
- package/dist/server/tunnel-proxy-router.js +110 -0
- package/dist/server/tunnel-proxy-router.js.map +1 -0
- package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
- package/dist/server/tunnel-proxy-router.test.js +229 -0
- package/dist/server/tunnel-proxy-router.test.js.map +1 -0
- package/dist/server/viewsDevServer.d.ts +14 -0
- package/dist/server/viewsDevServer.js +45 -0
- package/dist/server/viewsDevServer.js.map +1 -0
- package/dist/test/utils.d.ts +127 -0
- package/dist/test/utils.js +247 -0
- package/dist/test/utils.js.map +1 -0
- package/dist/test/view.test.d.ts +1 -0
- package/dist/test/view.test.js +568 -0
- package/dist/test/view.test.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/web/bridges/apps-sdk/adaptor.d.ts +54 -0
- package/dist/web/bridges/apps-sdk/adaptor.js +164 -0
- package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -0
- package/dist/web/bridges/apps-sdk/bridge.d.ts +11 -0
- package/dist/web/bridges/apps-sdk/bridge.js +47 -0
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
- package/dist/web/bridges/apps-sdk/index.d.ts +5 -0
- package/dist/web/bridges/apps-sdk/index.js +5 -0
- package/dist/web/bridges/apps-sdk/index.js.map +1 -0
- package/dist/web/bridges/apps-sdk/types.d.ts +147 -0
- package/dist/web/bridges/apps-sdk/types.js +10 -0
- package/dist/web/bridges/apps-sdk/types.js.map +1 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
- package/dist/web/bridges/get-adaptor.d.ts +9 -0
- package/dist/web/bridges/get-adaptor.js +15 -0
- package/dist/web/bridges/get-adaptor.js.map +1 -0
- package/dist/web/bridges/index.d.ts +5 -0
- package/dist/web/bridges/index.js +6 -0
- package/dist/web/bridges/index.js.map +1 -0
- package/dist/web/bridges/mcp-app/adaptor.d.ts +81 -0
- package/dist/web/bridges/mcp-app/adaptor.js +346 -0
- package/dist/web/bridges/mcp-app/adaptor.js.map +1 -0
- package/dist/web/bridges/mcp-app/bridge.d.ts +28 -0
- package/dist/web/bridges/mcp-app/bridge.js +124 -0
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
- package/dist/web/bridges/mcp-app/index.d.ts +4 -0
- package/dist/web/bridges/mcp-app/index.js +4 -0
- package/dist/web/bridges/mcp-app/index.js.map +1 -0
- package/dist/web/bridges/mcp-app/types.d.ts +8 -0
- package/dist/web/bridges/mcp-app/types.js +2 -0
- package/dist/web/bridges/mcp-app/types.js.map +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
- package/dist/web/bridges/types.d.ts +243 -0
- package/dist/web/bridges/types.js +2 -0
- package/dist/web/bridges/types.js.map +1 -0
- package/dist/web/bridges/use-host-context.d.ts +7 -0
- package/dist/web/bridges/use-host-context.js +13 -0
- package/dist/web/bridges/use-host-context.js.map +1 -0
- package/dist/web/components/modal-provider.d.ts +4 -0
- package/dist/web/components/modal-provider.js +45 -0
- package/dist/web/components/modal-provider.js.map +1 -0
- package/dist/web/create-store.d.ts +29 -0
- package/dist/web/create-store.js +64 -0
- package/dist/web/create-store.js.map +1 -0
- package/dist/web/create-store.test.d.ts +1 -0
- package/dist/web/create-store.test.js +129 -0
- package/dist/web/create-store.test.js.map +1 -0
- package/dist/web/data-llm.d.ts +47 -0
- package/dist/web/data-llm.js +100 -0
- package/dist/web/data-llm.js.map +1 -0
- package/dist/web/data-llm.test.d.ts +1 -0
- package/dist/web/data-llm.test.js +142 -0
- package/dist/web/data-llm.test.js.map +1 -0
- package/dist/web/generate-helpers.d.ts +120 -0
- package/dist/web/generate-helpers.js +115 -0
- package/dist/web/generate-helpers.js.map +1 -0
- package/dist/web/generate-helpers.test-d.d.ts +1 -0
- package/dist/web/generate-helpers.test-d.js +211 -0
- package/dist/web/generate-helpers.test-d.js.map +1 -0
- package/dist/web/generate-helpers.test.d.ts +1 -0
- package/dist/web/generate-helpers.test.js +17 -0
- package/dist/web/generate-helpers.test.js.map +1 -0
- package/dist/web/helpers/state.d.ts +7 -0
- package/dist/web/helpers/state.js +45 -0
- package/dist/web/helpers/state.js.map +1 -0
- package/dist/web/helpers/state.test.d.ts +1 -0
- package/dist/web/helpers/state.test.js +53 -0
- package/dist/web/helpers/state.test.js.map +1 -0
- package/dist/web/hooks/index.d.ts +17 -0
- package/dist/web/hooks/index.js +18 -0
- package/dist/web/hooks/index.js.map +1 -0
- package/dist/web/hooks/test/utils.d.ts +20 -0
- package/dist/web/hooks/test/utils.js +75 -0
- package/dist/web/hooks/test/utils.js.map +1 -0
- package/dist/web/hooks/use-call-tool.d.ts +146 -0
- package/dist/web/hooks/use-call-tool.js +96 -0
- package/dist/web/hooks/use-call-tool.js.map +1 -0
- package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
- package/dist/web/hooks/use-call-tool.test-d.js +104 -0
- package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
- package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
- package/dist/web/hooks/use-call-tool.test.js +211 -0
- package/dist/web/hooks/use-call-tool.test.js.map +1 -0
- package/dist/web/hooks/use-display-mode.d.ts +24 -0
- package/dist/web/hooks/use-display-mode.js +29 -0
- package/dist/web/hooks/use-display-mode.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test-d.js +8 -0
- package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test.js +41 -0
- package/dist/web/hooks/use-display-mode.test.js.map +1 -0
- package/dist/web/hooks/use-download.d.ts +5 -0
- package/dist/web/hooks/use-download.js +8 -0
- package/dist/web/hooks/use-download.js.map +1 -0
- package/dist/web/hooks/use-download.test.d.ts +1 -0
- package/dist/web/hooks/use-download.test.js +95 -0
- package/dist/web/hooks/use-download.test.js.map +1 -0
- package/dist/web/hooks/use-files.d.ts +39 -0
- package/dist/web/hooks/use-files.js +42 -0
- package/dist/web/hooks/use-files.js.map +1 -0
- package/dist/web/hooks/use-files.test.d.ts +1 -0
- package/dist/web/hooks/use-files.test.js +54 -0
- package/dist/web/hooks/use-files.test.js.map +1 -0
- package/dist/web/hooks/use-intent.d.ts +30 -0
- package/dist/web/hooks/use-intent.js +34 -0
- package/dist/web/hooks/use-intent.js.map +1 -0
- package/dist/web/hooks/use-intent.test.d.ts +1 -0
- package/dist/web/hooks/use-intent.test.js +85 -0
- package/dist/web/hooks/use-intent.test.js.map +1 -0
- package/dist/web/hooks/use-layout.d.ts +24 -0
- package/dist/web/hooks/use-layout.js +25 -0
- package/dist/web/hooks/use-layout.js.map +1 -0
- package/dist/web/hooks/use-layout.test.d.ts +1 -0
- package/dist/web/hooks/use-layout.test.js +96 -0
- package/dist/web/hooks/use-layout.test.js.map +1 -0
- package/dist/web/hooks/use-notify.d.ts +29 -0
- package/dist/web/hooks/use-notify.js +33 -0
- package/dist/web/hooks/use-notify.js.map +1 -0
- package/dist/web/hooks/use-notify.test.d.ts +1 -0
- package/dist/web/hooks/use-notify.test.js +105 -0
- package/dist/web/hooks/use-notify.test.js.map +1 -0
- package/dist/web/hooks/use-open-external.d.ts +20 -0
- package/dist/web/hooks/use-open-external.js +24 -0
- package/dist/web/hooks/use-open-external.js.map +1 -0
- package/dist/web/hooks/use-open-external.test.d.ts +1 -0
- package/dist/web/hooks/use-open-external.test.js +65 -0
- package/dist/web/hooks/use-open-external.test.js.map +1 -0
- package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
- package/dist/web/hooks/use-register-view-tool.js +50 -0
- package/dist/web/hooks/use-register-view-tool.js.map +1 -0
- package/dist/web/hooks/use-request-close.d.ts +16 -0
- package/dist/web/hooks/use-request-close.js +21 -0
- package/dist/web/hooks/use-request-close.js.map +1 -0
- package/dist/web/hooks/use-request-close.test.d.ts +1 -0
- package/dist/web/hooks/use-request-close.test.js +52 -0
- package/dist/web/hooks/use-request-close.test.js.map +1 -0
- package/dist/web/hooks/use-request-modal.d.ts +24 -0
- package/dist/web/hooks/use-request-modal.js +31 -0
- package/dist/web/hooks/use-request-modal.js.map +1 -0
- package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
- package/dist/web/hooks/use-request-modal.test.js +61 -0
- package/dist/web/hooks/use-request-modal.test.js.map +1 -0
- package/dist/web/hooks/use-request-size.d.ts +20 -0
- package/dist/web/hooks/use-request-size.js +24 -0
- package/dist/web/hooks/use-request-size.js.map +1 -0
- package/dist/web/hooks/use-request-size.test.d.ts +1 -0
- package/dist/web/hooks/use-request-size.test.js +65 -0
- package/dist/web/hooks/use-request-size.test.js.map +1 -0
- package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
- package/dist/web/hooks/use-send-follow-up-message.js +25 -0
- package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
- package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
- package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.js +43 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
- package/dist/web/hooks/use-tool-info.d.ts +87 -0
- package/dist/web/hooks/use-tool-info.js +49 -0
- package/dist/web/hooks/use-tool-info.js.map +1 -0
- package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
- package/dist/web/hooks/use-tool-info.test-d.js +91 -0
- package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
- package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
- package/dist/web/hooks/use-tool-info.test.js +130 -0
- package/dist/web/hooks/use-tool-info.test.js.map +1 -0
- package/dist/web/hooks/use-user.d.ts +20 -0
- package/dist/web/hooks/use-user.js +37 -0
- package/dist/web/hooks/use-user.js.map +1 -0
- package/dist/web/hooks/use-user.test.d.ts +1 -0
- package/dist/web/hooks/use-user.test.js +122 -0
- package/dist/web/hooks/use-user.test.js.map +1 -0
- package/dist/web/hooks/use-view-state.d.ts +25 -0
- package/dist/web/hooks/use-view-state.js +32 -0
- package/dist/web/hooks/use-view-state.js.map +1 -0
- package/dist/web/hooks/use-view-state.test.d.ts +1 -0
- package/dist/web/hooks/use-view-state.test.js +177 -0
- package/dist/web/hooks/use-view-state.test.js.map +1 -0
- package/dist/web/index.d.ts +7 -0
- package/dist/web/index.js +8 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/mount-view.d.ts +20 -0
- package/dist/web/mount-view.js +46 -0
- package/dist/web/mount-view.js.map +1 -0
- package/dist/web/plugin/data-llm.test.d.ts +1 -0
- package/dist/web/plugin/data-llm.test.js +81 -0
- package/dist/web/plugin/data-llm.test.js.map +1 -0
- package/dist/web/plugin/plugin.d.ts +33 -0
- package/dist/web/plugin/plugin.js +189 -0
- package/dist/web/plugin/plugin.js.map +1 -0
- package/dist/web/plugin/scan-views.d.ts +16 -0
- package/dist/web/plugin/scan-views.js +88 -0
- package/dist/web/plugin/scan-views.js.map +1 -0
- package/dist/web/plugin/scan-views.test.d.ts +1 -0
- package/dist/web/plugin/scan-views.test.js +99 -0
- package/dist/web/plugin/scan-views.test.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.d.ts +12 -0
- package/dist/web/plugin/transform-data-llm.js +96 -0
- package/dist/web/plugin/transform-data-llm.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.test.d.ts +1 -0
- package/dist/web/plugin/transform-data-llm.test.js +81 -0
- package/dist/web/plugin/transform-data-llm.test.js.map +1 -0
- package/dist/web/plugin/validate-view.d.ts +1 -0
- package/dist/web/plugin/validate-view.js +9 -0
- package/dist/web/plugin/validate-view.js.map +1 -0
- package/dist/web/plugin/validate-view.test.d.ts +1 -0
- package/dist/web/plugin/validate-view.test.js +24 -0
- package/dist/web/plugin/validate-view.test.js.map +1 -0
- package/dist/web/proxy.d.ts +1 -0
- package/dist/web/proxy.js +52 -0
- package/dist/web/proxy.js.map +1 -0
- package/dist/web/types.d.ts +20 -0
- package/dist/web/types.js +2 -0
- package/dist/web/types.js.map +1 -0
- package/package.json +125 -0
- package/scripts/postinstall.mjs +45 -0
- package/tsconfig.base.json +36 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/types.ts"],"names":[],"mappings":"AAoBA,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAC/D,MAAM,OAAO,iBAAkB,SAAQ,WAErC;IACkB,IAAI,GAAG,wBAAwB,CAAC;CACnD;AA8HD,sDAAsD;AACtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAC3D,MAAM,OAAO,eAAgB,SAAQ,WAEnC;IACkB,IAAI,GAAG,sBAAsB,CAAC;CACjD","sourcesContent":["import type { UnknownObject } from \"../../types.js\";\nimport type {\n CallToolArgs,\n CallToolResponse,\n FileMetadata,\n Intent,\n Notification,\n RequestModalOptions,\n UploadFileOptions,\n} from \"../types.js\";\n\ntype DisplayMode = \"pip\" | \"inline\" | \"fullscreen\" | \"modal\";\ntype RequestDisplayMode = Exclude<DisplayMode, \"modal\">;\n\nexport type AppsSdkWidgetState = {\n modelContent: Record<string, unknown>;\n privateContent: Record<string, unknown>;\n imageIds?: string[];\n};\n\nexport const TOOL_RESPONSE_EVENT_TYPE = \"openai:tool_response\";\nexport class ToolResponseEvent extends CustomEvent<{\n tool: { name: string; args: UnknownObject };\n}> {\n override readonly type = TOOL_RESPONSE_EVENT_TYPE;\n}\n\ndeclare global {\n interface Window {\n openai: AppsSdkMethods & AppsSdkContext;\n }\n\n interface WindowEventMap {\n [SET_GLOBALS_EVENT_TYPE]: SetGlobalsEvent;\n }\n}\n\nexport type AppsSdkContext<\n ToolInput extends UnknownObject = Record<never, unknown>,\n ToolOutput extends UnknownObject = UnknownObject,\n ToolResponseMetadata extends UnknownObject = UnknownObject,\n WS extends AppsSdkWidgetState = AppsSdkWidgetState,\n> = {\n theme: Theme;\n userAgent: UserAgent;\n locale: string;\n\n // layout\n maxHeight: number | undefined;\n displayMode: DisplayMode;\n safeArea: SafeArea;\n view: View;\n\n // state\n toolInput: ToolInput;\n toolOutput: ToolOutput | { text: string } | null;\n toolResponseMetadata: ToolResponseMetadata | null;\n widgetState: WS | null;\n};\n\nexport type AppsSdkMethods<WS extends AppsSdkWidgetState = AppsSdkWidgetState> =\n {\n /** Calls a tool on your MCP. Returns the full response. */\n callTool: <\n ToolArgs extends CallToolArgs = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n ) => Promise<ToolResponse>;\n\n /**\n * Triggers a followup turn in the ChatGPT conversation\n * scrollToBottom is optional, defaults to true, and can be\n * set to false to prevent auto-scroll.\n */\n sendFollowUpMessage: (args: {\n prompt: string;\n scrollToBottom?: boolean;\n }) => Promise<void>;\n\n /** Opens an external link, redirects web page or mobile app */\n openExternal(args: { href: string; redirectUrl?: false }): void;\n\n /** For transitioning an app from inline to fullscreen or pip */\n requestDisplayMode: (args: { mode: RequestDisplayMode }) => Promise<{\n /**\n * The granted display mode. The host may reject the request.\n * For mobile, PiP is always coerced to fullscreen.\n */\n mode: RequestDisplayMode;\n }>;\n\n /** Requests the host to close (dismiss) the widget. */\n requestClose: () => Promise<void>;\n\n /**\n * Sets the widget state.\n * This state is persisted across widget renders.\n */\n setWidgetState: (state: WS) => Promise<void>;\n\n /**\n * Opens a modal portaled outside of the widget iFrame.\n * This ensures the modal is correctly displayed and not limited to the widget's area.\n */\n requestModal: (args: RequestModalOptions) => Promise<void>;\n\n /** Uploads a new file to the host. Pass `{ library: true }` to also save to the user's ChatGPT file library. */\n uploadFile: (\n file: File,\n options?: UploadFileOptions,\n ) => Promise<FileMetadata>;\n\n /**\n * Opens ChatGPT's file library picker and returns app-authorized files.\n * Feature-detect before using: this method may not be available on all host versions.\n */\n selectFiles?: () => Promise<FileMetadata[]>;\n\n /**\n * Downloads a file from the host. Works for files uploaded by the widget,\n * files selected via selectFiles(), or files provided via tool/file params.\n */\n getFileDownloadUrl: (\n file: FileMetadata,\n ) => Promise<{ downloadUrl: string }>;\n\n /**\n * Sets the open in app URL.\n * This URL will be opened in the app when the user clicks on the top right button in fullscreen mode.\n */\n setOpenInAppUrl: (args: { href: string }) => Promise<void>;\n\n /**\n * enpilink extension (NOT part of the ChatGPT Apps SDK): surface a\n * notification to the host. Optional — feature-detected by the adaptor; if\n * the host doesn't provide it, the adaptor falls back to\n * `window.parent.postMessage`. The devtools emulator implements it.\n */\n notify?: (notification: Notification) => Promise<void>;\n\n /**\n * enpilink extension (NOT part of the ChatGPT Apps SDK): forward a\n * high-level intent to the host. Optional — feature-detected by the\n * adaptor; falls back to `window.parent.postMessage` when absent. The\n * devtools emulator implements it.\n */\n sendIntent?: (intent: Intent) => Promise<void>;\n };\n\n// Dispatched when any global changes in the host page\nexport const SET_GLOBALS_EVENT_TYPE = \"openai:set_globals\";\nexport class SetGlobalsEvent extends CustomEvent<{\n globals: Partial<AppsSdkContext>;\n}> {\n override readonly type = SET_GLOBALS_EVENT_TYPE;\n}\n\ntype View = {\n mode: DisplayMode;\n params?: Record<string, unknown>;\n};\n\ntype Theme = \"light\" | \"dark\";\n\ntype SafeAreaInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\ntype SafeArea = {\n insets: SafeAreaInsets;\n};\n\ntype DeviceType = \"mobile\" | \"tablet\" | \"desktop\" | \"unknown\";\n\ntype UserAgent = {\n device: { type: DeviceType };\n capabilities: {\n hover: boolean;\n touch: boolean;\n };\n};\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AppsSdkContext } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Read a single key from the raw Apps SDK (`window.openai`) context.
|
|
4
|
+
*
|
|
5
|
+
* Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
|
|
6
|
+
* `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
|
|
7
|
+
* this when you need ChatGPT-only fields not surfaced by the public hooks.
|
|
8
|
+
*
|
|
9
|
+
* Throws if called outside the Apps SDK runtime.
|
|
10
|
+
*
|
|
11
|
+
* @see https://docs.enpitech.dev/api-reference/use-apps-sdk-context
|
|
12
|
+
*/
|
|
13
|
+
export declare function useAppsSdkContext<K extends keyof AppsSdkContext>(key: K): AppsSdkContext[K];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
import { AppsSdkBridge } from "./bridge.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read a single key from the raw Apps SDK (`window.openai`) context.
|
|
5
|
+
*
|
|
6
|
+
* Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
|
|
7
|
+
* `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
|
|
8
|
+
* this when you need ChatGPT-only fields not surfaced by the public hooks.
|
|
9
|
+
*
|
|
10
|
+
* Throws if called outside the Apps SDK runtime.
|
|
11
|
+
*
|
|
12
|
+
* @see https://docs.enpitech.dev/api-reference/use-apps-sdk-context
|
|
13
|
+
*/
|
|
14
|
+
export function useAppsSdkContext(key) {
|
|
15
|
+
const bridge = AppsSdkBridge.getInstance();
|
|
16
|
+
return useSyncExternalStore(bridge.subscribe(key), () => bridge.getSnapshot(key));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=use-apps-sdk-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-apps-sdk-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/use-apps-sdk-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAM;IAEN,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { AppsSdkBridge } from \"./bridge.js\";\nimport type { AppsSdkContext } from \"./types.js\";\n\n/**\n * Read a single key from the raw Apps SDK (`window.openai`) context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,\n * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for\n * this when you need ChatGPT-only fields not surfaced by the public hooks.\n *\n * Throws if called outside the Apps SDK runtime.\n *\n * @see https://docs.enpitech.dev/api-reference/use-apps-sdk-context\n */\nexport function useAppsSdkContext<K extends keyof AppsSdkContext>(\n key: K,\n): AppsSdkContext[K] {\n const bridge = AppsSdkBridge.getInstance();\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Adaptor } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
* Resolve the host-specific {@link Adaptor} based on `window.enpilink.hostType`.
|
|
5
|
+
* Prefer the documented hooks (`useCallTool`, `useViewState`, etc.) over
|
|
6
|
+
* calling this directly — it's the escape hatch used by the hooks themselves
|
|
7
|
+
* and by advanced integrations.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getAdaptor: () => Adaptor;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AppsSdkAdaptor } from "./apps-sdk/adaptor.js";
|
|
2
|
+
import { McpAppAdaptor } from "./mcp-app/adaptor.js";
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
* Resolve the host-specific {@link Adaptor} based on `window.enpilink.hostType`.
|
|
6
|
+
* Prefer the documented hooks (`useCallTool`, `useViewState`, etc.) over
|
|
7
|
+
* calling this directly — it's the escape hatch used by the hooks themselves
|
|
8
|
+
* and by advanced integrations.
|
|
9
|
+
*/
|
|
10
|
+
export const getAdaptor = () => {
|
|
11
|
+
return window.enpilink.hostType === "apps-sdk"
|
|
12
|
+
? AppsSdkAdaptor.getInstance()
|
|
13
|
+
: McpAppAdaptor.getInstance();
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=get-adaptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/get-adaptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,GAAY,EAAE;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,UAAU;QAC5C,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE;QAC9B,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC,CAAC","sourcesContent":["import { AppsSdkAdaptor } from \"./apps-sdk/adaptor.js\";\nimport { McpAppAdaptor } from \"./mcp-app/adaptor.js\";\nimport type { Adaptor } from \"./types.js\";\n\n/**\n * @internal\n * Resolve the host-specific {@link Adaptor} based on `window.enpilink.hostType`.\n * Prefer the documented hooks (`useCallTool`, `useViewState`, etc.) over\n * calling this directly — it's the escape hatch used by the hooks themselves\n * and by advanced integrations.\n */\nexport const getAdaptor = (): Adaptor => {\n return window.enpilink.hostType === \"apps-sdk\"\n ? AppsSdkAdaptor.getInstance()\n : McpAppAdaptor.getInstance();\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/bridges/index.tsx"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export * from \"./apps-sdk/index.js\";\nexport { getAdaptor } from \"./get-adaptor.js\";\nexport * from \"./mcp-app/index.js\";\nexport * from \"./types.js\";\nexport { useHostContext } from \"./use-host-context.js\";\n"]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Adaptor, AnyViewToolHandler, CallToolResponse, DownloadParams, DownloadResult, HostContext, HostContextStore, Intent, Notification, OpenExternalOptions, RequestDisplayMode, RequestModalOptions, RequestSizeOptions, SendFollowUpMessageOptions, SetViewStateAction, ViewToolConfig } from "../types.js";
|
|
2
|
+
/** @internal MCP Apps implementation of {@link Adaptor}. Resolved via {@link getAdaptor}. */
|
|
3
|
+
export declare class McpAppAdaptor implements Adaptor {
|
|
4
|
+
private static instance;
|
|
5
|
+
private stores;
|
|
6
|
+
private _viewState;
|
|
7
|
+
private viewStateListeners;
|
|
8
|
+
private _viewUUID;
|
|
9
|
+
private _displayState;
|
|
10
|
+
private displayListeners;
|
|
11
|
+
private constructor();
|
|
12
|
+
static getInstance(): McpAppAdaptor;
|
|
13
|
+
static resetInstance(): void;
|
|
14
|
+
getHostContextStore<K extends keyof HostContext>(key: K): HostContextStore<K>;
|
|
15
|
+
callTool: <ToolArgs extends Record<string, unknown> | null = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string, args: ToolArgs) => Promise<ToolResponse>;
|
|
16
|
+
requestDisplayMode: (mode: RequestDisplayMode) => Promise<{
|
|
17
|
+
[x: string]: unknown;
|
|
18
|
+
mode: "inline" | "fullscreen" | "pip";
|
|
19
|
+
}>;
|
|
20
|
+
requestClose: () => Promise<void>;
|
|
21
|
+
requestSize: (size: RequestSizeOptions) => Promise<void>;
|
|
22
|
+
sendFollowUpMessage: (prompt: string, _options?: SendFollowUpMessageOptions) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Surface a notification to the host via the MCP Apps logging channel.
|
|
25
|
+
*
|
|
26
|
+
* Uses the **real** MCP protocol: `app.sendLog` (`notifications/message`).
|
|
27
|
+
* The `level` maps to the syslog levels the spec defines; `"success"` has no
|
|
28
|
+
* equivalent and is coerced to `"info"` (the structured `title`/`data` are
|
|
29
|
+
* preserved in the log payload). Hosts may render this as a toast or simply
|
|
30
|
+
* record it for debugging. Best-effort — failures are swallowed; never throws.
|
|
31
|
+
*
|
|
32
|
+
* @remarks Per-runtime: apps-sdk surfaces the same call via
|
|
33
|
+
* `window.openai.notify` / a `postMessage` fallback (see the apps-sdk
|
|
34
|
+
* adaptor); the MCP Apps runtime uses standard `notifications/message`.
|
|
35
|
+
*/
|
|
36
|
+
notify: (notification: Notification) => Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Forward a high-level intent to the host.
|
|
39
|
+
*
|
|
40
|
+
* The MCP Apps spec has **no intent/action primitive**, so this is an
|
|
41
|
+
* **enpilink extension**: the intent is delivered best-effort over the
|
|
42
|
+
* standard `notifications/message` channel (`app.sendLog`) tagged with
|
|
43
|
+
* `logger: "enpilink/intent"` and a structured `{ intent, params }` payload.
|
|
44
|
+
* A compliant host that doesn't understand intents simply records it as a
|
|
45
|
+
* log entry (no error). Never throws.
|
|
46
|
+
*
|
|
47
|
+
* @remarks enpilink extension — not part of the MCP Apps spec. Real-host
|
|
48
|
+
* routing of intents is therefore best-effort and unverifiable here.
|
|
49
|
+
*/
|
|
50
|
+
sendIntent: (intent: Intent) => Promise<void>;
|
|
51
|
+
download: (params: DownloadParams) => Promise<DownloadResult>;
|
|
52
|
+
openExternal(href: string, options?: OpenExternalOptions): void;
|
|
53
|
+
private initializeStores;
|
|
54
|
+
setViewState: (stateOrUpdater: SetViewStateAction) => Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* @throws File upload is not supported in MCP App.
|
|
57
|
+
*/
|
|
58
|
+
uploadFile(): Promise<{
|
|
59
|
+
fileId: string;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* @throws File download is not supported in MCP App.
|
|
63
|
+
*/
|
|
64
|
+
getFileDownloadUrl(): Promise<{
|
|
65
|
+
downloadUrl: string;
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* @throws File selection is not supported in MCP App.
|
|
69
|
+
*/
|
|
70
|
+
selectFiles(): Promise<{
|
|
71
|
+
fileId: string;
|
|
72
|
+
}[]>;
|
|
73
|
+
openModal(options: RequestModalOptions): void;
|
|
74
|
+
closeModal(): void;
|
|
75
|
+
setOpenInAppUrl(_href: string): Promise<void>;
|
|
76
|
+
registerViewTool: (config: ViewToolConfig, handler: AnyViewToolHandler) => (() => void);
|
|
77
|
+
private subscribeToViewUUID;
|
|
78
|
+
private restoreFromLocalStorage;
|
|
79
|
+
private persistToLocalStorage;
|
|
80
|
+
private createHostContextStore;
|
|
81
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { dequal } from "dequal/lite";
|
|
2
|
+
import { McpAppBridge } from "./bridge.js";
|
|
3
|
+
const STORAGE_PREFIX = "sb:";
|
|
4
|
+
const MAX_STORAGE_ENTRIES = 200;
|
|
5
|
+
function findStorageKey(viewUUID) {
|
|
6
|
+
const suffix = `:${viewUUID}`;
|
|
7
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
8
|
+
const key = localStorage.key(i);
|
|
9
|
+
if (key?.startsWith(STORAGE_PREFIX) && key.endsWith(suffix)) {
|
|
10
|
+
return key;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
/** @internal MCP Apps implementation of {@link Adaptor}. Resolved via {@link getAdaptor}. */
|
|
16
|
+
export class McpAppAdaptor {
|
|
17
|
+
static instance = null;
|
|
18
|
+
stores;
|
|
19
|
+
_viewState = null;
|
|
20
|
+
viewStateListeners = new Set();
|
|
21
|
+
_viewUUID = null;
|
|
22
|
+
_displayState = {
|
|
23
|
+
mode: "inline",
|
|
24
|
+
};
|
|
25
|
+
displayListeners = new Set();
|
|
26
|
+
constructor() {
|
|
27
|
+
this.stores = this.initializeStores();
|
|
28
|
+
this.subscribeToViewUUID();
|
|
29
|
+
}
|
|
30
|
+
static getInstance() {
|
|
31
|
+
if (!McpAppAdaptor.instance) {
|
|
32
|
+
McpAppAdaptor.instance = new McpAppAdaptor();
|
|
33
|
+
}
|
|
34
|
+
return McpAppAdaptor.instance;
|
|
35
|
+
}
|
|
36
|
+
static resetInstance() {
|
|
37
|
+
McpAppAdaptor.instance = null;
|
|
38
|
+
}
|
|
39
|
+
getHostContextStore(key) {
|
|
40
|
+
return this.stores[key];
|
|
41
|
+
}
|
|
42
|
+
callTool = async (name, args) => {
|
|
43
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
44
|
+
const response = await app.callServerTool({
|
|
45
|
+
name,
|
|
46
|
+
arguments: args ?? undefined,
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
content: response.content,
|
|
50
|
+
structuredContent: response.structuredContent ?? {},
|
|
51
|
+
isError: response.isError ?? false,
|
|
52
|
+
meta: response._meta ?? {},
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
requestDisplayMode = async (mode) => {
|
|
56
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
57
|
+
return app.requestDisplayMode({ mode });
|
|
58
|
+
};
|
|
59
|
+
requestClose = async () => {
|
|
60
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
61
|
+
await app.requestTeardown();
|
|
62
|
+
};
|
|
63
|
+
requestSize = async (size) => {
|
|
64
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
65
|
+
await app.sendSizeChanged(size);
|
|
66
|
+
};
|
|
67
|
+
sendFollowUpMessage = async (prompt, _options) => {
|
|
68
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
69
|
+
await app.sendMessage({
|
|
70
|
+
role: "user",
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: prompt,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Surface a notification to the host via the MCP Apps logging channel.
|
|
81
|
+
*
|
|
82
|
+
* Uses the **real** MCP protocol: `app.sendLog` (`notifications/message`).
|
|
83
|
+
* The `level` maps to the syslog levels the spec defines; `"success"` has no
|
|
84
|
+
* equivalent and is coerced to `"info"` (the structured `title`/`data` are
|
|
85
|
+
* preserved in the log payload). Hosts may render this as a toast or simply
|
|
86
|
+
* record it for debugging. Best-effort — failures are swallowed; never throws.
|
|
87
|
+
*
|
|
88
|
+
* @remarks Per-runtime: apps-sdk surfaces the same call via
|
|
89
|
+
* `window.openai.notify` / a `postMessage` fallback (see the apps-sdk
|
|
90
|
+
* adaptor); the MCP Apps runtime uses standard `notifications/message`.
|
|
91
|
+
*/
|
|
92
|
+
notify = async (notification) => {
|
|
93
|
+
try {
|
|
94
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
95
|
+
const level = notification.level === "success" ? "info" : notification.level;
|
|
96
|
+
await app.sendLog({
|
|
97
|
+
level: level ?? "info",
|
|
98
|
+
logger: "enpilink",
|
|
99
|
+
data: {
|
|
100
|
+
...(notification.title ? { title: notification.title } : {}),
|
|
101
|
+
message: notification.message,
|
|
102
|
+
...(notification.level ? { level: notification.level } : {}),
|
|
103
|
+
...(notification.data !== undefined
|
|
104
|
+
? { data: notification.data }
|
|
105
|
+
: {}),
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.warn("[enpilink] notify: failed to deliver notification", error);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Forward a high-level intent to the host.
|
|
115
|
+
*
|
|
116
|
+
* The MCP Apps spec has **no intent/action primitive**, so this is an
|
|
117
|
+
* **enpilink extension**: the intent is delivered best-effort over the
|
|
118
|
+
* standard `notifications/message` channel (`app.sendLog`) tagged with
|
|
119
|
+
* `logger: "enpilink/intent"` and a structured `{ intent, params }` payload.
|
|
120
|
+
* A compliant host that doesn't understand intents simply records it as a
|
|
121
|
+
* log entry (no error). Never throws.
|
|
122
|
+
*
|
|
123
|
+
* @remarks enpilink extension — not part of the MCP Apps spec. Real-host
|
|
124
|
+
* routing of intents is therefore best-effort and unverifiable here.
|
|
125
|
+
*/
|
|
126
|
+
sendIntent = async (intent) => {
|
|
127
|
+
try {
|
|
128
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
129
|
+
await app.sendLog({
|
|
130
|
+
level: "info",
|
|
131
|
+
logger: "enpilink/intent",
|
|
132
|
+
data: {
|
|
133
|
+
intent: intent.name,
|
|
134
|
+
...(intent.params ? { params: intent.params } : {}),
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.warn("[enpilink] sendIntent: failed to deliver intent", error);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
download = async (params) => {
|
|
143
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
144
|
+
if (!app.getHostCapabilities()?.downloadFile) {
|
|
145
|
+
console.error("[enpilink] download: host does not support ui/download-file");
|
|
146
|
+
return { isError: true };
|
|
147
|
+
}
|
|
148
|
+
return app.downloadFile(params);
|
|
149
|
+
};
|
|
150
|
+
openExternal(href, options) {
|
|
151
|
+
if (options?.redirectUrl === false) {
|
|
152
|
+
console.warn("[enpilink] redirectUrl option is not supported by the MCP ui/open-link protocol and will be ignored.");
|
|
153
|
+
}
|
|
154
|
+
McpAppBridge.getInstance()
|
|
155
|
+
.getApp()
|
|
156
|
+
.then((app) => app.openLink({ url: href }))
|
|
157
|
+
.catch((err) => {
|
|
158
|
+
console.error("Failed to open external link:", err);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
initializeStores() {
|
|
162
|
+
return {
|
|
163
|
+
theme: this.createHostContextStore(["theme"], ({ theme }) => theme ?? "light"),
|
|
164
|
+
locale: this.createHostContextStore(["locale"], ({ locale }) => locale ?? "en-US"),
|
|
165
|
+
safeArea: this.createHostContextStore(["safeAreaInsets"], ({ safeAreaInsets }) => ({
|
|
166
|
+
insets: safeAreaInsets ?? { top: 0, right: 0, bottom: 0, left: 0 },
|
|
167
|
+
})),
|
|
168
|
+
displayMode: this.createHostContextStore(["displayMode"], ({ displayMode }) => displayMode ?? "inline"),
|
|
169
|
+
maxHeight: this.createHostContextStore(["containerDimensions"], ({ containerDimensions }) => {
|
|
170
|
+
if (containerDimensions && "maxHeight" in containerDimensions) {
|
|
171
|
+
return containerDimensions.maxHeight;
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}),
|
|
175
|
+
userAgent: this.createHostContextStore(["platform", "deviceCapabilities"], ({ platform, deviceCapabilities }) => ({
|
|
176
|
+
device: {
|
|
177
|
+
type: platform === "web" ? "desktop" : (platform ?? "unknown"),
|
|
178
|
+
},
|
|
179
|
+
capabilities: {
|
|
180
|
+
hover: true,
|
|
181
|
+
touch: true,
|
|
182
|
+
...deviceCapabilities,
|
|
183
|
+
},
|
|
184
|
+
})),
|
|
185
|
+
toolInput: this.createHostContextStore(["toolInput"], ({ toolInput }) => toolInput ?? null),
|
|
186
|
+
toolOutput: this.createHostContextStore(["toolResult"], ({ toolResult }) => toolResult?.structuredContent ?? null),
|
|
187
|
+
toolResponseMetadata: this.createHostContextStore(["toolResult"], ({ toolResult }) => toolResult?._meta ?? null),
|
|
188
|
+
display: {
|
|
189
|
+
subscribe: (onChange) => {
|
|
190
|
+
this.displayListeners.add(onChange);
|
|
191
|
+
return () => {
|
|
192
|
+
this.displayListeners.delete(onChange);
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
getSnapshot: () => this._displayState,
|
|
196
|
+
},
|
|
197
|
+
viewState: {
|
|
198
|
+
subscribe: (onChange) => {
|
|
199
|
+
this.viewStateListeners.add(onChange);
|
|
200
|
+
return () => {
|
|
201
|
+
this.viewStateListeners.delete(onChange);
|
|
202
|
+
};
|
|
203
|
+
},
|
|
204
|
+
getSnapshot: () => this._viewState,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
setViewState = async (stateOrUpdater) => {
|
|
209
|
+
const newState = typeof stateOrUpdater === "function"
|
|
210
|
+
? stateOrUpdater(this._viewState)
|
|
211
|
+
: stateOrUpdater;
|
|
212
|
+
// must happen before the async bridge call to ensure the state is updated immediately for the UI,
|
|
213
|
+
// otherwise successive calls to setViewState may have stale state
|
|
214
|
+
this._viewState = newState;
|
|
215
|
+
this.viewStateListeners.forEach((listener) => {
|
|
216
|
+
listener();
|
|
217
|
+
});
|
|
218
|
+
this.persistToLocalStorage(newState);
|
|
219
|
+
try {
|
|
220
|
+
const app = await McpAppBridge.getInstance().getApp();
|
|
221
|
+
await app.updateModelContext({
|
|
222
|
+
structuredContent: newState,
|
|
223
|
+
content: [{ type: "text", text: JSON.stringify(newState) }],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
console.error("Failed to update view state in MCP App.", error);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* @throws File upload is not supported in MCP App.
|
|
232
|
+
*/
|
|
233
|
+
uploadFile() {
|
|
234
|
+
throw new Error("File upload is not supported in MCP App.");
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* @throws File download is not supported in MCP App.
|
|
238
|
+
*/
|
|
239
|
+
getFileDownloadUrl() {
|
|
240
|
+
throw new Error("File download is not supported in MCP App.");
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* @throws File selection is not supported in MCP App.
|
|
244
|
+
*/
|
|
245
|
+
selectFiles() {
|
|
246
|
+
throw new Error("File selection is not supported in MCP App.");
|
|
247
|
+
}
|
|
248
|
+
openModal(options) {
|
|
249
|
+
this._displayState = { mode: "modal", params: options.params };
|
|
250
|
+
this.displayListeners.forEach((listener) => {
|
|
251
|
+
listener();
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
closeModal() {
|
|
255
|
+
this._displayState = { mode: "inline" };
|
|
256
|
+
this.displayListeners.forEach((listener) => {
|
|
257
|
+
listener();
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
setOpenInAppUrl(_href) {
|
|
261
|
+
throw new Error("setOpenInAppUrl is not implemented in MCP App.");
|
|
262
|
+
}
|
|
263
|
+
registerViewTool = (config, handler) => {
|
|
264
|
+
return McpAppBridge.getInstance().registerViewTool(config, handler);
|
|
265
|
+
};
|
|
266
|
+
subscribeToViewUUID() {
|
|
267
|
+
const bridge = McpAppBridge.getInstance();
|
|
268
|
+
bridge.subscribe("toolResult")(() => {
|
|
269
|
+
const toolResult = bridge.getSnapshot("toolResult");
|
|
270
|
+
const viewUUID = toolResult?._meta?.viewUUID;
|
|
271
|
+
if (viewUUID && viewUUID !== this._viewUUID) {
|
|
272
|
+
this._viewUUID = viewUUID;
|
|
273
|
+
this.restoreFromLocalStorage(viewUUID);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
// localStorage keys: sb:{unix_ms}:{viewUUID}
|
|
278
|
+
// Timestamp is updated on every write (LRU); eviction drops the least recently used entries.
|
|
279
|
+
restoreFromLocalStorage(viewUUID) {
|
|
280
|
+
try {
|
|
281
|
+
const existingKey = findStorageKey(viewUUID);
|
|
282
|
+
if (existingKey) {
|
|
283
|
+
const stored = localStorage.getItem(existingKey);
|
|
284
|
+
if (stored !== null) {
|
|
285
|
+
this._viewState = JSON.parse(stored);
|
|
286
|
+
this.viewStateListeners.forEach((listener) => {
|
|
287
|
+
listener();
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
console.error(err);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
persistToLocalStorage(state) {
|
|
297
|
+
if (!this._viewUUID || state === null) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
// Remove old key for this view, write with fresh timestamp (LRU)
|
|
302
|
+
const oldKey = findStorageKey(this._viewUUID);
|
|
303
|
+
if (oldKey) {
|
|
304
|
+
localStorage.removeItem(oldKey);
|
|
305
|
+
}
|
|
306
|
+
const newKey = `${STORAGE_PREFIX}${Date.now()}:${this._viewUUID}`;
|
|
307
|
+
localStorage.setItem(newKey, JSON.stringify(state));
|
|
308
|
+
// lru cleanup
|
|
309
|
+
const keys = [];
|
|
310
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
311
|
+
const key = localStorage.key(i);
|
|
312
|
+
if (key?.startsWith(STORAGE_PREFIX)) {
|
|
313
|
+
keys.push(key);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (keys.length <= MAX_STORAGE_ENTRIES) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
keys.sort();
|
|
320
|
+
const toRemove = keys.slice(0, keys.length - MAX_STORAGE_ENTRIES);
|
|
321
|
+
for (const key of toRemove) {
|
|
322
|
+
localStorage.removeItem(key);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
console.error(err);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
createHostContextStore(keys, computeSnapshot) {
|
|
330
|
+
const bridge = McpAppBridge.getInstance();
|
|
331
|
+
let cachedValue;
|
|
332
|
+
return {
|
|
333
|
+
subscribe: bridge.subscribe(keys),
|
|
334
|
+
getSnapshot: () => {
|
|
335
|
+
const context = Object.fromEntries(keys.map((k) => [k, bridge.getSnapshot(k)]));
|
|
336
|
+
const newValue = computeSnapshot(context);
|
|
337
|
+
if (cachedValue !== undefined && dequal(cachedValue, newValue)) {
|
|
338
|
+
return cachedValue;
|
|
339
|
+
}
|
|
340
|
+
cachedValue = newValue;
|
|
341
|
+
return newValue;
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=adaptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/adaptor.ts"],"names":[],"mappings":"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","sourcesContent":["import { dequal } from \"dequal/lite\";\nimport type {\n Adaptor,\n AnyViewToolHandler,\n CallToolResponse,\n DownloadParams,\n DownloadResult,\n HostContext,\n HostContextStore,\n Intent,\n Notification,\n OpenExternalOptions,\n RequestDisplayMode,\n RequestModalOptions,\n RequestSizeOptions,\n SendFollowUpMessageOptions,\n SetViewStateAction,\n ViewToolConfig,\n} from \"../types.js\";\nimport { McpAppBridge } from \"./bridge.js\";\nimport type { McpAppContext, McpAppContextKey } from \"./types.js\";\n\n/** @internal */\ntype PickContext<K extends readonly McpAppContextKey[]> = {\n [P in K[number]]: McpAppContext[P];\n};\n\nconst STORAGE_PREFIX = \"sb:\";\nconst MAX_STORAGE_ENTRIES = 200;\n\nfunction findStorageKey(viewUUID: string): string | undefined {\n const suffix = `:${viewUUID}`;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX) && key.endsWith(suffix)) {\n return key;\n }\n }\n return undefined;\n}\n\n/** @internal MCP Apps implementation of {@link Adaptor}. Resolved via {@link getAdaptor}. */\nexport class McpAppAdaptor implements Adaptor {\n private static instance: McpAppAdaptor | null = null;\n private stores: {\n [K in keyof HostContext]: HostContextStore<K>;\n };\n private _viewState: HostContext[\"viewState\"] = null;\n private viewStateListeners = new Set<() => void>();\n private _viewUUID: string | null = null;\n\n private _displayState: HostContext[\"display\"] = {\n mode: \"inline\",\n };\n private displayListeners = new Set<() => void>();\n\n private constructor() {\n this.stores = this.initializeStores();\n this.subscribeToViewUUID();\n }\n\n public static getInstance(): McpAppAdaptor {\n if (!McpAppAdaptor.instance) {\n McpAppAdaptor.instance = new McpAppAdaptor();\n }\n return McpAppAdaptor.instance;\n }\n\n public static resetInstance(): void {\n McpAppAdaptor.instance = null;\n }\n\n public getHostContextStore<K extends keyof HostContext>(\n key: K,\n ): HostContextStore<K> {\n return this.stores[key];\n }\n\n public callTool = async <\n ToolArgs extends Record<string, unknown> | null = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n ): Promise<ToolResponse> => {\n const app = await McpAppBridge.getInstance().getApp();\n const response = await app.callServerTool({\n name,\n arguments: args ?? undefined,\n });\n\n return {\n content: response.content,\n structuredContent: response.structuredContent ?? {},\n isError: response.isError ?? false,\n meta: response._meta ?? {},\n } as ToolResponse;\n };\n\n public requestDisplayMode = async (mode: RequestDisplayMode) => {\n const app = await McpAppBridge.getInstance().getApp();\n return app.requestDisplayMode({ mode });\n };\n\n public requestClose = async (): Promise<void> => {\n const app = await McpAppBridge.getInstance().getApp();\n await app.requestTeardown();\n };\n\n public requestSize = async (size: RequestSizeOptions): Promise<void> => {\n const app = await McpAppBridge.getInstance().getApp();\n await app.sendSizeChanged(size);\n };\n\n public sendFollowUpMessage = async (\n prompt: string,\n _options?: SendFollowUpMessageOptions,\n ) => {\n const app = await McpAppBridge.getInstance().getApp();\n await app.sendMessage({\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: prompt,\n },\n ],\n });\n };\n\n /**\n * Surface a notification to the host via the MCP Apps logging channel.\n *\n * Uses the **real** MCP protocol: `app.sendLog` (`notifications/message`).\n * The `level` maps to the syslog levels the spec defines; `\"success\"` has no\n * equivalent and is coerced to `\"info\"` (the structured `title`/`data` are\n * preserved in the log payload). Hosts may render this as a toast or simply\n * record it for debugging. Best-effort — failures are swallowed; never throws.\n *\n * @remarks Per-runtime: apps-sdk surfaces the same call via\n * `window.openai.notify` / a `postMessage` fallback (see the apps-sdk\n * adaptor); the MCP Apps runtime uses standard `notifications/message`.\n */\n public notify = async (notification: Notification): Promise<void> => {\n try {\n const app = await McpAppBridge.getInstance().getApp();\n const level =\n notification.level === \"success\" ? \"info\" : notification.level;\n await app.sendLog({\n level: level ?? \"info\",\n logger: \"enpilink\",\n data: {\n ...(notification.title ? { title: notification.title } : {}),\n message: notification.message,\n ...(notification.level ? { level: notification.level } : {}),\n ...(notification.data !== undefined\n ? { data: notification.data }\n : {}),\n },\n });\n } catch (error) {\n console.warn(\"[enpilink] notify: failed to deliver notification\", error);\n }\n };\n\n /**\n * Forward a high-level intent to the host.\n *\n * The MCP Apps spec has **no intent/action primitive**, so this is an\n * **enpilink extension**: the intent is delivered best-effort over the\n * standard `notifications/message` channel (`app.sendLog`) tagged with\n * `logger: \"enpilink/intent\"` and a structured `{ intent, params }` payload.\n * A compliant host that doesn't understand intents simply records it as a\n * log entry (no error). Never throws.\n *\n * @remarks enpilink extension — not part of the MCP Apps spec. Real-host\n * routing of intents is therefore best-effort and unverifiable here.\n */\n public sendIntent = async (intent: Intent): Promise<void> => {\n try {\n const app = await McpAppBridge.getInstance().getApp();\n await app.sendLog({\n level: \"info\",\n logger: \"enpilink/intent\",\n data: {\n intent: intent.name,\n ...(intent.params ? { params: intent.params } : {}),\n },\n });\n } catch (error) {\n console.warn(\"[enpilink] sendIntent: failed to deliver intent\", error);\n }\n };\n\n public download = async (params: DownloadParams): Promise<DownloadResult> => {\n const app = await McpAppBridge.getInstance().getApp();\n if (!app.getHostCapabilities()?.downloadFile) {\n console.error(\n \"[enpilink] download: host does not support ui/download-file\",\n );\n return { isError: true };\n }\n return app.downloadFile(params);\n };\n\n public openExternal(href: string, options?: OpenExternalOptions): void {\n if (options?.redirectUrl === false) {\n console.warn(\n \"[enpilink] redirectUrl option is not supported by the MCP ui/open-link protocol and will be ignored.\",\n );\n }\n\n McpAppBridge.getInstance()\n .getApp()\n .then((app) => app.openLink({ url: href }))\n .catch((err) => {\n console.error(\"Failed to open external link:\", err);\n });\n }\n\n private initializeStores(): {\n [K in keyof HostContext]: HostContextStore<K>;\n } {\n return {\n theme: this.createHostContextStore(\n [\"theme\"],\n ({ theme }) => theme ?? \"light\",\n ),\n locale: this.createHostContextStore(\n [\"locale\"],\n ({ locale }) => locale ?? \"en-US\",\n ),\n safeArea: this.createHostContextStore(\n [\"safeAreaInsets\"],\n ({ safeAreaInsets }) => ({\n insets: safeAreaInsets ?? { top: 0, right: 0, bottom: 0, left: 0 },\n }),\n ),\n displayMode: this.createHostContextStore(\n [\"displayMode\"],\n ({ displayMode }) => displayMode ?? \"inline\",\n ),\n maxHeight: this.createHostContextStore(\n [\"containerDimensions\"],\n ({ containerDimensions }) => {\n if (containerDimensions && \"maxHeight\" in containerDimensions) {\n return containerDimensions.maxHeight;\n }\n\n return undefined;\n },\n ),\n userAgent: this.createHostContextStore(\n [\"platform\", \"deviceCapabilities\"],\n ({ platform, deviceCapabilities }) => ({\n device: {\n type: platform === \"web\" ? \"desktop\" : (platform ?? \"unknown\"),\n },\n capabilities: {\n hover: true,\n touch: true,\n ...deviceCapabilities,\n },\n }),\n ),\n toolInput: this.createHostContextStore(\n [\"toolInput\"],\n ({ toolInput }) => toolInput ?? null,\n ),\n toolOutput: this.createHostContextStore(\n [\"toolResult\"],\n ({ toolResult }) => toolResult?.structuredContent ?? null,\n ),\n toolResponseMetadata: this.createHostContextStore(\n [\"toolResult\"],\n ({ toolResult }) => toolResult?._meta ?? null,\n ),\n display: {\n subscribe: (onChange: () => void) => {\n this.displayListeners.add(onChange);\n return () => {\n this.displayListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._displayState,\n },\n viewState: {\n subscribe: (onChange: () => void) => {\n this.viewStateListeners.add(onChange);\n return () => {\n this.viewStateListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._viewState,\n },\n };\n }\n\n public setViewState = async (\n stateOrUpdater: SetViewStateAction,\n ): Promise<void> => {\n const newState =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this._viewState)\n : stateOrUpdater;\n\n // must happen before the async bridge call to ensure the state is updated immediately for the UI,\n // otherwise successive calls to setViewState may have stale state\n this._viewState = newState;\n this.viewStateListeners.forEach((listener) => {\n listener();\n });\n\n this.persistToLocalStorage(newState);\n\n try {\n const app = await McpAppBridge.getInstance().getApp();\n await app.updateModelContext({\n structuredContent: newState,\n content: [{ type: \"text\", text: JSON.stringify(newState) }],\n });\n } catch (error) {\n console.error(\"Failed to update view state in MCP App.\", error);\n }\n };\n\n /**\n * @throws File upload is not supported in MCP App.\n */\n public uploadFile(): Promise<{ fileId: string }> {\n throw new Error(\"File upload is not supported in MCP App.\");\n }\n\n /**\n * @throws File download is not supported in MCP App.\n */\n public getFileDownloadUrl(): Promise<{ downloadUrl: string }> {\n throw new Error(\"File download is not supported in MCP App.\");\n }\n\n /**\n * @throws File selection is not supported in MCP App.\n */\n public selectFiles(): Promise<{ fileId: string }[]> {\n throw new Error(\"File selection is not supported in MCP App.\");\n }\n\n public openModal(options: RequestModalOptions) {\n this._displayState = { mode: \"modal\", params: options.params };\n this.displayListeners.forEach((listener) => {\n listener();\n });\n }\n\n public closeModal() {\n this._displayState = { mode: \"inline\" };\n this.displayListeners.forEach((listener) => {\n listener();\n });\n }\n\n public setOpenInAppUrl(_href: string): Promise<void> {\n throw new Error(\"setOpenInAppUrl is not implemented in MCP App.\");\n }\n\n public registerViewTool = (\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): (() => void) => {\n return McpAppBridge.getInstance().registerViewTool(config, handler);\n };\n\n private subscribeToViewUUID(): void {\n const bridge = McpAppBridge.getInstance();\n bridge.subscribe(\"toolResult\")(() => {\n const toolResult = bridge.getSnapshot(\"toolResult\");\n const viewUUID = (\n toolResult?._meta as Record<string, unknown> | undefined\n )?.viewUUID as string | undefined;\n\n if (viewUUID && viewUUID !== this._viewUUID) {\n this._viewUUID = viewUUID;\n this.restoreFromLocalStorage(viewUUID);\n }\n });\n }\n\n // localStorage keys: sb:{unix_ms}:{viewUUID}\n // Timestamp is updated on every write (LRU); eviction drops the least recently used entries.\n private restoreFromLocalStorage(viewUUID: string): void {\n try {\n const existingKey = findStorageKey(viewUUID);\n if (existingKey) {\n const stored = localStorage.getItem(existingKey);\n if (stored !== null) {\n this._viewState = JSON.parse(stored);\n this.viewStateListeners.forEach((listener) => {\n listener();\n });\n }\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n private persistToLocalStorage(state: Record<string, unknown> | null): void {\n if (!this._viewUUID || state === null) {\n return;\n }\n try {\n // Remove old key for this view, write with fresh timestamp (LRU)\n const oldKey = findStorageKey(this._viewUUID);\n if (oldKey) {\n localStorage.removeItem(oldKey);\n }\n const newKey = `${STORAGE_PREFIX}${Date.now()}:${this._viewUUID}`;\n localStorage.setItem(newKey, JSON.stringify(state));\n\n // lru cleanup\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX)) {\n keys.push(key);\n }\n }\n if (keys.length <= MAX_STORAGE_ENTRIES) {\n return;\n }\n keys.sort();\n const toRemove = keys.slice(0, keys.length - MAX_STORAGE_ENTRIES);\n for (const key of toRemove) {\n localStorage.removeItem(key);\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n private createHostContextStore<\n const Keys extends readonly McpAppContextKey[],\n R,\n >(keys: Keys, computeSnapshot: (context: PickContext<Keys>) => R) {\n const bridge = McpAppBridge.getInstance();\n let cachedValue: R | undefined;\n\n return {\n subscribe: bridge.subscribe(keys),\n getSnapshot: () => {\n const context = Object.fromEntries(\n keys.map((k) => [k, bridge.getSnapshot(k)]),\n ) as PickContext<Keys>;\n const newValue = computeSnapshot(context);\n\n if (cachedValue !== undefined && dequal(cachedValue, newValue)) {\n return cachedValue;\n }\n\n cachedValue = newValue;\n return newValue;\n },\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { App } from "@modelcontextprotocol/ext-apps";
|
|
2
|
+
import { type Implementation } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { AnyViewToolHandler, Bridge, Subscribe, ViewToolConfig } from "../types.js";
|
|
4
|
+
import type { McpAppContext, McpAppContextKey } from "./types.js";
|
|
5
|
+
/** @internal Singleton bridge over the `ext-apps` JSON-RPC App connection. Used by {@link McpAppAdaptor}. */
|
|
6
|
+
export declare class McpAppBridge implements Bridge<McpAppContext> {
|
|
7
|
+
private static instance;
|
|
8
|
+
context: McpAppContext;
|
|
9
|
+
private listeners;
|
|
10
|
+
private app;
|
|
11
|
+
private connectPromise;
|
|
12
|
+
constructor(options: {
|
|
13
|
+
appInfo: Implementation;
|
|
14
|
+
});
|
|
15
|
+
private connect;
|
|
16
|
+
getApp(): Promise<App>;
|
|
17
|
+
registerViewTool(config: ViewToolConfig, handler: AnyViewToolHandler): () => void;
|
|
18
|
+
static getInstance(options?: Partial<{
|
|
19
|
+
appInfo: Implementation;
|
|
20
|
+
}>): McpAppBridge;
|
|
21
|
+
subscribe(key: McpAppContextKey): Subscribe;
|
|
22
|
+
subscribe(keys: readonly McpAppContextKey[]): Subscribe;
|
|
23
|
+
getSnapshot<K extends keyof McpAppContext>(key: K): McpAppContext[K];
|
|
24
|
+
cleanup: () => void;
|
|
25
|
+
static resetInstance(): void;
|
|
26
|
+
private emit;
|
|
27
|
+
private updateContext;
|
|
28
|
+
}
|