@apollo/client-ai-apps 0.1.1 → 0.2.1

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.
@@ -31,22 +31,22 @@ jobs:
31
31
  shell: bash
32
32
  run: npm run build
33
33
 
34
- # - name: Test
35
- # shell: bash
36
- # run: npm run test
37
-
38
- # - name: Configure Git
39
- # run: |
40
- # git config --global user.name GitHub Actions
41
- # git config user.email github-actions@github.com
42
-
43
- # - uses: knope-dev/action@v2.1.0
44
- # with:
45
- # version: 0.21.5
46
-
47
- # - run: knope release
48
- # env:
49
- # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34
+ - name: Test
35
+ shell: bash
36
+ run: npm run test
37
+
38
+ - name: Configure Git
39
+ run: |
40
+ git config --global user.name GitHub Actions
41
+ git config user.email github-actions@github.com
42
+
43
+ - uses: knope-dev/action@v2.1.0
44
+ with:
45
+ version: 0.21.5
46
+
47
+ - run: knope release
48
+ env:
49
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50
50
 
51
51
  - name: Publish to npm
52
52
  shell: bash
@@ -1,4 +1,6 @@
1
1
  import { DisplayMode } from "../types/openai";
2
2
  export declare const useRequestDisplayMode: () => (args: {
3
3
  mode: DisplayMode;
4
- }) => Promise<void>;
4
+ }) => Promise<{
5
+ mode: DisplayMode;
6
+ }>;
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ var useSendFollowUpMessage = () => {
51
51
  // src/hooks/useRequestDisplayMode.ts
52
52
  var useRequestDisplayMode = () => {
53
53
  return async (args) => {
54
- await window.openai?.requestDisplayMode(args);
54
+ return await window.openai?.requestDisplayMode(args);
55
55
  };
56
56
  };
57
57
 
@@ -6,13 +6,14 @@ export type ApplicationManifest = {
6
6
  hash: string;
7
7
  resource: string;
8
8
  operations: ManifestOperation[];
9
+ csp: ManifestCsp;
9
10
  };
10
11
  export type ManifestOperation = {
11
12
  id: string;
12
13
  name: string;
13
14
  type: "query" | "mutation";
14
15
  body: string;
15
- variables: Record<string, string>;
16
+ variables?: Record<string, string | undefined>;
16
17
  prefetch: boolean;
17
18
  prefetchID?: string;
18
19
  tools: ManifestTool[];
@@ -27,3 +28,7 @@ export type ManifestExtraInput = {
27
28
  description: string;
28
29
  type: "string" | "boolean" | "number";
29
30
  };
31
+ export type ManifestCsp = {
32
+ connectDomains: string[];
33
+ resourceDomains: string[];
34
+ };
@@ -1,6 +1,6 @@
1
1
  import { TypeNode, type DocumentNode } from "graphql";
2
2
  export declare function getTypeName(type: TypeNode): string;
3
- export declare const OperationManifestPlugin: () => {
3
+ export declare const ApplicationManifestPlugin: () => {
4
4
  name: string;
5
5
  configResolved(resolvedConfig: any): Promise<void>;
6
6
  buildStart(): Promise<void>;
@@ -1 +1 @@
1
- export * from "./operation_manifest_plugin";
1
+ export * from "./application_manifest_plugin";
@@ -1,4 +1,4 @@
1
- // src/vite/operation_manifest_plugin.ts
1
+ // src/vite/application_manifest_plugin.ts
2
2
  import { readFileSync, writeFileSync } from "fs";
3
3
  import { glob } from "glob";
4
4
  import { gqlPluckFromCodeStringSync } from "@graphql-tools/graphql-tag-pluck";
@@ -35,7 +35,7 @@ function getTypeName(type) {
35
35
  }
36
36
  return t.name.value;
37
37
  }
38
- var OperationManifestPlugin = () => {
38
+ var ApplicationManifestPlugin = () => {
39
39
  const cache = /* @__PURE__ */ new Map();
40
40
  let packageJson = null;
41
41
  let config = null;
@@ -127,7 +127,11 @@ var OperationManifestPlugin = () => {
127
127
  description: packageJson.description,
128
128
  hash: createHash("sha256").update(Date.now().toString()).digest("hex"),
129
129
  operations: Array.from(cache.values()).flatMap((entry) => entry.operations),
130
- resource
130
+ resource,
131
+ csp: {
132
+ connectDomains: packageJson.csp?.connectDomains ?? [],
133
+ resourceDomains: packageJson.csp?.resourceDomains ?? []
134
+ }
131
135
  };
132
136
  if (config.command === "build") {
133
137
  const dest = path.resolve(root, config.build.outDir, ".application-manifest.json");
@@ -204,7 +208,7 @@ function removeClientDirective(doc) {
204
208
  });
205
209
  }
206
210
  export {
207
- OperationManifestPlugin,
211
+ ApplicationManifestPlugin,
208
212
  getTypeName,
209
213
  sortTopLevelDefinitions
210
214
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo/client-ai-apps",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -52,4 +52,4 @@
52
52
  "crypto-hash": "^4.0.0",
53
53
  "glob": "^11.0.3"
54
54
  }
55
- }
55
+ }
@@ -0,0 +1,17 @@
1
+ import { expect, test, vi } from "vitest";
2
+ import { useRequestDisplayMode } from "./useRequestDisplayMode";
3
+ import { DisplayMode } from "../types/openai";
4
+
5
+ test("Should set display mode when returned function is called", async () => {
6
+ vi.stubGlobal("openai", {
7
+ requestDisplayMode: vi.fn(async (args: { mode: DisplayMode }) => {
8
+ return args;
9
+ }),
10
+ });
11
+
12
+ const requestDisplayMode = useRequestDisplayMode();
13
+ const result = await requestDisplayMode({ mode: "inline" });
14
+
15
+ expect(window.openai.requestDisplayMode).toBeCalledWith({ mode: "inline" });
16
+ expect(result).toEqual({ mode: "inline" });
17
+ });
@@ -2,6 +2,6 @@ import { DisplayMode } from "../types/openai";
2
2
 
3
3
  export const useRequestDisplayMode = () => {
4
4
  return async (args: { mode: DisplayMode }) => {
5
- await window.openai?.requestDisplayMode(args);
5
+ return await window.openai?.requestDisplayMode(args);
6
6
  };
7
7
  };
@@ -0,0 +1,13 @@
1
+ import { expect, test, vi } from "vitest";
2
+ import { useSendFollowUpMessage } from "./useSendFollowUpMessage";
3
+
4
+ test("Should set display mode when returned function is called", async () => {
5
+ vi.stubGlobal("openai", {
6
+ sendFollowUpMessage: vi.fn(async (args: { prompt: string }) => {}),
7
+ });
8
+
9
+ const sendFollowUpMessage = useSendFollowUpMessage();
10
+ await sendFollowUpMessage("Do a cool thing!");
11
+
12
+ expect(window.openai.sendFollowUpMessage).toBeCalledWith({ prompt: "Do a cool thing!" });
13
+ });
@@ -0,0 +1,50 @@
1
+ import { expect, test, vi } from "vitest";
2
+ import { useToolEffect, ToolUseProvider } from "./useToolEffect";
3
+ import { renderHook } from "@testing-library/react";
4
+
5
+ test("Should trigger effect when tool name matches toolResponseMetadata", async () => {
6
+ vi.stubGlobal("openai", {
7
+ toolResponseMetadata: { toolName: "my-app--my-tool" },
8
+ });
9
+ const navigate = vi.fn();
10
+ const wrapper = ({ children }: { children: any }) => <ToolUseProvider appName="my-app">{children}</ToolUseProvider>;
11
+
12
+ renderHook(() => useToolEffect("my-tool", () => navigate(), [navigate]), { wrapper });
13
+
14
+ expect(navigate).toBeCalled();
15
+ });
16
+
17
+ test("Should trigger effect when one of multiple tool name matches toolResponseMetadata", async () => {
18
+ vi.stubGlobal("openai", {
19
+ toolResponseMetadata: { toolName: "my-app--my-tool" },
20
+ });
21
+ const navigate = vi.fn();
22
+ const wrapper = ({ children }: { children: any }) => <ToolUseProvider appName="my-app">{children}</ToolUseProvider>;
23
+
24
+ renderHook(() => useToolEffect(["my-tool", "my-similar-tool"], () => navigate(), [navigate]), { wrapper });
25
+
26
+ expect(navigate).toBeCalled();
27
+ });
28
+
29
+ test("Should not trigger effect when tool name does not match toolResponseMetadata", async () => {
30
+ vi.stubGlobal("openai", {
31
+ toolResponseMetadata: { toolName: "my-app--my-other-tool" },
32
+ });
33
+ const navigate = vi.fn();
34
+ const wrapper = ({ children }: { children: any }) => <ToolUseProvider appName="my-app">{children}</ToolUseProvider>;
35
+
36
+ renderHook(() => useToolEffect("my-tool", () => navigate(), [navigate]), { wrapper });
37
+
38
+ expect(navigate).not.toBeCalled();
39
+ });
40
+
41
+ test("Should throw an error when used outside of a ToolUseProvider", async () => {
42
+ vi.stubGlobal("openai", {
43
+ toolResponseMetadata: { toolName: "my-app--my-other-tool" },
44
+ });
45
+ const navigate = vi.fn();
46
+
47
+ expect(() => renderHook(() => useToolEffect("my-tool", () => navigate(), [navigate]))).toThrowError(
48
+ "useToolEffect must be used within ToolUseProvider"
49
+ );
50
+ });
@@ -6,6 +6,7 @@ export type ApplicationManifest = {
6
6
  hash: string;
7
7
  resource: string;
8
8
  operations: ManifestOperation[];
9
+ csp: ManifestCsp;
9
10
  };
10
11
 
11
12
  export type ManifestOperation = {
@@ -13,7 +14,7 @@ export type ManifestOperation = {
13
14
  name: string;
14
15
  type: "query" | "mutation";
15
16
  body: string;
16
- variables: Record<string, string>;
17
+ variables?: Record<string, string | undefined>;
17
18
  prefetch: boolean;
18
19
  prefetchID?: string;
19
20
  tools: ManifestTool[];
@@ -30,3 +31,8 @@ export type ManifestExtraInput = {
30
31
  description: string;
31
32
  type: "string" | "boolean" | "number";
32
33
  };
34
+
35
+ export type ManifestCsp = {
36
+ connectDomains: string[];
37
+ resourceDomains: string[];
38
+ };
@@ -46,7 +46,7 @@ export function getTypeName(type: TypeNode): string {
46
46
  return (t as NamedTypeNode).name.value;
47
47
  }
48
48
 
49
- export const OperationManifestPlugin = () => {
49
+ export const ApplicationManifestPlugin = () => {
50
50
  const cache = new Map();
51
51
  let packageJson: any = null;
52
52
  let config: any = null;
@@ -166,6 +166,10 @@ export const OperationManifestPlugin = () => {
166
166
  hash: createHash("sha256").update(Date.now().toString()).digest("hex"),
167
167
  operations: Array.from(cache.values()).flatMap((entry) => entry.operations),
168
168
  resource,
169
+ csp: {
170
+ connectDomains: packageJson.csp?.connectDomains ?? [],
171
+ resourceDomains: packageJson.csp?.resourceDomains ?? [],
172
+ },
169
173
  };
170
174
 
171
175
  if (config.command === "build") {
package/src/vite/index.ts CHANGED
@@ -1 +1 @@
1
- export * from "./operation_manifest_plugin";
1
+ export * from "./application_manifest_plugin";