guideai-app 0.4.1 → 0.4.2

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 (36) hide show
  1. package/API_DATA_CONTRACTS.md +516 -0
  2. package/API_SESSIONID_TESTING.md +215 -0
  3. package/PII_HASHING_EPIC.md +886 -0
  4. package/PII_HASHING_STORIES_SUMMARY.md +275 -0
  5. package/SESSION_ID_VERIFICATION.md +122 -0
  6. package/VISIT_COUNT_TESTING.md +453 -0
  7. package/dist/GuideAI.js +1 -1
  8. package/dist/GuideAI.js.LICENSE.txt +20 -0
  9. package/dist/GuideAI.js.map +1 -1
  10. package/dist/index.d.ts +3 -0
  11. package/dist/metric/index.d.ts +0 -2
  12. package/dist/metric/metadata-tracker.d.ts +1 -2
  13. package/dist/types/GuideAI.types.d.ts +2 -0
  14. package/dist/types/metadata.types.d.ts +2 -0
  15. package/dist/utils/api.d.ts +5 -0
  16. package/dist/utils/elementInteractions.d.ts +92 -0
  17. package/dist/utils/gemini.d.ts +3 -0
  18. package/dist/utils/goToAElmLink.d.ts +1 -0
  19. package/dist/utils/highlightThenClick.d.ts +1 -0
  20. package/dist/utils/hoverThenClick.d.ts +1 -0
  21. package/dist/utils/logger.d.ts +1 -5
  22. package/dist/utils/session.d.ts +23 -0
  23. package/dist/visualContext/VisualContextScheduler.d.ts +43 -0
  24. package/dist/visualContext/VisualContextStore.d.ts +11 -0
  25. package/dist/visualContext/debug-overlay.d.ts +10 -0
  26. package/dist/visualContext/defaultProvider.d.ts +15 -0
  27. package/dist/visualContext/index.d.ts +5 -0
  28. package/dist/visualContext/types.d.ts +45 -0
  29. package/index.d.ts +5 -1
  30. package/jest.config.js +26 -0
  31. package/jest.setup.js +21 -0
  32. package/metadata-tracking-example.md +11 -11
  33. package/package.json +13 -3
  34. package/dist/metric/event-listner.d.ts +0 -141
  35. package/dist/utils/highlightAndClick.d.ts +0 -3
  36. package/dist/utils/hoverAndClick.d.ts +0 -4
package/dist/index.d.ts CHANGED
@@ -3,3 +3,6 @@ import TranscriptBox from './components/TranscriptBox';
3
3
  export default GuideAI;
4
4
  export { TranscriptBox };
5
5
  export type { GuideAIProps } from './types/GuideAI.types';
6
+ export * from './visualContext';
7
+ export * from './visualContext/types';
8
+ export { getSessionId, clearSessionId, peekSessionId } from './utils/session';
@@ -1,4 +1,2 @@
1
- export { default as EventTracker } from './event-listner';
2
- export type { EventData } from './event-listner';
3
1
  export { default as UserMetadataTracker } from './metadata-tracker';
4
2
  export type { UserMetadata, MetadataConfig, MetadataUpdate } from './metadata-tracker';
