npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@microlink/function

v0.3.4

Published

Write JavaScript functions and run them remotely with Microlink — Puppeteer access, npm packages, and zero infrastructure.

Readme

Highlights

  • Starts from $0/mo.
  • Run JavaScript remotely with no servers, bundles, or browser fleet to manage.
  • Full Puppeteer access when your function references page.
  • require() any npm package — dependencies are detected and installed on-the-fly.
  • Automatic serialization and compression of function bodies.
  • Execution metrics at result.profiling.

Documentation

The full guides live on microlink.io:

Installation

npm install @microlink/function

Load directly in the browser from a CDN:

<script src="https://cdn.jsdelivr.net/npm/@microlink/function/dist/microlink-function.min.js"></script>

Your first function

Pass a JavaScript function and a target URL. The library handles serialization, compression, and the API call:

const microlink = require('@microlink/function')

const fn = microlink(() => 40 + 2)

const result = await fn('https://example.com')

console.log(result.isFulfilled) // true
console.log(result.value)       // 42
console.log(result.profiling)   // { phases: { ... }, cpu, memory, size }

When your function references page, Microlink starts a headless browser and gives you full Puppeteer access:

const microlink = require('@microlink/function')

const getTitle = ({ page }) => page.title()

const fn = microlink(getTitle)

const result = await fn('https://example.com')

console.log(result.value) // 'Example Domain'

When your function does not reference page, no browser is started — execution is faster and cheaper.

Writing functions

Return any value

Functions can return strings, numbers, booleans, arrays, or plain objects:

const microlink = require('@microlink/function')

const fn = microlink(() => ({
  greeting: 'Hello',
  items: [1, 2, 3],
  nested: { works: true }
}))

const result = await fn('https://example.com')

console.log(result.value)
// { greeting: 'Hello', items: [1, 2, 3], nested: { works: true } }

The return value is always at result.value. If the function throws, result.isFulfilled is false and result.value contains the error details.

Custom parameters

Any extra option you pass to the returned function is forwarded to your code:

const microlink = require('@microlink/function')

const greet = ({ name, greeting }) => `${greeting}, ${name}!`

const fn = microlink(greet)

const result = await fn('https://example.com', {
  name: 'Kiko',
  greeting: 'Hello'
})

console.log(result.value) // 'Hello, Kiko!'

npm packages

You can require() any npm package inside your function. Dependencies are detected automatically and installed on-the-fly:

const microlink = require('@microlink/function')

const fn = microlink(() => {
  const { kebabCase } = require('lodash')
  return kebabCase('Hello World')
})

const result = await fn('https://example.com')

console.log(result.value) // 'hello-world'

Pin a version by appending it to the package name:

const cheerio = require('[email protected]')

When no version is specified, the latest version is installed. Check result.profiling.phases — a high install value on the first run is normal and drops to zero once cached.

Security restrictions

The runtime restricts certain system capabilities. Operations such as spawning child processes or writing to the filesystem outside the sandbox are not permitted:

{
  "isFulfilled": false,
  "value": {
    "name": "Error",
    "code": "ERR_ACCESS_DENIED",
    "permission": "ChildProcess",
    "message": "Access to this API has been restricted."
  }
}

Browser interaction

When your function references page, you get the full Puppeteer Page object:

const microlink = require('@microlink/function')

const scrape = ({ page }) =>
  page.$eval('h1', el => el.textContent.trim())

const fn = microlink(scrape)

const result = await fn('https://example.com')

console.log(result.value) // 'Example Domain'

Start with the high-level helpers before reaching for lower-level APIs:

  • page.title() — document title.
  • page.$eval() — run a function on the first matching element.
  • page.$$eval() — run a function on all matching elements.
  • page.url() — current URL.
  • page.content() — full page HTML.

Any Puppeteer Page method is available.

What your function receives

| Property | Description | | --- | --- | | page | Full Puppeteer access. Microlink navigates to the URL before calling your function. | | response | The HTTP response from the implicit navigation. Only available when the function uses page. | | headers | Request headers used to fetch the target URL. | | any extra parameter | Custom inputs forwarded from the request options. |

Click, wait, and navigate

const microlink = require('@microlink/function')

const scrapeAfterClick = ({ page }) =>
  page.click('button.load-more')
    .then(() => page.waitForSelector('.results'))
    .then(() => page.$$eval('.results li', items =>
      items.map(el => el.textContent.trim())
    ))

const fn = microlink(scrapeAfterClick)

const result = await fn('https://example.com')

Replace fixed waits like page.waitForTimeout(3000) with page.waitForSelector() or page.waitForNavigation() whenever possible.

Combine with other parameters

Because function is just another Microlink parameter, you can prepare the page before your function runs using scripts, modules, click, or waitForSelector:

const microlink = require('@microlink/function')

const fn = microlink(
  ({ page }) => page.evaluate('jQuery.fn.jquery'),
  { meta: false }
)

const result = await fn('https://microlink.io', {
  scripts: ['https://code.jquery.com/jquery-3.5.0.min.js']
})

console.log(result.value) // jQuery version string

Profiling and performance

Every function response includes profiling data:

const result = await fn('https://example.com')

console.log(result.profiling)
// {
//   phases: { install: 0, build: 120, spawn: 45, run: 890, total: 1055 },
//   cpu: 234,
//   memory: { total: 69996544, used: 2359296, heap: 4410880, external: 1742574 },
//   size: 156
// }

