@adminide-stack/yantra-mobile 12.0.69-alpha.9 → 12.0.70-alpha.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.
- package/lib/components/GatewayConnector/GatewayConnector.js +2 -2
- package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -1
- package/lib/components/KeyboardComposerDock.js +8 -1
- package/lib/components/KeyboardComposerDock.js.map +1 -1
- package/lib/components/NavigationHeader/NavigationHeader.js +2 -2
- package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -1
- package/lib/config/env-config.js +4 -0
- package/lib/config/env-config.js.map +1 -1
- package/lib/contexts/ChatLiveStreamContext.js +4 -1
- package/lib/contexts/ChatLiveStreamContext.js.map +1 -1
- package/lib/features/agent-chat/NativeAgentChat.js +2 -0
- package/lib/features/agent-chat/NativeAgentChat.js.map +1 -1
- package/lib/features/apps/AppsCatalog.js +2 -2
- package/lib/features/apps/AppsCatalog.js.map +1 -1
- package/lib/features/audio-input/MicErrorBoundary.js +2 -2
- package/lib/features/audio-input/MicErrorBoundary.js.map +1 -1
- package/lib/features/canvas/AudioEditorExperience.js +308 -0
- package/lib/features/canvas/AudioEditorExperience.js.map +1 -0
- package/lib/features/canvas/CanvasAgentChatPane.js +310 -0
- package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -0
- package/lib/features/canvas/CanvasBoardsGrid.js +414 -0
- package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -0
- package/lib/features/canvas/CanvasChatResultCard.js +113 -0
- package/lib/features/canvas/CanvasChatResultCard.js.map +1 -0
- package/lib/features/canvas/CanvasEditToolsPanel.js +179 -0
- package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -0
- package/lib/features/canvas/CanvasExperience.js +859 -0
- package/lib/features/canvas/CanvasExperience.js.map +1 -0
- package/lib/features/canvas/CanvasGeneratePanel.js +514 -0
- package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -0
- package/lib/features/canvas/CanvasLibrarySheet.js +355 -0
- package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -0
- package/lib/features/canvas/CanvasLooksPanel.js +184 -0
- package/lib/features/canvas/CanvasLooksPanel.js.map +1 -0
- package/lib/features/canvas/CanvasTasksPanel.js +138 -0
- package/lib/features/canvas/CanvasTasksPanel.js.map +1 -0
- package/lib/features/canvas/CanvasTemplatesPanel.js +226 -0
- package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -0
- package/lib/features/canvas/CanvasToolDock.js +423 -0
- package/lib/features/canvas/CanvasToolDock.js.map +1 -0
- package/lib/features/canvas/FrameExtractorExperience.js +242 -0
- package/lib/features/canvas/FrameExtractorExperience.js.map +1 -0
- package/lib/features/canvas/ImageEditorExperience.js +491 -0
- package/lib/features/canvas/ImageEditorExperience.js.map +1 -0
- package/lib/features/canvas/InfluencerStudioExperience.js +288 -0
- package/lib/features/canvas/InfluencerStudioExperience.js.map +1 -0
- package/lib/features/canvas/MoodboardExperience.js +205 -0
- package/lib/features/canvas/MoodboardExperience.js.map +1 -0
- package/lib/features/canvas/NativeCanvasViewer.js +929 -0
- package/lib/features/canvas/NativeCanvasViewer.js.map +1 -0
- package/lib/features/canvas/PromoContextFields.js +150 -0
- package/lib/features/canvas/PromoContextFields.js.map +1 -0
- package/lib/features/canvas/SetStudioExperience.js +323 -0
- package/lib/features/canvas/SetStudioExperience.js.map +1 -0
- package/lib/features/canvas/VideoClipsExperience.js +175 -0
- package/lib/features/canvas/VideoClipsExperience.js.map +1 -0
- package/lib/features/canvas/VideoEditExperience.js +824 -0
- package/lib/features/canvas/VideoEditExperience.js.map +1 -0
- package/lib/features/canvas/VideoEditorExperience.js +3050 -0
- package/lib/features/canvas/VideoEditorExperience.js.map +1 -0
- package/lib/features/canvas/VideoGeneratorExperience.js +415 -0
- package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -0
- package/lib/features/canvas/aiEdit.js +53 -0
- package/lib/features/canvas/aiEdit.js.map +1 -0
- package/lib/features/canvas/canvasAgentChat.js +76 -0
- package/lib/features/canvas/canvasAgentChat.js.map +1 -0
- package/lib/features/canvas/canvasBoardsCatalog.js +59 -0
- package/lib/features/canvas/canvasBoardsCatalog.js.map +1 -0
- package/lib/features/canvas/canvasBoardsSnapshot.js +14 -1
- package/lib/features/canvas/canvasBoardsSnapshot.js.map +1 -1
- package/lib/features/canvas/canvasChatDisplay.js +38 -0
- package/lib/features/canvas/canvasChatDisplay.js.map +1 -0
- package/lib/features/canvas/canvasChatTemplates.js +219 -0
- package/lib/features/canvas/canvasChatTemplates.js.map +1 -0
- package/lib/features/canvas/canvasCore.js +138 -1
- package/lib/features/canvas/canvasCore.js.map +1 -1
- package/lib/features/canvas/canvasEditOps.js +224 -0
- package/lib/features/canvas/canvasEditOps.js.map +1 -0
- package/lib/features/canvas/canvasTasks.js +187 -0
- package/lib/features/canvas/canvasTasks.js.map +1 -0
- package/lib/features/canvas/designPromptTemplates.js +3084 -0
- package/lib/features/canvas/designPromptTemplates.js.map +1 -0
- package/lib/features/canvas/editTools.js +54 -0
- package/lib/features/canvas/editTools.js.map +1 -0
- package/lib/features/canvas/extendVideo.js +5 -0
- package/lib/features/canvas/extendVideo.js.map +1 -0
- package/lib/features/canvas/frameExtract.js +33 -0
- package/lib/features/canvas/frameExtract.js.map +1 -0
- package/lib/features/canvas/generationModels.js +201 -0
- package/lib/features/canvas/generationModels.js.map +1 -0
- package/lib/features/canvas/influencer/influencerPipeline.js +170 -0
- package/lib/features/canvas/influencer/influencerPipeline.js.map +1 -0
- package/lib/features/canvas/influencer/productReel.js +72 -0
- package/lib/features/canvas/influencer/productReel.js.map +1 -0
- package/lib/features/canvas/influencer/reelPlan.js +159 -0
- package/lib/features/canvas/influencer/reelPlan.js.map +1 -0
- package/lib/features/canvas/moodboardCore.js +13 -0
- package/lib/features/canvas/moodboardCore.js.map +1 -0
- package/lib/features/canvas/promoProjectImport.js +99 -0
- package/lib/features/canvas/promoProjectImport.js.map +1 -0
- package/lib/features/canvas/promoVideo.js +312 -0
- package/lib/features/canvas/promoVideo.js.map +1 -0
- package/lib/features/canvas/recorder/CameraRecorderExperience.js +109 -0
- package/lib/features/canvas/recorder/CameraRecorderExperience.js.map +1 -0
- package/lib/features/canvas/sessionIdentity.js +28 -1
- package/lib/features/canvas/sessionIdentity.js.map +1 -1
- package/lib/features/canvas/set/SetViewportWebView.js +133 -0
- package/lib/features/canvas/set/SetViewportWebView.js.map +1 -0
- package/lib/features/canvas/set/cameraPath.js +194 -0
- package/lib/features/canvas/set/cameraPath.js.map +1 -0
- package/lib/features/canvas/set/setProject.js +24 -0
- package/lib/features/canvas/set/setProject.js.map +1 -0
- package/lib/features/canvas/storageLibrary.js +184 -0
- package/lib/features/canvas/storageLibrary.js.map +1 -0
- package/lib/features/canvas/studioCatalog.js +129 -0
- package/lib/features/canvas/studioCatalog.js.map +1 -0
- package/lib/features/canvas/studioLooks.js +189 -0
- package/lib/features/canvas/studioLooks.js.map +1 -0
- package/lib/features/canvas/surfaceIndex.js +63 -1
- package/lib/features/canvas/surfaceIndex.js.map +1 -1
- package/lib/features/canvas/templateImport/invideoNative.js +221 -0
- package/lib/features/canvas/templateImport/invideoNative.js.map +1 -0
- package/lib/features/canvas/templateImport/loadTemplate.js +43 -0
- package/lib/features/canvas/templateImport/loadTemplate.js.map +1 -0
- package/lib/features/canvas/templateImport/renderConfig.js +93 -0
- package/lib/features/canvas/templateImport/renderConfig.js.map +1 -0
- package/lib/features/canvas/useStudioCatalogTemplates.js +134 -0
- package/lib/features/canvas/useStudioCatalogTemplates.js.map +1 -0
- package/lib/features/canvas/video3d.js +109 -0
- package/lib/features/canvas/video3d.js.map +1 -0
- package/lib/features/canvas/videoClips.js +42 -0
- package/lib/features/canvas/videoClips.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +120 -0
- package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/agentLoop.js +69 -0
- package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/brainClient.js +45 -0
- package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/cutTools.js +129 -0
- package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -0
- package/lib/features/canvas/videoEditor/editorModel.js +346 -0
- package/lib/features/canvas/videoEditor/editorModel.js.map +1 -0
- package/lib/features/canvas/videoEditor/exportRenderer.js +214 -0
- package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -0
- package/lib/features/canvas/videoEditor/filters.js +41 -0
- package/lib/features/canvas/videoEditor/filters.js.map +1 -0
- package/lib/features/canvas/videoEditor/mediaActions.js +57 -0
- package/lib/features/canvas/videoEditor/mediaActions.js.map +1 -0
- package/lib/features/canvas/videoEditor/remoteMediaClient.js +129 -0
- package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -0
- package/lib/features/canvas/videoEditor/solidColorPng.js +115 -0
- package/lib/features/canvas/videoEditor/solidColorPng.js.map +1 -0
- package/lib/features/canvas/videoEditor/videoEditOps.js +191 -0
- package/lib/features/canvas/videoEditor/videoEditOps.js.map +1 -0
- package/lib/features/canvas/videoEditor/videoProjectsStore.js +82 -0
- package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -0
- package/lib/features/canvas/videoRenderer.js +8 -0
- package/lib/features/canvas/videoRenderer.js.map +1 -0
- package/lib/features/canvas/withRemoteSafeArea.js +2 -2
- package/lib/features/canvas/withRemoteSafeArea.js.map +1 -1
- package/lib/features/characters/characterStudioProps.js +14 -0
- package/lib/features/characters/characterStudioProps.js.map +1 -0
- package/lib/features/chat/ChatCodeBlock.js +7 -3
- package/lib/features/chat/ChatCodeBlock.js.map +1 -1
- package/lib/features/chat/ChatTranscript.js +7 -3
- package/lib/features/chat/ChatTranscript.js.map +1 -1
- package/lib/features/chat/ChatWidgetCard.js +13 -0
- package/lib/features/chat/ChatWidgetCard.js.map +1 -0
- package/lib/features/chat/ConnectorConnectCard.js +166 -0
- package/lib/features/chat/ConnectorConnectCard.js.map +1 -0
- package/lib/features/chat/ConnectorConnectPrompt.js +272 -0
- package/lib/features/chat/ConnectorConnectPrompt.js.map +1 -0
- package/lib/features/chat/MessageActionBar.js.map +1 -1
- package/lib/features/chat/QueuedFollowUps.js +71 -0
- package/lib/features/chat/QueuedFollowUps.js.map +1 -0
- package/lib/features/chat/chatWidgets.js +37 -0
- package/lib/features/chat/chatWidgets.js.map +1 -0
- package/lib/features/chat/connectorConnect.js +207 -0
- package/lib/features/chat/connectorConnect.js.map +1 -0
- package/lib/features/chat/connectorConnectHandbacks.js +55 -0
- package/lib/features/chat/connectorConnectHandbacks.js.map +1 -0
- package/lib/features/design/DesignEditorExperience.js +643 -0
- package/lib/features/design/DesignEditorExperience.js.map +1 -0
- package/lib/features/design/DesignExperience.js +444 -0
- package/lib/features/design/DesignExperience.js.map +1 -0
- package/lib/features/design/designCore.js +298 -0
- package/lib/features/design/designCore.js.map +1 -0
- package/lib/features/design/designIndex.js +150 -0
- package/lib/features/design/designIndex.js.map +1 -0
- package/lib/features/design/exportDesign.js +133 -0
- package/lib/features/design/exportDesign.js.map +1 -0
- package/lib/features/job-search/ApplicationsPanel.js +907 -0
- package/lib/features/job-search/ApplicationsPanel.js.map +1 -0
- package/lib/features/job-search/ContactsPanel.js +627 -0
- package/lib/features/job-search/ContactsPanel.js.map +1 -0
- package/lib/features/job-search/InsightsPanel.js +299 -0
- package/lib/features/job-search/InsightsPanel.js.map +1 -0
- package/lib/features/job-search/InterviewPanel.js +637 -0
- package/lib/features/job-search/InterviewPanel.js.map +1 -0
- package/lib/features/job-search/JdPastePrompt.js +130 -0
- package/lib/features/job-search/JdPastePrompt.js.map +1 -0
- package/lib/features/job-search/JobCard.js +199 -0
- package/lib/features/job-search/JobCard.js.map +1 -0
- package/lib/features/job-search/JobDetailSheet.js +255 -0
- package/lib/features/job-search/JobDetailSheet.js.map +1 -0
- package/lib/features/job-search/JobSearchAgentChatPane.js +377 -0
- package/lib/features/job-search/JobSearchAgentChatPane.js.map +1 -0
- package/lib/features/job-search/JobSearchExperience.js +1324 -0
- package/lib/features/job-search/JobSearchExperience.js.map +1 -0
- package/lib/features/job-search/JobSearchLocationField.js +231 -0
- package/lib/features/job-search/JobSearchLocationField.js.map +1 -0
- package/lib/features/job-search/ProfilePanel.js +679 -0
- package/lib/features/job-search/ProfilePanel.js.map +1 -0
- package/lib/features/job-search/RepliesPanel.js +344 -0
- package/lib/features/job-search/RepliesPanel.js.map +1 -0
- package/lib/features/job-search/SavedPanel.js +297 -0
- package/lib/features/job-search/SavedPanel.js.map +1 -0
- package/lib/features/job-search/chat/widgetContent.js +29 -0
- package/lib/features/job-search/chat/widgetContent.js.map +1 -0
- package/lib/features/job-search/cvText.js +91 -0
- package/lib/features/job-search/cvText.js.map +1 -0
- package/lib/features/job-search/jobAgentSwipe.js +7 -0
- package/lib/features/job-search/jobAgentSwipe.js.map +1 -0
- package/lib/features/job-search/jobSearchClient.js +184 -0
- package/lib/features/job-search/jobSearchClient.js.map +1 -0
- package/lib/features/job-search/jobSearchExec.js +14 -0
- package/lib/features/job-search/jobSearchExec.js.map +1 -0
- package/lib/features/job-search/jobSearchRuntime.js +50 -0
- package/lib/features/job-search/jobSearchRuntime.js.map +1 -0
- package/lib/features/job-search/jobSearchTheme.js +44 -0
- package/lib/features/job-search/jobSearchTheme.js.map +1 -0
- package/lib/features/job-search/savedJobs.js +85 -0
- package/lib/features/job-search/savedJobs.js.map +1 -0
- package/lib/features/job-search/searchHistory.js +117 -0
- package/lib/features/job-search/searchHistory.js.map +1 -0
- package/lib/features/job-search/types.js +36 -0
- package/lib/features/job-search/types.js.map +1 -0
- package/lib/features/job-search/useJobSearchSession.js +558 -0
- package/lib/features/job-search/useJobSearchSession.js.map +1 -0
- package/lib/features/messaging/ChatComponents.js +529 -0
- package/lib/features/messaging/ChatComponents.js.map +1 -0
- package/lib/features/messaging/ChatInviteDeepLink.js +116 -0
- package/lib/features/messaging/ChatInviteDeepLink.js.map +1 -0
- package/lib/features/messaging/ContactsScreen.js +288 -0
- package/lib/features/messaging/ContactsScreen.js.map +1 -0
- package/lib/features/messaging/ConversationListScreen.js +147 -0
- package/lib/features/messaging/ConversationListScreen.js.map +1 -0
- package/lib/features/messaging/MessageActions.js +290 -0
- package/lib/features/messaging/MessageActions.js.map +1 -0
- package/lib/features/messaging/NativeChatExperience.js +189 -0
- package/lib/features/messaging/NativeChatExperience.js.map +1 -0
- package/lib/features/messaging/RegistrationScreen.js +11 -14
- package/lib/features/messaging/RegistrationScreen.js.map +1 -1
- package/lib/features/messaging/ThreadScreen.js +215 -0
- package/lib/features/messaging/ThreadScreen.js.map +1 -0
- package/lib/features/messaging/chatInviteLink.js +52 -0
- package/lib/features/messaging/chatInviteLink.js.map +1 -0
- package/lib/features/messaging/chatModel.js +278 -0
- package/lib/features/messaging/chatModel.js.map +1 -0
- package/lib/features/messaging/chatOperations.js +106 -1
- package/lib/features/messaging/chatOperations.js.map +1 -1
- package/lib/features/messaging/emojiCatalog.js +60 -0
- package/lib/features/messaging/emojiCatalog.js.map +1 -0
- package/lib/features/messaging/emojiKeywords.js +1592 -0
- package/lib/features/messaging/emojiKeywords.js.map +1 -0
- package/lib/features/messaging/nativeChatChannelQuery.js +27 -0
- package/lib/features/messaging/nativeChatChannelQuery.js.map +1 -0
- package/lib/features/messaging/phoneNumbers.js +52 -1
- package/lib/features/messaging/phoneNumbers.js.map +1 -1
- package/lib/features/messaging/sha256.js +68 -0
- package/lib/features/messaging/sha256.js.map +1 -0
- package/lib/features/messaging/useChatData.js +421 -0
- package/lib/features/messaging/useChatData.js.map +1 -0
- package/lib/features/messaging/useContactMatches.js +191 -0
- package/lib/features/messaging/useContactMatches.js.map +1 -0
- package/lib/features/messaging/usePhoneVerification.js +12 -12
- package/lib/features/messaging/usePhoneVerification.js.map +1 -1
- package/lib/features/messaging/yantraChatOrg.js +8 -3
- package/lib/features/messaging/yantraChatOrg.js.map +1 -1
- package/lib/features/resume/AnnotateModal.js +100 -0
- package/lib/features/resume/AnnotateModal.js.map +1 -0
- package/lib/features/resume/AnnotationBar.js +69 -0
- package/lib/features/resume/AnnotationBar.js.map +1 -0
- package/lib/features/resume/ExportSheet.js +105 -0
- package/lib/features/resume/ExportSheet.js.map +1 -0
- package/lib/features/resume/ResumeAgentChatPane.js +95 -0
- package/lib/features/resume/ResumeAgentChatPane.js.map +1 -0
- package/lib/features/resume/ResumeEditor.js +676 -0
- package/lib/features/resume/ResumeEditor.js.map +1 -0
- package/lib/features/resume/ResumeExperience.js +235 -0
- package/lib/features/resume/ResumeExperience.js.map +1 -0
- package/lib/features/resume/ResumeListPanel.js +262 -0
- package/lib/features/resume/ResumeListPanel.js.map +1 -0
- package/lib/features/resume/ResumeToolbar.js +236 -0
- package/lib/features/resume/ResumeToolbar.js.map +1 -0
- package/lib/features/resume/annotations.js +17 -0
- package/lib/features/resume/annotations.js.map +1 -0
- package/lib/features/resume/documentCss.js +52 -0
- package/lib/features/resume/documentCss.js.map +1 -0
- package/lib/features/resume/draft.js +89 -0
- package/lib/features/resume/draft.js.map +1 -0
- package/lib/features/resume/exportResume.js +43 -0
- package/lib/features/resume/exportResume.js.map +1 -0
- package/lib/features/resume/pickResumePhoto.js +22 -0
- package/lib/features/resume/pickResumePhoto.js.map +1 -0
- package/lib/features/resume/renderResume.js +121 -0
- package/lib/features/resume/renderResume.js.map +1 -0
- package/lib/features/resume/resumeClient.js +69 -0
- package/lib/features/resume/resumeClient.js.map +1 -0
- package/lib/features/resume/resumeExec.js +14 -0
- package/lib/features/resume/resumeExec.js.map +1 -0
- package/lib/features/resume/resumeIndex.js +244 -0
- package/lib/features/resume/resumeIndex.js.map +1 -0
- package/lib/features/resume/resumeRuntime.js +50 -0
- package/lib/features/resume/resumeRuntime.js.map +1 -0
- package/lib/features/resume/resumeTheme.js +34 -0
- package/lib/features/resume/resumeTheme.js.map +1 -0
- package/lib/features/resume/resumeToolbox.js +49 -0
- package/lib/features/resume/resumeToolbox.js.map +1 -0
- package/lib/features/resume/templates.js +90 -0
- package/lib/features/resume/templates.js.map +1 -0
- package/lib/features/resume/types.js +10 -0
- package/lib/features/resume/types.js.map +1 -0
- package/lib/features/resume/useResumeSession.js +183 -0
- package/lib/features/resume/useResumeSession.js.map +1 -0
- package/lib/features/shopping/DealsPanel.js +254 -0
- package/lib/features/shopping/DealsPanel.js.map +1 -0
- package/lib/features/shopping/HistoryPanel.js +147 -0
- package/lib/features/shopping/HistoryPanel.js.map +1 -0
- package/lib/features/shopping/OrdersPanel.js +157 -0
- package/lib/features/shopping/OrdersPanel.js.map +1 -0
- package/lib/features/shopping/ProductCard.js +326 -0
- package/lib/features/shopping/ProductCard.js.map +1 -0
- package/lib/features/shopping/ProductDetailSheet.js +313 -0
- package/lib/features/shopping/ProductDetailSheet.js.map +1 -0
- package/lib/features/shopping/ProductFilterBar.js +153 -0
- package/lib/features/shopping/ProductFilterBar.js.map +1 -0
- package/lib/features/shopping/ProductPhoto.js +27 -0
- package/lib/features/shopping/ProductPhoto.js.map +1 -0
- package/lib/features/shopping/SavedPanel.js +139 -0
- package/lib/features/shopping/SavedPanel.js.map +1 -0
- package/lib/features/shopping/ShoppingAgentChatPane.js +436 -0
- package/lib/features/shopping/ShoppingAgentChatPane.js.map +1 -0
- package/lib/features/shopping/ShoppingExperience.js +888 -0
- package/lib/features/shopping/ShoppingExperience.js.map +1 -0
- package/lib/features/shopping/TrendingSections.js +199 -0
- package/lib/features/shopping/TrendingSections.js.map +1 -0
- package/lib/features/shopping/WatchlistPanel.js +148 -0
- package/lib/features/shopping/WatchlistPanel.js.map +1 -0
- package/lib/features/shopping/catalog.js +238 -0
- package/lib/features/shopping/catalog.js.map +1 -0
- package/lib/features/shopping/chat/ShoppingChatResultCard.js +175 -0
- package/lib/features/shopping/chat/ShoppingChatResultCard.js.map +1 -0
- package/lib/features/shopping/chat/streamAssistantReply.js +34 -0
- package/lib/features/shopping/chat/streamAssistantReply.js.map +1 -0
- package/lib/features/shopping/chat/widgetContent.js +233 -0
- package/lib/features/shopping/chat/widgetContent.js.map +1 -0
- package/lib/features/shopping/hooks/useTrendingProducts.js +162 -0
- package/lib/features/shopping/hooks/useTrendingProducts.js.map +1 -0
- package/lib/features/shopping/productImage.js +42 -0
- package/lib/features/shopping/productImage.js.map +1 -0
- package/lib/features/shopping/savedProducts.js +84 -0
- package/lib/features/shopping/savedProducts.js.map +1 -0
- package/lib/features/shopping/services/catalogActions.js +166 -0
- package/lib/features/shopping/services/catalogActions.js.map +1 -0
- package/lib/features/shopping/services/parsePriceCheckIntent.js +58 -0
- package/lib/features/shopping/services/parsePriceCheckIntent.js.map +1 -0
- package/lib/features/shopping/services/parseShoppingIntent.js +67 -0
- package/lib/features/shopping/services/parseShoppingIntent.js.map +1 -0
- package/lib/features/shopping/services/productAvailability.js +25 -0
- package/lib/features/shopping/services/productAvailability.js.map +1 -0
- package/lib/features/shopping/services/productFilters.js +72 -0
- package/lib/features/shopping/services/productFilters.js.map +1 -0
- package/lib/features/shopping/services/retailerUrl.js +75 -0
- package/lib/features/shopping/services/retailerUrl.js.map +1 -0
- package/lib/features/shopping/services/shoppingChatReply.js +46 -0
- package/lib/features/shopping/services/shoppingChatReply.js.map +1 -0
- package/lib/features/shopping/services/shoppingProductSearch.js +336 -0
- package/lib/features/shopping/services/shoppingProductSearch.js.map +1 -0
- package/lib/features/shopping/services/shoppingSearchConnectorClient.js +41 -0
- package/lib/features/shopping/services/shoppingSearchConnectorClient.js.map +1 -0
- package/lib/features/shopping/shopAgentSwipe.js +7 -0
- package/lib/features/shopping/shopAgentSwipe.js.map +1 -0
- package/lib/features/shopping/shoppingCart.js +116 -0
- package/lib/features/shopping/shoppingCart.js.map +1 -0
- package/lib/features/shopping/shoppingExec.js +14 -0
- package/lib/features/shopping/shoppingExec.js.map +1 -0
- package/lib/features/shopping/shoppingHistoryStore.js +176 -0
- package/lib/features/shopping/shoppingHistoryStore.js.map +1 -0
- package/lib/features/shopping/shoppingRuntime.js +63 -0
- package/lib/features/shopping/shoppingRuntime.js.map +1 -0
- package/lib/features/shopping/timeAgo.js +14 -0
- package/lib/features/shopping/timeAgo.js.map +1 -0
- package/lib/features/shopping/useShoppingSearch.js +262 -0
- package/lib/features/shopping/useShoppingSearch.js.map +1 -0
- package/lib/features/travel/BookHeaderGlow.js +48 -0
- package/lib/features/travel/BookHeaderGlow.js.map +1 -0
- package/lib/features/travel/BookingsPanel.js +29 -0
- package/lib/features/travel/BookingsPanel.js.map +1 -0
- package/lib/features/travel/DiscoverPanel.js +155 -0
- package/lib/features/travel/DiscoverPanel.js.map +1 -0
- package/lib/features/travel/FlightCompareBar.js +86 -0
- package/lib/features/travel/FlightCompareBar.js.map +1 -0
- package/lib/features/travel/FlightDealsBoard.js +100 -0
- package/lib/features/travel/FlightDealsBoard.js.map +1 -0
- package/lib/features/travel/HistoryPanel.js +82 -0
- package/lib/features/travel/HistoryPanel.js.map +1 -0
- package/lib/features/travel/PopularDestinations.js +144 -0
- package/lib/features/travel/PopularDestinations.js.map +1 -0
- package/lib/features/travel/SavedPanel.js +27 -0
- package/lib/features/travel/SavedPanel.js.map +1 -0
- package/lib/features/travel/TravelAgentChatPane.js +303 -0
- package/lib/features/travel/TravelAgentChatPane.js.map +1 -0
- package/lib/features/travel/TravelBookHero.js +425 -0
- package/lib/features/travel/TravelBookHero.js.map +1 -0
- package/lib/features/travel/TravelDatesField.js +234 -0
- package/lib/features/travel/TravelDatesField.js.map +1 -0
- package/lib/features/travel/TravelDetailSheet.js +106 -0
- package/lib/features/travel/TravelDetailSheet.js.map +1 -0
- package/lib/features/travel/TravelExperience.js +624 -0
- package/lib/features/travel/TravelExperience.js.map +1 -0
- package/lib/features/travel/TravelGuestsField.js +85 -0
- package/lib/features/travel/TravelGuestsField.js.map +1 -0
- package/lib/features/travel/TravelLanding.js +318 -0
- package/lib/features/travel/TravelLanding.js.map +1 -0
- package/lib/features/travel/TravelLocationField.js +179 -0
- package/lib/features/travel/TravelLocationField.js.map +1 -0
- package/lib/features/travel/TravelPropertyCard.js +266 -0
- package/lib/features/travel/TravelPropertyCard.js.map +1 -0
- package/lib/features/travel/TravelPropertyPhoto.js +22 -0
- package/lib/features/travel/TravelPropertyPhoto.js.map +1 -0
- package/lib/features/travel/TravelRailFlyout.js +79 -0
- package/lib/features/travel/TravelRailFlyout.js.map +1 -0
- package/lib/features/travel/TravelResultsMap.js +126 -0
- package/lib/features/travel/TravelResultsMap.js.map +1 -0
- package/lib/features/travel/WorkspacePanel.js +148 -0
- package/lib/features/travel/WorkspacePanel.js.map +1 -0
- package/lib/features/travel/appNav.js +244 -0
- package/lib/features/travel/appNav.js.map +1 -0
- package/lib/features/travel/calendarDays.js +50 -0
- package/lib/features/travel/calendarDays.js.map +1 -0
- package/lib/features/travel/catalog.js +72 -0
- package/lib/features/travel/catalog.js.map +1 -0
- package/lib/features/travel/chat/TravelChatResultCard.js +107 -0
- package/lib/features/travel/chat/TravelChatResultCard.js.map +1 -0
- package/lib/features/travel/chat/widgetContent.js +107 -0
- package/lib/features/travel/chat/widgetContent.js.map +1 -0
- package/lib/features/travel/flightDeals.js +65 -0
- package/lib/features/travel/flightDeals.js.map +1 -0
- package/lib/features/travel/mapCoordinates.js +36 -0
- package/lib/features/travel/mapCoordinates.js.map +1 -0
- package/lib/features/travel/parseTravelIntent.js +303 -0
- package/lib/features/travel/parseTravelIntent.js.map +1 -0
- package/lib/features/travel/savedStays.js +66 -0
- package/lib/features/travel/savedStays.js.map +1 -0
- package/lib/features/travel/services/flightDealsBoard.js +111 -0
- package/lib/features/travel/services/flightDealsBoard.js.map +1 -0
- package/lib/features/travel/services/flightSearchConnectorClient.js +42 -0
- package/lib/features/travel/services/flightSearchConnectorClient.js.map +1 -0
- package/lib/features/travel/services/geocodeLocation.js +79 -0
- package/lib/features/travel/services/geocodeLocation.js.map +1 -0
- package/lib/features/travel/services/placePredictions.js +113 -0
- package/lib/features/travel/services/placePredictions.js.map +1 -0
- package/lib/features/travel/services/resolveOriginCity.js +27 -0
- package/lib/features/travel/services/resolveOriginCity.js.map +1 -0
- package/lib/features/travel/services/resortifiConnectorClient.js +76 -0
- package/lib/features/travel/services/resortifiConnectorClient.js.map +1 -0
- package/lib/features/travel/services/travelFlightSearch.js +289 -0
- package/lib/features/travel/services/travelFlightSearch.js.map +1 -0
- package/lib/features/travel/services/travelPropertySearch.js +377 -0
- package/lib/features/travel/services/travelPropertySearch.js.map +1 -0
- package/lib/features/travel/travelAgentSwipe.js +7 -0
- package/lib/features/travel/travelAgentSwipe.js.map +1 -0
- package/lib/features/travel/travelExec.js +14 -0
- package/lib/features/travel/travelExec.js.map +1 -0
- package/lib/features/travel/travelHistoryStore.js +108 -0
- package/lib/features/travel/travelHistoryStore.js.map +1 -0
- package/lib/features/travel/travelRuntime.js +62 -0
- package/lib/features/travel/travelRuntime.js.map +1 -0
- package/lib/features/travel/types.js +9 -0
- package/lib/features/travel/types.js.map +1 -0
- package/lib/features/travel/useTravelSearch.js +330 -0
- package/lib/features/travel/useTravelSearch.js.map +1 -0
- package/lib/features/travel/workspaceContent.js +548 -0
- package/lib/features/travel/workspaceContent.js.map +1 -0
- package/lib/hooks/useCdecliChannel.js +128 -6
- package/lib/hooks/useCdecliChannel.js.map +1 -1
- package/lib/hooks/useChatApi.js +4 -2
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +77 -63
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/hooks/useHostConnectorCard.js +24 -0
- package/lib/hooks/useHostConnectorCard.js.map +1 -0
- package/lib/hooks/useObtainSystemToken.js +23 -5
- package/lib/hooks/useObtainSystemToken.js.map +1 -1
- package/lib/hooks/webViewRetentionPolicy.js +1 -0
- package/lib/hooks/webViewRetentionPolicy.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/screens/Chat/index.js +51 -22
- package/lib/screens/Chat/index.js.map +1 -1
- package/lib/screens/ChatNative/index.js +13 -2
- package/lib/screens/ChatNative/index.js.map +1 -1
- package/lib/screens/Home/HomeScreen.js +3 -3
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/ChatHistoryLanding.js +32 -32
- package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
- package/lib/screens/JobSearchNative/useJobSearchHostChat.js +12 -6
- package/lib/screens/JobSearchNative/useJobSearchHostChat.js.map +1 -1
- package/lib/screens/ResumeNative/useResumeHostChat.js +12 -6
- package/lib/screens/ResumeNative/useResumeHostChat.js.map +1 -1
- package/lib/screens/ShoppingNative/useShoppingHostChat.js +12 -6
- package/lib/screens/ShoppingNative/useShoppingHostChat.js.map +1 -1
- package/lib/screens/TravelNative/useTravelHostChat.js +12 -6
- package/lib/screens/TravelNative/useTravelHostChat.js.map +1 -1
- package/lib/screens/WebBuilder/WebViewWithNavigation.js +2 -2
- package/lib/screens/WebBuilder/WebViewWithNavigation.js.map +1 -1
- package/lib/services/brainQuickReply.js +38 -1
- package/lib/services/brainQuickReply.js.map +1 -1
- package/lib/state/chatThreadMerge.js +6 -1
- package/lib/state/chatThreadMerge.js.map +1 -1
- package/package.json +6 -4
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {SOURCE_LABELS,isProductSource}from'../catalog.js';import {keepSellableProducts}from'../services/productAvailability.js';var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
const WIDGET_FENCE = /```(?:yantra:widget|json)\s*([\s\S]*?)```/gi;
|
|
21
|
+
const GENERIC_CARD_FIELDS = 7;
|
|
22
|
+
const UI_TURN_COPY = {
|
|
23
|
+
shop: {
|
|
24
|
+
noun: "product",
|
|
25
|
+
actionLabel: "View products",
|
|
26
|
+
title: (q) => q ? `Products for ${q}` : "Product results",
|
|
27
|
+
empty: "No products found. Try a different search."
|
|
28
|
+
},
|
|
29
|
+
deals: {
|
|
30
|
+
noun: "deal",
|
|
31
|
+
actionLabel: "View deals",
|
|
32
|
+
title: (q) => q ? `Deals for ${q}` : "Deals",
|
|
33
|
+
empty: "No deals match those filters. Try a lower discount or a higher price ceiling."
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
function productMetaLine(p) {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
const price = (_a = p.priceLabel) != null ? _a : typeof p.price === "number" && p.price > 0 ? `$${p.price.toFixed(2)}` : void 0;
|
|
39
|
+
const rating = typeof p.rating === "number" && p.rating > 0 ? `\u2605 ${p.rating.toFixed(1)}` : void 0;
|
|
40
|
+
const source = (_b = p.source) == null ? void 0 : _b.trim().toLowerCase();
|
|
41
|
+
const retailer = isProductSource(source) ? SOURCE_LABELS[source] : void 0;
|
|
42
|
+
const stock = p.inStock === true ? "in stock" : void 0;
|
|
43
|
+
const parts = [price, rating, retailer, stock].filter(Boolean);
|
|
44
|
+
return parts.length > 0 ? parts.join(" \xB7 ") : void 0;
|
|
45
|
+
}
|
|
46
|
+
function toWidgetItem(p) {
|
|
47
|
+
var _a;
|
|
48
|
+
return __spreadValues(__spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
49
|
+
id: p.id,
|
|
50
|
+
title: p.name
|
|
51
|
+
}, p.price > 0 ? {
|
|
52
|
+
price: p.price
|
|
53
|
+
} : {}), p.rating > 0 ? {
|
|
54
|
+
rating: p.rating
|
|
55
|
+
} : {}), p.reviews > 0 ? {
|
|
56
|
+
reviews: p.reviews
|
|
57
|
+
} : {}), p.imageUrl ? {
|
|
58
|
+
imageUrl: p.imageUrl
|
|
59
|
+
} : {}), p.url ? {
|
|
60
|
+
url: p.url
|
|
61
|
+
} : {}), {
|
|
62
|
+
source: (_a = p.source) != null ? _a : "yantra"
|
|
63
|
+
}), typeof p.inStock === "boolean" ? {
|
|
64
|
+
inStock: p.inStock
|
|
65
|
+
} : {}), p.linkVerified ? {
|
|
66
|
+
linkVerified: true
|
|
67
|
+
} : {}), p.priceVerified ? {
|
|
68
|
+
priceVerified: true
|
|
69
|
+
} : {});
|
|
70
|
+
}
|
|
71
|
+
function toGenericCardAttachment(attachment) {
|
|
72
|
+
var _a, _b, _c;
|
|
73
|
+
const count = (_a = attachment.totalCount) != null ? _a : attachment.properties.length;
|
|
74
|
+
const query = (_b = attachment.query) == null ? void 0 : _b.trim();
|
|
75
|
+
const shown = attachment.properties.slice(0, GENERIC_CARD_FIELDS);
|
|
76
|
+
const remaining = count - shown.length;
|
|
77
|
+
const fields = shown.map((p) => {
|
|
78
|
+
var _a2;
|
|
79
|
+
return {
|
|
80
|
+
label: p.title,
|
|
81
|
+
value: (_a2 = productMetaLine(p)) != null ? _a2 : ""
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
if (remaining > 0) fields.push({
|
|
85
|
+
label: `+ ${remaining} more`,
|
|
86
|
+
value: ""
|
|
87
|
+
});
|
|
88
|
+
return __spreadProps(__spreadValues({}, attachment), {
|
|
89
|
+
title: attachment.title || (query ? `Products for ${query}` : "Products"),
|
|
90
|
+
subtitle: count > 0 ? `${count} product${count === 1 ? "" : "s"}` : void 0,
|
|
91
|
+
actionLabel: (_c = attachment.actionLabel) != null ? _c : "View products",
|
|
92
|
+
items: attachment.properties.map((p) => ({
|
|
93
|
+
title: p.title,
|
|
94
|
+
imageUrl: p.imageUrl,
|
|
95
|
+
url: p.url
|
|
96
|
+
})),
|
|
97
|
+
fields
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function visibleAssistantContent(messageContent) {
|
|
101
|
+
return messageContent.replace(WIDGET_FENCE, (match, body) => {
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(String(body).trim());
|
|
104
|
+
if (typeof (parsed == null ? void 0 : parsed.propsComponent) === "string") return "";
|
|
105
|
+
} catch (e) {
|
|
106
|
+
return match;
|
|
107
|
+
}
|
|
108
|
+
return match;
|
|
109
|
+
}).replace(/\n{3,}/g, "\n\n").trim();
|
|
110
|
+
}
|
|
111
|
+
function extractShoppingAttachment(messageContent) {
|
|
112
|
+
var _a, _b, _c, _d;
|
|
113
|
+
let found = null;
|
|
114
|
+
for (const match of messageContent.matchAll(WIDGET_FENCE)) {
|
|
115
|
+
try {
|
|
116
|
+
const parsed = JSON.parse(String((_a = match[1]) != null ? _a : "").trim());
|
|
117
|
+
const attachment = (parsed == null ? void 0 : parsed.propsComponent) === "shopping" ? (_c = (_b = parsed.propsConfiguration) == null ? void 0 : _b.contents) == null ? void 0 : _c.attachment : void 0;
|
|
118
|
+
if ((_d = attachment == null ? void 0 : attachment.properties) == null ? void 0 : _d.length) found = attachment;
|
|
119
|
+
} catch (e) {
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return found;
|
|
123
|
+
}
|
|
124
|
+
function buildShoppingAttachment(products, opts = {}) {
|
|
125
|
+
var _a, _b, _c, _d;
|
|
126
|
+
const copy = UI_TURN_COPY[(_a = opts.kind) != null ? _a : "shop"];
|
|
127
|
+
const sellable = keepSellableProducts(products);
|
|
128
|
+
const rows = sellable.length > 0 ? sellable : products.filter((p) => p.inStock !== false);
|
|
129
|
+
const count = opts.totalCount != null && rows.length === products.length ? opts.totalCount : rows.length;
|
|
130
|
+
const query = (_b = opts.query) == null ? void 0 : _b.trim();
|
|
131
|
+
const title = (_c = opts.title) != null ? _c : copy.title(query != null ? query : "");
|
|
132
|
+
return {
|
|
133
|
+
title,
|
|
134
|
+
query,
|
|
135
|
+
properties: rows.map(toWidgetItem),
|
|
136
|
+
totalCount: count,
|
|
137
|
+
actionLabel: (_d = opts.actionLabel) != null ? _d : copy.actionLabel
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function summarizeShoppingAttachment(attachment, opts = {}) {
|
|
141
|
+
var _a, _b, _c, _d;
|
|
142
|
+
const count = (_a = attachment.totalCount) != null ? _a : attachment.properties.length;
|
|
143
|
+
const query = (_b = attachment.query) == null ? void 0 : _b.trim();
|
|
144
|
+
const noun = (_c = opts.noun) != null ? _c : "product";
|
|
145
|
+
const plural = (n) => `${noun}${n === 1 ? "" : "s"}`;
|
|
146
|
+
if (count === 0) {
|
|
147
|
+
return query ? `I couldn't find ${plural(2)} matching **${query}**. Try refining your search.` : `I couldn't find any ${plural(2)} for that request. Try a different query.`;
|
|
148
|
+
}
|
|
149
|
+
const header = query ? `I found **${count} ${plural(count)}** for **${query}**:` : `I found **${count} ${plural(count)}**:`;
|
|
150
|
+
const preview = attachment.properties.slice(0, 5);
|
|
151
|
+
const lines = preview.map((p, i) => {
|
|
152
|
+
var _a2;
|
|
153
|
+
const price = (_a2 = p.priceLabel) != null ? _a2 : typeof p.price === "number" && p.price > 0 ? `$${Math.round(p.price)}` : void 0;
|
|
154
|
+
const meta = [price, typeof p.rating === "number" ? `\u2605 ${p.rating.toFixed(1)}` : void 0, p.inStock === true ? "in stock" : void 0].filter(Boolean).join(" \xB7 ");
|
|
155
|
+
const label = p.title.replace(/\[/g, "\\[").replace(/\]/g, "\\]");
|
|
156
|
+
return meta ? `${i + 1}. **${label}** \u2014 ${meta}` : `${i + 1}. **${label}**`;
|
|
157
|
+
});
|
|
158
|
+
const remaining = count - preview.length;
|
|
159
|
+
const parts = [header, "", ...lines];
|
|
160
|
+
if (remaining > 0) {
|
|
161
|
+
parts.push("", `_+ ${remaining} more in the card below._`);
|
|
162
|
+
}
|
|
163
|
+
parts.push("", `Tap **${(_d = attachment.actionLabel) != null ? _d : "View products"}** below to browse the full list on the shop page.`);
|
|
164
|
+
return parts.join("\n");
|
|
165
|
+
}
|
|
166
|
+
function appendShoppingWidgetBlock(prose, attachment) {
|
|
167
|
+
const envelope = {
|
|
168
|
+
propsComponent: "shopping",
|
|
169
|
+
propsConfiguration: {
|
|
170
|
+
contents: {
|
|
171
|
+
attachment: toGenericCardAttachment(attachment)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
return `${prose.trim()}
|
|
176
|
+
|
|
177
|
+
\`\`\`json
|
|
178
|
+
${JSON.stringify(envelope)}
|
|
179
|
+
\`\`\``;
|
|
180
|
+
}
|
|
181
|
+
function buildShoppingWidgetMessage(products, query, opts = {}) {
|
|
182
|
+
var _a;
|
|
183
|
+
const copy = UI_TURN_COPY[(_a = opts.kind) != null ? _a : "shop"];
|
|
184
|
+
const attachment = buildShoppingAttachment(products, {
|
|
185
|
+
query,
|
|
186
|
+
kind: opts.kind,
|
|
187
|
+
title: opts.title,
|
|
188
|
+
actionLabel: opts.actionLabel
|
|
189
|
+
});
|
|
190
|
+
return appendShoppingWidgetBlock(summarizeShoppingAttachment(attachment, {
|
|
191
|
+
noun: copy.noun
|
|
192
|
+
}), attachment);
|
|
193
|
+
}
|
|
194
|
+
function isShoppingConversation(text) {
|
|
195
|
+
const trimmed = text.trim();
|
|
196
|
+
if (!trimmed) return true;
|
|
197
|
+
if (/^(hi|hey|hello|yo|thanks|thank you|thx|ok|okay)[\s!.?]*$/i.test(trimmed)) return true;
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
function isVisualIdentifyQuery(text) {
|
|
201
|
+
const trimmed = text.trim().replace(/[.!?]+$/g, "").trim();
|
|
202
|
+
if (!trimmed) return true;
|
|
203
|
+
return /^(what(?:'s| is) this|whats this|what is that|identify(?: this)?|what product|which product|find this)\b/i.test(trimmed);
|
|
204
|
+
}
|
|
205
|
+
function isGenericProductFindAsk(text) {
|
|
206
|
+
const t = text.trim().replace(/[.!?]+$/g, "");
|
|
207
|
+
if (!t) return false;
|
|
208
|
+
return /^(?:please\s+)?(?:find|search|shop(?:\s+for)?|show|get|buy)\s+(?:similar\s+)?(?:products?|this|these|it)(?:\s+to\s+buy)?$/i.test(t);
|
|
209
|
+
}
|
|
210
|
+
function shouldRunNativeShopSearch(text) {
|
|
211
|
+
const trimmed = text.trim();
|
|
212
|
+
if (!trimmed) return false;
|
|
213
|
+
if (isShoppingConversation(trimmed) || isVisualIdentifyQuery(trimmed)) return false;
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
function extractProductQueryFromAssistant(text) {
|
|
217
|
+
var _a;
|
|
218
|
+
const prose = visibleAssistantContent(text).split("\n").map((line) => line.trim()).filter((line) => line && !/^[⚙🔧]/.test(line) && !/^used\s+\d+\s+tools/i.test(line)).join(" ");
|
|
219
|
+
if (!prose) return null;
|
|
220
|
+
const patterns = [/\b(?:same|it'?s|this is|these are|looks like)\s+(?:a pair of\s+)?([^.]{8,90}?)(?:\.|,|photographed|—|–|\s-\s)/i, /\bsearch(?:ing)? for\s+(?:similar\s+)?([^.]{8,90}?)(?:\.|$)/i];
|
|
221
|
+
for (const pattern of patterns) {
|
|
222
|
+
const match = prose.match(pattern);
|
|
223
|
+
const raw = ((_a = match == null ? void 0 : match[1]) != null ? _a : "").replace(/\s+/g, " ").trim();
|
|
224
|
+
if (raw.length >= 8) return raw.replace(/^(?:a|an|the)\s+/i, "");
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
function shouldUseHostLane(text, fileCount) {
|
|
229
|
+
if (fileCount > 0) return true;
|
|
230
|
+
const trimmed = text.trim();
|
|
231
|
+
if (!trimmed) return false;
|
|
232
|
+
return isVisualIdentifyQuery(trimmed) || isShoppingConversation(trimmed);
|
|
233
|
+
}export{UI_TURN_COPY,WIDGET_FENCE,appendShoppingWidgetBlock,buildShoppingAttachment,buildShoppingWidgetMessage,extractProductQueryFromAssistant,extractShoppingAttachment,isGenericProductFindAsk,isShoppingConversation,isVisualIdentifyQuery,shouldRunNativeShopSearch,shouldUseHostLane,summarizeShoppingAttachment,toGenericCardAttachment,visibleAssistantContent};//# sourceMappingURL=widgetContent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widgetContent.js","sources":["../../../../src/features/shopping/chat/widgetContent.ts"],"sourcesContent":["/**\n * Shopping chat widget contract — native twin of surface\n * `buildShoppingWidgetMessage` + `buildShoppingAttachment` + chat heuristics.\n */\nimport { isProductSource, SOURCE_LABELS, type Product } from '../catalog';\nimport { keepSellableProducts } from '../services/productAvailability';\n\nexport const WIDGET_FENCE = /```(?:yantra:widget|json)\\s*([\\s\\S]*?)```/gi;\n\nconst GENERIC_CARD_FIELDS = 7;\n\nexport interface ShoppingChatCardItem {\n id?: string;\n title: string;\n price?: number;\n priceLabel?: string;\n rating?: number;\n reviews?: number;\n imageUrl?: string;\n url?: string;\n source?: string;\n inStock?: boolean;\n linkVerified?: boolean;\n priceVerified?: boolean;\n}\n\nexport interface ShoppingChatAttachment {\n title: string;\n subtitle?: string;\n query?: string;\n actionLabel?: string;\n totalCount?: number;\n properties: ShoppingChatCardItem[];\n items?: Array<{ title: string; imageUrl?: string; url?: string }>;\n fields?: Array<{ label: string; value: string }>;\n}\n\nexport type ShoppingUiSearchKind = 'shop' | 'deals';\n\nexport const UI_TURN_COPY: Record<\n ShoppingUiSearchKind,\n { noun: string; actionLabel: string; title: (q: string) => string; empty: string }\n> = {\n shop: {\n noun: 'product',\n actionLabel: 'View products',\n title: (q) => (q ? `Products for ${q}` : 'Product results'),\n empty: 'No products found. Try a different search.',\n },\n deals: {\n noun: 'deal',\n actionLabel: 'View deals',\n title: (q) => (q ? `Deals for ${q}` : 'Deals'),\n empty: 'No deals match those filters. Try a lower discount or a higher price ceiling.',\n },\n};\n\nfunction productMetaLine(p: ShoppingChatCardItem): string | undefined {\n const price = p.priceLabel ?? (typeof p.price === 'number' && p.price > 0 ? `$${p.price.toFixed(2)}` : undefined);\n const rating = typeof p.rating === 'number' && p.rating > 0 ? `★ ${p.rating.toFixed(1)}` : undefined;\n const source = p.source?.trim().toLowerCase();\n const retailer = isProductSource(source) ? SOURCE_LABELS[source] : undefined;\n const stock = p.inStock === true ? 'in stock' : undefined;\n const parts = [price, rating, retailer, stock].filter(Boolean);\n return parts.length > 0 ? parts.join(' · ') : undefined;\n}\n\nfunction toWidgetItem(p: Product): ShoppingChatCardItem {\n return {\n id: p.id,\n title: p.name,\n ...(p.price > 0 ? { price: p.price } : {}),\n ...(p.rating > 0 ? { rating: p.rating } : {}),\n ...(p.reviews > 0 ? { reviews: p.reviews } : {}),\n ...(p.imageUrl ? { imageUrl: p.imageUrl } : {}),\n ...(p.url ? { url: p.url } : {}),\n source: p.source ?? 'yantra',\n ...(typeof p.inStock === 'boolean' ? { inStock: p.inStock } : {}),\n ...(p.linkVerified ? { linkVerified: true } : {}),\n ...(p.priceVerified ? { priceVerified: true } : {}),\n };\n}\n\n/** Shape for the shared generic chat card (thumbnails + fields rows). */\nexport function toGenericCardAttachment(attachment: ShoppingChatAttachment): ShoppingChatAttachment {\n const count = attachment.totalCount ?? attachment.properties.length;\n const query = attachment.query?.trim();\n const shown = attachment.properties.slice(0, GENERIC_CARD_FIELDS);\n const remaining = count - shown.length;\n\n const fields = shown.map((p) => ({ label: p.title, value: productMetaLine(p) ?? '' }));\n if (remaining > 0) fields.push({ label: `+ ${remaining} more`, value: '' });\n\n return {\n ...attachment,\n title: attachment.title || (query ? `Products for ${query}` : 'Products'),\n subtitle: count > 0 ? `${count} product${count === 1 ? '' : 's'}` : undefined,\n actionLabel: attachment.actionLabel ?? 'View products',\n items: attachment.properties.map((p) => ({\n title: p.title,\n imageUrl: p.imageUrl,\n url: p.url,\n })),\n fields,\n };\n}\n\nexport function visibleAssistantContent(messageContent: string): string {\n return messageContent\n .replace(WIDGET_FENCE, (match, body: string) => {\n try {\n const parsed = JSON.parse(String(body).trim()) as { propsComponent?: unknown };\n if (typeof parsed?.propsComponent === 'string') return '';\n } catch {\n return match;\n }\n return match;\n })\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n}\n\nexport function extractShoppingAttachment(messageContent: string): ShoppingChatAttachment | null {\n let found: ShoppingChatAttachment | null = null;\n for (const match of messageContent.matchAll(WIDGET_FENCE)) {\n try {\n const parsed = JSON.parse(String(match[1] ?? '').trim()) as {\n propsComponent?: string;\n propsConfiguration?: { contents?: { attachment?: ShoppingChatAttachment } };\n };\n const attachment =\n parsed?.propsComponent === 'shopping' ? parsed.propsConfiguration?.contents?.attachment : undefined;\n if (attachment?.properties?.length) found = attachment;\n } catch {\n /* skip */\n }\n }\n return found;\n}\n\nexport function buildShoppingAttachment(\n products: Product[],\n opts: {\n query?: string;\n totalCount?: number;\n title?: string;\n actionLabel?: string;\n kind?: ShoppingUiSearchKind;\n } = {},\n): ShoppingChatAttachment {\n const copy = UI_TURN_COPY[opts.kind ?? 'shop'];\n const sellable = keepSellableProducts(products);\n // When every row lacks a product URL (rare connector gaps / unit fixtures),\n // still show non-oos rows so the agent is not empty — live SERP usually has URLs.\n const rows = sellable.length > 0 ? sellable : products.filter((p) => p.inStock !== false);\n const count = opts.totalCount != null && rows.length === products.length ? opts.totalCount : rows.length;\n const query = opts.query?.trim();\n const title = opts.title ?? copy.title(query ?? '');\n\n return {\n title,\n query,\n properties: rows.map(toWidgetItem),\n totalCount: count,\n actionLabel: opts.actionLabel ?? copy.actionLabel,\n };\n}\n\n/** Prose above the widget — same contract as surface `summarizeShoppingAttachment`. */\nexport function summarizeShoppingAttachment(attachment: ShoppingChatAttachment, opts: { noun?: string } = {}): string {\n const count = attachment.totalCount ?? attachment.properties.length;\n const query = attachment.query?.trim();\n const noun = opts.noun ?? 'product';\n const plural = (n: number) => `${noun}${n === 1 ? '' : 's'}`;\n\n if (count === 0) {\n return query\n ? `I couldn't find ${plural(2)} matching **${query}**. Try refining your search.`\n : `I couldn't find any ${plural(2)} for that request. Try a different query.`;\n }\n\n const header = query\n ? `I found **${count} ${plural(count)}** for **${query}**:`\n : `I found **${count} ${plural(count)}**:`;\n\n const preview = attachment.properties.slice(0, 5);\n const lines = preview.map((p, i) => {\n const price =\n p.priceLabel ?? (typeof p.price === 'number' && p.price > 0 ? `$${Math.round(p.price)}` : undefined);\n const meta = [\n price,\n typeof p.rating === 'number' ? `★ ${p.rating.toFixed(1)}` : undefined,\n p.inStock === true ? 'in stock' : undefined,\n ]\n .filter(Boolean)\n .join(' · ');\n const label = p.title.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n return meta ? `${i + 1}. **${label}** — ${meta}` : `${i + 1}. **${label}**`;\n });\n\n const remaining = count - preview.length;\n const parts = [header, '', ...lines];\n if (remaining > 0) {\n parts.push('', `_+ ${remaining} more in the card below._`);\n }\n parts.push(\n '',\n `Tap **${attachment.actionLabel ?? 'View products'}** below to browse the full list on the shop page.`,\n );\n return parts.join('\\n');\n}\n\nexport function appendShoppingWidgetBlock(prose: string, attachment: ShoppingChatAttachment): string {\n const envelope = {\n propsComponent: 'shopping',\n propsConfiguration: { contents: { attachment: toGenericCardAttachment(attachment) } },\n };\n return `${prose.trim()}\\n\\n\\`\\`\\`json\\n${JSON.stringify(envelope)}\\n\\`\\`\\``;\n}\n\nexport function buildShoppingWidgetMessage(\n products: Product[],\n query: string,\n opts: { kind?: ShoppingUiSearchKind; title?: string; actionLabel?: string } = {},\n): string {\n const copy = UI_TURN_COPY[opts.kind ?? 'shop'];\n const attachment = buildShoppingAttachment(products, {\n query,\n kind: opts.kind,\n title: opts.title,\n actionLabel: opts.actionLabel,\n });\n return appendShoppingWidgetBlock(summarizeShoppingAttachment(attachment, { noun: copy.noun }), attachment);\n}\n\n/** @deprecated Prefer summarizeShoppingAttachment — kept for call-site clarity. */\nexport function summarizeShoppingResults(products: Product[], query: string): string {\n return summarizeShoppingAttachment(buildShoppingAttachment(products, { query }));\n}\n\n/** Greetings / chit-chat — not a product ask. Same split as hosted shopping. */\nexport function isShoppingConversation(text: string): boolean {\n const trimmed = text.trim();\n if (!trimmed) return true;\n if (/^(hi|hey|hello|yo|thanks|thank you|thx|ok|okay)[\\s!.?]*$/i.test(trimmed)) return true;\n return false;\n}\n\n/** Photo in hand — \"what is this\" is not a SERP query. */\nexport function isVisualIdentifyQuery(text: string): boolean {\n const trimmed = text\n .trim()\n .replace(/[.!?]+$/g, '')\n .trim();\n if (!trimmed) return true;\n return /^(what(?:'s| is) this|whats this|what is that|identify(?: this)?|what product|which product|find this)\\b/i.test(\n trimmed,\n );\n}\n\n/** Native shop has no vision lane locally — photos go to host chat. */\nexport function shouldSkipShoppingSearch(text: string, attachmentCount: number): boolean {\n if (attachmentCount < 1) return false;\n const trimmed = text.trim();\n return !trimmed || isVisualIdentifyQuery(trimmed) || isShoppingConversation(trimmed);\n}\n\n/** Generic \"search this photo\" — wait for vision, then native shop. */\nexport function isGenericProductFindAsk(text: string): boolean {\n const t = text.trim().replace(/[.!?]+$/g, '');\n if (!t) return false;\n return /^(?:please\\s+)?(?:find|search|shop(?:\\s+for)?|show|get|buy)\\s+(?:similar\\s+)?(?:products?|this|these|it)(?:\\s+to\\s+buy)?$/i.test(\n t,\n );\n}\n\n/** User asked to shop, not just identify the photo. */\nexport function shouldRunNativeShopSearch(text: string): boolean {\n const trimmed = text.trim();\n if (!trimmed) return false;\n if (isShoppingConversation(trimmed) || isVisualIdentifyQuery(trimmed)) return false;\n return true;\n}\n\n/** Pull a retailer search query from the vision/agent reply. */\nexport function extractProductQueryFromAssistant(text: string): string | null {\n const prose = visibleAssistantContent(text)\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line && !/^[⚙🔧]/.test(line) && !/^used\\s+\\d+\\s+tools/i.test(line))\n .join(' ');\n if (!prose) return null;\n const patterns = [\n /\\b(?:same|it'?s|this is|these are|looks like)\\s+(?:a pair of\\s+)?([^.]{8,90}?)(?:\\.|,|photographed|—|–|\\s-\\s)/i,\n /\\bsearch(?:ing)? for\\s+(?:similar\\s+)?([^.]{8,90}?)(?:\\.|$)/i,\n ];\n for (const pattern of patterns) {\n const match = prose.match(pattern);\n const raw = (match?.[1] ?? '').replace(/\\s+/g, ' ').trim();\n if (raw.length >= 8) return raw.replace(/^(?:a|an|the)\\s+/i, '');\n }\n return null;\n}\n\n/** Web HostedShoppingChatPane: attachments and chit-chat/vision go on hostChat.send. */\nexport function shouldUseHostLane(text: string, fileCount: number): boolean {\n if (fileCount > 0) return true;\n const trimmed = text.trim();\n if (!trimmed) return false;\n return isVisualIdentifyQuery(trimmed) || isShoppingConversation(trimmed);\n}\n"],"names":["_a"],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {useState,useEffect}from'react';import {DEPARTMENT_SEARCH_PRESETS,searchShoppingProductsRest,mergeShoppingProductSources,searchShoppingProductsFast}from'../services/shoppingProductSearch.js';var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
const EMPTY = {
|
|
18
|
+
products: [],
|
|
19
|
+
isLoading: false,
|
|
20
|
+
isEnriching: false,
|
|
21
|
+
error: null
|
|
22
|
+
};
|
|
23
|
+
const cache = /* @__PURE__ */ new Map();
|
|
24
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
25
|
+
const RAIL_CONCURRENCY = 2;
|
|
26
|
+
let railsActive = 0;
|
|
27
|
+
const railQueue = [];
|
|
28
|
+
function acquireRailSlot() {
|
|
29
|
+
if (railsActive < RAIL_CONCURRENCY) {
|
|
30
|
+
railsActive += 1;
|
|
31
|
+
return Promise.resolve();
|
|
32
|
+
}
|
|
33
|
+
return new Promise((resolve) => railQueue.push(() => {
|
|
34
|
+
railsActive += 1;
|
|
35
|
+
resolve();
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
function releaseRailSlot() {
|
|
39
|
+
var _a;
|
|
40
|
+
railsActive -= 1;
|
|
41
|
+
(_a = railQueue.shift()) == null ? void 0 : _a();
|
|
42
|
+
}
|
|
43
|
+
function cacheKey(departmentId, deep) {
|
|
44
|
+
return `${departmentId}:${deep ? "deep" : "fast"}`;
|
|
45
|
+
}
|
|
46
|
+
const TRENDING_FAST_MS = 2e4;
|
|
47
|
+
function withTimeout(promise, ms, label) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const timer = setTimeout(() => reject(new Error(`${label} timed out`)), ms);
|
|
50
|
+
promise.then((value) => {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
resolve(value);
|
|
53
|
+
}, (err) => {
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
reject(err);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function fetchFast(departmentId, limit) {
|
|
60
|
+
const key = cacheKey(departmentId, false);
|
|
61
|
+
const cached = cache.get(key);
|
|
62
|
+
if (cached && cached.length > 0) return cached;
|
|
63
|
+
const pending = inFlight.get(key);
|
|
64
|
+
if (pending) return pending;
|
|
65
|
+
const preset = DEPARTMENT_SEARCH_PRESETS[departmentId];
|
|
66
|
+
const run = (async () => {
|
|
67
|
+
await acquireRailSlot();
|
|
68
|
+
try {
|
|
69
|
+
const result = await withTimeout(searchShoppingProductsFast(__spreadValues({
|
|
70
|
+
query: "",
|
|
71
|
+
departmentId,
|
|
72
|
+
maxResults: limit
|
|
73
|
+
}, preset ? {
|
|
74
|
+
category: preset.category
|
|
75
|
+
} : {})), TRENDING_FAST_MS, `Trending ${departmentId}`);
|
|
76
|
+
const rows = result.products.slice(0, limit);
|
|
77
|
+
if (rows.length > 0) cache.set(key, rows);
|
|
78
|
+
return rows;
|
|
79
|
+
} finally {
|
|
80
|
+
inFlight.delete(key);
|
|
81
|
+
releaseRailSlot();
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
84
|
+
inFlight.set(key, run);
|
|
85
|
+
return run;
|
|
86
|
+
}
|
|
87
|
+
function useTrendingProducts(departmentId, options = {}) {
|
|
88
|
+
var _a;
|
|
89
|
+
const enabled = options.enabled !== false;
|
|
90
|
+
const deep = Boolean(options.deep);
|
|
91
|
+
const limit = (_a = options.limit) != null ? _a : 12;
|
|
92
|
+
const [state, setState] = useState(EMPTY);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
var _a2;
|
|
95
|
+
if (!enabled || !departmentId || !DEPARTMENT_SEARCH_PRESETS[departmentId]) {
|
|
96
|
+
setState(EMPTY);
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
let cancelled = false;
|
|
100
|
+
const key = cacheKey(departmentId, deep);
|
|
101
|
+
const cached = (_a2 = cache.get(key)) != null ? _a2 : !deep ? cache.get(cacheKey(departmentId, false)) : void 0;
|
|
102
|
+
if (cached && cached.length > 0) {
|
|
103
|
+
setState({
|
|
104
|
+
products: cached,
|
|
105
|
+
isLoading: false,
|
|
106
|
+
isEnriching: deep,
|
|
107
|
+
error: null
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
setState({
|
|
111
|
+
products: [],
|
|
112
|
+
isLoading: true,
|
|
113
|
+
isEnriching: false,
|
|
114
|
+
error: null
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
void (async () => {
|
|
118
|
+
try {
|
|
119
|
+
const fast = await fetchFast(departmentId, limit);
|
|
120
|
+
if (cancelled) return;
|
|
121
|
+
setState({
|
|
122
|
+
products: fast,
|
|
123
|
+
isLoading: false,
|
|
124
|
+
isEnriching: deep,
|
|
125
|
+
error: null
|
|
126
|
+
});
|
|
127
|
+
if (!deep) return;
|
|
128
|
+
const preset = DEPARTMENT_SEARCH_PRESETS[departmentId];
|
|
129
|
+
const rest = await searchShoppingProductsRest(__spreadValues({
|
|
130
|
+
query: "",
|
|
131
|
+
departmentId,
|
|
132
|
+
maxResults: limit
|
|
133
|
+
}, preset ? {
|
|
134
|
+
category: preset.category
|
|
135
|
+
} : {})).catch(() => ({
|
|
136
|
+
products: []
|
|
137
|
+
}));
|
|
138
|
+
if (cancelled) return;
|
|
139
|
+
const merged = mergeShoppingProductSources([fast, rest.products]).slice(0, limit);
|
|
140
|
+
cache.set(key, merged);
|
|
141
|
+
setState({
|
|
142
|
+
products: merged,
|
|
143
|
+
isLoading: false,
|
|
144
|
+
isEnriching: false,
|
|
145
|
+
error: null
|
|
146
|
+
});
|
|
147
|
+
} catch (err) {
|
|
148
|
+
if (cancelled) return;
|
|
149
|
+
setState({
|
|
150
|
+
products: [],
|
|
151
|
+
isLoading: false,
|
|
152
|
+
isEnriching: false,
|
|
153
|
+
error: err instanceof Error ? err.message : "Trending search failed"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
return () => {
|
|
158
|
+
cancelled = true;
|
|
159
|
+
};
|
|
160
|
+
}, [departmentId, enabled, deep, limit]);
|
|
161
|
+
return state;
|
|
162
|
+
}export{useTrendingProducts};//# sourceMappingURL=useTrendingProducts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTrendingProducts.js","sources":["../../../../src/features/shopping/hooks/useTrendingProducts.ts"],"sourcesContent":["/**\n * Trending rails — native twin of surface `useTrendingProducts`.\n * Fast lane always; rest only when `deep`. No browser / subgraph on phone.\n */\nimport { useEffect, useState } from 'react';\nimport type { Product } from '../catalog';\nimport {\n DEPARTMENT_SEARCH_PRESETS,\n mergeShoppingProductSources,\n searchShoppingProductsFast,\n searchShoppingProductsRest,\n} from '../services/shoppingProductSearch';\n\nexport interface TrendingState {\n products: Product[];\n isLoading: boolean;\n isEnriching: boolean;\n error: string | null;\n}\n\nconst EMPTY: TrendingState = { products: [], isLoading: false, isEnriching: false, error: null };\n\nconst cache = new Map<string, Product[]>();\nconst inFlight = new Map<string, Promise<Product[]>>();\nconst RAIL_CONCURRENCY = 2;\nlet railsActive = 0;\nconst railQueue: Array<() => void> = [];\n\nfunction acquireRailSlot(): Promise<void> {\n if (railsActive < RAIL_CONCURRENCY) {\n railsActive += 1;\n return Promise.resolve();\n }\n return new Promise((resolve) =>\n railQueue.push(() => {\n railsActive += 1;\n resolve();\n }),\n );\n}\n\nfunction releaseRailSlot(): void {\n railsActive -= 1;\n railQueue.shift()?.();\n}\n\nfunction cacheKey(departmentId: string, deep: boolean): string {\n return `${departmentId}:${deep ? 'deep' : 'fast'}`;\n}\n\nconst TRENDING_FAST_MS = 20_000;\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`${label} timed out`)), ms);\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\nasync function fetchFast(departmentId: string, limit: number): Promise<Product[]> {\n const key = cacheKey(departmentId, false);\n const cached = cache.get(key);\n // Empty arrays are a miss — an early EMPTY-runtime race must not stick forever.\n if (cached && cached.length > 0) return cached;\n const pending = inFlight.get(key);\n if (pending) return pending;\n\n const preset = DEPARTMENT_SEARCH_PRESETS[departmentId];\n const run = (async () => {\n await acquireRailSlot();\n try {\n // Match web: department preset is the query (empty typed query + departmentId).\n const result = await withTimeout(\n searchShoppingProductsFast({\n query: '',\n departmentId,\n maxResults: limit,\n ...(preset ? { category: preset.category } : {}),\n }),\n TRENDING_FAST_MS,\n `Trending ${departmentId}`,\n );\n const rows = result.products.slice(0, limit);\n if (rows.length > 0) cache.set(key, rows);\n return rows;\n } finally {\n inFlight.delete(key);\n releaseRailSlot();\n }\n })();\n inFlight.set(key, run);\n return run;\n}\n\nexport function useTrendingProducts(\n departmentId: string | null,\n options: { enabled?: boolean; deep?: boolean; limit?: number } = {},\n): TrendingState {\n const enabled = options.enabled !== false;\n const deep = Boolean(options.deep);\n const limit = options.limit ?? 12;\n const [state, setState] = useState<TrendingState>(EMPTY);\n\n useEffect(() => {\n if (!enabled || !departmentId || !DEPARTMENT_SEARCH_PRESETS[departmentId]) {\n setState(EMPTY);\n return undefined;\n }\n\n let cancelled = false;\n const key = cacheKey(departmentId, deep);\n const cached = cache.get(key) ?? (!deep ? cache.get(cacheKey(departmentId, false)) : undefined);\n if (cached && cached.length > 0) {\n setState({ products: cached, isLoading: false, isEnriching: deep, error: null });\n } else {\n setState({ products: [], isLoading: true, isEnriching: false, error: null });\n }\n\n void (async () => {\n try {\n const fast = await fetchFast(departmentId, limit);\n if (cancelled) return;\n setState({ products: fast, isLoading: false, isEnriching: deep, error: null });\n if (!deep) return;\n\n const preset = DEPARTMENT_SEARCH_PRESETS[departmentId];\n const rest = await searchShoppingProductsRest({\n query: '',\n departmentId,\n maxResults: limit,\n ...(preset ? { category: preset.category } : {}),\n }).catch(() => ({ products: [] as Product[] }));\n if (cancelled) return;\n const merged = mergeShoppingProductSources([fast, rest.products]).slice(0, limit);\n cache.set(key, merged);\n setState({ products: merged, isLoading: false, isEnriching: false, error: null });\n } catch (err) {\n if (cancelled) return;\n setState({\n products: [],\n isLoading: false,\n isEnriching: false,\n error: err instanceof Error ? err.message : 'Trending search failed',\n });\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [departmentId, enabled, deep, limit]);\n\n return state;\n}\n"],"names":["_a"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {amazonImageUrlFromAsin}from'./catalog.js';const IMAGE_EXT = /\.(avif|gif|jpe?g|png|svg|webp)(\?.*)?$/i;
|
|
2
|
+
const IMAGE_CDN_HOST = /(?:images\.amazon|m\.media-amazon|images-na\.ssl-images-amazon|amazon-adsystem|i\.ebayimg|walmartimages\.com|target\.scene7|cdn\.shopify\.com|images\.costco|ssl\.gstatic\.com\/shopping)/i;
|
|
3
|
+
const BING_THUMB = /(?:tse\d\.)?mm\.bing\.net/i;
|
|
4
|
+
function looksLikeImageUrl(url) {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = new URL(url);
|
|
7
|
+
if (IMAGE_EXT.test(parsed.pathname)) return true;
|
|
8
|
+
if (IMAGE_CDN_HOST.test(parsed.hostname)) return true;
|
|
9
|
+
if (/\/image|\/img|format=pjpg/i.test(`${parsed.pathname}${parsed.search}`)) return true;
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return IMAGE_EXT.test(url);
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
function searchThumbnailUrl(name, source) {
|
|
16
|
+
const query = name.trim();
|
|
17
|
+
if (query.length < 2) return void 0;
|
|
18
|
+
const NON_RETAILER = ["yantra", "catalog", "google"];
|
|
19
|
+
const retailer = source && !NON_RETAILER.includes(source) ? source : "";
|
|
20
|
+
const q = retailer ? `${query} ${retailer}` : query;
|
|
21
|
+
return `https://tse1.mm.bing.net/th?q=${encodeURIComponent(q)}`;
|
|
22
|
+
}
|
|
23
|
+
function asinFromUrl(url) {
|
|
24
|
+
var _a;
|
|
25
|
+
return (_a = url == null ? void 0 : url.match(/\/(?:dp|gp\/product|gp\/aw\/d|product)\/([A-Z0-9]{10})(?:[/?#]|$)/i)) == null ? void 0 : _a[1];
|
|
26
|
+
}
|
|
27
|
+
function productImageCandidates(product) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const out = [];
|
|
30
|
+
const push = (url) => {
|
|
31
|
+
const trimmed = url == null ? void 0 : url.trim();
|
|
32
|
+
if (trimmed && !out.includes(trimmed)) out.push(trimmed);
|
|
33
|
+
};
|
|
34
|
+
const fromAsin = amazonImageUrlFromAsin(product.asin) || amazonImageUrlFromAsin(asinFromUrl(product.url));
|
|
35
|
+
const imageUrl = (_a = product.imageUrl) == null ? void 0 : _a.trim();
|
|
36
|
+
const imageIsBing = !!imageUrl && BING_THUMB.test(imageUrl);
|
|
37
|
+
if (imageUrl && looksLikeImageUrl(imageUrl) && !(fromAsin && imageIsBing)) push(imageUrl);
|
|
38
|
+
push(fromAsin);
|
|
39
|
+
if (product.url && looksLikeImageUrl(product.url)) push(product.url);
|
|
40
|
+
push(searchThumbnailUrl((_b = product.name) != null ? _b : "", product.source));
|
|
41
|
+
return out;
|
|
42
|
+
}export{looksLikeImageUrl,productImageCandidates,searchThumbnailUrl};//# sourceMappingURL=productImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"productImage.js","sources":["../../../src/features/shopping/productImage.ts"],"sourcesContent":["import { amazonImageUrlFromAsin, type Product, type ProductSource } from './catalog';\n\nconst IMAGE_EXT = /\\.(avif|gif|jpe?g|png|svg|webp)(\\?.*)?$/i;\nconst IMAGE_CDN_HOST =\n /(?:images\\.amazon|m\\.media-amazon|images-na\\.ssl-images-amazon|amazon-adsystem|i\\.ebayimg|walmartimages\\.com|target\\.scene7|cdn\\.shopify\\.com|images\\.costco|ssl\\.gstatic\\.com\\/shopping)/i;\nconst BING_THUMB = /(?:tse\\d\\.)?mm\\.bing\\.net/i;\n\nexport function looksLikeImageUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n if (IMAGE_EXT.test(parsed.pathname)) return true;\n if (IMAGE_CDN_HOST.test(parsed.hostname)) return true;\n if (/\\/image|\\/img|format=pjpg/i.test(`${parsed.pathname}${parsed.search}`)) return true;\n } catch {\n return IMAGE_EXT.test(url);\n }\n return false;\n}\n\nexport function searchThumbnailUrl(name: string, source?: string): string | undefined {\n const query = name.trim();\n if (query.length < 2) return undefined;\n const NON_RETAILER = ['yantra', 'catalog', 'google'];\n const retailer = source && !NON_RETAILER.includes(source) ? source : '';\n const q = retailer ? `${query} ${retailer}` : query;\n return `https://tse1.mm.bing.net/th?q=${encodeURIComponent(q)}`;\n}\n\nfunction asinFromUrl(url?: string): string | undefined {\n return url?.match(/\\/(?:dp|gp\\/product|gp\\/aw\\/d|product)\\/([A-Z0-9]{10})(?:[/?#]|$)/i)?.[1];\n}\n\n/**\n * Thumbnail candidates, best first. Bing name-search is last: it often returns\n * a wrong product (laptop on a headphones card). Prefer a retailer CDN / ASIN\n * image, and skip an existing Bing URL when we have an ASIN.\n */\nexport function productImageCandidates(\n product: Pick<Product, 'imageUrl' | 'url' | 'name' | 'asin' | 'source'>,\n): string[] {\n const out: string[] = [];\n const push = (url?: string) => {\n const trimmed = url?.trim();\n if (trimmed && !out.includes(trimmed)) out.push(trimmed);\n };\n\n const fromAsin = amazonImageUrlFromAsin(product.asin) || amazonImageUrlFromAsin(asinFromUrl(product.url));\n const imageUrl = product.imageUrl?.trim();\n const imageIsBing = !!imageUrl && BING_THUMB.test(imageUrl);\n\n if (imageUrl && looksLikeImageUrl(imageUrl) && !(fromAsin && imageIsBing)) push(imageUrl);\n push(fromAsin);\n if (product.url && looksLikeImageUrl(product.url)) push(product.url);\n push(searchThumbnailUrl(product.name ?? '', product.source as ProductSource | undefined));\n return out;\n}\n\nexport function resolveProductDisplayImage(\n product: Pick<Product, 'imageUrl' | 'url' | 'name' | 'asin' | 'source'>,\n): string | undefined {\n return productImageCandidates(product)[0];\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {useSyncExternalStore}from'react';var _a;
|
|
2
|
+
const STORAGE_KEY = "yantra.shopping.saved";
|
|
3
|
+
const MAX_ITEMS = 100;
|
|
4
|
+
let AsyncStorage = null;
|
|
5
|
+
try {
|
|
6
|
+
AsyncStorage = (_a = require("@react-native-async-storage/async-storage").default) != null ? _a : null;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
AsyncStorage = null;
|
|
9
|
+
}
|
|
10
|
+
let _items = [];
|
|
11
|
+
let _updatedAt = 0;
|
|
12
|
+
let _ids = /* @__PURE__ */ new Set();
|
|
13
|
+
const _listeners = /* @__PURE__ */ new Set();
|
|
14
|
+
function persist() {
|
|
15
|
+
try {
|
|
16
|
+
void (AsyncStorage == null ? void 0 : AsyncStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
17
|
+
items: _items,
|
|
18
|
+
updatedAt: _updatedAt
|
|
19
|
+
})));
|
|
20
|
+
} catch (e) {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function emit() {
|
|
24
|
+
_items = _items.slice(0, MAX_ITEMS);
|
|
25
|
+
_ids = new Set(_items.map((e) => e.product.id));
|
|
26
|
+
_updatedAt = Date.now();
|
|
27
|
+
persist();
|
|
28
|
+
_listeners.forEach((l) => l());
|
|
29
|
+
}
|
|
30
|
+
async function hydrateSaved() {
|
|
31
|
+
if (!AsyncStorage) return;
|
|
32
|
+
try {
|
|
33
|
+
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
|
34
|
+
if (!raw) return;
|
|
35
|
+
const parsed = JSON.parse(raw);
|
|
36
|
+
if (!Array.isArray(parsed.items)) return;
|
|
37
|
+
_items = parsed.items.filter((e) => {
|
|
38
|
+
var _a2;
|
|
39
|
+
return Boolean((_a2 = e == null ? void 0 : e.product) == null ? void 0 : _a2.id) && typeof e.ts === "number";
|
|
40
|
+
});
|
|
41
|
+
_updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : 0;
|
|
42
|
+
_ids = new Set(_items.map((e) => e.product.id));
|
|
43
|
+
_listeners.forEach((l) => l());
|
|
44
|
+
} catch (e) {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function subscribe(listener) {
|
|
48
|
+
_listeners.add(listener);
|
|
49
|
+
return () => _listeners.delete(listener);
|
|
50
|
+
}
|
|
51
|
+
function saveProduct(product) {
|
|
52
|
+
if (!(product == null ? void 0 : product.id)) return;
|
|
53
|
+
_items = [{
|
|
54
|
+
product,
|
|
55
|
+
ts: Date.now()
|
|
56
|
+
}, ..._items.filter((e) => e.product.id !== product.id)];
|
|
57
|
+
emit();
|
|
58
|
+
}
|
|
59
|
+
function unsaveProduct(productId) {
|
|
60
|
+
if (!_ids.has(productId)) return;
|
|
61
|
+
_items = _items.filter((e) => e.product.id !== productId);
|
|
62
|
+
emit();
|
|
63
|
+
}
|
|
64
|
+
function toggleSavedProduct(product) {
|
|
65
|
+
if (!(product == null ? void 0 : product.id)) return false;
|
|
66
|
+
if (_ids.has(product.id)) {
|
|
67
|
+
unsaveProduct(product.id);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
saveProduct(product);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function clearSavedProducts() {
|
|
74
|
+
if (_items.length === 0) return;
|
|
75
|
+
_items = [];
|
|
76
|
+
emit();
|
|
77
|
+
}
|
|
78
|
+
const EMPTY = [];
|
|
79
|
+
function useSavedProducts() {
|
|
80
|
+
return useSyncExternalStore(subscribe, () => _items, () => EMPTY);
|
|
81
|
+
}
|
|
82
|
+
function useIsProductSaved(productId) {
|
|
83
|
+
return useSyncExternalStore(subscribe, () => _ids.has(productId), () => false);
|
|
84
|
+
}export{clearSavedProducts,hydrateSaved,saveProduct,toggleSavedProduct,unsaveProduct,useIsProductSaved,useSavedProducts};//# sourceMappingURL=savedProducts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"savedProducts.js","sources":["../../../src/features/shopping/savedProducts.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react';\nimport type { Product } from './catalog';\n\nexport interface SavedProduct {\n product: Product;\n ts: number;\n}\n\nexport interface DurableSaved {\n items: SavedProduct[];\n updatedAt: number;\n}\n\nconst STORAGE_KEY = 'yantra.shopping.saved';\nconst MAX_ITEMS = 100;\n\ntype StorageLike = { getItem(key: string): Promise<string | null>; setItem(key: string, value: string): Promise<void> };\nlet AsyncStorage: StorageLike | null = null;\ntry {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, global-require\n AsyncStorage = require('@react-native-async-storage/async-storage').default ?? null;\n} catch {\n AsyncStorage = null;\n}\n\nlet _items: SavedProduct[] = [];\nlet _updatedAt = 0;\nlet _ids = new Set<string>();\nconst _listeners = new Set<() => void>();\n\nfunction persist(): void {\n try {\n void AsyncStorage?.setItem(STORAGE_KEY, JSON.stringify({ items: _items, updatedAt: _updatedAt }));\n } catch {\n /* best-effort */\n }\n}\n\nfunction emit(): void {\n _items = _items.slice(0, MAX_ITEMS);\n _ids = new Set(_items.map((e) => e.product.id));\n _updatedAt = Date.now();\n persist();\n _listeners.forEach((l) => l());\n}\n\nexport async function hydrateSaved(): Promise<void> {\n if (!AsyncStorage) return;\n try {\n const raw = await AsyncStorage.getItem(STORAGE_KEY);\n if (!raw) return;\n const parsed = JSON.parse(raw) as Partial<DurableSaved>;\n if (!Array.isArray(parsed.items)) return;\n _items = parsed.items.filter((e) => Boolean(e?.product?.id) && typeof e.ts === 'number');\n _updatedAt = typeof parsed.updatedAt === 'number' ? parsed.updatedAt : 0;\n _ids = new Set(_items.map((e) => e.product.id));\n _listeners.forEach((l) => l());\n } catch {\n /* memory-only */\n }\n}\n\nfunction subscribe(listener: () => void): () => void {\n _listeners.add(listener);\n return () => _listeners.delete(listener);\n}\n\nexport function saveProduct(product: Product): void {\n if (!product?.id) return;\n _items = [{ product, ts: Date.now() }, ..._items.filter((e) => e.product.id !== product.id)];\n emit();\n}\n\nexport function unsaveProduct(productId: string): void {\n if (!_ids.has(productId)) return;\n _items = _items.filter((e) => e.product.id !== productId);\n emit();\n}\n\nexport function toggleSavedProduct(product: Product): boolean {\n if (!product?.id) return false;\n if (_ids.has(product.id)) {\n unsaveProduct(product.id);\n return false;\n }\n saveProduct(product);\n return true;\n}\n\nexport function clearSavedProducts(): void {\n if (_items.length === 0) return;\n _items = [];\n emit();\n}\n\nconst EMPTY: SavedProduct[] = [];\n\nexport function useSavedProducts(): SavedProduct[] {\n return useSyncExternalStore(\n subscribe,\n () => _items,\n () => EMPTY,\n );\n}\n\nexport function useIsProductSaved(productId: string): boolean {\n return useSyncExternalStore(\n subscribe,\n () => _ids.has(productId),\n () => false,\n );\n}\n\nexport function __resetSaved(): void {\n _items = [];\n _ids = new Set();\n _updatedAt = 0;\n persist();\n _listeners.forEach((l) => l());\n}\n"],"names":["_a"],"mappings":"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"}
|