fix(host): bound listDirectory levels at a configurable maxEntries
One list call now materializes at most maxEntries child rows (config, default 1000 - GitHub's web-UI directory-listing bound). Candidates sort before probing so a cut level keeps the name-sorted head and symlink probing stops with the bound, and DirectoryListing carries a required truncated flag on the seam and the wire so clients can state incompleteness instead of silently missing tail entries.
This commit is contained in:
@@ -880,6 +880,8 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
|
||||
crumbs: crumbsOf(target),
|
||||
entries: [...children].sort((a, b) => a.localeCompare(b))
|
||||
.map(name => ({ name, path: target === '/' ? `/${name}` : `${target}/${name}`, hidden: name.startsWith('.') })),
|
||||
// The fixture tree is tiny; no level ever reaches a backend bound.
|
||||
truncated: false,
|
||||
})
|
||||
},
|
||||
createDirectory: (request) => {
|
||||
|
||||
@@ -75,8 +75,9 @@ export class FakeApiClient implements IApiClient {
|
||||
home: string
|
||||
crumbs: { name: string; path: string; hidden: boolean }[]
|
||||
entries: { name: string; path: string; hidden: boolean }[]
|
||||
truncated: boolean
|
||||
}>> =
|
||||
() => Promise.resolve(ok({ path: '/home/fake', home: '/home/fake', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [] }))
|
||||
() => Promise.resolve(ok({ path: '/home/fake', home: '/home/fake', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [], truncated: false }))
|
||||
|
||||
onCreateDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string }>> =
|
||||
() => Promise.resolve(ok({ path: '/home/fake/new' }))
|
||||
|
||||
@@ -93,8 +93,9 @@ export class FakeApiClient implements IApiClient {
|
||||
home: string
|
||||
crumbs: { name: string; path: string; hidden: boolean }[]
|
||||
entries: { name: string; path: string; hidden: boolean }[]
|
||||
truncated: boolean
|
||||
}>> =
|
||||
() => Promise.resolve(ok({ path: '/home/fake', home: '/home/fake', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [] }))
|
||||
() => Promise.resolve(ok({ path: '/home/fake', home: '/home/fake', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [], truncated: false }))
|
||||
|
||||
onCreateDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string }>> =
|
||||
() => Promise.resolve(ok({ path: '/home/fake/new' }))
|
||||
|
||||
@@ -242,7 +242,7 @@ describe('WorkspacesService', () => {
|
||||
const ctx = new Context()
|
||||
const api = new FakeApiClient()
|
||||
const workspaces = new WorkspacesService(ctx, api, new SessionsService(ctx, api))
|
||||
const listing = { path: '/home/u', home: '/home/u', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [{ name: 'p', path: '/home/u/p', hidden: false }] }
|
||||
const listing = { path: '/home/u', home: '/home/u', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [{ name: 'p', path: '/home/u/p', hidden: false }], truncated: false }
|
||||
api.onListDirectory = () => Promise.resolve(ok(listing))
|
||||
await expect(workspaces.listDirectory()).resolves.toEqual(listing)
|
||||
await expect(workspaces.listDirectory('/home/u')).resolves.toEqual(listing)
|
||||
|
||||
Reference in New Issue
Block a user