skybridge 0.0.0-dev.f431826 → 0.0.0-dev.f76ccdc

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 (93) hide show
  1. package/README.md +74 -2
  2. package/dist/src/server/server.d.ts +1 -0
  3. package/dist/src/server/server.js +15 -6
  4. package/dist/src/server/server.js.map +1 -1
  5. package/dist/src/server/templateHelper.d.ts +9 -8
  6. package/dist/src/server/templateHelper.js +0 -8
  7. package/dist/src/server/templateHelper.js.map +1 -1
  8. package/dist/src/server/templates/development.hbs +1 -0
  9. package/dist/src/server/templates/production.hbs +3 -2
  10. package/dist/src/test/widget.test.js +23 -2
  11. package/dist/src/test/widget.test.js.map +1 -1
  12. package/dist/src/web/hooks/index.d.ts +13 -0
  13. package/dist/src/web/hooks/index.js +14 -0
  14. package/dist/src/web/hooks/index.js.map +1 -0
  15. package/dist/src/web/hooks/use-call-tool.d.ts +54 -0
  16. package/dist/src/web/hooks/use-call-tool.js +44 -0
  17. package/dist/src/web/hooks/use-call-tool.js.map +1 -0
  18. package/dist/src/web/hooks/use-call-tool.test.d.ts +1 -0
  19. package/dist/src/web/hooks/use-call-tool.test.js +66 -0
  20. package/dist/src/web/hooks/use-call-tool.test.js.map +1 -0
  21. package/dist/src/web/hooks/use-display-mode.d.ts +4 -0
  22. package/dist/src/web/hooks/use-display-mode.js +7 -0
  23. package/dist/src/web/hooks/use-display-mode.js.map +1 -0
  24. package/dist/src/web/hooks/use-display-mode.test.d.ts +1 -0
  25. package/dist/src/web/hooks/use-display-mode.test.js +40 -0
  26. package/dist/src/web/hooks/use-display-mode.test.js.map +1 -0
  27. package/dist/src/web/hooks/use-locale.d.ts +1 -0
  28. package/dist/src/web/hooks/use-locale.js +5 -0
  29. package/dist/src/web/hooks/use-locale.js.map +1 -0
  30. package/dist/src/web/hooks/use-locale.test.d.ts +1 -0
  31. package/dist/src/web/hooks/use-locale.test.js +21 -0
  32. package/dist/src/web/hooks/use-locale.test.js.map +1 -0
  33. package/dist/src/web/hooks/use-open-external.d.ts +1 -0
  34. package/dist/src/web/hooks/use-open-external.js +6 -0
  35. package/dist/src/web/hooks/use-open-external.js.map +1 -0
  36. package/dist/src/web/hooks/use-open-external.test.d.ts +1 -0
  37. package/dist/src/web/hooks/use-open-external.test.js +24 -0
  38. package/dist/src/web/hooks/use-open-external.test.js.map +1 -0
  39. package/dist/src/web/{use-openai-global.d.ts → hooks/use-openai-global.d.ts} +1 -1
  40. package/dist/src/web/{use-openai-global.js → hooks/use-openai-global.js} +1 -1
  41. package/dist/src/web/hooks/use-openai-global.js.map +1 -0
  42. package/dist/src/web/hooks/use-request-modal.d.ts +5 -0
  43. package/dist/src/web/hooks/use-request-modal.js +9 -0
  44. package/dist/src/web/hooks/use-request-modal.js.map +1 -0
  45. package/dist/src/web/hooks/use-request-modal.test.d.ts +1 -0
  46. package/dist/src/web/hooks/use-request-modal.test.js +24 -0
  47. package/dist/src/web/hooks/use-request-modal.test.js.map +1 -0
  48. package/dist/src/web/hooks/use-send-follow-up-message.d.ts +1 -0
  49. package/dist/src/web/hooks/use-send-follow-up-message.js +11 -0
  50. package/dist/src/web/hooks/use-send-follow-up-message.js.map +1 -0
  51. package/dist/src/web/hooks/use-theme.d.ts +1 -0
  52. package/dist/src/web/hooks/use-theme.js +5 -0
  53. package/dist/src/web/hooks/use-theme.js.map +1 -0
  54. package/dist/src/web/hooks/use-theme.test.d.ts +1 -0
  55. package/dist/src/web/hooks/use-theme.test.js +26 -0
  56. package/dist/src/web/hooks/use-theme.test.js.map +1 -0
  57. package/dist/src/web/hooks/use-tool-info.d.ts +5 -0
  58. package/dist/src/web/hooks/use-tool-info.js +9 -0
  59. package/dist/src/web/hooks/use-tool-info.js.map +1 -0
  60. package/dist/src/web/hooks/use-tool-info.test.d.ts +1 -0
  61. package/dist/src/web/hooks/use-tool-info.test.js +38 -0
  62. package/dist/src/web/hooks/use-tool-info.test.js.map +1 -0
  63. package/dist/src/web/hooks/use-tool-output.d.ts +4 -0
  64. package/dist/src/web/hooks/use-tool-output.js +9 -0
  65. package/dist/src/web/hooks/use-tool-output.js.map +1 -0
  66. package/dist/src/web/hooks/use-tool-response-metadata.d.ts +4 -0
  67. package/dist/src/web/hooks/use-tool-response-metadata.js +8 -0
  68. package/dist/src/web/hooks/use-tool-response-metadata.js.map +1 -0
  69. package/dist/src/web/hooks/use-user-agent.d.ts +1 -0
  70. package/dist/src/web/hooks/use-user-agent.js +5 -0
  71. package/dist/src/web/hooks/use-user-agent.js.map +1 -0
  72. package/dist/src/web/hooks/use-user-agent.test.d.ts +1 -0
  73. package/dist/src/web/hooks/use-user-agent.test.js +31 -0
  74. package/dist/src/web/hooks/use-user-agent.test.js.map +1 -0
  75. package/dist/src/web/hooks/use-widget-state.d.ts +4 -0
  76. package/dist/src/web/hooks/use-widget-state.js +30 -0
  77. package/dist/src/web/hooks/use-widget-state.js.map +1 -0
  78. package/dist/src/web/hooks/use-widget-state.test.d.ts +1 -0
  79. package/dist/src/web/hooks/use-widget-state.test.js +61 -0
  80. package/dist/src/web/hooks/use-widget-state.test.js.map +1 -0
  81. package/dist/src/web/index.d.ts +2 -2
  82. package/dist/src/web/index.js +2 -2
  83. package/dist/src/web/index.js.map +1 -1
  84. package/dist/src/web/plugin.d.ts +2 -0
  85. package/dist/src/web/plugin.js +28 -0
  86. package/dist/src/web/plugin.js.map +1 -0
  87. package/dist/src/web/types.d.ts +16 -2
  88. package/dist/src/web/types.js.map +1 -1
  89. package/package.json +8 -3
  90. package/dist/src/web/use-openai-global.js.map +0 -1
  91. package/dist/src/web/use-tool-output.d.ts +0 -3
  92. package/dist/src/web/use-tool-output.js +0 -5
  93. package/dist/src/web/use-tool-output.js.map +0 -1
