skybridge 0.0.0-dev.66b8f6b → 0.0.0-dev.6b57ab9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +321 -1
  2. package/dist/src/server/index.d.ts +4 -0
  3. package/dist/{server/index.d.ts → src/server/index.js} +1 -1
  4. package/dist/src/server/index.js.map +1 -0
  5. package/dist/src/server/inferUtilityTypes.d.ts +46 -0
  6. package/dist/src/server/inferUtilityTypes.js +2 -0
  7. package/dist/src/server/inferUtilityTypes.js.map +1 -0
  8. package/dist/src/server/server.d.ts +37 -0
  9. package/dist/src/server/server.js +62 -0
  10. package/dist/src/server/server.js.map +1 -0
  11. package/dist/src/server/templateHelper.d.ts +15 -0
  12. package/dist/src/server/templateHelper.js +29 -0
  13. package/dist/src/server/templateHelper.js.map +1 -0
  14. package/dist/src/server/templates/development.hbs +12 -0
  15. package/dist/src/server/templates/production.hbs +6 -0
  16. package/dist/{server → src/server}/widgetsDevServer.d.ts +5 -2
  17. package/dist/{server → src/server}/widgetsDevServer.js +5 -2
  18. package/dist/src/server/widgetsDevServer.js.map +1 -0
  19. package/dist/src/test/utils.d.ts +69 -0
  20. package/dist/src/test/utils.js +136 -0
  21. package/dist/src/test/utils.js.map +1 -0
  22. package/dist/src/test/widget.test.d.ts +1 -0
  23. package/dist/src/test/widget.test.js +90 -0
  24. package/dist/src/test/widget.test.js.map +1 -0
  25. package/dist/src/web/hooks/index.d.ts +14 -0
  26. package/dist/src/web/hooks/index.js +15 -0
  27. package/dist/src/web/hooks/index.js.map +1 -0
  28. package/dist/src/web/hooks/use-call-tool.d.ts +62 -0
  29. package/dist/src/web/hooks/use-call-tool.js +68 -0
  30. package/dist/src/web/hooks/use-call-tool.js.map +1 -0
  31. package/dist/src/web/hooks/use-call-tool.test.d.ts +1 -0
  32. package/dist/src/web/hooks/use-call-tool.test.js +163 -0
  33. package/dist/src/web/hooks/use-call-tool.test.js.map +1 -0
  34. package/dist/src/web/hooks/use-display-mode.d.ts +4 -0
  35. package/dist/src/web/hooks/use-display-mode.js +7 -0
  36. package/dist/src/web/hooks/use-display-mode.js.map +1 -0
  37. package/dist/src/web/hooks/use-display-mode.test.d.ts +1 -0
  38. package/dist/src/web/hooks/use-display-mode.test.js +40 -0
  39. package/dist/src/web/hooks/use-display-mode.test.js.map +1 -0
  40. package/dist/src/web/hooks/use-files.d.ts +10 -0
  41. package/dist/src/web/hooks/use-files.js +7 -0
  42. package/dist/src/web/hooks/use-files.js.map +1 -0
  43. package/dist/src/web/hooks/use-files.test.d.ts +1 -0
  44. package/dist/src/web/hooks/use-files.test.js +29 -0
  45. package/dist/src/web/hooks/use-files.test.js.map +1 -0
  46. package/dist/src/web/hooks/use-locale.d.ts +1 -0
  47. package/dist/src/web/hooks/use-locale.js +5 -0
  48. package/dist/src/web/hooks/use-locale.js.map +1 -0
  49. package/dist/src/web/hooks/use-locale.test.d.ts +1 -0
  50. package/dist/src/web/hooks/use-locale.test.js +21 -0
  51. package/dist/src/web/hooks/use-locale.test.js.map +1 -0
  52. package/dist/src/web/hooks/use-open-external.d.ts +1 -0
  53. package/dist/src/web/hooks/use-open-external.js +6 -0
  54. package/dist/src/web/hooks/use-open-external.js.map +1 -0
  55. package/dist/src/web/hooks/use-open-external.test.d.ts +1 -0
  56. package/dist/src/web/hooks/use-open-external.test.js +24 -0
  57. package/dist/src/web/hooks/use-open-external.test.js.map +1 -0
  58. package/dist/{web → src/web/hooks}/use-openai-global.d.ts +1 -1
  59. package/dist/{web → src/web/hooks}/use-openai-global.js +4 -2
  60. package/dist/src/web/hooks/use-openai-global.js.map +1 -0
  61. package/dist/src/web/hooks/use-request-modal.d.ts +6 -0
  62. package/dist/src/web/hooks/use-request-modal.js +9 -0
  63. package/dist/src/web/hooks/use-request-modal.js.map +1 -0
  64. package/dist/src/web/hooks/use-request-modal.test.d.ts +1 -0
  65. package/dist/src/web/hooks/use-request-modal.test.js +24 -0
  66. package/dist/src/web/hooks/use-request-modal.test.js.map +1 -0
  67. package/dist/src/web/hooks/use-send-follow-up-message.d.ts +1 -0
  68. package/dist/src/web/hooks/use-send-follow-up-message.js +11 -0
  69. package/dist/src/web/hooks/use-send-follow-up-message.js.map +1 -0
  70. package/dist/src/web/hooks/use-theme.d.ts +1 -0
  71. package/dist/src/web/hooks/use-theme.js +5 -0
  72. package/dist/src/web/hooks/use-theme.js.map +1 -0
  73. package/dist/src/web/hooks/use-theme.test.d.ts +1 -0
  74. package/dist/src/web/hooks/use-theme.test.js +26 -0
  75. package/dist/src/web/hooks/use-theme.test.js.map +1 -0
  76. package/dist/src/web/hooks/use-tool-info.d.ts +25 -0
  77. package/dist/src/web/hooks/use-tool-info.js +22 -0
  78. package/dist/src/web/hooks/use-tool-info.js.map +1 -0
  79. package/dist/src/web/hooks/use-tool-info.test-d.d.ts +1 -0
  80. package/dist/src/web/hooks/use-tool-info.test-d.js +74 -0
  81. package/dist/src/web/hooks/use-tool-info.test-d.js.map +1 -0
  82. package/dist/src/web/hooks/use-tool-info.test.d.ts +1 -0
  83. package/dist/src/web/hooks/use-tool-info.test.js +59 -0
  84. package/dist/src/web/hooks/use-tool-info.test.js.map +1 -0
  85. package/dist/src/web/hooks/use-tool-output.d.ts +4 -0
  86. package/dist/src/web/hooks/use-tool-output.js +9 -0
  87. package/dist/src/web/hooks/use-tool-output.js.map +1 -0
  88. package/dist/src/web/hooks/use-tool-response-metadata.d.ts +4 -0
  89. package/dist/src/web/hooks/use-tool-response-metadata.js +8 -0
  90. package/dist/src/web/hooks/use-tool-response-metadata.js.map +1 -0
  91. package/dist/src/web/hooks/use-user-agent.d.ts +1 -0
  92. package/dist/src/web/hooks/use-user-agent.js +5 -0
  93. package/dist/src/web/hooks/use-user-agent.js.map +1 -0
  94. package/dist/src/web/hooks/use-user-agent.test.d.ts +1 -0
  95. package/dist/src/web/hooks/use-user-agent.test.js +31 -0
  96. package/dist/src/web/hooks/use-user-agent.test.js.map +1 -0
  97. package/dist/src/web/hooks/use-widget-state.d.ts +4 -0
  98. package/dist/src/web/hooks/use-widget-state.js +30 -0
  99. package/dist/src/web/hooks/use-widget-state.js.map +1 -0
  100. package/dist/src/web/hooks/use-widget-state.test.d.ts +1 -0
  101. package/dist/src/web/hooks/use-widget-state.test.js +60 -0
  102. package/dist/src/web/hooks/use-widget-state.test.js.map +1 -0
  103. package/dist/src/web/index.d.ts +5 -0
  104. package/dist/src/web/index.js +6 -0
  105. package/dist/src/web/index.js.map +1 -0
  106. package/dist/src/web/mount-widget.js +19 -0
  107. package/dist/src/web/mount-widget.js.map +1 -0
  108. package/dist/src/web/plugin.d.ts +2 -0
  109. package/dist/src/web/plugin.js +28 -0
  110. package/dist/src/web/plugin.js.map +1 -0
  111. package/dist/src/web/proxy.d.ts +1 -0
  112. package/dist/src/web/proxy.js +48 -0
  113. package/dist/src/web/proxy.js.map +1 -0
  114. package/dist/src/web/typed-hooks.d.ts +107 -0
  115. package/dist/src/web/typed-hooks.js +111 -0
  116. package/dist/src/web/typed-hooks.js.map +1 -0
  117. package/dist/src/web/typed-hooks.test-d.d.ts +1 -0
  118. package/dist/src/web/typed-hooks.test-d.js +87 -0
  119. package/dist/src/web/typed-hooks.test-d.js.map +1 -0
  120. package/dist/src/web/typed-hooks.test.d.ts +1 -0
  121. package/dist/src/web/typed-hooks.test.js +17 -0
  122. package/dist/src/web/typed-hooks.test.js.map +1 -0
  123. package/dist/{web → src/web}/types.d.ts +39 -15
  124. package/dist/src/web/types.js.map +1 -0
  125. package/dist/vitest.config.d.ts +2 -0
  126. package/dist/vitest.config.js +8 -0
  127. package/dist/vitest.config.js.map +1 -0
  128. package/package.json +26 -12
  129. package/dist/server/index.js +0 -4
  130. package/dist/server/index.js.map +0 -1
  131. package/dist/server/middleware.d.ts +0 -3
  132. package/dist/server/middleware.js +0 -47
  133. package/dist/server/middleware.js.map +0 -1
  134. package/dist/server/server.d.ts +0 -12
  135. package/dist/server/server.js +0 -70
  136. package/dist/server/server.js.map +0 -1
  137. package/dist/server/widgetsDevServer.js.map +0 -1
  138. package/dist/web/index.d.ts +0 -4
  139. package/dist/web/index.js +0 -5
  140. package/dist/web/index.js.map +0 -1
  141. package/dist/web/mount-widget.js +0 -10
  142. package/dist/web/mount-widget.js.map +0 -1
  143. package/dist/web/types.js.map +0 -1
  144. package/dist/web/use-openai-global.js.map +0 -1
  145. package/dist/web/use-tool-output.d.ts +0 -3
  146. package/dist/web/use-tool-output.js +0 -5
  147. package/dist/web/use-tool-output.js.map +0 -1
  148. /package/dist/{web → src/web}/mount-widget.d.ts +0 -0
  149. /package/dist/{web → src/web}/types.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-tool-output.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-tool-output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;IAEjC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @deprecated This hook is deprecated. Use `useToolInfo()` instead and access the `responseMetadata` property.
