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
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Every [microlink.io](https://microlink.io) product maps to a client method:
| Lighthouse | `lighthouse(url)` |
| Technologies | `technologies(url)` |
| Search | `search(query)` |
| Function | `run(url, code)` (alias `function`) |
| Function | `function(url, code)` |

Plus library extras: `links` / `images` / `videos` / `audios` / `emails` collections and `extract` for custom data rules.

Expand Down Expand Up @@ -254,19 +254,19 @@ while (page) {
}
```

### run(url, code, options)
### function(url, code, options)

Run any JavaScript remotely in a sandboxed runtime — no Lambda bundle, no browser fleet, no server ([guide](https://microlink.io/docs/guides/function)). Also exposed as `function`, matching the API parameter name. You write a plain function; the library handles serialization, compression and the API call for you. When the code doesn't reference `page`, no browser is started, making execution faster and cheaper:
Run any JavaScript remotely in a sandboxed runtime — no Lambda bundle, no browser fleet, no server ([guide](https://microlink.io/docs/guides/function)). You write a plain function; the library handles serialization, compression and the API call for you. When the code doesn't reference `page`, no browser is started, making execution faster and cheaper:

```mjs
const { value } = await microlink.run('https://example.com', () => 40 + 2)
const { value } = await microlink.function('https://example.com', () => 40 + 2)
console.log(value) // → 42
```

When it references `page`, Microlink starts a headless browser and navigates to the URL first, handing your code the full [puppeteer `page`](https://pptr.dev/api/puppeteer.page) for clicks, waits, evaluation and navigation ([browser interaction](https://microlink.io/docs/guides/function/browser-interaction)):

```mjs
const { value } = await microlink.run('https://example.com', async ({ page }) => {
const { value } = await microlink.function('https://example.com', async ({ page }) => {
await page.waitForSelector('h1')
return page.$eval('h1', el => el.textContent)
})
Expand All @@ -276,7 +276,7 @@ console.log(value) // → 'Example Domain'
Any extra option you pass is forwarded into the function scope — the simplest way to make one function reusable across requests ([custom parameters](https://microlink.io/docs/guides/function/writing-functions)):

```mjs
const { value } = await microlink.run(
const { value } = await microlink.function(
'https://example.com',
({ page, selector }) => page.$eval(selector, el => el.textContent),
{ selector: 'h1' }
Expand All @@ -287,7 +287,7 @@ console.log(value)
You can `require()` any npm package inside the function — dependencies are detected, installed on the fly into the sandbox, and cached for subsequent runs. Pin a version with `require('cheerio@1.0.0')`:

```mjs
const { value } = await microlink.run('https://news.ycombinator.com', async ({ page }) => {
const { value } = await microlink.function('https://news.ycombinator.com', async ({ page }) => {
const cheerio = require('cheerio')
const $ = cheerio.load(await page.content())
return $('.titleline > a').map((i, el) => $(el).text()).toArray()
Expand All @@ -298,7 +298,7 @@ console.log(value) // → ['Top HN story', ...]
The result carries more than the return value — `console.log` calls are captured in `logging`, and `profiling` reports peak cpu/memory plus per-phase timings (`install`/`build`/`spawn`/`run`) so you can spot the bottleneck ([profiling](https://microlink.io/docs/guides/function/profiling-and-performance)):

```mjs
const { isFulfilled, value, logging, profiling } = await microlink.run('https://example.com', ({ page }) => {
const { isFulfilled, value, logging, profiling } = await microlink.function('https://example.com', ({ page }) => {
console.log('visiting page')
return page.title()
})
Expand Down Expand Up @@ -359,7 +359,7 @@ npx microlink.io function https://example.com --file ./fn.js

- [@microlink/mql](https://github.com/microlinkhq/mql) — the low-level Microlink Query Language client (raw envelopes, `buffer`/`stream` access).
- [@microlink/google](https://github.com/microlinkhq/google) — structured Google data, powering `search`.
- [@microlink/function](https://github.com/microlinkhq/function) — remote JavaScript functions, powering `function`/`run` ([guides](https://microlink.io/docs/guides/function)).
- [@microlink/function](https://github.com/microlinkhq/function) — remote JavaScript functions, powering `function` ([guides](https://microlink.io/docs/guides/function)).

## License

Expand Down
7 changes: 2 additions & 5 deletions packages/core/bin/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ const COLLECTION = [
['--type', 'Cast each value (url, image, email, ...)']
]

const ALIAS = { run: 'function' }

const COMMANDS = {
help: {
usage: 'help [command]',
Expand Down Expand Up @@ -371,7 +369,6 @@ const render = (name, product) => {
}

module.exports = command => {
const name = ALIAS[command] ?? command
if (COMMANDS[name]) return render(name, COMMANDS[name])
return PRODUCTS[name] ? render(name, PRODUCTS[name]) : global
if (COMMANDS[command]) return render(command, COMMANDS[command])
return PRODUCTS[command] ? render(command, PRODUCTS[command]) : global
}
9 changes: 3 additions & 6 deletions packages/core/bin/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,7 @@ const run = async (argvInput, host) => {
if (help || !target) return showHelp(command)
if (command !== 'search') target = asUrl(target) ?? target

if (
isTrace &&
(command === 'search' || command === 'function' || command === 'run')
) {
if (isTrace && (command === 'search' || command === 'function')) {
writeLine(stderr, `\`--trace\` is not supported for \`${command}\`.`)
return finish(1)
}
Expand All @@ -110,7 +107,7 @@ const run = async (argvInput, host) => {
}
}

if ((command === 'function' || command === 'run') && !file) {
if (command === 'function' && !file) {
printFail({ message: 'Missing `--file` with the function source code' })
return finish(1)
}
Expand All @@ -119,7 +116,7 @@ const run = async (argvInput, host) => {
if (command === 'extract') {
return client.extract(target, rules, options)
}
if (command === 'function' || command === 'run') {
if (command === 'function') {
const code = host.readFile(file)
return client.function(target, code, options)
}
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ interface MicrolinkClient {
code: FunctionInput,
options?: Options
): Promise<FunctionResult<T>>
run: MicrolinkClient['function']
}

interface create {
Expand Down
11 changes: 4 additions & 7 deletions packages/core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,6 @@ const create = (ctx = {}) => {
)
}

const run = (url, code, options) => {
const { top, got } = route(options)
return fn(code, top, got)(url)
}

const client = {
metadata: (url, options) => {
const { top, got } = route(options)
Expand Down Expand Up @@ -197,8 +192,10 @@ const create = (ctx = {}) => {
const { top } = route(options)
return googleClient(query, top)
},
function: run,
run
function: (url, code, options) => {
const { top, got } = route(options)
return fn(code, top, got)(url)
}
}

Object.defineProperty(client, 'last', { value: last })
Expand Down
1 change: 0 additions & 1 deletion packages/core/test/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const PRODUCTS = [
'markdown',
'metadata',
'pdf',
'run',
'screenshot',
'search',
'technologies',
Expand Down
1 change: 0 additions & 1 deletion packages/core/test/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ async function assertions (): Promise<void> {

const fnResult = await client.function('https://example.com', '() => 1')
expectType<boolean>(fnResult.isFulfilled)
expectType<typeof client.function>(client.run)
}

void assertions()
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/integration.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ test.skip('video detects the primary video', async t => {
})

test('function runs code remotely with injected scope variables', async t => {
const { isFulfilled, value } = await microlink.run(
const { isFulfilled, value } = await microlink.function(
targetUrl,
({ greeting }) => greeting,
{ greeting: 'hello' }
Expand Down
5 changes: 2 additions & 3 deletions packages/core/test/unit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,11 @@ test('per-call options override the factory context', async t => {
t.is(calls[0].mqlOpts.apiKey, 'override')
})

test('function/run are the same method', async t => {
test('function runs remote code with routed options', async t => {
const { create, fnCalls } = setup()
const client = create({ apiKey: 'secret' })
t.is(client.function, client.run)
const code = '({ page }) => page.title()'
const result = await client.run(URL, code, {
const result = await client.function(URL, code, {
headers: { 'x-foo': 'bar' }
})
t.deepEqual(result, { isFulfilled: true, value: URL })
Expand Down