package/README.md CHANGED
@@ -99,15 +99,87 @@ export default defineConfig({
99
99
 
100
100
  **Hooks**
101
101
 
102
- The `skybridge/web` package comes with a set of hooks to help you build your widgets.
102
+ The `skybridge/web` package comes with a set of hooks to help you build your widgets :
103
+
104
+ - `useOpenAiGlobal`: A generic hook to get any global data from the OpenAI iFrame skybridge runtime (in `window.openai`).
105
+ - `useToolOutput`: A hook to get the initial tool `structuredContent` returned when rendering the widget for the first time. The data inside this hook is not updated when the tool is called again.
106
+ - `useToolResponseMetadata`: A hook to get the initial tool `meta` returned when rendering the widget for the first time. The data inside this hook is not updated when the tool is called again.
107
+ - `useCallTool`: A @tanstack/react-query inspired hook to send make additional tool calls inside a widget.
108
+
109
+ _useOpenAiGlobal_
110
+
111
+ ```ts
112
+ import { useOpenAiGlobal } from "skybridge/web";
113
+
114
+ const theme = useOpenAiGlobal("theme");
115
+ ```
116
+
117
+ _useToolOutput_
103
118
 
104
119
  ```ts
105
120
  import { useToolOutput } from "skybridge/web";
106
121
 
107
- // Initial data returned by the tool invocation on structuredOutput
108
122
  const toolOutput = useToolOutput();
109
123
  ```
110
124
 
125
+ _useToolResponseMetadata_
126
+
127
+ ```ts
128
+ import { useToolResponseMetadata } from "skybridge/web";
129
+
130
+ const toolResponseMetadata = useToolResponseMetadata();
131
+ ```
132
+
133
+ _useCallTool_ in synchronous mode
134
+
135
+ ```ts
136
+ import { useCallTool } from "skybridge/web";
137
+
138
+ export const TestTool: React.FunctionComponent = () => {
139
+ const { callTool, isPending } = useCallTool("myToolName");
140
+
141
+ return (
142
+ <div>
143
+ <button
144
+ disabled={isPending}
145
+ onClick={() => {
146
+ callTool({ input: "test input" }, {
147
+ onSuccess: (data) => {
148
+ alert("Tool returned: " + data);
149
+ },
150
+ });
151
+ >
152
+ Call Tool inside a widget
153
+ </button>
154
+ </div>
155
+ );
156
+ };
157
+ ```
158
+
159
+ _useCallTool_ in asynchronous mode
160
+
161
+ ```ts
162
+ import { useCallTool } from "skybridge/web";
163
+
164
+ export const TestTool: React.FunctionComponent = () => {
165
+ const { callToolAsync, isPending } = useCallTool("myToolName");
166
+
167
+ return (
168
+ <div>
169
+ <button
170
+ disabled={isPending}
171
+ onClick={async () => {
172
+ const data = await callToolAsync({ input: "test input" });
173
+ alert("Tool returned: " + data);
174
+ }}
175
+ >
176
+ Call Tool inside a widget
177
+ </button>
178
+ </div>
179
+ );
180
+ };
181
+ ```
182
+
111
183
  ## Migrate your existing MCP server to a ChatGPT app
112
184
 
113
185
  If you're already using the `@modelcontextprotocol/sdk` to build a MCP server, you can migrate to a ChatGPT app by following these steps:
@@ -8,5 +8,6 @@ export declare class McpServer extends McpServerBase {
8
8
  inputSchema?: InputArgs;
9
9
  outputSchema?: OutputArgs;
10
10
  }, toolCallback: ToolCallback<InputArgs>): void;
11
+ private lookupDistFile;
11
12
  }
