11import { db } from '@sim/db'
2- import {
3- document ,
4- knowledgeBase ,
5- knowledgeConnector ,
6- member ,
7- organization ,
8- organizationSearchHistory ,
9- organizationSearchIntegration ,
10- user ,
11- } from '@sim/db/schema'
2+ import { member , organization , organizationSearchHistory , user } from '@sim/db/schema'
123import { generateId } from '@sim/utils/id'
134import { and , eq , inArray } from 'drizzle-orm'
145import { afterAll , beforeAll , beforeEach , describe , expect , it , vi } from 'vitest'
@@ -21,16 +12,10 @@ import { SEARCH_HISTORY_LIMIT } from '@/lib/knowledge/search/history/limits'
2112
2213vi . mock ( '@/lib/knowledge/access/availability' , ( ) => ( {
2314 requireOrganizationSearchAvailable : vi . fn ( ) ,
24- resolveKnowledgeAccessAvailability : vi . fn ( async ( ) => ( {
25- sourceMirrored : true ,
26- memberScoped : true ,
27- } ) ) ,
2815} ) )
2916
3017const userIds = [ generateId ( ) , generateId ( ) ]
3118const orgIds = [ generateId ( ) , generateId ( ) ]
32- const indexId = generateId ( )
33- const connectorId = generateId ( )
3419const principal = { kind : 'session' , userId : userIds [ 0 ] , sessionId : 'history-test' } as const
3520const input = { organizationId : orgIds [ 0 ] }
3621const scope = and (
@@ -56,20 +41,6 @@ beforeAll(async () => {
5641 await db
5742 . insert ( organization )
5843 . values ( orgIds . map ( ( id ) => ( { id, name : 'History fixture' , slug : id } ) ) )
59- await db . insert ( knowledgeBase ) . values ( {
60- id : indexId ,
61- organizationId : orgIds [ 0 ] ,
62- userId : userIds [ 0 ] ,
63- name : 'Search' ,
64- isSearchIndex : true ,
65- } )
66- await db . insert ( knowledgeConnector ) . values ( {
67- id : connectorId ,
68- knowledgeBaseId : indexId ,
69- connectorType : 'google_drive' ,
70- sourceConfig : { } ,
71- accessMode : 'admin' ,
72- } )
7344 await db . insert ( member ) . values (
7445 userIds . map ( ( userId ) => ( {
7546 id : generateId ( ) ,
@@ -80,33 +51,6 @@ beforeAll(async () => {
8051 )
8152} )
8253beforeEach ( async ( ) => {
83- await db
84- . delete ( organizationSearchIntegration )
85- . where ( eq ( organizationSearchIntegration . organizationId , orgIds [ 0 ] ) )
86- await db
87- . update ( knowledgeConnector )
88- . set ( { archivedAt : null } )
89- . where ( eq ( knowledgeConnector . id , connectorId ) )
90- await db . delete ( document ) . where ( eq ( document . knowledgeBaseId , indexId ) )
91- await db . insert ( document ) . values (
92- [
93- source . url ,
94- 'https://example.com/other' ,
95- ...Array . from ( { length : 24 } , ( _ , i ) => `https://example.com/${ i } ` ) ,
96- ] . map ( ( url ) => ( {
97- id : generateId ( ) ,
98- knowledgeBaseId : indexId ,
99- filename : url === 'https://example.com/23' ? 'Updated title' : source . title ,
100- fileUrl : url ,
101- sourceUrl : url ,
102- fileSize : 1 ,
103- mimeType : 'text/plain' ,
104- acl : [ 'pub' ] ,
105- connectorId,
106- aclVerifiedAt : new Date ( ) ,
107- processingStatus : 'completed' ,
108- } ) )
109- )
11054 await db
11155 . delete ( organizationSearchHistory )
11256 . where ( inArray ( organizationSearchHistory . organizationId , orgIds ) )
@@ -173,49 +117,20 @@ describe('private search navigation history', () => {
173117 expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toHaveLength ( 1 )
174118 } )
175119
176- it ( 'revalidates current document access and metadata instead of replaying saved titles' , async ( ) => {
177- await recordSearchHistory . execute ( {
178- principal,
179- input : { ...input , event : { kind : 'source' , source } } ,
180- } )
181- await db
182- . update ( document )
183- . set ( { filename : 'Current title' } )
184- . where ( eq ( document . sourceUrl , source . url ) )
185- expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources [ 0 ] ?. title ) . toBe (
186- 'Current title'
120+ it ( 'retains live and internal navigation without an organization search index' , async ( ) => {
121+ const visits = [
122+ { ...source , siteName : 'Google Docs' , connectorType : 'google_drive' } ,
123+ { url : 'https://sim.example.com/o/fixture/knowledge/base/document' , title : 'Upload' } ,
124+ ]
125+ for ( const visit of visits ) {
126+ await recordSearchHistory . execute ( {
127+ principal,
128+ input : { ...input , event : { kind : 'source' , source : visit } } ,
129+ } )
130+ }
131+ expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toMatchObject (
132+ [ ...visits ] . reverse ( )
187133 )
188- await db
189- . update ( document )
190- . set ( { acl : [ 'u:another@fixture.test' ] } )
191- . where ( eq ( document . sourceUrl , source . url ) )
192- expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toEqual ( [ ] )
193- await db
194- . update ( document )
195- . set ( { acl : [ 'pub' ] , userExcluded : true } )
196- . where ( eq ( document . sourceUrl , source . url ) )
197- expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toEqual ( [ ] )
198- await db . update ( document ) . set ( { userExcluded : false } ) . where ( eq ( document . sourceUrl , source . url ) )
199- await db
200- . insert ( organizationSearchIntegration )
201- . values ( { organizationId : orgIds [ 0 ] , connectorType : 'google_drive' , approved : false } )
202- expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toEqual ( [ ] )
203- await db
204- . delete ( organizationSearchIntegration )
205- . where ( eq ( organizationSearchIntegration . organizationId , orgIds [ 0 ] ) )
206- await db
207- . update ( knowledgeConnector )
208- . set ( { archivedAt : new Date ( ) } )
209- . where ( eq ( knowledgeConnector . id , connectorId ) )
210- expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toEqual ( [ ] )
211- await recordSearchHistory . execute ( {
212- principal,
213- input : {
214- ...input ,
215- event : { kind : 'source' , source : { ...source , url : 'https://example.com/unverifiable' } } ,
216- } ,
217- } )
218- expect ( ( await listSearchHistory . execute ( { principal, input } ) ) . sources ) . toEqual ( [ ] )
219134 } )
220135
221136 it ( 'deduplicates and bounds concurrent visits without losing unrelated queries' , async ( ) => {
@@ -245,7 +160,7 @@ describe('private search navigation history', () => {
245160 ...input ,
246161 event : {
247162 kind : 'source' ,
248- source : { ...source , url : 'https://example.com/23' } ,
163+ source : { ...source , url : 'https://example.com/23' , title : 'Updated title' } ,
249164 } ,
250165 } ,
251166 } )
0 commit comments