Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kentcdodds/dropbox

src/search.ts

64 lines · 1.7 KB · TypeScript
import { dropboxRpc } from './request.ts'
import type { JsonRecord } from './types.ts'
import {
	optionalBoolean,
	optionalNumber,
	optionalString,
	requireDropboxPath,
	requireRecord,
	requireString,
} from './types.ts'

export type SearchDropboxInput = {
	query?: string
	cursor?: string
	path?: string
	maxResults?: number
	filenameOnly?: boolean
}

export type SearchDropboxResult = {
	matches: JsonRecord[]
	has_more: boolean
	cursor?: string
}

export async function searchDropbox(
	input: SearchDropboxInput,
): Promise<SearchDropboxResult> {
	const cursor = optionalString(input.cursor, 'cursor')
	if (cursor) {
		return dropboxRpc<SearchDropboxResult>('files/search/continue_v2', { cursor })
	}

	const query = requireString(input.query, 'query')
	const path = requireDropboxPath(input.path ?? '', 'path', { allowRoot: true })
	const maxResults = optionalNumber(input.maxResults, 'maxResults')
	if (
		maxResults !== undefined &&
		(!Number.isInteger(maxResults) || maxResults < 1 || maxResults > 1000)
	) {
		throw new Error('maxResults must be an integer from 1 through 1000.')
	}

	return dropboxRpc<SearchDropboxResult>('files/search_v2', {
		query,
		options: {
			path,
			filename_only: optionalBoolean(input.filenameOnly, 'filenameOnly') ?? false,
			...(maxResults === undefined ? {} : { max_results: maxResults }),
		},
	})
}

/**
 * Search Dropbox file and folder names, or continue with a previous cursor.
 * @example
 * import search from 'kody:@kentcdodds/dropbox/search'
 * const results = await search({ query: 'invoice', path: '/documents' })
 */
export default async function searchDropboxEntrypoint(
	params: Partial<SearchDropboxInput> & Record<string, unknown> = {},
) {
	return searchDropbox(requireRecord(params, 'search') as SearchDropboxInput)
}