@@ -17,7 +17,7 @@ declare class UserMetadataTracker {
17
17
  init(): void;
18
18
  updateUserInfo(userInfo: Partial<UserMetadata>): void;
19
19
  trackLogin(additionalInfo?: Partial<UserMetadata>): void;
20
- private trackVisitOncePerSession;
20
+ private trackVisitIfNewSession;
21
21
  trackVisit(): void;
22
22
  resetSessionVisitTracking(): void;
23
23
  trackVisitManually(): void;
@@ -35,7 +35,6 @@ declare class UserMetadataTracker {
35
35
  private addPendingUpdate;
36
36
  private isDataDuplicate;
37
37
  private generateDataHash;
38
- private setupEventTrackerIntegration;
39
38
  private stopSyncTimer;
40
39
  private emitPendingUpdates;
41
40
  private emitPendingUpdatesImmediate;
@@ -1,4 +1,5 @@
1
1
  import { MetadataConfig, UserMetadata } from './metadata.types';
2
+ import { VisualContextConfig } from '../visualContext/types';
2
3
  export type RecordingStatus = 'idle' | 'recording' | 'processing' | 'playing';
3
4
  export type UseStateHook = <T>(initialState: T | (() => T)) => [T, (value: T | ((prev: T) => T)) => void];
4
5
  export type UseEffectHook = (effect: () => void | (() => void), deps?: any[]) => void;
@@ -39,5 +40,6 @@ export interface GuideAIProps {
39
40
  defaultMode?: 'voice' | 'text';
40
41
  placeholder?: string;
41
42
  };
43
+ visualContext?: VisualContextConfig;
42
44
  }
43
45
  export type PopupPosition = 'above' | 'below';
@@ -1,5 +1,6 @@
1
1
  export interface UserMetadata {
2
2
  userId?: string;
3
+ email?: string;
3
4
  userType?: 'agent' | 'admin' | 'manager' | 'customer' | 'guest' | string;
4
5
  customerType?: 'individual' | 'business' | 'enterprise' | string;
5
6
  customerLicense?: string;
@@ -31,6 +32,7 @@ export interface MetadataConfig {
31
32
  customFields?: string[];
32
33
  collectBrowserInfo?: boolean;
33
34
  collectUserAgent?: boolean;
35
+ sessionTimeout?: number;
34
36
  }
35
37
  export interface MetadataStorageData {
36
38
  metadata: UserMetadata;
@@ -14,6 +14,11 @@ interface ConversationData {
14
14
  ephemeralToken: string;
15
15
  prompt: string;
16
16
  workflows: Workflow[];
17
+ userMetadata?: {
18
+ visitCount: number;
19
+ loginCount?: number;
20
+ email?: string;
21
+ };
17
22
  }
18
23
  export declare const createNewConversation: (organizationKey: string, onError: (error: Error, context: string) => void, workflowKey?: string) => Promise<ConversationData | null>;
19
24
  export type { Workflow };
@@ -0,0 +1,92 @@
1
+ export declare const HOVER_EFFECT_KEEP_ALIVE_TIME = 3000;
2
+ export declare const createHoverEffect: (element: Element, initialRect: DOMRect, cursorElement?: HTMLElement | null, duration?: number) => Promise<void>;
3
+ export declare const clickElement: (element: Element, rect: DOMRect, withEffects?: boolean) => Promise<void>;
4
+ export declare const parseCustomSelector: (selector: string) => {
5
+ type: "text" | "css" | "xpath";
6
+ cssSelector?: string;
7
+ textContent?: string;
8
+ originalSelector?: string;
9
+ };
10
+ export declare const findElementBySelectorStrict: (selector: string) => Element | null;
11
+ export declare const findElementBySelector: (selector: string) => Element | null;
12
+ type ElementInteractionType = "HIGHLIGHT" | "HOVERANDCLICK";
13
+ export declare const interactWithElement: (element: Element, cursorElement: HTMLElement | null, state: ElementInteractionType, hoverTime?: number) => Promise<HTMLElement | null>;
14
+ export declare const processSelectorsInteraction: (selectors: string | string[], isInteracting: boolean, setIsInteracting: (interacting: boolean) => void, onEachElement: (element: Element, cursor: HTMLElement | null, index: number) => Promise<HTMLElement | null>, onComplete?: (lastElement: Element | null, cursor: HTMLElement | null) => Promise<void>) => Promise<boolean>;
15
+ export declare const Highlight_Tool: {
16
+ type: string;
17
+ name: string;
18
+ description: string;
19
+ parameters: {
20
+ type: string;
21
+ properties: {
22
+ selector: {
23
+ oneOf: ({
24
+ type: string;
25
+ description: string;
26
+ items?: undefined;
27
+ } | {
28
+ type: string;
29
+ items: {
30
+ type: string;
31
+ };
32
+ description: string;
33
+ })[];
34
+ description: string;
35
+ };
36
+ };
37
+ required: string[];
38
+ };
39
+ };
40
+ export declare const Hover_Tool: {
41
+ type: string;
42
+ name: string;
43
+ description: string;
44
+ parameters: {
45
+ type: string;
46
+ properties: {
47
+ selector: {
48
+ oneOf: ({
49
+ type: string;
50
+ description: string;
51
+ items?: undefined;
52
+ } | {
53
+ type: string;
54
+ items: {
55
+ type: string;
56
+ };
57
+ description: string;
58
+ })[];
59
+ description: string;
60
+ };
61
+ hoverTime: {
62
+ type: string;
63
+ description: string;
64
+ minimum: number;
65
+ maximum: number;
66
+ };
67
+ };
68
+ required: string[];
69
+ };
70
+ };
71
+ export declare const Go_To_A_Elm_Link_Tool: {
72
+ type: string;
73
+ name: string;
74
+ description: string;
75
+ parameters: {
76
+ type: string;
77
+ properties: {
78
+ linkText: {
79
+ type: string;
80
+ description: string;
81
+ };
82
+ delay: {
83
+ type: string;
84
+ description: string;
85
+ minimum: number;
86
+ maximum: number;
87
+ };
88
+ };
89
+ required: string[];
90
+ };
91
+ };
92
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare const parse_args: (prompt: string, argsToUse: any, geminiFlash: Function) => Promise<any>;
2
+ export declare const HIGHLIGHT_TOOL_PROMPT = "Validate the following JSON string and return ONLY a correct JSON object:\nNote: The selector(s) should be either a css selector or an xpath, so modify those if invalid.\nAlso, [url=''] is a valid css selector, so do not modify it if it's present.\nDo not add any other text or newlines to the response.\nIt should be of the following format:\n{ \"selector\": \"string\" }\nor\n{ \"selector\": [\"string\", ...] }\nDO NOT add any other text or newlines to the response, it should begin and end with curly braces.\nDO NOT add '''json to the response.\nThe JSON string is:\n";
3
+ export declare const HOVER_TOOL_PROMPT = "Validate the following JSON string and return ONLY a correct JSON object:\nNote: The selector(s) should be either a css selector or an xpath, so modify those if invalid.\nAlso, [url=''] is a valid css selector, so do not modify it if it's present.\nDo not add any other text or newlines to the response.\nIt should be of the following format:\n{ \"selector\": \"string\" }\nor\n{ \"selector\": [\"string\", ...] }\nor\n{ \"selector\": \"string\", \"hoverTime\": number }\nor\n{ \"selector\": [\"string\", ...], \"hoverTime\": number }\nThe hoverTime parameter is optional and represents time to hover in milliseconds (500-10000).\nIf not provided, default to 3000ms.\nDO NOT add any other text or newlines to the response, it should begin and end with curly braces.\nDO NOT add '''json to the response.\nThe JSON string is:\n";
@@ -0,0 +1 @@
1
+ export declare const goToAElmLink: (linkText: string, delay?: number) => Promise<boolean>;
@@ -0,0 +1 @@
1
+ export declare const highlightThenClick: (selector: string | string[], isHighlighting: boolean, setIsHighlighting: (highlighting: boolean) => void) => Promise<boolean>;
@@ -0,0 +1 @@
1
+ export declare const hoverThenClick: (selector: string | string[], isHovering: boolean, setIsHovering: (hovering: boolean) => void, hoverTime?: number) => Promise<boolean>;
@@ -2,7 +2,7 @@
2
2
  * Standardized logging utility for GuideAI package
3
3
  * Provides consistent formatting and development gating across all components
4
4
  */
5
- type Component = 'GuideAI' | 'EventTracker' | 'UserMetadata' | 'API' | 'TranscriptBox' | 'Onboarding';
5
+ type Component = 'GuideAI' | 'UserMetadata' | 'API' | 'TranscriptBox' | 'Onboarding';
6
6
  declare class Logger {
7
7
  private static formatMessage;
8
8
  /**
@@ -29,10 +29,6 @@ declare class Logger {
29
29
  * Conversation flow tracking
30
30
  */
31
31
  static conversation(action: string, data?: any): void;
32
- /**
33
- * Event tracking logging
34
- */
35
- static event(action: string, data?: any): void;
36
32
  /**
37
33
  * Metadata tracking logging
38
34
  */
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Gets the current session ID from sessionStorage, or generates a new one if it doesn't exist.
3
+ * The session ID persists across page navigations within the same browser tab,
4
+ * but is cleared when the tab is closed.
5
+ *
6
+ * @returns {string} The current session ID (UUID v4 format)
7
+ */
8
+ export declare function getSessionId(): string;
9
+ /**
10
+ * Clears the current session ID from sessionStorage.
11
+ * This will force a new session ID to be generated on the next call to getSessionId().
12
+ *
13
+ * Note: This is primarily for testing purposes. In normal operation,
14
+ * the browser automatically clears sessionStorage when the tab is closed.
15
+ */
16
+ export declare function clearSessionId(): void;
17
+ /**
18
+ * Gets the current session ID without generating a new one.
19
+ * Returns null if no session ID exists.
20
+ *
21
+ * @returns {string | null} The current session ID or null if none exists
22
+ */
23
+ export declare function peekSessionId(): string | null;
@@ -0,0 +1,43 @@
1
+ import { ScreenshotFrame, ScreenshotProvider } from './types';
2
+ export declare class VisualContextScheduler {
3
+ private getContainer;
4
+ private screenshotProvider;
5
+ private isRunning;
6
+ private isCaptureInFlight;
7
+ private hasPendingCapture;
8
+ private pendingReason;
9
+ private lastHash;
10
+ private lastCaptureAt;
11
+ private lastScrollAt;
12
+ private lastDomBurstAt;
13
+ private domChangeCounter;
14
+ private domBurstWindowMs;
15
+ private domBurstThreshold;
16
+ private minIntervalMs;
17
+ private scrollDebounceMs;
18
+ private scrollTimer;
19
+ private mode;
20
+ private buttonObserver;
21
+ private domObserver;
22
+ private targetWidth;
23
+ private rootElement;
24
+ private quality;
25
+ private minQuality;
26
+ private maxBytes;
27
+ private onFrame;
28
+ constructor(getContainer: () => HTMLElement | null, screenshotProvider: ScreenshotProvider, onFrame: (frame: ScreenshotFrame) => void, options?: {
29
+ targetWidth?: number;
30
+ quality?: number;
31
+ minQuality?: number;
32
+ maxBytes?: number;
33
+ });
34
+ setRootElement(root: HTMLElement | ShadowRoot | Document): void;
35
+ start(): void;
36
+ stop(): void;
37
+ private observeButtonState;
38
+ private observeDomChanges;
39
+ private observeScroll;
40
+ scheduleCapture(reason: 'preview' | 'final' | 'change'): void;
41
+ private performCapture;
42
+ private maybeRunPending;
43
+ }
@@ -0,0 +1,11 @@
1
+ import { ScreenshotFrame } from './types';
2
+ export declare class VisualContextStore {
3
+ private maxItems;
4
+ private frames;
5
+ constructor(maxItems?: number);
6
+ add(frame: ScreenshotFrame): void;
7
+ latest(): ScreenshotFrame | null;
8
+ all(): ScreenshotFrame[];
9
+ clear(): void;
10
+ setMaxItems(maxItems: number): void;
11
+ }
@@ -0,0 +1,10 @@
1
+ import { ScreenshotFrame } from './types';
2
+ interface DebugOverlayProps {
3
+ React: typeof import('react');
4
+ frames: ScreenshotFrame[];
5
+ latencyMs: number | null;
6
+ onToggleGallery?: () => void;
7
+ showGallery?: boolean;
8
+ }
9
+ export declare const DebugOverlay: ({ React, frames, latencyMs, onToggleGallery, showGallery }: DebugOverlayProps) => import("react").DetailedReactHTMLElement<import("react").HTMLAttributes<HTMLElement>, HTMLElement>;
10
+ export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Default screenshot provider using html2canvas
3
+ * Automatically detects and uses html2canvas if available
4
+ */
5
+ import type { ScreenshotProvider } from './types';
6
+ /**
7
+ * Creates a default screenshot provider using html2canvas
8
+ * Returns null if html2canvas is not available
9
+ */
10
+ export declare const createDefaultScreenshotProvider: () => ScreenshotProvider | null;
11
+ /**
12
+ * Get the default screenshot provider
13
+ * Returns null if unavailable (graceful degradation)
14
+ */
15
+ export declare const getDefaultScreenshotProvider: () => ScreenshotProvider | null;
@@ -0,0 +1,5 @@
1
+ export { VisualContextStore } from './VisualContextStore';
2
+ export { VisualContextScheduler } from './VisualContextScheduler';
3
+ export { DebugOverlay } from './debug-overlay';
4
+ export { createDefaultScreenshotProvider, getDefaultScreenshotProvider } from './defaultProvider';
5
+ export type { ScreenshotResponse, ScreenshotFrame, ScreenshotOptions, ScreenshotProvider, VisualContextConfig } from './types';
@@ -0,0 +1,45 @@
1
+ export type ScreenshotResponse = {
2
+ ok?: boolean;
3
+ dataUrl?: string;
4
+ width?: number;
5
+ height?: number;
6
+ hash?: string;
7
+ isDuplicate?: boolean;
8
+ timestamp?: number;
9
+ error?: any;
10
+ metadata?: {
11
+ width?: number;
12
+ height?: number;
13
+ quality?: number;
14
+ [key: string]: any;
15
+ };
16
+ };
17
+ export type ScreenshotFrame = {
18
+ dataUrl: string;
19
+ width?: number;
20
+ height?: number;
21
+ hash?: string;
22
+ reason: 'preview' | 'final' | 'change';
23
+ timestamp?: number;
24
+ sentToLLM?: boolean;
25
+ llmReceivedAt?: number;
26
+ };
27
+ export type ScreenshotOptions = {
28
+ targetElement?: HTMLElement;
29
+ targetWidth?: number;
30
+ quality?: number;
31
+ minQuality?: number;
32
+ maxBytes?: number;
33
+ };
34
+ export type ScreenshotProvider = (options: ScreenshotOptions) => Promise<ScreenshotResponse>;
35
+ export type VisualContextConfig = {
36
+ enabled: boolean;
37
+ screenshotProvider?: ScreenshotProvider;
38
+ shadowRoot?: ShadowRoot;
39
+ debug?: boolean;
40
+ maxFrames?: number;
41
+ targetWidth?: number;
42
+ quality?: number;
43
+ minQuality?: number;
44
+ maxBytes?: number;
45
+ };
package/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
1
  import GuideAI from './GuideAI';
2
+ import TranscriptBox from './components/TranscriptBox';
2
3
  export default GuideAI;
3
- export type { GuideAIProps } from './GuideAI';
4
+ export { TranscriptBox };
5
+ export type { GuideAIProps } from './types/GuideAI.types';
6
+ export * from './visualContext';
7
+ export * from './visualContext/types';
package/jest.config.js ADDED
@@ -0,0 +1,26 @@
1
+ module.exports = {
2
+ preset: 'ts-jest',
3
+ testEnvironment: 'jsdom',
4
+ roots: ['<rootDir>/src'],
5
+ testMatch: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'],
6
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
7
+ collectCoverageFrom: [
8
+ 'src/**/*.{ts,tsx}',
9
+ '!src/**/*.d.ts',
10
+ '!src/**/*.types.ts'
11
+ ],
12
+ setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
13
+ transform: {
14
+ '^.+\\.tsx?$': ['ts-jest', {
15
+ tsconfig: {
16
+ jsx: 'react',
17
+ esModuleInterop: true,
18
+ allowSyntheticDefaultImports: true
19
+ }
20
+ }]
21
+ },
22
+ moduleNameMapper: {
23
+ '^@/(.*)$': '<rootDir>/src/$1'
24
+ }
25
+ };
26
+
package/jest.setup.js ADDED
@@ -0,0 +1,21 @@
1
+ // Jest setup file
2
+ require('jest-localstorage-mock');
3
+ require('@testing-library/jest-dom');
4
+
5
+ // Mock console methods to reduce noise in tests
6
+ global.console = {
7
+ ...console,
8
+ log: jest.fn(),
9
+ warn: jest.fn(),
10
+ error: jest.fn(),
11
+ };
12
+
13
+ // Setup localStorage and sessionStorage mocks
14
+ Object.defineProperty(window, 'localStorage', {
15
+ value: global.localStorage,
16
+ });
17
+
18
+ Object.defineProperty(window, 'sessionStorage', {
19
+ value: global.sessionStorage,
20
+ });
21
+
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- The GuideAI package now includes comprehensive user metadata tracking capabilities designed for integration with Overproof. This system tracks the following metadata:
5
+ The GuideAI package now includes comprehensive user metadata tracking capabilities designed for integration with client. This system tracks the following metadata:
6
6
 
7
7
  - **User's First Visit** - Timestamp of the first time the user interacted with GuideAI
8
8
  - **User's Last Visit** - Timestamp of the most recent user interaction
@@ -181,7 +181,7 @@ interface UserMetadata {
181
181
  platform?: string;
182
182
  };
183
183
 
184
- // Custom fields for Overproof-specific needs
184
+ // Custom fields for client-specific needs
185
185
  customFields?: Record<string, string | number | boolean>;
186
186
  }
187
187
  ```
@@ -255,14 +255,14 @@ guideAIRef.current?.trackCustomEvent('document_viewed', {
255
255
  });
256
256
  ```
257
257
 
258
- ## Overproof Integration Example
258
+ ## client Integration Example
259
259
 
260
260
  ```typescript
261
- function OverproofApp() {
261
+ function clientApp() {
262
262
  const guideAIRef = useRef();
263
263
 
264
- // Track when user logs into Overproof
265
- const handleOverproofLogin = (user) => {
264
+ // Track when user logs into client
265
+ const handleclientLogin = (user) => {
266
266
  guideAIRef.current?.trackLogin({
267
267
  userId: user.id,
268
268
  userType: user.role, // 'agent', 'admin', etc.
@@ -291,18 +291,18 @@ function OverproofApp() {
291
291
  return (
292
292
  <GuideAI
293
293
  ref={guideAIRef}
294
- organizationKey="overproof-org-key"
294
+ organizationKey="demo-org-key"
295
295
  metadata={{
296
296
  config: {
297
297
  trackVisits: true,
298
298
  trackLogins: true,
299
- syncInterval: 15000, // More frequent syncing for Overproof
299
+ syncInterval: 15000, // More frequent syncing for client
300
300
  customFields: ['agencyId', 'territory', 'permissions'],
301
301
  collectBrowserInfo: true
302
302
  },
303
303
  onMetadataUpdate: (metadata) => {
304
- // Send to Overproof analytics
305
- window.OverproofAnalytics?.track('guideai_metadata_update', metadata);
304
+ // Send to client analytics
305
+ window.clientAnalytics?.track('guideai_metadata_update', metadata);
306
306
  }
307
307
  }}
308
308
  />
@@ -321,4 +321,4 @@ Metadata is automatically:
321
321
  - Synced to backend at configured intervals
322
322
  - Restored when user returns (if using persistent storage)
323
323
 
324
- This implementation provides a robust foundation for tracking user metadata in the Overproof environment while maintaining flexibility for other use cases.
324
+ This implementation provides a robust foundation for tracking user metadata in the client environment while maintaining flexibility for other use cases.
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "guideai-app",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "AI-powered guide component for React applications",
5
5
  "main": "dist/GuideAI.js",
6
- "types": "dist/GuideAI.d.ts",
6
+ "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "webpack && tsc --emitDeclarationOnly && javascript-obfuscator dist/GuideAI.js --config obfuscator.json --output dist/GuideAI.js",
9
9
  "prepare": "npm run build",
10
- "test": "echo \"Error: no test specified\" && exit 1"
10
+ "test": "jest",
11
+ "test:watch": "jest --watch",
12
+ "test:coverage": "jest --coverage"
11
13
  },
12
14
  "keywords": [
13
15
  "react",
@@ -20,6 +22,7 @@
20
22
  "dependencies": {
21
23
  "@google/generative-ai": "^0.2.1",
22
24
  "guideai-app": "^0.3.4",
25
+ "html2canvas": "^1.4.1",
23
26
  "openai": "^4.28.0"
24
27
  },
25
28
  "peerDependencies": {
@@ -27,10 +30,17 @@
27
30
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
28
31
  },
29
32
  "devDependencies": {
33
+ "@testing-library/jest-dom": "^6.9.1",
34
+ "@testing-library/react": "^16.3.0",
35
+ "@types/jest": "^30.0.0",
30
36
  "@types/react": "^18.2.0",
31
37
  "javascript-obfuscator": "^4.1.0",
38
+ "jest": "^30.2.0",
39
+ "jest-environment-jsdom": "^30.2.0",
40
+ "jest-localstorage-mock": "^2.4.26",
32
41
  "process": "^0.11.10",
33
42
  "stream-browserify": "^3.0.0",
43
+ "ts-jest": "^29.4.5",
34
44
  "ts-loader": "^9.5.2",
35
45
  "typescript": "^5.0.0",
36
46
  "util": "^0.12.5",