12
13
  export {};
@@ -1,5 +1,7 @@
1
1
  import { McpServer as McpServerBase, } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { templateHelper } from "./templateHelper.js";
3
+ import { readFileSync } from "node:fs";
4
+ import path from "node:path";
3
5
  export class McpServer extends McpServerBase {
4
6
  widget(name, resourceConfig, toolConfig, toolCallback) {
5
7
  const uri = `ui://widgets/${name}.html`;
@@ -15,13 +17,16 @@ export class McpServer extends McpServerBase {
15
17
  ? `https://${extra?.requestInfo?.headers?.["x-forwarded-host"] ??
16
18
  extra?.requestInfo?.headers?.host}`
17
19
  : `http://localhost:3000`;
18
- const templateData = {
19
- serverUrl,
20
- widgetName: name,
21
- };
22
20
  const html = process.env.NODE_ENV === "production"
23
- ? templateHelper.renderProduction(templateData)
24
- : templateHelper.renderDevelopment(templateData);
21
+ ? templateHelper.renderProduction({
22
+ serverUrl,
23
+ widgetFile: this.lookupDistFile(`src/widgets/${name}.tsx`),
24
+ styleFile: this.lookupDistFile("style.css"),
25
+ })
26
+ : templateHelper.renderDevelopment({
27
+ serverUrl,
28
+ widgetName: name,
29
+ });
25
30
  return {
26
31
  contents: [
27
32
  {
@@ -41,5 +46,9 @@ export class McpServer extends McpServerBase {
41
46
  _meta: toolMeta,
42
47
  }, toolCallback);
43
48
  }
49
+ lookupDistFile(key) {
50
+ const manifest = JSON.parse(readFileSync(path.join(process.cwd(), "dist", "assets", ".vite", "manifest.json"), "utf-8"));
51
+ return manifest[key]?.file;
52
+ }
44
53
  }
45
54
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,IAAI,aAAa,GAE3B,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA4BrD,MAAM,OAAO,SAAU,SAAQ,aAAa;IAC1C,MAAM,CACJ,IAAY,EACZ,cAA+C,EAC/C,UAGC,EACD,YAAqC;QAErC,MAAM,GAAG,GAAG,gBAAgB,IAAI,OAAO,CAAC;QACxC,MAAM,gBAAgB,GAAiB,EAAE,GAAG,CAAC,cAAc,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3E,IAAI,UAAU,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACzC,gBAAgB,CAAC,0BAA0B,CAAC,GAAG,UAAU,CAAC,WAAW,CAAC;QACxE,CAAC;QAED,IAAI,CAAC,QAAQ,CACX,IAAI,EACJ,GAAG,EACH;YACE,GAAG,cAAc;YACjB,KAAK,EAAE,gBAAgB;SACxB,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;YACpB,MAAM,SAAS,GACb,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;gBACnC,CAAC,CAAC,WACE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,kBAAkB,CAAC;oBACjD,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,IAC/B,EAAE;gBACJ,CAAC,CAAC,uBAAuB,CAAC;YAE9B,MAAM,YAAY,GAAG;gBACnB,SAAS;gBACT,UAAU,EAAE,IAAI;aACjB,CAAC;YAEF,MAAM,IAAI,GACR,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;gBACnC,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,YAAY,CAAC;gBAC/C,CAAC,CAAC,cAAc,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;YAErD,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG;wBACH,QAAQ,EAAE,qBAAqB;wBAC/B,IAAI,EAAE,IAAI;qBACX;iBACF;aACF,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,MAAM,QAAQ,GAAa;YACzB,GAAG,UAAU,CAAC,KAAK;YACnB,uBAAuB,EAAE,GAAG;SAC7B,CAAC;QAEF,IAAI,CAAC,YAAY,CACf,IAAI,EACJ;YACE,GAAG,UAAU;YACb,KAAK,EAAE,QAAQ;SAChB,EACD,YAAY,CACb,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,IAAI,aAAa,GAE3B,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AA4B7B,MAAM,OAAO,SAAU,SAAQ,aAAa;IAC1C,MAAM,CACJ,IAAY,EACZ,cAA+C,EAC/C,UAGC,EACD,YAAqC;QAErC,MAAM,GAAG,GAAG,gBAAgB,IAAI,OAAO,CAAC;QACxC,MAAM,gBAAgB,GAAiB,EAAE,GAAG,CAAC,cAAc,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3E,IAAI,UAAU,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACzC,gBAAgB,CAAC,0BAA0B,CAAC,GAAG,UAAU,CAAC,WAAW,CAAC;QACxE,CAAC;QAED,IAAI,CAAC,QAAQ,CACX,IAAI,EACJ,GAAG,EACH;YACE,GAAG,cAAc;YACjB,KAAK,EAAE,gBAAgB;SACxB,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;YACpB,MAAM,SAAS,GACb,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;gBACnC,CAAC,CAAC,WACE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,kBAAkB,CAAC;oBACjD,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,IAC/B,EAAE;gBACJ,CAAC,CAAC,uBAAuB,CAAC;YAE9B,MAAM,IAAI,GACR,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;gBACnC,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC;oBAC9B,SAAS;oBACT,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,eAAe,IAAI,MAAM,CAAC;oBAC1D,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC;iBAC5C,CAAC;gBACJ,CAAC,CAAC,cAAc,CAAC,iBAAiB,CAAC;oBAC/B,SAAS;oBACT,UAAU,EAAE,IAAI;iBACjB,CAAC,CAAC;YAET,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG;wBACH,QAAQ,EAAE,qBAAqB;wBAC/B,IAAI,EAAE,IAAI;qBACX;iBACF;aACF,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,MAAM,QAAQ,GAAa;YACzB,GAAG,UAAU,CAAC,KAAK;YACnB,uBAAuB,EAAE,GAAG;SAC7B,CAAC;QAEF,IAAI,CAAC,YAAY,CACf,IAAI,EACJ;YACE,GAAG,UAAU;YACb,KAAK,EAAE,QAAQ;SAChB,EACD,YAAY,CACb,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,GAAW;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,YAAY,CACV,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAC,EACpE,OAAO,CACR,CACF,CAAC;QAEF,OAAO,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;IAC7B,CAAC;CACF"}
@@ -1,14 +1,15 @@
1
- type TemplateData = {
2
- serverUrl: string;
3
- widgetName: string;
4
- };
5
1
  declare class TemplateHelper {
6
2
  private templateCache;
7
3
  private loadTemplate;
8
- renderProduction(data: TemplateData): string;
9
- renderDevelopment(data: TemplateData): string;
10
- renderViteClient(data: TemplateData): string;
11
- injectViteClient(html: string, data: TemplateData): string;
4
+ renderProduction(data: {
5
+ serverUrl: string;
6
+ widgetFile: string;
7
+ styleFile: string;
8
+ }): string;
9
+ renderDevelopment(data: {
10
+ serverUrl: string;
11
+ widgetName: string;
12
+ }): string;
12
13
  }
13
14
  export declare const templateHelper: TemplateHelper;
14
15
  export {};
@@ -24,14 +24,6 @@ class TemplateHelper {
24
24
  const template = this.loadTemplate("development");
25
25
  return template(data);
26
26
  }
27
- renderViteClient(data) {
28
- const template = this.loadTemplate("vite-client");
29
- return template(data);
30
- }
31
- injectViteClient(html, data) {
32
- const viteClientScript = this.renderViteClient(data);
33
- return viteClientScript + html;
34
- }
35
27
  }
36
28
  export const templateHelper = new TemplateHelper();
37
29
  //# sourceMappingURL=templateHelper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"templateHelper.js","sourceRoot":"","sources":["../../../src/server/templateHelper.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAOtC,MAAM,cAAc;IACV,aAAa,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE9D,YAAY,CAAC,YAAoB;QACvC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC;QAC/C,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,YAAY,MAAM,CAAC,CAAC;QACzE,MAAM,cAAc,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAEpD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,gBAAgB,CAAC,IAAkB;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QACjD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,iBAAiB,CAAC,IAAkB;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAClD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,gBAAgB,CAAC,IAAkB;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAClD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,gBAAgB,CAAC,IAAY,EAAE,IAAkB;QAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO,gBAAgB,GAAG,IAAI,CAAC;IACjC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"templateHelper.js","sourceRoot":"","sources":["../../../src/server/templateHelper.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAOtC,MAAM,cAAc;IACV,aAAa,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE9D,YAAY,CAAC,YAAoB;QACvC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC;QAC/C,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,YAAY,MAAM,CAAC,CAAC;QACzE,MAAM,cAAc,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAEpD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,gBAAgB,CAAC,IAIhB;QACC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QACjD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,iBAAiB,CAAC,IAA+C;QAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAClD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"}
@@ -1,3 +1,4 @@
1
+ <base href="{{serverUrl}}" />
1
2
  <script type="module">
2
3
  import { injectIntoGlobalHook } from "{{serverUrl}}/@react-refresh";
3
4
  injectIntoGlobalHook(window); window.$RefreshReg$ = () => {};
@@ -1,5 +1,6 @@
1
+ <base href="{{serverUrl}}" />
1
2
  <div id="root"></div>
2
3
  <script type="module">
3
- import('{{serverUrl}}/assets/{{widgetName}}.js');
4
+ import('{{serverUrl}}/assets/{{widgetFile}}');
4
5
  </script>
5
- <link rel="stylesheet" crossorigin href="{{serverUrl}}/assets/style.css" />
6
+ <link rel="stylesheet" crossorigin href="{{serverUrl}}/assets/{{styleFile}}" />
@@ -1,10 +1,31 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach, } from "vitest";
1
+ import * as fs from "node:fs";
2
+ import { afterEach, beforeEach, describe, expect, it, vi, } from "vitest";
2
3
  import { McpServer } from "../server/server.js";
3
- import { createMockMcpServer, createMockExtra, setTestEnv, resetTestEnv, } from "./utils.js";
4
+ import { createMockExtra, createMockMcpServer, resetTestEnv, setTestEnv, } from "./utils.js";
5
+ const mockManifest = {
6
+ "src/widgets/my-widget.tsx": { file: "my-widget.js" },
7
+ "style.css": { file: "style.css" },
8
+ };
9
+ vi.mock("node:fs", async () => {
10
+ const actual = await vi.importActual("node:fs");
11
+ const readFileSync = vi.fn((path, ...args) => {
12
+ if (typeof path === "string" && path.includes("manifest.json")) {
13
+ return JSON.stringify(mockManifest);
14
+ }
15
+ return actual.readFileSync(path, ...args);
16
+ });
17
+ return {
18
+ readFileSync,
19
+ default: {
20
+ readFileSync,
21
+ },
22
+ };
23
+ });
4
24
  describe("McpServer.widget", () => {
5
25
  let server;
6
26
  let mockResource;
7
27
  let mockRegisterTool;
28
+ let readFileSyncSpy = null;
8
29
  beforeEach(() => {
9
30
  ({ server, mockResource, mockRegisterTool } = createMockMcpServer());
10
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"widget.test.js","sourceRoot":"","sources":["../../../src/test/widget.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"widget.test.js","sourceRoot":"","sources":["../../../src/test/widget.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { useCallTool } from "./use-call-tool.js";
2
+ export { useDisplayMode } from "./use-display-mode.js";
3
+ export { useLocale } from "./use-locale.js";
4
+ export { useOpenExternal } from "./use-open-external.js";
5
+ export { useOpenAiGlobal } from "./use-openai-global.js";
6
+ export { useRequestModal } from "./use-request-modal.js";
7
+ export { useSendFollowUpMessage } from "./use-send-follow-up-message.js";
8
+ export { useTheme } from "./use-theme.js";
9
+ export { useToolInfo } from "./use-tool-info.js";
10
+ export { useToolOutput } from "./use-tool-output.js";
11
+ export { useToolResponseMetadata } from "./use-tool-response-metadata.js";
12
+ export { useUserAgent } from "./use-user-agent.js";
13
+ export { useWidgetState } from "./use-widget-state.js";
@@ -0,0 +1,14 @@
1
+ export { useCallTool } from "./use-call-tool.js";
2
+ export { useDisplayMode } from "./use-display-mode.js";
3
+ export { useLocale } from "./use-locale.js";
4
+ export { useOpenExternal } from "./use-open-external.js";
5
+ export { useOpenAiGlobal } from "./use-openai-global.js";
6
+ export { useRequestModal } from "./use-request-modal.js";
7
+ export { useSendFollowUpMessage } from "./use-send-follow-up-message.js";
8
+ export { useTheme } from "./use-theme.js";
9
+ export { useToolInfo } from "./use-tool-info.js";
10
+ export { useToolOutput } from "./use-tool-output.js";
11
+ export { useToolResponseMetadata } from "./use-tool-response-metadata.js";
12
+ export { useUserAgent } from "./use-user-agent.js";
13
+ export { useWidgetState } from "./use-widget-state.js";
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/web/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { CallToolArgs, CallToolResponse } from "../types.js";
2
+ export declare const useCallTool: <ToolArgs extends CallToolArgs = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string) => {
3
+ callTool: (toolArgs: ToolArgs, sideEffects?: {
4
+ onSuccess?: (data: ToolResponse, toolArgs: ToolArgs) => void;
5
+ onError?: (error: unknown, toolArgs: ToolArgs) => void;
6
+ }) => void;
7
+ callToolAsync: (toolArgs: ToolArgs) => Promise<ToolResponse>;
8
+ status: "idle";
9
+ isIdle: true;
10
+ isPending: false;
11
+ isSuccess: false;
12
+ isError: false;
13
+ data: undefined;
14
+ error: undefined;
15
+ } | {
16
+ callTool: (toolArgs: ToolArgs, sideEffects?: {
17
+ onSuccess?: (data: ToolResponse, toolArgs: ToolArgs) => void;
18
+ onError?: (error: unknown, toolArgs: ToolArgs) => void;
19
+ }) => void;
20
+ callToolAsync: (toolArgs: ToolArgs) => Promise<ToolResponse>;
21
+ status: "pending";
22
+ isIdle: false;
23
+ isPending: true;
24
+ isSuccess: false;
25
+ isError: false;
26
+ data: undefined;
27
+ error: undefined;
28
+ } | {
29
+ callTool: (toolArgs: ToolArgs, sideEffects?: {
30
+ onSuccess?: (data: ToolResponse, toolArgs: ToolArgs) => void;
31
+ onError?: (error: unknown, toolArgs: ToolArgs) => void;
32
+ }) => void;
33
+ callToolAsync: (toolArgs: ToolArgs) => Promise<ToolResponse>;
34
+ status: "error";
35
+ isIdle: false;
36
+ isPending: false;
37
+ isSuccess: false;
38
+ isError: true;
39
+ data: undefined;
40
+ error: unknown;
41
+ } | {
42
+ callTool: (toolArgs: ToolArgs, sideEffects?: {
43
+ onSuccess?: (data: ToolResponse, toolArgs: ToolArgs) => void;
44
+ onError?: (error: unknown, toolArgs: ToolArgs) => void;
45
+ }) => void;
46
+ callToolAsync: (toolArgs: ToolArgs) => Promise<ToolResponse>;
47
+ status: "success";
48
+ isIdle: false;
49
+ isPending: false;
50
+ isSuccess: true;
51
+ isError: false;
52
+ data: ToolResponse;
53
+ error: undefined;
54
+ };
@@ -0,0 +1,44 @@
1
+ import { useState } from "react";
2
+ export const useCallTool = (name) => {
3
+ const [{ status, data, error }, setCallToolState] = useState({ status: "idle", data: undefined, error: undefined });
4
+ const callToolAsync = async (toolArgs) => {
5
+ setCallToolState({ status: "pending", data: undefined, error: undefined });
6
+ try {
7
+ const data = await window.openai.callTool(name, toolArgs);
8
+ setCallToolState({ status: "success", data, error: undefined });
9
+ return data;
10
+ }
11
+ catch (error) {
12
+ setCallToolState({ status: "error", data: undefined, error });
13
+ throw error;
14
+ }
15
+ };
16
+ const callTool = (toolArgs, sideEffects) => {
17
+ callToolAsync(toolArgs)
18
+ .then((data) => {
19
+ if (sideEffects?.onSuccess) {
20
+ sideEffects.onSuccess(data, toolArgs);
21
+ }
22
+ })
23
+ .catch((error) => {
24
+ if (sideEffects?.onError) {
25
+ sideEffects.onError(error, toolArgs);
26
+ }
27
+ });
28
+ };
29
+ const callToolState = {
30
+ status,
31
+ data,
32
+ error,
33
+ isIdle: status === "idle",
34
+ isPending: status === "pending",
35
+ isSuccess: status === "success",
36
+ isError: status === "error",
37
+ };
38
+ return {
39
+ ...callToolState,
40
+ callTool,
41
+ callToolAsync,
42
+ };
43
+ };
44
+ //# sourceMappingURL=use-call-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-call-tool.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-call-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AA4BjC,MAAM,CAAC,MAAM,WAAW,GAAG,CAIzB,IAAY,EACZ,EAAE;IACF,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAK1D,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAEzD,MAAM,aAAa,GAAG,KAAK,EAAE,QAAkB,EAAE,EAAE;QACjD,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3E,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,CACvC,IAAI,EACJ,QAAQ,CACT,CAAC;YACF,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAEhE,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gBAAgB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,CACf,QAAkB,EAClB,WAGC,EACD,EAAE;QACF,aAAa,CAAC,QAAQ,CAAC;aACpB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,WAAW,EAAE,SAAS,EAAE,CAAC;gBAC3B,WAAW,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACxC,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAI,WAAW,EAAE,OAAO,EAAE,CAAC;gBACzB,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;QACH,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG;QACpB,MAAM;QACN,IAAI;QACJ,KAAK;QACL,MAAM,EAAE,MAAM,KAAK,MAAM;QACzB,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,SAAS,EAAE,MAAM,KAAK,SAAS;QAC/B,OAAO,EAAE,MAAM,KAAK,OAAO;KACG,CAAC;IAEjC,OAAO;QACL,GAAG,aAAa;QAChB,QAAQ;QACR,aAAa;KACd,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ import { useCallTool } from "./use-call-tool.js";
2
+ import { describe, it, expect, vi, beforeEach, afterEach, } from "vitest";
3
+ import { renderHook, act, waitFor } from "@testing-library/react";
4
+ describe("useCallTool - onSuccess callback", () => {
5
+ let OpenaiMock;
6
+ beforeEach(() => {
7
+ OpenaiMock = {
8
+ callTool: vi.fn(),
9
+ };
10
+ vi.stubGlobal("openai", OpenaiMock);
11
+ });
12
+ afterEach(() => {
13
+ vi.unstubAllGlobals();
14
+ vi.resetAllMocks();
15
+ });
16
+ const toolName = "test-tool";
17
+ const args = { input: "test input" };
18
+ const data = {
19
+ content: [{ type: "text", text: "test result" }],
20
+ structuredContent: { result: "test" },
21
+ isError: false,
22
+ result: "test result",
23
+ meta: {},
24
+ };
25
+ const error = new Error("test error");
26
+ it("should call window.openai.callTool with correct arguments", async () => {
27
+ const { result } = renderHook(() => useCallTool(toolName));
28
+ act(() => {
29
+ result.current.callTool(args);
30
+ });
31
+ expect(OpenaiMock.callTool).toHaveBeenCalledWith(toolName, args);
32
+ });
33
+ it("should call onSuccess callback with correct data and toolArgs on successful execution", async () => {
34
+ const onSuccess = vi.fn();
35
+ const onError = vi.fn();
36
+ OpenaiMock.callTool.mockResolvedValueOnce(data);
37
+ const { result } = renderHook(() => useCallTool(toolName));
38
+ act(() => {
39
+ result.current.callTool(args, {
40
+ onSuccess,
41
+ onError,
42
+ });
43
+ });
44
+ await waitFor(() => {
45
+ expect(onSuccess).toHaveBeenCalledWith(data, args);
46
+ expect(onError).not.toHaveBeenCalled();
47
+ });
48
+ });
49
+ it("should call onError callback with error and toolArgs on failed execution", async () => {
50
+ const onSuccess = vi.fn();
51
+ const onError = vi.fn();
52
+ OpenaiMock.callTool.mockRejectedValueOnce(error);
53
+ const { result } = renderHook(() => useCallTool(toolName));
54
+ act(() => {
55
+ result.current.callTool(args, {
56
+ onSuccess,
57
+ onError,
58
+ });
59
+ });
60
+ await waitFor(() => {
61
+ expect(onSuccess).not.toHaveBeenCalled();
62
+ expect(onError).toHaveBeenCalledWith(error, args);
63
+ });
64
+ });
65
+ });
66
+ //# sourceMappingURL=use-call-tool.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-call-tool.test.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-call-tool.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { DisplayMode } from "../types.js";
2
+ export declare function useDisplayMode(): readonly [DisplayMode, (mode: DisplayMode) => Promise<{
3
+ mode: DisplayMode;
4
+ }>];
@@ -0,0 +1,7 @@
1
+ import { useOpenAiGlobal } from "./use-openai-global.js";
2
+ export function useDisplayMode() {
3
+ const displayMode = useOpenAiGlobal("displayMode");
4
+ const setDisplayMode = (mode) => window.openai.requestDisplayMode({ mode });
5
+ return [displayMode, setDisplayMode];
6
+ }
7
+ //# sourceMappingURL=use-display-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-display-mode.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-display-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,MAAM,UAAU,cAAc;IAC5B,MAAM,WAAW,GAAG,eAAe,CAAC,aAAa,CAAE,CAAC;IACpD,MAAM,cAAc,GAAG,CAAC,IAAiB,EAAE,EAAE,CAC3C,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,OAAO,CAAC,WAAW,EAAE,cAAc,CAAU,CAAC;AAChD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { useDisplayMode } from "./use-display-mode.js";
2
+ import { describe, it, expect, vi, beforeEach, afterEach, } from "vitest";
3
+ import { renderHook, act } from "@testing-library/react";
4
+ describe("useDisplayMode", () => {
5
+ let OpenaiMock;
6
+ beforeEach(() => {
7
+ OpenaiMock = {
8
+ displayMode: "inline",
9
+ requestDisplayMode: vi.fn().mockResolvedValue({ mode: "inline" }),
10
+ };
11
+ vi.stubGlobal("openai", OpenaiMock);
12
+ });
13
+ afterEach(() => {
14
+ vi.unstubAllGlobals();
15
+ vi.resetAllMocks();
16
+ });
17
+ it("should return the current display mode from window.openai.displayMode", () => {
18
+ OpenaiMock.displayMode = "inline";
19
+ const { result } = renderHook(() => useDisplayMode());
20
+ expect(result.current[0]).toBe("inline");
21
+ });
22
+ it("should return different display modes when window.openai.displayMode changes", () => {
23
+ OpenaiMock.displayMode = "inline";
24
+ const { result, rerender } = renderHook(() => useDisplayMode());
25
+ expect(result.current[0]).toBe("inline");
26
+ OpenaiMock.displayMode = "fullscreen";
27
+ rerender();
28
+ expect(result.current[0]).toBe("fullscreen");
29
+ });
30
+ it("should call window.openai.requestDisplayMode with correct mode when setDisplayMode is called", async () => {
31
+ const { result } = renderHook(() => useDisplayMode());
32
+ await act(async () => {
33
+ await result.current[1]("fullscreen");
34
+ });
35
+ expect(OpenaiMock.requestDisplayMode).toHaveBeenCalledWith({
36
+ mode: "fullscreen",
37
+ });
38
+ });
39
+ });
40
+ //# sourceMappingURL=use-display-mode.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-display-mode.test.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-display-mode.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,QAAQ,EACR,EAAE,EACF,MAAM,EACN,EAAE,EACF,UAAU,EACV,SAAS,GAEV,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAGzD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,UAGH,CAAC;IAEF,UAAU,CAAC,GAAG,EAAE;QACd,UAAU,GAAG;YACX,WAAW,EAAE,QAAQ;YACrB,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;SAClE,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,uEAAuE,EAAE,GAAG,EAAE;QAC/E,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC;QAClC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAEtD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC;QAClC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAEhE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEzC,UAAU,CAAC,WAAW,GAAG,YAAY,CAAC;QACtC,QAAQ,EAAE,CAAC;QAEX,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8FAA8F,EAAE,KAAK,IAAI,EAAE;QAC5G,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAEtD,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC;YACzD,IAAI,EAAE,YAAY;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function useLocale(): string;
@@ -0,0 +1,5 @@
1
+ import { useOpenAiGlobal } from "./use-openai-global.js";
2
+ export function useLocale() {
3
+ return useOpenAiGlobal("locale");
4
+ }
5
+ //# sourceMappingURL=use-locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-locale.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-locale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,UAAU,SAAS;IACvB,OAAO,eAAe,CAAC,QAAQ,CAAE,CAAC;AACpC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import { useLocale } from "./use-locale.js";
2
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
3
+ import { renderHook } from "@testing-library/react";
4
+ describe("useLocale", () => {
5
+ let OpenaiMock;
6
+ beforeEach(() => {
7
+ OpenaiMock = {
8
+ locale: "en-US",
9
+ };
10
+ vi.stubGlobal("openai", OpenaiMock);
11
+ });
12
+ afterEach(() => {
13
+ vi.unstubAllGlobals();
14
+ vi.resetAllMocks();
15
+ });
16
+ it("should return the current locale from window.openai.locale", () => {
17
+ const { result } = renderHook(() => useLocale());
18
+ expect(result.current).toBe("en-US");
19
+ });
20
+ });
21
+ //# sourceMappingURL=use-locale.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-locale.test.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-locale.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAI,UAEH,CAAC;IAEF,UAAU,CAAC,GAAG,EAAE;QACd,UAAU,GAAG;YACX,MAAM,EAAE,OAAO;SAChB,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,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;QAEjD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function useOpenExternal(): (href: string) => void;
@@ -0,0 +1,6 @@
1
+ export function useOpenExternal() {
2
+ return (href) => {
3
+ window.openai.openExternal({ href });
4
+ };
5
+ }
6
+ //# sourceMappingURL=use-open-external.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-open-external.js","sourceRoot":"","sources":["../../../../src/web/hooks/use-open-external.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,IAAY,EAAE,EAAE;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};