Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,11 @@ const autocomplete = await microlink.search('how to fine tune', { type: 'autocom
console.log(autocomplete.results.map(r => r.value)) // → ['how to fine tune llm', ...]
```

`location` (ISO 3166-1 country code) localizes ranking and language; `period` (`hour`/`day`/`week`/`month`/`year`) constrains freshness; `limit` caps results per page:
`location` (ISO 3166-1 country code) localizes ranking and language; `period` (`hour`/`day`/`week`/`month`/`year`) constrains freshness; `limit` caps results per page; `page` selects which page to fetch (1 default):

```mjs
await microlink.search('recetas de pasta', { location: 'es', limit: 10 })
await microlink.search('node.js frameworks', { page: 2 })
```

Results compose in depth: every result with a `url` exposes lazy `.html()` and `.markdown()` for fetching the full page content only when needed — the source-expansion pattern for RAG:
Expand All @@ -243,7 +244,7 @@ const markdown = await page.markdown() // the SERP as Markdown
const html = await page.html() // the SERP as HTML
```

Pages chain with `.next()`:
Pages chain with `.next()`, or jump ahead with `{ page: 2 }`:

```mjs
let page = await microlink.search('node.js frameworks')
Expand Down
4 changes: 3 additions & 1 deletion packages/core/bin/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ const PRODUCTS = {
'news, images, videos, places, maps, shopping, scholar, patents, autocomplete'
],
['--limit', 'Maximum number of results'],
['--page', 'Results page (1 default)'],
['--html', 'Fetch HTML for the results page and each result'],
['--markdown', 'Fetch Markdown for the results page and each result'],
['--location', 'Country or locale (e.g. es)'],
Expand All @@ -261,7 +262,8 @@ const PRODUCTS = {
[
'search "the matrix" --markdown',
'include Markdown for the SERP and each result'
]
],
['search "the matrix" --page 2', 'second page of results']
]
},
function: {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/test/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ test('prints command help for product --help', async t => {
t.false(stdout.includes('Products'))
})

test('search help documents html, markdown, and limit flags', async t => {
test('search help documents html, markdown, limit, and page flags', async t => {
const { stdout } = await $('node', [bin, 'search', '--help'])
t.true(stdout.includes('search <query>'))
t.true(stdout.includes('--html'))
t.true(stdout.includes('--markdown'))
t.true(stdout.includes('--limit'))
t.true(stdout.includes('--page'))
})

test('prints command help for --help before the product', async t => {
Expand Down
1 change: 1 addition & 0 deletions packages/mcp/src/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ export const searchInputSchema = z
])
.optional(),
limit: z.coerce.number().int().positive().optional(),
page: z.coerce.number().int().positive().optional(),
location: z.string().min(1).optional(),
period: z.enum(['hour', 'day', 'week', 'month', 'year']).optional()
})
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp/src/tools/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function search (server) {
[
'Search Google and get structured results via Microlink (requires an API key).',
'Returns `results` (title, url, description) plus `knowledgeGraph`, `peopleAlsoAsk`, and `relatedSearches` when available.',
'Use `type` for a vertical ("search" default, "news", "images", "videos", "places", "maps", "shopping", "scholar", "patents", "autocomplete"), and `limit` / `location` / `period` to refine.',
'Use `type` for a vertical ("search" default, "news", "images", "videos", "places", "maps", "shopping", "scholar", "patents", "autocomplete"), and `limit` / `page` / `location` / `period` to refine.',
'Google search operators (`site:`, `filetype:`, quotes, ...) work as-is. Mirrors the `microlink.search(query)` library method.'
].join(' '),
searchInputSchema,
Expand Down
8 changes: 7 additions & 1 deletion packages/search/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,13 @@ for (const result of results) {

### Pagination

Pages chain naturally:
Jump to a page with `page` (1 default), matching the API query param:

```js
const page2 = await google('node.js frameworks', { page: 2 })
```

Pages also chain with `.next()`:

```js
const page1 = await google('node.js frameworks')
Expand Down
1 change: 1 addition & 0 deletions packages/search/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export declare function buildUrl(
location?: string
type?: Type
period?: Period
page?: number
}
): URL

Expand Down
5 changes: 3 additions & 2 deletions packages/search/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ const buildPath = (query, limit, location) =>
.filter(v => v !== undefined)
.join('/')

const buildUrl = (query, { limit, location, type, period } = {}) => {
const buildUrl = (query, { limit, location, type, period, page } = {}) => {
const url = new URL(`https://${DOMAIN}/${buildPath(query, limit, location)}`)
if (type) url.searchParams.set('type', type)
if (period) url.searchParams.set('period', period)
if (page > 1) url.searchParams.set('page', String(page))
return url
}

Expand Down Expand Up @@ -71,7 +72,7 @@ const createGoogleClient = ctxOpts => {
query,
{ limit, location, type, period, html, markdown, page = 1, ...opts } = {}
) => {
const url = buildUrl(query, { limit, location, type, period })
const url = buildUrl(query, { limit, location, type, period, page })
const result = await fetchPage(url, { ...ctxOpts, ...opts }, page, query)
if (html) {
await resolve(result, 'html')
Expand Down
14 changes: 13 additions & 1 deletion packages/search/test/build-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,26 @@ test('omits falsy params', t => {
t.is(url.searchParams.get('period'), null)
})

test('sets page param when greater than 1', t => {
const url = buildUrl('q', { page: 2 })
t.is(url.searchParams.get('page'), '2')
})

test('omits page on the first page', t => {
t.is(buildUrl('q').searchParams.get('page'), null)
t.is(buildUrl('q', { page: 1 }).searchParams.get('page'), null)
})

test('combines all options', t => {
const url = buildUrl('q', {
limit: 5,
location: 'fr',
type: 'images',
period: 'last_month'
period: 'last_month',
page: 3
})
t.is(url.pathname, '/q/5/fr')
t.is(url.searchParams.get('type'), 'images')
t.is(url.searchParams.get('period'), 'last_month')
t.is(url.searchParams.get('page'), '3')
})