| Field | Description | | --- | --- | | phases.install | Time spent installing npm dependencies (0 when none are used). | | phases.build | Time spent bundling the function code. | | phases.spawn | Time spent starting the isolated process. | | phases.run | Time spent executing the function. | | phases.total | Wall-clock time from start to finish. | | cpu | Peak CPU time in milliseconds. | | memory.total | Resident memory of the sandbox, Node.js baseline included, in bytes. | | memory.used | Resident memory attributable to your function, in bytes. | | memory.heap | V8 heap in use, in bytes. The only field the memory limit bounds. | | memory.external | Off-heap Buffer/ArrayBuffer memory, in bytes. | | size | Bundled code size in bytes. |

Plan limits

| | Free | Pro | | --- | --- | --- | | Timeout | 5 seconds | Up to 60 seconds | | Memory | 16 MB | 32 MB | | Code size | 1024 bytes | Unlimited | | Concurrency | 1 per IP | Unlimited |

The free plan is enough to prototype workflows. For production workloads that need more time, memory, or parameters such as headers, proxy, ttl, or staleTtl, use a pro plan.

Skip metadata

Most function-only workflows do not need normalized metadata. Set meta: false to skip it — this is usually the biggest speedup:

const fn = microlink(({ page }) => page.title(), { meta: false })

If you still need the rendered markup, call page.content() inside the function.

Compression

@microlink/function compresses function bodies automatically before sending them to the API. You can also compress manually via microlink.compress() — useful when calling MQL directly:

const compressed = await microlink.compress(({ page }) => page.title())
// 'br#...' on Node.js (brotli), 'lz#...' as fallback

Supported prefixes: lz# (lz-string), br# (brotli), gz# (gzip).

Optimization checklist

  1. Set meta: false unless you need normalized metadata.
  2. Use page.title() and page.$eval() instead of page.evaluate() when possible.
  3. Replace fixed waits with page.waitForSelector().
  4. Check result.profiling.phases to find the bottleneck.
  5. Minimize dependencies — each require() adds install and build time.

Troubleshooting

Error handling

When a function throws, the result comes back with isFulfilled: false and the error details at result.value:

const failing = ({ name }) => name()

const fn = microlink(failing)

const result = await fn('https://example.com', { name: 'Kiko' })

console.log(result.isFulfilled)    // false
console.log(result.value.name)     // 'TypeError'
console.log(result.value.message)  // 'name is not a function'

Non-Error throws (like throw 'oh no') are normalized into a NonError with the thrown value as the message.

Resource errors

When a function exceeds its plan limits, the API returns a descriptive error:

| Error | Trigger | | --- | --- | | TimeoutError | Wall-clock time exceeded the plan limit. | | CpuTimeError | CPU time exceeded the plan limit. | | MemoryError | Memory usage exceeded the plan limit. | | CodeSizeError | Code exceeds the 1024 bytes free plan limit. | | ConcurrencyError | Too many concurrent executions for the free plan (1 per IP). | | OutgoingRequestError | Cross-origin network request on the free plan. |

Function-specific errors

  • EINVALFUNCTION — invalid JavaScript syntax in the function string.
  • EINVALEVAL — the function executed but threw at runtime.

Debugging tips

  1. Start simple — reduce the function to ({ page }) => page.title() to isolate the problem.
  2. Set meta: false unless metadata is required.
  3. Inspect result.profiling to see where time is spent.
  4. Keep orchestration in the outer function and DOM-only code inside page.evaluate().
  5. Watch for null — DOM queries return null when the element does not exist.

See the troubleshooting guide for detailed remediation steps.

Choose the lightest tool

Use function when the built-in parameters stop being expressive enough, not as the default for every workflow.

| If you need | Best option | Why | | --- | --- | --- | | Simple field extraction from the DOM | data | Declarative rules are shorter and easier to maintain. | | Inject CSS or JavaScript before another workflow | styles, modules, or scripts | Lighter than full browser automation. | | Click, wait, compute, reshape, or orchestrate custom logic | function | Puppeteer access plus any npm package. |

Authentication

Pass your API key via the third argument (gotOpts):

const microlink = require('@microlink/function')

const fn = microlink(
  ({ page }) => page.title(),
  {},
  { headers: { 'x-api-key': process.env.MICROLINK_API_KEY } }
)

const result = await fn('https://example.com')

See authentication for endpoint and quota details.

Examples

See examples.

API

microlink(fn, [mqlOpts], [gotOpts])

Returns an async function (url, [mqlOpts], [gotOpts]) => Promise<FunctionResponse>.

fn

Required Type: function

The function to execute remotely.

mqlOpts

Type: object

Default options forwarded to @microlink/mql. Per-call options merge on top.

gotOpts

Type: object

HTTP client options forwarded to got inside MQL — use this for authentication headers and other request settings.

Response shape

type FunctionResponse =
  | {
      isFulfilled: true
      value: any
      profiling: FunctionProfiling
      logging: Record<string, unknown>
    }
  | {
      isFulfilled: false
      value: { name: string; message: string; [key: string]: unknown }
      profiling: FunctionProfiling
      logging: Record<string, unknown>
    }

Static properties

  • microlink.compress(code) — compress a function body for manual MQL usage.
  • microlink.mql — the underlying @microlink/mql client.
  • microlink.version — package version string.

License

@microlink/function © Microlink, released under the MIT License. Authored and maintained by Kiko Beats with help from contributors.

microlink.io · GitHub @MicrolinkHQ · X @microlinkhq