skybridge 0.0.0-dev.a664594 → 0.0.0-dev.a6e5f63
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/README.md +2 -0
- package/dist/cli/build-helpers.d.ts +11 -0
- package/dist/cli/build-helpers.js +107 -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 +130 -0
- package/dist/cli/build-helpers.test.js.map +1 -0
- package/dist/cli/build-steps.d.ts +2 -0
- package/dist/cli/build-steps.js +73 -0
- package/dist/cli/build-steps.js.map +1 -0
- package/dist/cli/build-steps.test.d.ts +1 -0
- package/dist/cli/build-steps.test.js +52 -0
- package/dist/cli/build-steps.test.js.map +1 -0
- package/dist/cli/detect-port.d.ts +2 -2
- package/dist/cli/detect-port.js +9 -20
- package/dist/cli/detect-port.js.map +1 -1
- package/dist/cli/header.d.ts +1 -1
- package/dist/cli/resolve-skybridge-config.d.ts +5 -0
- package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
- package/dist/cli/resolve-skybridge-config.js.map +1 -0
- package/dist/cli/run-plain.d.ts +18 -0
- package/dist/cli/run-plain.js +89 -0
- package/dist/cli/run-plain.js.map +1 -0
- package/dist/cli/use-nodemon.d.ts +14 -0
- package/dist/cli/use-nodemon.js +71 -60
- package/dist/cli/use-nodemon.js.map +1 -1
- package/dist/cli/use-typescript-check.d.ts +8 -2
- package/dist/cli/use-typescript-check.js +70 -67
- package/dist/cli/use-typescript-check.js.map +1 -1
- package/dist/commands/build.d.ts +0 -3
- package/dist/commands/build.js +2 -58
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +34 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/start.js +7 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/server/auth/discovery.d.ts +32 -0
- package/dist/server/auth/discovery.js +56 -0
- package/dist/server/auth/discovery.js.map +1 -0
- package/dist/server/auth/discovery.test.d.ts +1 -0
- package/dist/server/auth/discovery.test.js +93 -0
- package/dist/server/auth/discovery.test.js.map +1 -0
- package/dist/server/auth/index.d.ts +18 -0
- package/dist/server/auth/index.js +2 -0
- package/dist/server/auth/index.js.map +1 -0
- package/dist/server/auth/providers/auth0.d.ts +18 -0
- package/dist/server/auth/providers/auth0.js +31 -0
- package/dist/server/auth/providers/auth0.js.map +1 -0
- package/dist/server/auth/providers/auth0.test.d.ts +1 -0
- package/dist/server/auth/providers/auth0.test.js +48 -0
- package/dist/server/auth/providers/auth0.test.js.map +1 -0
- package/dist/server/auth/providers/authplane.d.ts +47 -0
- package/dist/server/auth/providers/authplane.js +57 -0
- package/dist/server/auth/providers/authplane.js.map +1 -0
- package/dist/server/auth/providers/authplane.test.d.ts +1 -0
- package/dist/server/auth/providers/authplane.test.js +138 -0
- package/dist/server/auth/providers/authplane.test.js.map +1 -0
- package/dist/server/auth/providers/clerk.d.ts +14 -0
- package/dist/server/auth/providers/clerk.js +16 -0
- package/dist/server/auth/providers/clerk.js.map +1 -0
- package/dist/server/auth/providers/clerk.test.d.ts +1 -0
- package/dist/server/auth/providers/clerk.test.js +28 -0
- package/dist/server/auth/providers/clerk.test.js.map +1 -0
- package/dist/server/auth/providers/custom.d.ts +32 -0
- package/dist/server/auth/providers/custom.js +49 -0
- package/dist/server/auth/providers/custom.js.map +1 -0
- package/dist/server/auth/providers/custom.test.d.ts +1 -0
- package/dist/server/auth/providers/custom.test.js +156 -0
- package/dist/server/auth/providers/custom.test.js.map +1 -0
- package/dist/server/auth/providers/descope.d.ts +15 -0
- package/dist/server/auth/providers/descope.js +44 -0
- package/dist/server/auth/providers/descope.js.map +1 -0
- package/dist/server/auth/providers/descope.test.d.ts +1 -0
- package/dist/server/auth/providers/descope.test.js +60 -0
- package/dist/server/auth/providers/descope.test.js.map +1 -0
- package/dist/server/auth/providers/shared.d.ts +2 -0
- package/dist/server/auth/providers/shared.js +6 -0
- package/dist/server/auth/providers/shared.js.map +1 -0
- package/dist/server/auth/providers/shared.test.d.ts +1 -0
- package/dist/server/auth/providers/shared.test.js +10 -0
- package/dist/server/auth/providers/shared.test.js.map +1 -0
- package/dist/server/auth/providers/stytch.d.ts +12 -0
- package/dist/server/auth/providers/stytch.js +13 -0
- package/dist/server/auth/providers/stytch.js.map +1 -0
- package/dist/server/auth/providers/workos.d.ts +11 -0
- package/dist/server/auth/providers/workos.js +12 -0
- package/dist/server/auth/providers/workos.js.map +1 -0
- package/dist/server/auth/security-schemes.d.ts +23 -0
- package/dist/server/auth/security-schemes.js +64 -0
- package/dist/server/auth/security-schemes.js.map +1 -0
- package/dist/server/auth/security-schemes.test.d.ts +1 -0
- package/dist/server/auth/security-schemes.test.js +99 -0
- package/dist/server/auth/security-schemes.test.js.map +1 -0
- package/dist/server/auth/setup.d.ts +6 -0
- package/dist/server/auth/setup.js +92 -0
- package/dist/server/auth/setup.js.map +1 -0
- package/dist/server/auth/setup.test.d.ts +1 -0
- package/dist/server/auth/setup.test.js +474 -0
- package/dist/server/auth/setup.test.js.map +1 -0
- package/dist/server/auth/verify.d.ts +12 -0
- package/dist/server/auth/verify.js +38 -0
- package/dist/server/auth/verify.js.map +1 -0
- package/dist/server/auth/verify.test.d.ts +1 -0
- package/dist/server/auth/verify.test.js +100 -0
- package/dist/server/auth/verify.test.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/express.test.js +61 -0
- package/dist/server/express.test.js.map +1 -1
- package/dist/server/host.d.ts +2 -0
- package/dist/server/host.js +11 -0
- package/dist/server/host.js.map +1 -0
- package/dist/server/host.test.d.ts +1 -0
- package/dist/server/host.test.js +13 -0
- package/dist/server/host.test.js.map +1 -0
- package/dist/server/index.d.ts +11 -2
- package/dist/server/index.js +9 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/requestOrigin.d.ts +7 -0
- package/dist/server/requestOrigin.js +25 -0
- package/dist/server/requestOrigin.js.map +1 -0
- package/dist/server/server.d.ts +96 -39
- package/dist/server/server.js +310 -140
- package/dist/server/server.js.map +1 -1
- package/dist/server/skills-integration.test.d.ts +1 -0
- package/dist/server/skills-integration.test.js +63 -0
- package/dist/server/skills-integration.test.js.map +1 -0
- package/dist/server/skills.d.ts +23 -0
- package/dist/server/skills.js +178 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/skills.test.d.ts +1 -0
- package/dist/server/skills.test.js +210 -0
- package/dist/server/skills.test.js.map +1 -0
- package/dist/server/view-name.test-d.d.ts +1 -0
- package/dist/server/view-name.test-d.js +8 -0
- package/dist/server/view-name.test-d.js.map +1 -0
- package/dist/server/view-resource-resolution.test.d.ts +6 -0
- package/dist/server/view-resource-resolution.test.js +171 -0
- package/dist/server/view-resource-resolution.test.js.map +1 -0
- package/dist/server/viewsDevServer.js +4 -1
- package/dist/server/viewsDevServer.js.map +1 -1
- package/dist/test/view.test.js +70 -102
- package/dist/test/view.test.js.map +1 -1
- package/dist/web/bridges/adaptor.d.ts +9 -6
- package/dist/web/bridges/adaptor.js +107 -74
- package/dist/web/bridges/adaptor.js.map +1 -1
- package/dist/web/bridges/adaptor.test.js +93 -244
- package/dist/web/bridges/adaptor.test.js.map +1 -1
- package/dist/web/bridges/apps-sdk/bridge.d.ts +5 -1
- package/dist/web/bridges/apps-sdk/bridge.js +12 -0
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
- package/dist/web/bridges/get-adaptor.d.ts +0 -2
- package/dist/web/bridges/get-adaptor.js +1 -21
- package/dist/web/bridges/get-adaptor.js.map +1 -1
- package/dist/web/bridges/get-adaptor.test.js +3 -19
- package/dist/web/bridges/get-adaptor.test.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.d.ts +14 -2
- package/dist/web/bridges/mcp-app/bridge.js +72 -4
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.test.js +1 -5
- package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
- package/dist/web/bridges/mcp-app/types.d.ts +2 -0
- package/dist/web/bridges/mcp-app/types.js.map +1 -1
- package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
- package/dist/web/bridges/types.d.ts +34 -6
- package/dist/web/bridges/types.js.map +1 -1
- package/dist/web/components/modal-provider.d.ts +1 -1
- package/dist/web/create-store.test.js +4 -3
- package/dist/web/create-store.test.js.map +1 -1
- package/dist/web/data-llm.d.ts +1 -1
- package/dist/web/data-llm.test.js +12 -3
- package/dist/web/data-llm.test.js.map +1 -1
- package/dist/web/generate-helpers.test-d.js +4 -2
- package/dist/web/generate-helpers.test-d.js.map +1 -1
- package/dist/web/hooks/index.d.ts +2 -0
- package/dist/web/hooks/index.js +2 -0
- package/dist/web/hooks/index.js.map +1 -1
- package/dist/web/hooks/test/utils.d.ts +2 -1
- package/dist/web/hooks/test/utils.js +1 -1
- package/dist/web/hooks/test/utils.js.map +1 -1
- package/dist/web/hooks/use-call-tool.test.js +6 -5
- package/dist/web/hooks/use-call-tool.test.js.map +1 -1
- package/dist/web/hooks/use-display-mode.test.js +4 -3
- package/dist/web/hooks/use-display-mode.test.js.map +1 -1
- package/dist/web/hooks/use-download.test.js +5 -5
- package/dist/web/hooks/use-download.test.js.map +1 -1
- package/dist/web/hooks/use-files.test.js +3 -3
- package/dist/web/hooks/use-files.test.js.map +1 -1
- package/dist/web/hooks/use-host-info.d.ts +22 -0
- package/dist/web/hooks/use-host-info.js +30 -0
- package/dist/web/hooks/use-host-info.js.map +1 -0
- package/dist/web/hooks/use-host-info.test.d.ts +1 -0
- package/dist/web/hooks/use-host-info.test.js +59 -0
- package/dist/web/hooks/use-host-info.test.js.map +1 -0
- package/dist/web/hooks/use-layout.test.js +5 -5
- package/dist/web/hooks/use-layout.test.js.map +1 -1
- package/dist/web/hooks/use-open-external.test.js +7 -11
- package/dist/web/hooks/use-open-external.test.js.map +1 -1
- 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.test.js +5 -4
- package/dist/web/hooks/use-request-close.test.js.map +1 -1
- package/dist/web/hooks/use-request-modal.test.js +3 -3
- package/dist/web/hooks/use-request-modal.test.js.map +1 -1
- package/dist/web/hooks/use-request-size.test.js +3 -3
- package/dist/web/hooks/use-request-size.test.js.map +1 -1
- package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -2
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
- package/dist/web/hooks/use-tool-info.d.ts +25 -7
- package/dist/web/hooks/use-tool-info.js +5 -8
- package/dist/web/hooks/use-tool-info.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test-d.js +11 -29
- package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test.js +8 -8
- package/dist/web/hooks/use-tool-info.test.js.map +1 -1
- package/dist/web/hooks/use-user.test.js +5 -5
- package/dist/web/hooks/use-user.test.js.map +1 -1
- package/dist/web/hooks/use-view-state.js +19 -9
- package/dist/web/hooks/use-view-state.js.map +1 -1
- package/dist/web/hooks/use-view-state.test.js +34 -3
- package/dist/web/hooks/use-view-state.test.js.map +1 -1
- package/dist/web/plugin/plugin.d.ts +6 -0
- package/dist/web/plugin/plugin.js +3 -3
- package/dist/web/plugin/plugin.js.map +1 -1
- package/package.json +23 -19
- package/dist/cli/resolve-views-dir.d.ts +0 -1
- package/dist/cli/resolve-views-dir.js.map +0 -1
- package/dist/web/bridges/host-context-stores.d.ts +0 -27
- package/dist/web/bridges/host-context-stores.js +0 -73
- package/dist/web/bridges/host-context-stores.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-open-external.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use-open-external.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-open-external.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,IAAI,gBAA0C,CAAC;QAC/C,IAAI,eAAgE,CAAC;QAErE,UAAU,CAAC,GAAG,EAAE;YACd,gBAAgB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;gBACtB,YAAY,EAAE,gBAAgB;aAC/B,CAAC,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;YACrD,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;YACpD,eAAe,GAAG,4BAA4B,EAAE,CAAC;YACjD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,GAAG,EAAE;YACb,WAAW,CAAC,aAAa,EAAE,CAAC;YAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;YAC7B,EAAE,CAAC,gBAAgB,EAAE,CAAC;YACtB,EAAE,CAAC,aAAa,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;YAClF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,MAAM,IAAI,GAAG,qBAAqB,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAErB,MAAM,CAAC,gBAAgB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAC9C,MAAM,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,EACnD,GAAG,CACJ,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;YAC1E,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,MAAM,IAAI,GAAG,qBAAqB,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;YAE7C,MAAM,CAAC,gBAAgB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC;gBAC5C,IAAI;gBACJ,WAAW,EAAE,KAAK;aACnB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,IAAI,eAAgE,CAAC;QAErE,UAAU,CAAC,GAAG,EAAE;YACd,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACnC,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YACpD,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;YACpD,eAAe,GAAG,4BAA4B,EAAE,CAAC;YACjD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,KAAK,IAAI,EAAE;YACnB,WAAW,CAAC,aAAa,EAAE,CAAC;YAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;YAC7B,EAAE,CAAC,gBAAgB,EAAE,CAAC;YACtB,EAAE,CAAC,aAAa,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;YACxF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,MAAM,IAAI,GAAG,qBAAqB,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;YAE7C,MAAM,OAAO,CAAC,GAAG,EAAE;gBACjB,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAC1C,MAAM,CAAC,gBAAgB,CAAC;oBACtB,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,cAAc;oBACtB,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE;iBACtB,CAAC,EACF,GAAG,CACJ,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\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 let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n openExternalMock = vi.fn();\n vi.stubGlobal(\"openai\", {\n openExternal: openExternalMock,\n });\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n });\n\n it(\"should call window.openai.openExternal even without a redirectUrl option\", () => {\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 expect(postMessageMock).not.toHaveBeenCalledWith(\n expect.objectContaining({ method: \"ui/open-link\" }),\n \"*\",\n );\n });\n\n it(\"should call window.openai.openExternal when redirectUrl is false\", () => {\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(\"openai\", undefined);\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n postMessageMock = getMcpAppHostPostMessageMock();\n vi.stubGlobal(\"parent\", { postMessage: postMessageMock });\n });\n\n afterEach(async () => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.unstubAllGlobals();\n vi.resetAllMocks();\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 "skybridge/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.skybridge.tech/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 "skybridge/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.skybridge.tech/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 \"skybridge/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.skybridge.tech/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"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { act, renderHook } from "@testing-library/react";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import {
|
|
3
|
+
import { HostAdaptor } from "../bridges/adaptor.js";
|
|
4
|
+
import { getAdaptor } from "../bridges/get-adaptor.js";
|
|
4
5
|
import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
|
|
5
6
|
import { useRequestClose } from "./use-request-close.js";
|
|
6
7
|
describe("useRequestClose", () => {
|
|
7
8
|
beforeEach(() => {
|
|
8
|
-
|
|
9
|
+
HostAdaptor.resetInstance();
|
|
9
10
|
McpAppBridge.resetInstance();
|
|
10
11
|
vi.stubGlobal("skybridge", { hostType: "mcp-app" });
|
|
11
12
|
vi.stubGlobal("openai", undefined);
|
|
@@ -14,7 +15,7 @@ describe("useRequestClose", () => {
|
|
|
14
15
|
afterEach(() => {
|
|
15
16
|
vi.unstubAllGlobals();
|
|
16
17
|
vi.resetAllMocks();
|
|
17
|
-
|
|
18
|
+
HostAdaptor.resetInstance();
|
|
18
19
|
McpAppBridge.resetInstance();
|
|
19
20
|
});
|
|
20
21
|
it("calls app.requestTeardown via the MCP path", async () => {
|
|
@@ -30,7 +31,7 @@ describe("useRequestClose", () => {
|
|
|
30
31
|
});
|
|
31
32
|
it("calls app.requestTeardown even when window.openai is present", async () => {
|
|
32
33
|
vi.stubGlobal("openai", { requestClose: vi.fn() });
|
|
33
|
-
|
|
34
|
+
HostAdaptor.resetInstance();
|
|
34
35
|
McpAppBridge.resetInstance();
|
|
35
36
|
const requestTeardown = vi.fn().mockResolvedValue(undefined);
|
|
36
37
|
// biome-ignore lint/suspicious/noExplicitAny: test seam
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-request-close.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-close.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use-request-close.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-close.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { act, renderHook } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { getAdaptor } from \"../bridges/get-adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport { useRequestClose } from \"./use-request-close.js\";\n\ndescribe(\"useRequestClose\", () => {\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n it(\"calls app.requestTeardown via the MCP path\", async () => {\n const requestTeardown = vi.fn().mockResolvedValue(undefined);\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n const adaptor = getAdaptor() as any;\n adaptor.mcp.getApp = vi.fn().mockResolvedValue({ requestTeardown });\n\n const { result } = renderHook(() => useRequestClose());\n await act(async () => {\n await result.current();\n });\n\n expect(requestTeardown).toHaveBeenCalledTimes(1);\n });\n\n it(\"calls app.requestTeardown even when window.openai is present\", async () => {\n vi.stubGlobal(\"openai\", { requestClose: vi.fn() });\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n\n const requestTeardown = vi.fn().mockResolvedValue(undefined);\n // biome-ignore lint/suspicious/noExplicitAny: test seam\n const adaptor = getAdaptor() as any;\n adaptor.mcp.getApp = vi.fn().mockResolvedValue({ requestTeardown });\n\n const { result } = renderHook(() => useRequestClose());\n await act(async () => {\n await result.current();\n });\n\n expect(requestTeardown).toHaveBeenCalledTimes(1);\n });\n});\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { renderHook } from "@testing-library/react";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { HostAdaptor } from "../bridges/adaptor.js";
|
|
3
4
|
import { AppsSdkBridge } from "../bridges/apps-sdk/bridge.js";
|
|
4
|
-
import { _resetAdaptor } from "../bridges/get-adaptor.js";
|
|
5
5
|
import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
|
|
6
6
|
import { useRequestModal } from "./use-request-modal.js";
|
|
7
7
|
describe("useRequestModal", () => {
|
|
8
8
|
let requestModalMock;
|
|
9
9
|
beforeEach(() => {
|
|
10
|
-
|
|
10
|
+
HostAdaptor.resetInstance();
|
|
11
11
|
McpAppBridge.resetInstance();
|
|
12
12
|
AppsSdkBridge.resetInstance();
|
|
13
13
|
requestModalMock = vi.fn();
|
|
@@ -21,7 +21,7 @@ describe("useRequestModal", () => {
|
|
|
21
21
|
afterEach(() => {
|
|
22
22
|
vi.unstubAllGlobals();
|
|
23
23
|
vi.resetAllMocks();
|
|
24
|
-
|
|
24
|
+
HostAdaptor.resetInstance();
|
|
25
25
|
McpAppBridge.resetInstance();
|
|
26
26
|
AppsSdkBridge.resetInstance();
|
|
27
27
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-request-modal.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-modal.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use-request-modal.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-modal.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { AppsSdkBridge } from \"../bridges/apps-sdk/bridge.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport { useRequestModal } from \"./use-request-modal.js\";\n\ndescribe(\"useRequestModal\", () => {\n let requestModalMock: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n requestModalMock = vi.fn();\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n vi.stubGlobal(\"openai\", {\n requestModal: requestModalMock,\n view: { mode: \"inline\" },\n });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"should return an object with open, isOpen, and params properties where isOpen is false when mode is not modal\", () => {\n const { result } = renderHook(() => useRequestModal());\n\n expect(typeof result.current).toBe(\"object\");\n expect(result.current).toHaveProperty(\"open\");\n expect(result.current).toHaveProperty(\"isOpen\");\n expect(result.current).toHaveProperty(\"params\");\n\n const { open, isOpen, params } = result.current;\n expect(typeof open).toBe(\"function\");\n expect(isOpen).toBe(false);\n expect(params).toBeUndefined();\n });\n\n it(\"should return isOpen as true when mode is modal\", () => {\n vi.stubGlobal(\"openai\", {\n requestModal: requestModalMock,\n view: { mode: \"modal\" },\n });\n\n const { result } = renderHook(() => useRequestModal());\n const { isOpen } = result.current;\n\n expect(isOpen).toBe(true);\n });\n\n it(\"should return params from view when available\", () => {\n const testParams = { foo: \"bar\", baz: 42 };\n vi.stubGlobal(\"openai\", {\n requestModal: requestModalMock,\n view: { mode: \"modal\", params: testParams },\n });\n\n const { result } = renderHook(() => useRequestModal());\n const { params } = result.current;\n\n expect(params).toEqual(testParams);\n });\n\n it(\"should call window.openai.requestModal with the options when open is called\", () => {\n const { result } = renderHook(() => useRequestModal());\n const { open } = result.current;\n\n const options = {\n title: \"Test Modal\",\n params: { foo: \"bar\" },\n template: \"ui://view/modal-template.html\",\n };\n open(options);\n\n expect(requestModalMock).toHaveBeenCalledTimes(1);\n expect(requestModalMock).toHaveBeenCalledWith(options);\n });\n});\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { renderHook, waitFor } from "@testing-library/react";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import {
|
|
3
|
+
import { HostAdaptor } from "../bridges/adaptor.js";
|
|
4
4
|
import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
|
|
5
5
|
import { getMcpAppHostPostMessageMock, MockResizeObserver, } from "./test/utils.js";
|
|
6
6
|
import { useRequestSize } from "./use-request-size.js";
|
|
7
7
|
describe("useRequestSize", () => {
|
|
8
8
|
let postMessageMock;
|
|
9
9
|
beforeEach(() => {
|
|
10
|
-
|
|
10
|
+
HostAdaptor.resetInstance();
|
|
11
11
|
McpAppBridge.resetInstance();
|
|
12
12
|
vi.stubGlobal("skybridge", { hostType: "mcp-app" });
|
|
13
13
|
vi.stubGlobal("openai", undefined);
|
|
@@ -18,7 +18,7 @@ describe("useRequestSize", () => {
|
|
|
18
18
|
afterEach(() => {
|
|
19
19
|
vi.unstubAllGlobals();
|
|
20
20
|
vi.resetAllMocks();
|
|
21
|
-
|
|
21
|
+
HostAdaptor.resetInstance();
|
|
22
22
|
McpAppBridge.resetInstance();
|
|
23
23
|
});
|
|
24
24
|
it("sends a ui/notifications/size-changed notification with width and height", async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-request-size.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-size.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use-request-size.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-request-size.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,eAAgE,CAAC;IAErE,UAAU,CAAC,GAAG,EAAE;QACd,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;QACpD,eAAe,GAAG,4BAA4B,EAAE,CAAC;QACjD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAEtD,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAElD,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAC1C,MAAM,CAAC,gBAAgB,CAAC;gBACtB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,+BAA+B;gBACvC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;aACpC,CAAC,EACF,GAAG,CACJ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAEtD,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAEtC,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAC1C,MAAM,CAAC,gBAAgB,CAAC;gBACtB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,+BAA+B;gBACvC,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;aACxB,CAAC,EACF,GAAG,CACJ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"./test/utils.js\";\nimport { useRequestSize } from \"./use-request-size.js\";\n\ndescribe(\"useRequestSize\", () => {\n let postMessageMock: ReturnType<typeof getMcpAppHostPostMessageMock>;\n\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"openai\", undefined);\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 HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n it(\"sends a ui/notifications/size-changed notification with width and height\", async () => {\n const { result } = renderHook(() => useRequestSize());\n\n await result.current({ width: 800, height: 400 });\n\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n jsonrpc: \"2.0\",\n method: \"ui/notifications/size-changed\",\n params: { width: 800, height: 400 },\n }),\n \"*\",\n );\n });\n });\n\n it(\"forwards height-only payloads as-is\", async () => {\n const { result } = renderHook(() => useRequestSize());\n\n await result.current({ height: 400 });\n\n await waitFor(() => {\n expect(postMessageMock).toHaveBeenCalledWith(\n expect.objectContaining({\n jsonrpc: \"2.0\",\n method: \"ui/notifications/size-changed\",\n params: { height: 400 },\n }),\n \"*\",\n );\n });\n });\n});\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { renderHook } from "@testing-library/react";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { HostAdaptor } from "../bridges/adaptor.js";
|
|
3
4
|
import { AppsSdkBridge } from "../bridges/apps-sdk/bridge.js";
|
|
4
|
-
import { _resetAdaptor } from "../bridges/get-adaptor.js";
|
|
5
5
|
import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
|
|
6
6
|
import { NotSupportedError } from "../bridges/types.js";
|
|
7
7
|
import { useSetOpenInAppUrl } from "./use-set-open-in-app-url.js";
|
|
@@ -9,7 +9,7 @@ describe("useSetOpenInAppUrl", () => {
|
|
|
9
9
|
afterEach(() => {
|
|
10
10
|
vi.unstubAllGlobals();
|
|
11
11
|
vi.resetAllMocks();
|
|
12
|
-
|
|
12
|
+
HostAdaptor.resetInstance();
|
|
13
13
|
AppsSdkBridge.resetInstance();
|
|
14
14
|
McpAppBridge.resetInstance();
|
|
15
15
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-set-open-in-app-url.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-set-open-in-app-url.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use-set-open-in-app-url.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-set-open-in-app-url.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHook } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { AppsSdkBridge } from \"../bridges/apps-sdk/bridge.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport { NotSupportedError } from \"../bridges/types.js\";\nimport { useSetOpenInAppUrl } from \"./use-set-open-in-app-url.js\";\n\ndescribe(\"useSetOpenInAppUrl\", () => {\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.resetAllMocks();\n HostAdaptor.resetInstance();\n AppsSdkBridge.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n describe(\"apps-sdk host\", () => {\n let setOpenInAppUrlMock: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n setOpenInAppUrlMock = vi.fn().mockResolvedValue(undefined);\n vi.stubGlobal(\"openai\", {\n setOpenInAppUrl: setOpenInAppUrlMock,\n });\n vi.stubGlobal(\"skybridge\", {\n hostType: \"apps-sdk\",\n serverUrl: \"https://example.com\",\n });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n\n it(\"should return a function that calls window.openai.setOpenInAppUrl with the href\", async () => {\n const { result } = renderHook(() => useSetOpenInAppUrl());\n\n const href = \"https://example.com/path\";\n await result.current(href);\n\n expect(setOpenInAppUrlMock).toHaveBeenCalledTimes(1);\n expect(setOpenInAppUrlMock).toHaveBeenCalledWith({ href });\n });\n\n it(\"should reject when href is empty\", async () => {\n const { result } = renderHook(() => useSetOpenInAppUrl());\n\n await expect(result.current(\"\")).rejects.toThrow(\n \"The href parameter is required.\",\n );\n });\n\n it(\"should call setOpenInAppUrl when href origin differs from serverUrl origin\", async () => {\n const { result } = renderHook(() => useSetOpenInAppUrl());\n\n const href = \"https://different-domain.com/path\";\n await result.current(href);\n\n expect(setOpenInAppUrlMock).toHaveBeenCalledTimes(1);\n expect(setOpenInAppUrlMock).toHaveBeenCalledWith({ href });\n });\n });\n\n describe(\"mcp-app host\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"openai\", undefined);\n vi.stubGlobal(\"skybridge\", {\n hostType: \"mcp-app\",\n serverUrl: \"https://example.com\",\n });\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n\n it(\"should throw NotSupportedError when called from an MCP App runtime\", async () => {\n const { result } = renderHook(() => useSetOpenInAppUrl());\n\n await expect(\n result.current(\"https://example.com/path\"),\n ).rejects.toBeInstanceOf(NotSupportedError);\n });\n });\n});\n"]}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { UnknownObject } from "../types.js";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* {@link useToolInfo} state before the tool has been invoked.
|
|
4
|
+
*
|
|
5
|
+
* @deprecated `useToolInfo` no longer returns the idle state — it starts in
|
|
6
|
+
* `"pending"` and transitions to `"success"`, so `isIdle` is always `false` at
|
|
7
|
+
* runtime. This type is retained in {@link ToolState} for backwards
|
|
8
|
+
* compatibility and will be removed in the next major.
|
|
9
|
+
*/
|
|
3
10
|
export type ToolIdleState = {
|
|
4
11
|
status: "idle";
|
|
5
12
|
isIdle: true;
|
|
@@ -9,29 +16,40 @@ export type ToolIdleState = {
|
|
|
9
16
|
output: undefined;
|
|
10
17
|
responseMetadata: undefined;
|
|
11
18
|
};
|
|
12
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* {@link useToolInfo} state while the tool is executing — `output` is not yet
|
|
21
|
+
* available.
|
|
22
|
+
*
|
|
23
|
+
* `input` is optional: the host may render the view before delivering the
|
|
24
|
+
* tool arguments.
|
|
25
|
+
*/
|
|
13
26
|
export type ToolPendingState<ToolInput extends UnknownObject> = {
|
|
14
27
|
status: "pending";
|
|
15
28
|
isIdle: false;
|
|
16
29
|
isPending: true;
|
|
17
30
|
isSuccess: false;
|
|
18
|
-
input: ToolInput;
|
|
31
|
+
input: ToolInput | undefined;
|
|
19
32
|
output: undefined;
|
|
20
33
|
responseMetadata: undefined;
|
|
21
34
|
};
|
|
22
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* {@link useToolInfo} state once the tool returned — `output` is available.
|
|
37
|
+
*
|
|
38
|
+
* `input` is optional: the host may not have surfaced the tool arguments by
|
|
39
|
+
* the time `output` arrives.
|
|
40
|
+
*/
|
|
23
41
|
export type ToolSuccessState<ToolInput extends UnknownObject, ToolOutput extends UnknownObject, ToolResponseMetadata extends UnknownObject> = {
|
|
24
42
|
status: "success";
|
|
25
43
|
isIdle: false;
|
|
26
44
|
isPending: false;
|
|
27
45
|
isSuccess: true;
|
|
28
|
-
input: ToolInput;
|
|
46
|
+
input: ToolInput | undefined;
|
|
29
47
|
output: ToolOutput;
|
|
30
48
|
responseMetadata: ToolResponseMetadata;
|
|
31
49
|
};
|
|
32
50
|
/**
|
|
33
51
|
* Discriminated union describing the tool invocation that triggered the
|
|
34
|
-
* current view render. Use `
|
|
52
|
+
* current view render. Use `isPending` / `isSuccess` to narrow.
|
|
35
53
|
*/
|
|
36
54
|
export type ToolState<ToolInput extends UnknownObject, ToolOutput extends UnknownObject, ToolResponseMetadata extends UnknownObject> = ToolIdleState | ToolPendingState<ToolInput> | ToolSuccessState<ToolInput, ToolOutput, ToolResponseMetadata>;
|
|
37
55
|
type ToolSignature = {
|
|
@@ -42,7 +60,7 @@ type ToolSignature = {
|
|
|
42
60
|
/**
|
|
43
61
|
* Access the tool invocation that produced the current view: its `input`,
|
|
44
62
|
* resulting `output`, and `responseMetadata`. The shape evolves as the tool
|
|
45
|
-
* runs (
|
|
63
|
+
* runs (pending → success), exposed through {@link ToolState}.
|
|
46
64
|
*
|
|
47
65
|
* For full input/output typing per tool name, prefer the typed `useToolInfo`
|
|
48
66
|
* returned by {@link generateHelpers} over the generic form.
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { useHostContext } from "../bridges/index.js";
|
|
2
|
-
function deriveStatus(
|
|
3
|
-
if (input === null) {
|
|
4
|
-
return "idle";
|
|
5
|
-
}
|
|
2
|
+
function deriveStatus(output, responseMetadata) {
|
|
6
3
|
if (output === null && responseMetadata === null) {
|
|
7
4
|
return "pending";
|
|
8
5
|
}
|
|
@@ -11,7 +8,7 @@ function deriveStatus(input, output, responseMetadata) {
|
|
|
11
8
|
/**
|
|
12
9
|
* Access the tool invocation that produced the current view: its `input`,
|
|
13
10
|
* resulting `output`, and `responseMetadata`. The shape evolves as the tool
|
|
14
|
-
* runs (
|
|
11
|
+
* runs (pending → success), exposed through {@link ToolState}.
|
|
15
12
|
*
|
|
16
13
|
* For full input/output typing per tool name, prefer the typed `useToolInfo`
|
|
17
14
|
* returned by {@link generateHelpers} over the generic form.
|
|
@@ -38,11 +35,11 @@ export function useToolInfo() {
|
|
|
38
35
|
const input = useHostContext("toolInput");
|
|
39
36
|
const output = useHostContext("toolOutput");
|
|
40
37
|
const responseMetadata = useHostContext("toolResponseMetadata");
|
|
41
|
-
const status = deriveStatus(
|
|
38
|
+
const status = deriveStatus(output, responseMetadata);
|
|
42
39
|
return {
|
|
43
|
-
input,
|
|
40
|
+
input: input ?? undefined,
|
|
44
41
|
status,
|
|
45
|
-
isIdle:
|
|
42
|
+
isIdle: false,
|
|
46
43
|
isPending: status === "pending",
|
|
47
44
|
isSuccess: status === "success",
|
|
48
45
|
output,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tool-info.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"use-tool-info.js","sourceRoot":"","sources":["../../../src/web/hooks/use-tool-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA6ErD,SAAS,YAAY,CACnB,MAAsC,EACtC,gBAAgD;IAEhD,IAAI,MAAM,KAAK,IAAI,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,WAAW;IAGzB,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAC5C,MAAM,gBAAgB,GAAG,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAMtD,OAAO;QACL,KAAK,EAAE,KAAK,IAAI,SAAS;QACzB,MAAM;QACN,MAAM,EAAE,KAAK;QACb,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,MAAM;QACN,gBAAgB;KACqB,CAAC;AAC1C,CAAC","sourcesContent":["import { useHostContext } from \"../bridges/index.js\";\nimport type { UnknownObject } from \"../types.js\";\n\n/**\n * {@link useToolInfo} state before the tool has been invoked.\n *\n * @deprecated `useToolInfo` no longer returns the idle state — it starts in\n * `\"pending\"` and transitions to `\"success\"`, so `isIdle` is always `false` at\n * runtime. This type is retained in {@link ToolState} for backwards\n * compatibility and will be removed in the next major.\n */\nexport type ToolIdleState = {\n status: \"idle\";\n isIdle: true;\n isPending: false;\n isSuccess: false;\n input: undefined;\n output: undefined;\n responseMetadata: undefined;\n};\n\n/**\n * {@link useToolInfo} state while the tool is executing — `output` is not yet\n * available.\n *\n * `input` is optional: the host may render the view before delivering the\n * tool arguments.\n */\nexport type ToolPendingState<ToolInput extends UnknownObject> = {\n status: \"pending\";\n isIdle: false;\n isPending: true;\n isSuccess: false;\n input: ToolInput | undefined;\n output: undefined;\n responseMetadata: undefined;\n};\n\n/**\n * {@link useToolInfo} state once the tool returned — `output` is available.\n *\n * `input` is optional: the host may not have surfaced the tool arguments by\n * the time `output` arrives.\n */\nexport type ToolSuccessState<\n ToolInput extends UnknownObject,\n ToolOutput extends UnknownObject,\n ToolResponseMetadata extends UnknownObject,\n> = {\n status: \"success\";\n isIdle: false;\n isPending: false;\n isSuccess: true;\n input: ToolInput | undefined;\n output: ToolOutput;\n responseMetadata: ToolResponseMetadata;\n};\n\n/**\n * Discriminated union describing the tool invocation that triggered the\n * current view render. Use `isPending` / `isSuccess` to narrow.\n */\nexport type ToolState<\n ToolInput extends UnknownObject,\n ToolOutput extends UnknownObject,\n ToolResponseMetadata extends UnknownObject,\n> =\n | ToolIdleState\n | ToolPendingState<ToolInput>\n | ToolSuccessState<ToolInput, ToolOutput, ToolResponseMetadata>;\n\ntype ToolSignature = {\n input: UnknownObject;\n output: UnknownObject;\n responseMetadata: UnknownObject;\n};\n\nfunction deriveStatus(\n output: Record<string, unknown> | null,\n responseMetadata: Record<string, unknown> | null,\n): \"pending\" | \"success\" {\n if (output === null && responseMetadata === null) {\n return \"pending\";\n }\n return \"success\";\n}\n\n/**\n * Access the tool invocation that produced the current view: its `input`,\n * resulting `output`, and `responseMetadata`. The shape evolves as the tool\n * runs (pending → success), exposed through {@link ToolState}.\n *\n * For full input/output typing per tool name, prefer the typed `useToolInfo`\n * returned by {@link generateHelpers} over the generic form.\n *\n * @typeParam TS - Optional partial shape `{ input, output, responseMetadata }`\n * to refine each field's type. When omitted, each typed field resolves to\n * `never` — pass an explicit shape or use the typed helper from\n * {@link generateHelpers} to get usable types.\n *\n * @example\n * ```tsx\n * const { isSuccess, input, output } = useToolInfo<{\n * input: { query: string };\n * output: { results: Result[] };\n * }>();\n *\n * if (!isSuccess || !output) return <Skeleton />;\n * return <Results items={output.results} />;\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-tool-info\n */\nexport function useToolInfo<\n TS extends Partial<ToolSignature> = Record<string, never>,\n>() {\n const input = useHostContext(\"toolInput\");\n const output = useHostContext(\"toolOutput\");\n const responseMetadata = useHostContext(\"toolResponseMetadata\");\n\n const status = deriveStatus(output, responseMetadata);\n\n type Input = UnknownObject & TS[\"input\"];\n type Output = UnknownObject & TS[\"output\"];\n type Metadata = UnknownObject & TS[\"responseMetadata\"];\n\n return {\n input: input ?? undefined,\n status,\n isIdle: false,\n isPending: status === \"pending\",\n isSuccess: status === \"success\",\n output,\n responseMetadata,\n } as ToolState<Input, Output, Metadata>;\n}\n"]}
|
|
@@ -11,19 +11,15 @@ test("useToolInfo - TypeScript typing", () => {
|
|
|
11
11
|
});
|
|
12
12
|
test("should correctly type input, output, and responseMetadata with explicit ToolSignature", () => {
|
|
13
13
|
const result = useToolInfo();
|
|
14
|
-
// When
|
|
15
|
-
|
|
16
|
-
expectTypeOf(result.input);
|
|
17
|
-
expectTypeOf(result.output);
|
|
18
|
-
expectTypeOf(result.responseMetadata);
|
|
19
|
-
}
|
|
20
|
-
// When pending, output and responseMetadata should be undefined
|
|
14
|
+
// When pending, input may be undefined (host hasn't delivered args yet,
|
|
15
|
+
// or the tool has no input schema)
|
|
21
16
|
if (result.status === "pending") {
|
|
22
17
|
expectTypeOf(result.input);
|
|
23
18
|
expectTypeOf(result.output);
|
|
24
19
|
expectTypeOf(result.responseMetadata);
|
|
25
20
|
}
|
|
26
|
-
// When success, output and responseMetadata
|
|
21
|
+
// When success, output and responseMetadata are defined; input may still
|
|
22
|
+
// be undefined if the host hasn't surfaced the tool arguments
|
|
27
23
|
if (result.status === "success") {
|
|
28
24
|
expectTypeOf(result.input);
|
|
29
25
|
expectTypeOf(result.output);
|
|
@@ -32,34 +28,18 @@ test("useToolInfo - TypeScript typing", () => {
|
|
|
32
28
|
});
|
|
33
29
|
test("should correctly narrow types based on status discriminated union", () => {
|
|
34
30
|
const result = useToolInfo();
|
|
35
|
-
// Test type narrowing for idle
|
|
36
|
-
if (result.isIdle) {
|
|
37
|
-
expectTypeOf(result.status);
|
|
38
|
-
expectTypeOf(result.isIdle);
|
|
39
|
-
expectTypeOf(result.isPending);
|
|
40
|
-
expectTypeOf(result.isSuccess);
|
|
41
|
-
expectTypeOf(result.input);
|
|
42
|
-
expectTypeOf(result.output);
|
|
43
|
-
expectTypeOf(result.responseMetadata);
|
|
44
|
-
}
|
|
45
31
|
// Test type narrowing for pending
|
|
46
32
|
if (result.isPending) {
|
|
47
33
|
expectTypeOf(result.status);
|
|
48
34
|
expectTypeOf(result.isIdle);
|
|
49
35
|
expectTypeOf(result.isPending);
|
|
50
36
|
expectTypeOf(result.isSuccess);
|
|
37
|
+
expectTypeOf(result.input);
|
|
51
38
|
expectTypeOf(result.output);
|
|
52
39
|
expectTypeOf(result.responseMetadata);
|
|
53
40
|
}
|
|
54
41
|
if (result.isSuccess) {
|
|
55
42
|
expectTypeOf(result.status);
|
|
56
|
-
expectTypeOf(result.isIdle);
|
|
57
|
-
expectTypeOf(result.isPending);
|
|
58
|
-
expectTypeOf(result.isSuccess);
|
|
59
|
-
expectTypeOf(result.output);
|
|
60
|
-
expectTypeOf(result.responseMetadata);
|
|
61
|
-
}
|
|
62
|
-
if (result.status === "idle") {
|
|
63
43
|
expectTypeOf(result.isIdle);
|
|
64
44
|
expectTypeOf(result.isPending);
|
|
65
45
|
expectTypeOf(result.isSuccess);
|
|
@@ -86,22 +66,24 @@ test("useToolInfo - TypeScript typing", () => {
|
|
|
86
66
|
});
|
|
87
67
|
test("should handle partial ToolSignature with only input specified", () => {
|
|
88
68
|
const result = useToolInfo();
|
|
89
|
-
// Input
|
|
90
|
-
|
|
69
|
+
// Input is optional in both states — undefined while args haven't arrived
|
|
70
|
+
// (pending) and for no-input tools (success).
|
|
71
|
+
if (result.status === "pending") {
|
|
91
72
|
expectTypeOf(result.input);
|
|
92
73
|
}
|
|
93
74
|
if (result.status === "success") {
|
|
75
|
+
expectTypeOf(result.input);
|
|
94
76
|
expectTypeOf(result.output);
|
|
95
77
|
expectTypeOf(result.responseMetadata);
|
|
96
78
|
}
|
|
97
79
|
});
|
|
98
80
|
test("should handle ToolSignature with only output specified", () => {
|
|
99
81
|
const result = useToolInfo();
|
|
100
|
-
|
|
101
|
-
if (result.status === "pending" || result.status === "success") {
|
|
82
|
+
if (result.status === "pending") {
|
|
102
83
|
expectTypeOf(result.input);
|
|
103
84
|
}
|
|
104
85
|
if (result.status === "success") {
|
|
86
|
+
expectTypeOf(result.input);
|
|
105
87
|
expectTypeOf(result.output);
|
|
106
88
|
}
|
|
107
89
|
});
|