Skip to content

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

Package listing

@kentcdodds/notion

src/search.ts

49 lines · 1.6 KB · TypeScript
import { nextCursor, notionRequest, type JsonRecord } from './request.ts'
import { boundedPageSize, inputRecord, optionalString } from './validation.ts'

type SearchResponse = {
  results?: unknown[]
  has_more?: boolean
  next_cursor?: string | null
  [key: string]: unknown
}

/** Search pages and databases shared with the connected Notion integration. */
export default async function search(params: Record<string, unknown> = {}) {
  const input = inputRecord(params)

  const body: JsonRecord = {
    query: optionalString(input, 'query'),
    page_size: boundedPageSize(input.pageSize),
    start_cursor: optionalString(input, 'startCursor'),
  }

  const objectType = optionalString(input, 'objectType')
  if (objectType !== undefined) {
    if (objectType !== 'page' && objectType !== 'data_source') {
      throw new Error("objectType must be 'page' or 'data_source' (databases surface as data sources).")
    }
    body.filter = { property: 'object', value: objectType }
  }

  const sortDirection = optionalString(input, 'sortDirection')
  if (sortDirection !== undefined) {
    if (sortDirection !== 'ascending' && sortDirection !== 'descending') {
      throw new Error("sortDirection must be 'ascending' or 'descending'.")
    }
    body.sort = { direction: sortDirection, timestamp: 'last_edited_time' }
  }

  const result = await notionRequest<SearchResponse>('/search', {
    method: 'POST',
    body,
    account: optionalString(input, 'account'),
    integration: optionalString(input, 'integration'),
  })

  return {
    results: result.results ?? [],
    hasMore: result.has_more === true,
    nextCursor: nextCursor(result),
  }
}