/** Sources are supplied by the host; the SDK never infers a host filesystem path. */ export type PickerSource = 'server' | 'localFile'; export type PickerSelectionMode = 'single-file' | 'multi-file' | 'folder' | 'folder+files'; /** `list` shows one folder at a time (the default); `tree` adds disclosure triangles. */ export type PickerView = 'list' | 'tree'; /** Row order inside each folder; folders always come before files. */ export type PickerSort = 'newest' | 'oldest' | 'name' | 'name-desc'; interface PickerNodeBase { path: string; name: string; parentPath?: string | null; parentName?: string; bytes?: number | null; /** ISO timestamp of the last change, shown in the list and the preview. */ modifiedAt?: string | null; /** An explicit adapter failure makes a row inert, including its disclosure. */ unavailableReason?: string; } export interface PickerFolder extends PickerNodeBase { kind: 'folder'; fileCount?: number | null; formats?: Record; hasChildren?: boolean; } export interface PickerFile extends PickerNodeBase { kind: 'file'; format: string; /** Present only for browser-selected files. The picker does not read its bytes. */ file?: File; } export type PickerNode = PickerFolder | PickerFile; export interface PickerRequest { signal?: AbortSignal; source?: PickerSource; /** * Set only when the user pressed Refresh. Adapters that cache listings (or * ask a server to bypass its own cache) should re-read the location then and * serve cached data otherwise; the picker keeps folder contents while it is * open and re-reads the current location on each open. */ refresh?: true; } /** What a search found before a server or walk limit stopped it. */ export interface PickerSearchResult { nodes: PickerNode[]; truncated: boolean; } export interface PickerAdapter { /** * `listRoot()` returns mount points. FilePicker then shows them as header * sources and opens the first reachable one instead of listing the root. */ mounts?: boolean; /** The path of the mount holding `path`, so an initial folder inside a mount can name it. */ mountOf?(path: string): string | undefined; /** Discard cached and pending results on close, source changes, or refresh. */ invalidate?(): void; listRoot(request?: PickerRequest): Promise; listChildren(path: string, request?: PickerRequest): Promise; search(query: string, scope: { path: string; recursive: boolean; }, request?: PickerRequest): Promise; } export interface PickerCapability { /** Case-insensitive suffixes, including compound extensions such as mzML.gz. */ formats: string[]; maxBytes?: number; /** Optional host-owned blank classification; no filename heuristics in the SDK. */ isBlank?: (node: PickerNode) => boolean; } export type PickerCapabilities = Partial>; export type PickerExclusionReason = 'deselected' | 'unsupported' | 'tooLarge' | 'blank' | 'unreadable' | 'forbidden'; export interface PickerExcluded { /** Opaque identity prevents collisions between equal filenames in different folders. */ path: string; name: string; reason: PickerExclusionReason; } export type PickerSelection = { source: 'server'; folders: string[]; files: PickerFile[]; excluded: PickerExcluded[]; } | { source: 'localFile'; files: File[]; relativePaths?: string[]; }; export interface PickerTreeRow { node: PickerNode; depth: number; expanded: boolean; loading: boolean; error?: string; } export {};