@box/box-ai-agent-selector 0.37.1 → 0.38.0

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.
@@ -1,20 +1,21 @@
1
- const t = "click", o = "keypress", E = "programmatic", e = "selector", G = "agentSelector", O = {
1
+ const t = "click", A = "keypress", E = "programmatic", G = "selector", e = "agentSelector", O = "aiAgent", _ = {
2
2
  LOADED_AGENTS: "loadedAgents",
3
3
  ERROR_LOADING_AGENTS: "errorLoadingAgents",
4
4
  RETRY_LOADING_AGENTS: "retryLoadingAgents",
5
5
  OPEN_SELECTOR: "openSelector",
6
6
  SELECT_AGENT: "selectAgent"
7
- }, A = {
7
+ }, o = {
8
8
  action: E,
9
- component: e,
10
- feature: G
9
+ component: G,
10
+ feature: e
11
11
  };
12
12
  export {
13
+ O as AI_AGENTS_LOCAL_STORAGE_KEY,
13
14
  t as LOGGER_ACTION_CLICK,
14
- o as LOGGER_ACTION_KEYPRESS,
15
+ A as LOGGER_ACTION_KEYPRESS,
15
16
  E as LOGGER_ACTION_PROGRAMMATIC,
16
- A as LOGGER_BASE_CONFIG,
17
- e as LOGGER_COMPONENT,
18
- G as LOGGER_FEATURE,
19
- O as LOGGER_TARGET
17
+ o as LOGGER_BASE_CONFIG,
18
+ G as LOGGER_COMPONENT,
19
+ e as LOGGER_FEATURE,
20
+ _ as LOGGER_TARGET
20
21
  };
@@ -0,0 +1,74 @@
1
+ import { renderHook as n, act as c } from "@testing-library/react";
2
+ import l from "../useLocalStorageAIAgents.js";
3
+ describe("useLocalStorageAIAgents", () => {
4
+ const t = "testAgentKey", a = "agent-456";
5
+ let u, i, d;
6
+ beforeEach(() => {
7
+ u = jest.spyOn(Storage.prototype, "setItem"), i = jest.spyOn(Storage.prototype, "getItem"), d = jest.spyOn(Storage.prototype, "removeItem"), localStorage.clear();
8
+ }), afterEach(() => {
9
+ jest.clearAllMocks();
10
+ }), test("should initialize with null when localStorage is empty", () => {
11
+ const {
12
+ result: e
13
+ } = n(() => l(t)), [o] = e.current;
14
+ expect(o).toBeNull(), expect(i).toHaveBeenCalledWith(t);
15
+ }), test("should initialize with value from localStorage if it exists and is valid", () => {
16
+ const e = "agent-123";
17
+ localStorage.setItem(t, e);
18
+ const {
19
+ result: o
20
+ } = n(() => l(t)), [r] = o.current;
21
+ expect(r).toBe(e), expect(i).toHaveBeenCalledWith(t);
22
+ }), test("should return null if localStorage value contains invalid characters", () => {
23
+ [
24
+ `><script>alert('XSS Attack!');<\/script><div class="`,
25
+ "admin'; DROP TABLE users; --",
26
+ // eslint-disable-next-line no-template-curly-in-string
27
+ "${process.env.SECRET_KEY}",
28
+ "../../../etc/passwd",
29
+ "agent@123!"
30
+ ].forEach((o) => {
31
+ localStorage.setItem(t, o);
32
+ const {
33
+ result: r
34
+ } = n(() => l(t)), [s] = r.current;
35
+ expect(s).toBeNull(), expect(d).toHaveBeenCalledWith(t);
36
+ });
37
+ }), test("should update localStorage when state changes", () => {
38
+ const {
39
+ result: e,
40
+ rerender: o
41
+ } = n(() => l(t));
42
+ let [r, s] = e.current;
43
+ expect(r).not.toBe(a), c(() => {
44
+ s(a);
45
+ }), o(), [r] = e.current, expect(r).toBe(a), expect(u).toHaveBeenCalledWith(t, a);
46
+ }), test("should remove localStorage item when setting to null", () => {
47
+ const {
48
+ result: e,
49
+ rerender: o
50
+ } = n(() => l(t));
51
+ let [r, s] = e.current;
52
+ expect(r).toBeNull(), c(() => {
53
+ s(a);
54
+ }), o(), [r] = e.current, expect(r).toBe(a), c(() => {
55
+ s(null);
56
+ }), o(), [r] = e.current, expect(r).toBeNull(), expect(d).toHaveBeenCalledWith(t);
57
+ }), test("should handle valid alphanumeric characters with underscores and hyphens", () => {
58
+ const e = "valid-agent_123", {
59
+ result: o,
60
+ rerender: r
61
+ } = n(() => l(t)), [, s] = o.current;
62
+ c(() => {
63
+ s(e);
64
+ }), r();
65
+ const [g] = o.current;
66
+ expect(g).toBe(e), expect(u).toHaveBeenCalledWith(t, e);
67
+ }), test("should return null for whitespace-only values in localStorage", () => {
68
+ localStorage.setItem(t, " ");
69
+ const {
70
+ result: e
71
+ } = n(() => l(t)), [o] = e.current;
72
+ expect(o).toBeNull();
73
+ });
74
+ });
@@ -0,0 +1,4 @@
1
+ import { default as o } from "./useLocalStorageAIAgents.js";
2
+ export {
3
+ o as useLocalStorageAIAgents
4
+ };
@@ -0,0 +1,21 @@
1
+ import { useState as l, useEffect as s } from "react";
2
+ const c = (e, o = !0) => {
3
+ const [t, a] = l(() => {
4
+ try {
5
+ const r = localStorage.getItem(e);
6
+ if (!r)
7
+ return null;
8
+ if (o && !/^[a-zA-Z0-9_-]+$/.test(r))
9
+ throw new Error("Invalid characters in stored value");
10
+ return r;
11
+ } catch {
12
+ return localStorage.removeItem(e), null;
13
+ }
14
+ });
15
+ return s(() => {
16
+ t ? localStorage.setItem(e, t) : localStorage.removeItem(e);
17
+ }, [t, e]), [t, a];
18
+ };
19
+ export {
20
+ c as default
21
+ };
@@ -1,5 +1,7 @@
1
1
  export * from './lib/box-ai-agent-selector';
2
2
  export * from './lib/box-ai-agent-selector-with-api';
3
3
  export * from './lib/box-ai-agent-selector-with-api-container';
4
+ export { AI_AGENTS_LOCAL_STORAGE_KEY } from './lib/constants';
4
5
  export * from './lib/contexts';
6
+ export * from './lib/hooks';
5
7
  export * from './lib/types';
@@ -4,6 +4,7 @@ export declare const LOGGER_ACTION_KEYPRESS = "keypress";
4
4
  export declare const LOGGER_ACTION_PROGRAMMATIC = "programmatic";
5
5
  export declare const LOGGER_COMPONENT = "selector";
6
6
  export declare const LOGGER_FEATURE = "agentSelector";
7
+ export declare const AI_AGENTS_LOCAL_STORAGE_KEY = "aiAgent";
7
8
  export declare const LOGGER_TARGET: {
8
9
  LOADED_AGENTS: string;
9
10
  ERROR_LOADING_AGENTS: string;
@@ -0,0 +1 @@
1
+ export { default as useLocalStorageAIAgents } from './useLocalStorageAIAgents';
@@ -0,0 +1,2 @@
1
+ declare const useLocalStorageAIAgents: <T extends string | null>(key: string, alphaNumDashValidation?: boolean) => readonly [T, import('react').Dispatch<import('react').SetStateAction<T>>];
2
+ export default useLocalStorageAIAgents;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/box-ai-agent-selector",
3
- "version": "0.37.1",
3
+ "version": "0.38.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "peerDependencies": {
6
6
  "@ariakit/react": "^0.4.15",
@@ -13,10 +13,11 @@
13
13
  "devDependencies": {
14
14
  "@ariakit/react": "^0.4.15",
15
15
  "@box/babel-plugin-target-attributes": "1.3.0",
16
- "@box/blueprint-web": "^11.0.3",
16
+ "@box/blueprint-web": "^11.1.0",
17
17
  "@box/blueprint-web-assets": "^4.40.0",
18
18
  "@box/eslint-plugin-blueprint": "^1.0.3",
19
19
  "@box/storybook-utils": "^0.9.2",
20
+ "@testing-library/react": "^15.0.6",
20
21
  "react-intl": "^6.4.2"
21
22
  },
22
23
  "publishConfig": {