3
+ */
4
+ export declare function useToolResponseMetadata(): import("../types.js").UnknownObject | null | undefined;
@@ -0,0 +1,8 @@
1
+ import { useOpenAiGlobal } from "./use-openai-global.js";
2
+ /**
3
+ * @deprecated This hook is deprecated. Use `useToolInfo()` instead and access the `responseMetadata` property.
4
+ */
5
+ export function useToolResponseMetadata() {
6
+ return useOpenAiGlobal("toolResponseMetadata");
7
+ }
8
+ //# sourceMappingURL=use-tool-response-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-tool-response-metadata.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-tool-response-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,eAAe,CAAC,sBAAsB,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function useUserAgent(): import("../types.js").UserAgent;
@@ -0,0 +1,5 @@
1
+ import { useOpenAiGlobal } from "./use-openai-global.js";
2
+ export function useUserAgent() {
3
+ return useOpenAiGlobal("userAgent");
4
+ }
5
+ //# sourceMappingURL=use-user-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-user-agent.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-user-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,UAAU,YAAY;IAC1B,OAAO,eAAe,CAAC,WAAW,CAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import { useUserAgent } from "./use-user-agent.js";
2
+ import { describe, it, expect, vi, beforeEach, afterEach, } from "vitest";
3
+ import { renderHook } from "@testing-library/react";
4
+ describe("useUserAgent", () => {
5
+ let OpenaiMock;
6
+ beforeEach(() => {
7
+ OpenaiMock = {
8
+ userAgent: {
9
+ device: { type: "mobile" },
10
+ capabilities: { hover: false, touch: true },
11
+ },
12
+ };
13
+ vi.stubGlobal("openai", OpenaiMock);
14
+ });
15
+ afterEach(() => {
16
+ vi.unstubAllGlobals();
17
+ vi.resetAllMocks();
18
+ });
19
+ it("should return the current user agent from window.openai.userAgent", () => {
20
+ OpenaiMock.userAgent = {
21
+ device: { type: "mobile" },
22
+ capabilities: { hover: false, touch: true },
23
+ };
24
+ const { result } = renderHook(() => useUserAgent());
25
+ expect(result.current).toEqual({
26
+ device: { type: "mobile" },
27
+ capabilities: { hover: false, touch: true },
28
+ });
29
+ });
30
+ });
31
+ //# sourceMappingURL=use-user-agent.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-user-agent.test.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-user-agent.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,QAAQ,EACR,EAAE,EACF,MAAM,EACN,EAAE,EACF,UAAU,EACV,SAAS,GAEV,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,UAEH,CAAC;IAEF,UAAU,CAAC,GAAG,EAAE;QACd,UAAU,GAAG;YACX,SAAS,EAAE;gBACT,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC1B,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;aAC5C;SACF,CAAC;QACF,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,UAAU,CAAC,SAAS,GAAG;YACrB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1B,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;SAC5C,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;QAEpD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1B,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;SAC5C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type SetStateAction } from "react";
2
+ import type { UnknownObject } from "../types.js";
3
+ export declare function useWidgetState<T extends UnknownObject>(defaultState: T | (() => T)): readonly [T, (state: SetStateAction<T>) => void];
4
+ export declare function useWidgetState<T extends UnknownObject>(defaultState?: T | (() => T | null) | null): readonly [T | null, (state: SetStateAction<T | null>) => void];
@@ -0,0 +1,30 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useOpenAiGlobal } from "./use-openai-global.js";
3
+ export function useWidgetState(defaultState) {
4
+ const widgetStateFromWindow = useOpenAiGlobal("widgetState");
5
+ const [widgetState, _setWidgetState] = useState(() => {
6
+ if (widgetStateFromWindow !== null) {
7
+ return widgetStateFromWindow;
8
+ }
9
+ return typeof defaultState === "function"
10
+ ? defaultState()
11
+ : defaultState ?? null;
12
+ });
13
+ useEffect(() => {
14
+ // Fixes openai implementation bug
15
+ if (widgetStateFromWindow !== null) {
16
+ _setWidgetState(widgetStateFromWindow);
17
+ }
18
+ }, [widgetStateFromWindow]);
19
+ const setWidgetState = useCallback((state) => {
20
+ _setWidgetState((prevState) => {
21
+ const newState = typeof state === "function" ? state(prevState) : state;
22
+ if (newState !== null) {
23
+ window.openai.setWidgetState(newState);
24
+ }
25
+ return newState;
26
+ });
27
+ }, [window.openai.setWidgetState]);
28
+ return [widgetState, setWidgetState];
29
+ }
30
+ //# sourceMappingURL=use-widget-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-widget-state.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-widget-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAuB,MAAM,OAAO,CAAC;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAQzD,MAAM,UAAU,cAAc,CAC5B,YAA0C;IAE1C,MAAM,qBAAqB,GAAG,eAAe,CAAC,aAAa,CAAM,CAAC;IAElE,MAAM,CAAC,WAAW,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAW,GAAG,EAAE;QAC7D,IAAI,qBAAqB,KAAK,IAAI,EAAE,CAAC;YACnC,OAAO,qBAAqB,CAAC;QAC/B,CAAC;QAED,OAAO,OAAO,YAAY,KAAK,UAAU;YACvC,CAAC,CAAC,YAAY,EAAE;YAChB,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,kCAAkC;QAClC,IAAI,qBAAqB,KAAK,IAAI,EAAE,CAAC;YACnC,eAAe,CAAC,qBAAqB,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAE5B,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,KAA+B,EAAE,EAAE;QAClC,eAAe,CAAC,CAAC,SAAS,EAAE,EAAE;YAC5B,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAExE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACzC,CAAC;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAC/B,CAAC;IAEF,OAAO,CAAC,WAAW,EAAE,cAAc,CAAU,CAAC;AAChD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ import { useWidgetState } from "./use-widget-state.js";
2
+ import { describe, it, expect, vi, beforeEach, afterEach, } from "vitest";
3
+ import { renderHook, act } from "@testing-library/react";
4
+ describe("useWidgetState", () => {
5
+ let OpenaiMock;
6
+ beforeEach(() => {
7
+ OpenaiMock = {
8
+ widgetState: null,
9
+ setWidgetState: vi.fn().mockResolvedValue(undefined),
10
+ };
11
+ vi.stubGlobal("openai", OpenaiMock);
12
+ });
13
+ afterEach(() => {
14
+ vi.unstubAllGlobals();
15
+ vi.resetAllMocks();
16
+ });
17
+ const defaultState = { count: 0, name: "test" };
18
+ const windowState = { count: 5, name: "window" };
19
+ it("should initialize with default state when window.openai.widgetState is null", () => {
20
+ OpenaiMock.widgetState = null;
21
+ const { result } = renderHook(() => useWidgetState(defaultState));
22
+ expect(result.current[0]).toEqual(defaultState);
23
+ });
24
+ it("should initialize with window.openai.widgetState when available", () => {
25
+ OpenaiMock.widgetState = windowState;
26
+ const { result } = renderHook(() => useWidgetState(defaultState));
27
+ expect(result.current[0]).toEqual(windowState);
28
+ });
29
+ it("should call window.openai.setWidgetState when setWidgetState is called with a new state", async () => {
30
+ const { result } = renderHook(() => useWidgetState(defaultState));
31
+ const newState = { count: 10, name: "updated" };
32
+ act(() => {
33
+ result.current[1](newState);
34
+ });
35
+ expect(OpenaiMock.setWidgetState).toHaveBeenCalledWith(newState);
36
+ expect(result.current[0]).toEqual(newState);
37
+ });
38
+ it("should call window.openai.setWidgetState when setWidgetState is called with a function updater", async () => {
39
+ const { result } = renderHook(() => useWidgetState(defaultState));
40
+ act(() => {
41
+ result.current[1]((prev) => ({ ...prev, count: prev.count + 1 }));
42
+ });
43
+ expect(OpenaiMock.setWidgetState).toHaveBeenCalledWith({
44
+ count: 1,
45
+ name: "test",
46
+ });
47
+ expect(result.current[0]).toEqual({ count: 1, name: "test" });
48
+ });
49
+ it("should update state when window.openai.widgetState changes", () => {
50
+ OpenaiMock.widgetState = defaultState;
51
+ const { result, rerender } = renderHook(() => useWidgetState(defaultState));
52
+ expect(result.current[0]).toEqual(defaultState);
53
+ // Simulate window.openai.widgetState changing
54
+ OpenaiMock.widgetState = windowState;
55
+ // Trigger re-render to simulate the useEffect running
56
+ rerender();
57
+ expect(result.current[0]).toEqual(windowState);
58
+ });
59
+ });
60
+ //# sourceMappingURL=use-widget-state.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-widget-state.test.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-widget-state.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from "./types.js";
2
+ export { mountWidget } from "./mount-widget.js";
3
+ export { skybridge } from "./plugin.js";
4
+ export * from "./hooks/index.js";
5
+ export { createTypedHooks } from "./typed-hooks.js";
@@ -0,0 +1,6 @@
1
+ export * from "./types.js";
2
+ export { mountWidget } from "./mount-widget.js";
3
+ export { skybridge } from "./plugin.js";
4
+ export * from "./hooks/index.js";
5
+ export { createTypedHooks } from "./typed-hooks.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /// <reference types="vite/client" />
2
+ import { createElement, StrictMode } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+ import { installOpenAILoggingProxy } from "./proxy.js";
5
+ let rootInstance = null;
6
+ export const mountWidget = (component) => {
7
+ const rootElement = document.getElementById("root");
8
+ if (!rootElement) {
9
+ throw new Error("Root element not found");
10
+ }
11
+ if (!rootInstance) {
12
+ rootInstance = createRoot(rootElement);
13
+ }
14
+ if (import.meta.env.DEV) {
15
+ installOpenAILoggingProxy();
16
+ }
17
+ rootInstance.render(createElement(StrictMode, null, component));
18
+ };
19
+ //# sourceMappingURL=mount-widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-widget.js","sourceRoot":"","sources":["../../../src/web/mount-widget.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,UAAU,EAAa,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEvD,IAAI,YAAY,GAAgB,IAAI,CAAC;AAErC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,SAA0B,EAAE,EAAE;IACxD,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACxB,yBAAyB,EAAE,CAAC;IAC9B,CAAC;IAED,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from "vite";
2
+ export declare function skybridge(): Plugin;
@@ -0,0 +1,28 @@
1
+ export function skybridge() {
2
+ return {
3
+ name: "skybridge",
4
+ async config(config) {
5
+ // Dynamic imports to ensure Node modules are only loaded in Node.js context
6
+ const { globSync } = await import("node:fs");
7
+ const { resolve } = await import("node:path");
8
+ const projectRoot = config.root || process.cwd();
9
+ const widgetsPattern = resolve(projectRoot, "src/widgets/*.{js,ts,jsx,tsx,html}");
10
+ const input = Object.fromEntries(globSync(widgetsPattern).map((file) => [
11
+ file.match(/src\/widgets\/(.+)\.tsx$/)?.[1],
12
+ file,
13
+ ]));
14
+ return {
15
+ base: "/assets",
16
+ build: {
17
+ manifest: true,
18
+ minify: true,
19
+ cssCodeSplit: false,
20
+ rollupOptions: {
21
+ input,
22
+ },
23
+ },
24
+ };
25
+ },
26
+ };
27
+ }
28
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/web/plugin.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,IAAI,EAAE,WAAW;QAEjB,KAAK,CAAC,MAAM,CAAC,MAAM;YACjB,4EAA4E;YAC5E,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YAE9C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YACjD,MAAM,cAAc,GAAG,OAAO,CAC5B,WAAW,EACX,oCAAoC,CACrC,CAAC;YAEF,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,QAAQ,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;gBACrC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC3C,IAAI;aACL,CAAC,CACH,CAAC;YAEF,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE;oBACL,QAAQ,EAAE,IAAI;oBACd,MAAM,EAAE,IAAI;oBACZ,YAAY,EAAE,KAAK;oBACnB,aAAa,EAAE;wBACb,KAAK;qBACN;iBACF;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function installOpenAILoggingProxy(): void;
@@ -0,0 +1,48 @@
1
+ const colors = {
2
+ brand: "#6366f1",
3
+ info: "#22223b",
4
+ success: "#22c55e",
5
+ error: "#ef4444",
6
+ };
7
+ export function installOpenAILoggingProxy() {
8
+ if (typeof window === "undefined" || !window.openai) {
9
+ console.warn("[openai-proxy] window.openai not found, skipping proxy installation");
10
+ return;
11
+ }
12
+ const originalOpenAI = window.openai;
13
+ const handler = {
14
+ get(target, prop, receiver) {
15
+ const value = Reflect.get(target, prop, receiver);
16
+ if (typeof value !== "function") {
17
+ return value;
18
+ }
19
+ return function (...args) {
20
+ const methodName = String(prop);
21
+ console.group(`%c[openai] %cmethod %c${methodName}`, `color: ${colors.brand}; font-weight: normal`, `color: ${colors.info}; font-weight: normal`, `color: ${colors.success}`);
22
+ console.log("%c← args:", `color: ${colors.info}`, args);
23
+ const result = value.apply(target, args);
24
+ if (result && typeof result.then === "function") {
25
+ return result.then((resolved) => {
26
+ console.log("%c→ resolved:", `color: ${colors.success}`, resolved);
27
+ console.groupEnd();
28
+ return resolved;
29
+ }, (error) => {
30
+ console.error("%c→ rejected:", `color: ${colors.error}`, error);
31
+ console.groupEnd();
32
+ throw error;
33
+ });
34
+ }
35
+ console.log("%c→ returned:", `color: ${colors.success}`, result);
36
+ console.groupEnd();
37
+ return result;
38
+ };
39
+ },
40
+ set(target, prop, value, receiver) {
41
+ console.log(`%c[openai] %cupdate %c${String(prop)}`, `color: ${colors.brand}`, `color: ${colors.info}`, `color: ${colors.success}; font-weight: bold`, "←", value);
42
+ return Reflect.set(target, prop, value, receiver);
43
+ },
44
+ };
45
+ window.openai = new Proxy(originalOpenAI, handler);
46
+ console.log("%c[openai-proxy] %cInstalled logging proxy for window.openai", `color: ${colors.brand}`, `color: ${colors.info}`);
47
+ }
48
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../../src/web/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import { useCallTool } from "./hooks/use-call-tool.js";
2
+ import type { ToolPendingState, ToolSuccessState } from "./hooks/use-tool-info.js";
3
+ import type { McpServer, InferTools, AnyToolRegistry, ToolInput, ToolOutput } from "../server/index.js";
4
+ import type { CallToolArgs, UnknownObject } from "./types.js";
5
+ type TypedCallToolReturn<TInput, TOutput> = ReturnType<typeof useCallTool<TInput & CallToolArgs, {
6
+ structuredContent: TOutput & UnknownObject;
7
+ }>>;
8
+ type TypedToolInfoReturn<TInput extends UnknownObject, TOutput extends UnknownObject, TResponseMetadata extends UnknownObject> = ToolPendingState<TInput> | ToolSuccessState<TInput, TOutput, TResponseMetadata>;
9
+ /**
10
+ * Creates typed versions of skybridge hooks with full type inference
11
+ * for tool names, inputs, and outputs.
12
+ *
13
+ * This is the recommended way to use skybridge hooks in your widgets.
14
+ * Set this up once in a dedicated file and export the typed hooks for use across your app.
15
+ *
16
+ * @typeParam T - The type of your McpServer instance. Use `typeof server`.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // server/src/index.ts
21
+ * const server = new McpServer({ name: "my-app", version: "1.0" }, {})
22
+ * .widget("search-voyage", {}, {
23
+ * inputSchema: { destination: z.string() },
24
+ * outputSchema: { results: z.array(z.string()) },
25
+ * }, async ({ destination }) => {
26
+ * return { content: [{ type: "text", text: `Found trips to ${destination}` }] };
27
+ * });
28
+ *
29
+ * export type AppType = typeof server;
30
+ * ```
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * // web/src/skybridge.ts (one-time setup)
35
+ * import type { AppType } from "../server";
36
+ * import { createTypedHooks } from "skybridge/web";
37
+ *
38
+ * export const { useCallTool, useToolInfo } = createTypedHooks<AppType>();
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // web/src/widgets/search.tsx (usage)
44
+ * import { useCallTool, useToolInfo } from "../skybridge";
45
+ *
46
+ * export function SearchWidget() {
47
+ * const { callTool, data } = useCallTool("search-voyage");
48
+ * // ^ autocomplete for tool names
49
+ * callTool({ destination: "Spain" });
50
+ * // ^ autocomplete for input fields
51
+ *
52
+ * const toolInfo = useToolInfo<"search-voyage">();
53
+ * // ^ autocomplete for widget names
54
+ * // toolInfo.input is typed based on widget input schema
55
+ * // toolInfo.output is typed based on widget output schema
56
+ * }
57
+ * ```
58
+ */
59
+ export declare function createTypedHooks<T extends McpServer<AnyToolRegistry>>(): {
60
+ /**
61
+ * Typed version of `useCallTool` that provides autocomplete for tool names
62
+ * and type inference for inputs and outputs.
63
+ *
64
+ * @param name - The name of the widget to call. Autocompletes based on your server's widget registry.
65
+ * @returns A hook with typed `callTool` function and `data` property.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * const { callTool, data, isPending } = useCallTool("search-voyage");
70
+ * // TypeScript knows callTool expects { destination: string }
71
+ * callTool({ destination: "Spain" });
72
+ *
73
+ * // data.structuredContent is typed based on your outputSchema
74
+ * if (data) {
75
+ * console.log(data.structuredContent.results);
76
+ * }
77
+ * ```
78
+ */
79
+ useCallTool: <K extends keyof InferTools<T> & string>(name: K) => TypedCallToolReturn<InferTools<T>[K]["input"], InferTools<T>[K]["output"]>;
80
+ /**
81
+ * Typed version of `useToolInfo` that provides autocomplete for widget names
82
+ * and type inference for inputs, outputs, and responseMetadata.
83
+ *
84
+ * @typeParam K - The name of the widget. Autocompletes based on your server's widget registry.
85
+ * @returns A discriminated union with `status: "pending" | "success"` that narrows correctly.
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const toolInfo = useToolInfo<"search-voyage">();
90
+ * // toolInfo.input is typed as { destination: string; ... }
91
+ * // toolInfo.output is typed as { results: Array<...>; ... } | undefined
92
+ * // toolInfo.status narrows correctly: "pending" | "success"
93
+ *
94
+ * if (toolInfo.isPending) {
95
+ * // TypeScript knows output is undefined here
96
+ * console.log(toolInfo.input.destination);
97
+ * }
98
+ *
99
+ * if (toolInfo.isSuccess) {
100
+ * // TypeScript knows output is defined here
101
+ * console.log(toolInfo.output.results);
102
+ * }
103
+ * ```
104
+ */
105
+ useToolInfo: <K extends keyof InferTools<T> & string>() => TypedToolInfoReturn<ToolInput<T, K> & UnknownObject, ToolOutput<T, K> & UnknownObject, UnknownObject>;
106
+ };
107
+ export {};
@@ -0,0 +1,111 @@
1
+ import { useCallTool } from "./hooks/use-call-tool.js";
2
+ import { useToolInfo } from "./hooks/use-tool-info.js";
3
+ /**
4
+ * Creates typed versions of skybridge hooks with full type inference
5
+ * for tool names, inputs, and outputs.
6
+ *
7
+ * This is the recommended way to use skybridge hooks in your widgets.
8
+ * Set this up once in a dedicated file and export the typed hooks for use across your app.
9
+ *
10
+ * @typeParam T - The type of your McpServer instance. Use `typeof server`.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // server/src/index.ts
15
+ * const server = new McpServer({ name: "my-app", version: "1.0" }, {})
16
+ * .widget("search-voyage", {}, {
17
+ * inputSchema: { destination: z.string() },
18
+ * outputSchema: { results: z.array(z.string()) },
19
+ * }, async ({ destination }) => {
20
+ * return { content: [{ type: "text", text: `Found trips to ${destination}` }] };
21
+ * });
22
+ *
23
+ * export type AppType = typeof server;
24
+ * ```
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // web/src/skybridge.ts (one-time setup)
29
+ * import type { AppType } from "../server";
30
+ * import { createTypedHooks } from "skybridge/web";
31
+ *
32
+ * export const { useCallTool, useToolInfo } = createTypedHooks<AppType>();
33
+ * ```
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * // web/src/widgets/search.tsx (usage)
38
+ * import { useCallTool, useToolInfo } from "../skybridge";
39
+ *
40
+ * export function SearchWidget() {
41
+ * const { callTool, data } = useCallTool("search-voyage");
42
+ * // ^ autocomplete for tool names
43
+ * callTool({ destination: "Spain" });
44
+ * // ^ autocomplete for input fields
45
+ *
46
+ * const toolInfo = useToolInfo<"search-voyage">();
47
+ * // ^ autocomplete for widget names
48
+ * // toolInfo.input is typed based on widget input schema
49
+ * // toolInfo.output is typed based on widget output schema
50
+ * }
51
+ * ```
52
+ */
53
+ export function createTypedHooks() {
54
+ return {
55
+ /**
56
+ * Typed version of `useCallTool` that provides autocomplete for tool names
57
+ * and type inference for inputs and outputs.
58
+ *
59
+ * @param name - The name of the widget to call. Autocompletes based on your server's widget registry.
60
+ * @returns A hook with typed `callTool` function and `data` property.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const { callTool, data, isPending } = useCallTool("search-voyage");
65
+ * // TypeScript knows callTool expects { destination: string }
66
+ * callTool({ destination: "Spain" });
67
+ *
68
+ * // data.structuredContent is typed based on your outputSchema
69
+ * if (data) {
70
+ * console.log(data.structuredContent.results);
71
+ * }
72
+ * ```
73
+ */
74
+ useCallTool: (name) => {
75
+ // Type assertion is safe here because the runtime types are compatible.
76
+ // The underlying hook accepts broader types, but we expose narrower, more specific types.
77
+ return useCallTool(name);
78
+ },
79
+ /**
80
+ * Typed version of `useToolInfo` that provides autocomplete for widget names
81
+ * and type inference for inputs, outputs, and responseMetadata.
82
+ *
83
+ * @typeParam K - The name of the widget. Autocompletes based on your server's widget registry.
84
+ * @returns A discriminated union with `status: "pending" | "success"` that narrows correctly.
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const toolInfo = useToolInfo<"search-voyage">();
89
+ * // toolInfo.input is typed as { destination: string; ... }
90
+ * // toolInfo.output is typed as { results: Array<...>; ... } | undefined
91
+ * // toolInfo.status narrows correctly: "pending" | "success"
92
+ *
93
+ * if (toolInfo.isPending) {
94
+ * // TypeScript knows output is undefined here
95
+ * console.log(toolInfo.input.destination);
96
+ * }
97
+ *
98
+ * if (toolInfo.isSuccess) {
99
+ * // TypeScript knows output is defined here
100
+ * console.log(toolInfo.output.results);
101
+ * }
102
+ * ```
103
+ */
104
+ useToolInfo: () => {
105
+ // Type assertion is safe here because the runtime types are compatible.
106
+ // The underlying hook accepts broader types, but we expose narrower, more specific types.
107
+ return useToolInfo();
108
+ },
109
+ };
110
+ }
111
+ //# sourceMappingURL=typed-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-hooks.js","sourceRoot":"","sources":["../../../src/web/typed-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAgCvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,UAAU,gBAAgB;IAI9B,OAAO;QACL;;;;;;;;;;;;;;;;;;WAkBG;QACH,WAAW,EAAE,CACX,IAAO,EAIP,EAAE;YACF,wEAAwE;YACxE,0FAA0F;YAC1F,OAAO,WAAW,CAGhB,IAAI,CAGL,CAAC;QACJ,CAAC;QACD;;;;;;;;;;;;;;;;;;;;;;;;WAwBG;QACH,WAAW,EAAE,GAIX,EAAE;YACF,wEAAwE;YACxE,0FAA0F;YAC1F,OAAO,WAAW,EAQjB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,87 @@
1
+ import { expectTypeOf, test } from "vitest";
2
+ import { createTypedHooks } from "./typed-hooks.js";
3
+ import { createTestServer } from "../test/utils.js";
4
+ const server = createTestServer();
5
+ test("InferTools extracts the tool registry type (widgets + registerTool)", () => {
6
+ expectTypeOf().toHaveProperty("search-voyage");
7
+ expectTypeOf().toHaveProperty("get-trip-details");
8
+ expectTypeOf().toHaveProperty("no-input-widget");
9
+ expectTypeOf().toHaveProperty("calculate-price");
10
+ });
11
+ test("ToolNames returns a union of tool name literals (widgets + registerTool)", () => {
12
+ expectTypeOf().toEqualTypeOf();
13
+ });
14
+ test("ToolInput extracts the correct input type from Zod schema", () => {
15
+ expectTypeOf().toEqualTypeOf();
16
+ expectTypeOf().toEqualTypeOf();
17
+ expectTypeOf().toEqualTypeOf();
18
+ });
19
+ test("ToolOutput extracts the correct output type from Zod schema", () => {
20
+ expectTypeOf().toEqualTypeOf();
21
+ expectTypeOf().toEqualTypeOf();
22
+ expectTypeOf().toEqualTypeOf();
23
+ });
24
+ test("createTypedHooks provides autocomplete for tool names (widgets + registerTool)", () => {
25
+ const { useCallTool } = createTypedHooks();
26
+ useCallTool("search-voyage");
27
+ useCallTool("get-trip-details");
28
+ useCallTool("no-input-widget");
29
+ useCallTool("calculate-price");
30
+ // @ts-expect-error - "invalid-name" is not a valid tool name
31
+ useCallTool("invalid-name");
32
+ });
33
+ test("useCallTool returns correctly typed callTool function", () => {
34
+ const { useCallTool } = createTypedHooks();
35
+ const { callTool } = useCallTool("search-voyage");
36
+ callTool({ destination: "Spain" });
37
+ callTool({ destination: "France", departureDate: "2024-06-01" });
38
+ callTool({ destination: "Italy", maxPrice: 1000 });
39
+ const { callTool: calculateTool } = useCallTool("calculate-price");
40
+ calculateTool({ tripId: "123", passengers: 2 });
41
+ });
42
+ test("useCallTool returns correctly typed data", () => {
43
+ const { useCallTool } = createTypedHooks();
44
+ const { data } = useCallTool("search-voyage");
45
+ if (data) {
46
+ expectTypeOf(data.structuredContent).toExtend();
47
+ expectTypeOf(data.structuredContent.results).toBeArray();
48
+ expectTypeOf(data.structuredContent.totalCount).toBeNumber();
49
+ }
50
+ });
51
+ test("tools with no outputSchema have empty object output type", () => {
52
+ expectTypeOf().toEqualTypeOf();
53
+ });
54
+ test("createTypedHooks provides autocomplete for tool names in useToolInfo (widgets + registerTool)", () => {
55
+ const { useToolInfo } = createTypedHooks();
56
+ useToolInfo();
57
+ useToolInfo();
58
+ useToolInfo();
59
+ useToolInfo();
60
+ // @ts-expect-error - "invalid-name" is not a valid tool name
61
+ useToolInfo();
62
+ });
63
+ test("useToolInfo infers input types from ToolInput utility", () => {
64
+ const { useToolInfo } = createTypedHooks();
65
+ const toolInfo = useToolInfo();
66
+ expectTypeOf(toolInfo.input).toExtend();
67
+ const detailsInfo = useToolInfo();
68
+ expectTypeOf(detailsInfo.input).toExtend();
69
+ const calculateInfo = useToolInfo();
70
+ expectTypeOf(calculateInfo.input).toExtend();
71
+ });
72
+ test("useToolInfo infers output types from ToolOutput utility", () => {
73
+ const { useToolInfo } = createTypedHooks();
74
+ const toolInfo = useToolInfo();
75
+ if (toolInfo.status === "success") {
76
+ expectTypeOf(toolInfo.output).toExtend();
77
+ }
78
+ const detailsInfo = useToolInfo();
79
+ if (detailsInfo.status === "success") {
80
+ expectTypeOf(detailsInfo.output).toExtend();
81
+ }
82
+ const calculateInfo = useToolInfo();
83
+ if (calculateInfo.status === "success") {
84
+ expectTypeOf(calculateInfo.output).toExtend();
85
+ }
86
+ });
87
+ //# sourceMappingURL=typed-hooks.test-d.js.map