├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── examples ├── page.js ├── query.js ├── require.js └── response.js ├── index.html ├── lightweight ├── index.d.ts └── package.json ├── package.json ├── rollup.config.js ├── src ├── lightweight.mjs └── node.js └── test ├── build.mjs ├── clients.mjs ├── index.mjs └── lightweight.test-d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | max_line_length = 80 13 | indent_brace_style = 1TBS 14 | spaces_around_operators = true 15 | quote_type = auto 16 | 17 | [package.json] 18 | indent_style = space 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: '/' 5 | schedule: 6 | interval: daily 7 | - package-ecosystem: 'github-actions' 8 | directory: '/' 9 | schedule: 10 | # Check for updates to GitHub Actions every weekday 11 | interval: 'daily' 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | - name: Setup Node.js 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: lts/* 21 | - name: Setup PNPM 22 | uses: pnpm/action-setup@v4 23 | with: 24 | version: latest 25 | run_install: true 26 | - name: Test 27 | run: npm test 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############################ 2 | # npm 3 | ############################ 4 | node_modules 5 | npm-debug.log 6 | .node_history 7 | yarn.lock 8 | package-lock.json 9 | 10 | ############################ 11 | # tmp, editor & OS files 12 | ############################ 13 | .tmp 14 | *.swo 15 | *.swp 16 | *.swn 17 | *.swm 18 | .DS_Store 19 | *# 20 | *~ 21 | .idea 22 | *sublime* 23 | nbproject 24 | 25 | ############################ 26 | # Tests 27 | ############################ 28 | testApp 29 | coverage 30 | .nyc_output 31 | 32 | ############################ 33 | # Other 34 | ############################ 35 | .env 36 | .envrc 37 | stats.html 38 | src/node.mjs 39 | lightweight/index.js 40 | lightweight/index-bundled.d.ts 41 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | unsafe-perm=true 2 | save-prefix=~ 3 | shrinkwrap=false 4 | save=false 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.2.2](https://github.com/microlinkhq/function/compare/v0.2.1...v0.2.2) (2023-11-05) 6 | 7 | ### [0.2.1](https://github.com/microlinkhq/function/compare/v0.2.0...v0.2.1) (2023-11-05) 8 | 9 | ## [0.2.0](https://github.com/microlinkhq/function/compare/v0.1.7...v0.2.0) (2023-11-05) 10 | 11 | 12 | ### Features 13 | 14 | * add ESM bundle ([77eccc3](https://github.com/microlinkhq/function/commit/77eccc309ad88dc1853cb6e09931a8455a38ccb8)) 15 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2021 Microlink (microlink.io) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | microlink logo 3 | microlink logo 4 |
5 |
6 |
7 |

Microlink Function allows you to run JavaScript Serverless functions with Headless Chromium programmatic access.

8 |
9 | 10 |
11 | 12 |
13 | 14 | ## Highlights 15 | 16 | - Starts from \$0/mo. 17 | - Run Serverless Javascript functions (also [locally](https://github.com/microlinkhq/local)). 18 | - Ability to require to require any of the [allowed](#npm-packages) NPM packages. 19 | - Headless Chromium browser access in the same request cycle. 20 | - No servers to maintain, no hidden cost or infrastructure complexity. 21 | 22 | ## Contents 23 | 24 | - [How it works](#how-it-works) 25 | - [Installation](#installation) 26 | - [from NPM](#from-npm) 27 | - [from CDN](#from-cdn) 28 | - [Get Started](#get-started) 29 | - [Input](#input) 30 | - [NPM packages](#npm-packages) 31 | - [Output](#output) 32 | - [Examples](#examples) 33 | - [Pricing](#pricing) 34 | - [API](#api) 35 | - [License](#license) 36 | 37 | ## How it works 38 | 39 | Every time you call a **Microlink Function**, the code function will be compiled and executed remotely in a safe V8 sandbox. 40 | 41 | It's pretty similar to AWS Lambda, but rather than bundle your code, all the code will be executed remotely, giving the result of the execution back to you. 42 | 43 | **Microlink Function** can be invoked in frontend or backend side. There is nothing to deploy or hidden infrastructure cost associated. 44 | 45 | ## Installation 46 | 47 | ### from NPM 48 | 49 | It's available as [npm package](https://www.npmjs.com/package/@microlink/function): 50 | 51 | ```bash 52 | $ npm install @microlink/function --save 53 | ``` 54 | 55 | ### from CDN 56 | 57 | Load directly in the browser from your favorite CDN: 58 | 59 | ```html 60 | 61 | ``` 62 | 63 | ## Get Started 64 | 65 | ### Input 66 | 67 | Let say you have a JavaScript like this: 68 | 69 | ```js 70 | const ping = ({ statusCode, response }) => 71 | statusCode ? response.status() : response.statusText() 72 | ``` 73 | 74 | To run the previous code as **Microlink Function**, all you need to do is wrap the function with the `microlink` decorator: 75 | 76 | ```js 77 | const microlink = require('@microlink/function') 78 | 79 | const ping = microlink(({ response }) => 80 | statusCode ? response.status() : response.statusText() 81 | ) 82 | ``` 83 | 84 | Then, just call the function as you would normally: 85 | 86 | ```js 87 | const result = await ping('https://example.com', { statusCode: true }) 88 | 89 | console.log(result) 90 | 91 | // { 92 | // isFullfilled: true, 93 | // isRejected: false, 94 | // value: 200 95 | // } 96 | ``` 97 | 98 | When a function is wrapped by **Microlink Function** the function execution is done remotely, giving back the result. 99 | 100 | Any **Microlink Function** will receive the following parameters: 101 | 102 | - `html`: When [meta](https://microlink.io/docs/api/parameters/meta) is enabled, the HTML markup of the website is provided. 103 | - `page`: The [`puppeteer#page`](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#class-page) instance to interact with the headless browser. 104 | - `response`: The [`puppeteer#response`](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#class-httpresponse) as result of the implicit [`page.goto`](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagegotourl-options). 105 | 106 | #### NPM packages 107 | 108 | Additionally, you can require a allowed list of common NPM packages inside your code blocks: 109 | 110 | ```js 111 | const microlink = require('@microlink/function') 112 | 113 | const ping = microlink(({ statusCode, response }) => { 114 | const { result } = require('lodash') 115 | return result(response, statusCode ? 'status' : 'statusText') 116 | }) 117 | ``` 118 | 119 | The list of allowed NPM packages are: 120 | 121 | - [`path`](https://nodejs.org/api/path.html) 122 | - [`url`](https://nodejs.org/api/url.html) 123 | - [`@aws-sdk/client-s3`](https://npm.im/@aws-sdk/client-s3) 124 | - [`@metascraper`](https://npm.im/@metascraper) 125 | - [`@mozilla/readability`](https://npm.im/@mozilla/readability) 126 | - [`async`](https://npm.im/async) 127 | - [`cheerio`](https://npm.im/cheerio) 128 | - [`extract-email-address`](https://npm.im/extract-email-address) 129 | - [`got`](https://npm.im/got) 130 | - [`ioredis`](https://npm.im/ioredis) 131 | - [`jsdom`](https://npm.im/jsdom) 132 | - [`lodash`](https://npm.im/lodash) 133 | - [`metascraper`](https://npm.im/metascraper) 134 | - [`p-reflect`](https://npm.im/p-reflect) 135 | - [`p-retry`](https://npm.im/p-retry) 136 | - [`p-timeout`](https://npm.im/p-timeout) 137 | 138 | Do you miss any NPM modules there? open a [new issue](/issues/new) and we make it available. 139 | 140 | ### Output 141 | 142 | When a **Microlink Function** is executed, the result response object has the following interface: 143 | 144 | - `isFulfilled` 145 | - `isRejected` 146 | - `value` or `reason`, depending on whether the promise fulfilled or rejected. 147 | 148 | ## Testing 149 | 150 | Check [`@microlink/local`](https://github.com/microlinkhq/local) for executing your Microlink Functions locally. 151 | 152 | ## Examples 153 | 154 | Check [examples](/examples). 155 | 156 | ## Pricing 157 | 158 | **Microlink Function** has been designed to be cheap and affordable. 159 | 160 | The first 50 [uncached](https://microlink.io/blog/edge-cdn/) requests of every day are **free**. If you need more, you should to buy a [pro plan](https://microlink.io/#pricing). 161 | 162 | For [authenticating](https://microlink.io/docs/api/basics/authentication) your requests, you should to provide your API key: 163 | 164 | ```js 165 | const microlink = require('@microlink/function') 166 | 167 | const code = ({ statusCode, response }) => { 168 | const { result } = require('lodash') 169 | return result(response, statusCode ? 'status' : 'statusText') 170 | } 171 | 172 | const ping = microlink(code, { apiKey: process.env.MICROLINK_API_KEY }) 173 | ``` 174 | 175 | ## API 176 | 177 | ### microlink(fn, [mqlOpts], [gotoOpts]) 178 | 179 | #### fn 180 | 181 | _Required_
182 | Type: `function` 183 | 184 | The function that be executed inside Microlink API browser. 185 | 186 | #### mqlOpts 187 | 188 | Type: `object` 189 | 190 | The function that be executed inside Microlink API browser. 191 | 192 | Any option passed here will bypass to [mql](https://github.com/microlinkhq/mql). 193 | 194 | #### gotoOpts 195 | 196 | Type: `object` 197 | 198 | Any option passed here will bypass to [browserless#goto](https://browserless.js.org/#/?id=options-5). 199 | 200 | ## License 201 | 202 | **microlink-function** © [Microlink](https://microlink.io), released under the [MIT](https://github.com/microlink/microlink-function/blob/master/LICENSE.md) License.
203 | Authored and maintained by [Kiko Beats](https://kikobeats.com) with help from [contributors](https://github.com/microlink/microlink-function/contributors). 204 | 205 | > [microlink.io](https://microlink.io) · GitHub [@MicrolinkHQ](https://github.com/microlinkhq) · X [@microlinkhq](https://x.com/microlinkhq) 206 | -------------------------------------------------------------------------------- /examples/page.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const microlink = require('..') 4 | 5 | const fn = microlink(({ page }) => page.title()) 6 | 7 | fn('https://example.com').then(result => console.log(result)) 8 | -------------------------------------------------------------------------------- /examples/query.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const microlink = require('..') 4 | 5 | const ping = microlink(({ statusCode, response }) => 6 | statusCode ? response.status() : response.statusText() 7 | ) 8 | 9 | ping('https://example.com', { statusCode: true }).then(result => 10 | console.log(result) 11 | ) 12 | -------------------------------------------------------------------------------- /examples/require.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const microlink = require('..') 4 | 5 | const ping = microlink(({ statusCode, response }) => { 6 | const { result } = require('lodash') 7 | return result(response, statusCode ? 'status' : 'statusText') 8 | }) 9 | 10 | ping('https://example.com', { statusCode: true }).then(result => 11 | console.log(result) 12 | ) 13 | -------------------------------------------------------------------------------- /examples/response.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const microlink = require('..') 4 | 5 | const fn = microlink(({ response }) => response.status()) 6 | 7 | fn('https://example.com').then(result => console.log(result)) 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Microlink Function 9 | 10 | 11 | 37 | 38 | 39 | 40 | 41 |
42 | 60 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /lightweight/index.d.ts: -------------------------------------------------------------------------------- 1 | import { MqlOptions } from '@microlink/mql' 2 | import { Page, HTTPResponse } from 'puppeteer-core' 3 | 4 | export type FunctionResponse = { 5 | isFulfilled: true, 6 | isRejected: false, 7 | value: any 8 | } 9 | 10 | export type FunctionArgs = { 11 | page: object; 12 | response: object; 13 | url: string; 14 | } 15 | 16 | export type FunctionInput = (args: { 17 | page: Page; 18 | response: HTTPResponse; 19 | [key: string]: any; 20 | }) => any; 21 | 22 | 23 | declare function microlinkFunction( 24 | fn: FunctionInput, 25 | mqlOpts?: MqlOptions, 26 | gotOpts?: object 27 | ): ( 28 | url: string, 29 | mqlOpts?: MqlOptions, 30 | gotOpts?: object 31 | ) => Promise; 32 | 33 | export default microlinkFunction; 34 | -------------------------------------------------------------------------------- /lightweight/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js", 3 | "type": "module", 4 | "types": "index-bundled.d.ts" 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@microlink/function", 3 | "description": "Browser functions as Service. Interacting with browser pages, remotely.", 4 | "homepage": "https://function.microlink.io", 5 | "version": "0.2.2", 6 | "types": "lightweight/index.d.ts", 7 | "exports": { 8 | "require": "./src/node.js", 9 | "default": "./lightweight/index.js" 10 | }, 11 | "author": { 12 | "email": "josefrancisco.verdu@gmail.com", 13 | "name": "Kiko Beats", 14 | "url": "https://github.com/Kikobeats" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/microlinkhq/function.git" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/microlinkhq/function/issues" 22 | }, 23 | "keywords": [ 24 | "browserless", 25 | "chrome", 26 | "chromium", 27 | "function", 28 | "microlink", 29 | "playwright", 30 | "puppeteer", 31 | "serverless" 32 | ], 33 | "dependencies": { 34 | "@microlink/mql": "~0.13.4", 35 | "base64-url": "~2.3.3" 36 | }, 37 | "devDependencies": { 38 | "@commitlint/cli": "latest", 39 | "@commitlint/config-conventional": "latest", 40 | "@ksmithut/prettier-standard": "latest", 41 | "@rollup/plugin-commonjs": "latest", 42 | "@rollup/plugin-node-resolve": "latest", 43 | "@rollup/plugin-replace": "latest", 44 | "@rollup/plugin-terser": "latest", 45 | "async-listen": "latest", 46 | "ava": "latest", 47 | "c8": "latest", 48 | "ci-publish": "latest", 49 | "execa": "latest", 50 | "git-authors-cli": "latest", 51 | "github-generate-release": "latest", 52 | "nano-staged": "latest", 53 | "prettier-standard": "latest", 54 | "puppeteer-core": "latest", 55 | "rollup": "latest", 56 | "rollup-plugin-filesize": "latest", 57 | "rollup-plugin-rewrite": "latest", 58 | "rollup-plugin-visualizer": "latest", 59 | "simple-git-hooks": "latest", 60 | "standard": "latest", 61 | "standard-markdown": "latest", 62 | "standard-version": "latest", 63 | "stream-to-promise": "latest", 64 | "tsd": "latest" 65 | }, 66 | "engines": { 67 | "node": ">= 18" 68 | }, 69 | "files": [ 70 | "lightweight", 71 | "src/factory.js", 72 | "src/node.js" 73 | ], 74 | "scripts": { 75 | "build": "rollup -c rollup.config.js --bundleConfigAsCjs", 76 | "clean": "rm -rf node_modules", 77 | "clean:build": "rm -rf lightweight/index.js", 78 | "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true", 79 | "dev": "npm run build -- -w", 80 | "lint": "standard && tsd", 81 | "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)", 82 | "prebuild": "npm run clean:build", 83 | "prepublishOnly": "npm run build", 84 | "pretest": "npm run lint && npm run build", 85 | "release": "standard-version -a", 86 | "release:github": "github-generate-release", 87 | "release:tags": "git push --follow-tags origin HEAD:master", 88 | "test": "c8 ava --verbose" 89 | }, 90 | "license": "MIT", 91 | "ava": { 92 | "files": [ 93 | "test/**/*", 94 | "!test/clients.mjs" 95 | ], 96 | "timeout": "1m" 97 | }, 98 | "commitlint": { 99 | "extends": [ 100 | "@commitlint/config-conventional" 101 | ], 102 | "rules": { 103 | "body-max-line-length": [ 104 | 0 105 | ] 106 | } 107 | }, 108 | "nano-staged": { 109 | "*.js": [ 110 | "prettier-standard", 111 | "standard --fix" 112 | ], 113 | "*.md": [ 114 | "standard-markdown" 115 | ], 116 | "package.json": [ 117 | "finepack" 118 | ] 119 | }, 120 | "simple-git-hooks": { 121 | "commit-msg": "npx commitlint --edit", 122 | "pre-commit": "npx nano-staged" 123 | }, 124 | "standard": { 125 | "ignore": [ 126 | "lightweight/index.js", 127 | "src/node.mjs" 128 | ] 129 | }, 130 | "tsd": { 131 | "directory": "test" 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from '@rollup/plugin-node-resolve' 2 | import { visualizer } from 'rollup-plugin-visualizer' 3 | import commonjs from '@rollup/plugin-commonjs' 4 | import filesize from 'rollup-plugin-filesize' 5 | import replace from '@rollup/plugin-replace' 6 | import terser from '@rollup/plugin-terser' 7 | 8 | const build = ({ input, output, plugins = [], compress }) => { 9 | return { 10 | input, 11 | output, 12 | plugins: [ 13 | replace({ 14 | values: { 15 | "require('../package.json').version": "'__MFN_VERSION__'", 16 | __MFN_VERSION__: require('./package.json').version 17 | } 18 | }), 19 | ...plugins, 20 | compress && 21 | terser({ 22 | format: { 23 | comments: false 24 | } 25 | }), 26 | filesize(), 27 | visualizer() 28 | ] 29 | } 30 | } 31 | 32 | const builds = [ 33 | /* This build is just for testing using ESM interface */ 34 | build({ 35 | input: './src/node.js', 36 | output: { file: 'src/node.mjs', format: 'es' }, 37 | plugins: [commonjs()] 38 | }), 39 | build({ 40 | compress: true, 41 | input: 'src/lightweight.mjs', 42 | output: { file: 'lightweight/index.js', format: 'es' }, 43 | plugins: [nodeResolve()] 44 | }) 45 | ] 46 | 47 | export default builds 48 | -------------------------------------------------------------------------------- /src/lightweight.mjs: -------------------------------------------------------------------------------- 1 | import mql from '@microlink/mql' 2 | 3 | const fn = (code, mqlOpts, gotOpts) => async (url, opts) => { 4 | const { data } = await mql( 5 | url, 6 | { 7 | function: code.toString(), 8 | meta: false, 9 | ...mqlOpts, 10 | ...opts 11 | }, 12 | gotOpts 13 | ) 14 | 15 | return data.function 16 | } 17 | 18 | fn.mql = mql 19 | fn.render = mql.render 20 | fn.version = require('../package.json').version 21 | 22 | export default fn 23 | -------------------------------------------------------------------------------- /src/node.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { escape } = require('base64-url') 4 | const { promisify } = require('util') 5 | const mql = require('@microlink/mql') 6 | const zlib = require('zlib') 7 | 8 | const brotliCompress = promisify(zlib.brotliCompress) 9 | 10 | const toCompress = code => 11 | brotliCompress(code.toString()).then( 12 | data => `br#${escape(data.toString('base64'))}` 13 | ) 14 | 15 | const fn = (code, mqlOpts, gotOpts) => { 16 | const compress = toCompress(code) 17 | 18 | return async (url, opts) => { 19 | const { data } = await mql( 20 | url, 21 | { 22 | function: await compress, 23 | meta: false, 24 | ping: false, 25 | ...mqlOpts, 26 | ...opts 27 | }, 28 | gotOpts 29 | ) 30 | 31 | return data.function 32 | } 33 | } 34 | 35 | fn.mql = mql 36 | fn.render = mql.render 37 | fn.version = require('../package.json').version 38 | 39 | module.exports = fn 40 | -------------------------------------------------------------------------------- /test/build.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module' 2 | import $ from 'tinyspawn' 3 | import test from 'ava' 4 | 5 | const pkg = createRequire(import.meta.url)('../package.json') 6 | 7 | const evalScript = (code, flags = []) => $('node', ['--eval', code, ...flags]) 8 | evalScript.esm = code => evalScript(code, ['--input-type', 'module']) 9 | 10 | test('cjs', async t => { 11 | // eslint-disable-next-line no-template-curly-in-string 12 | const code = "console.log(`ƒ v${require('@microlink/function').version}`)" 13 | const { stdout } = await evalScript(code) 14 | t.is(stdout, `ƒ v${pkg.version}`) 15 | }) 16 | 17 | test('esm', async t => { 18 | // eslint-disable-next-line no-template-curly-in-string 19 | const code = "import f from '@microlink/function'; console.log(`ƒ v${f.version}`)" 20 | const { stdout } = await evalScript.esm(code) 21 | t.is(stdout, `ƒ v${pkg.version}`) 22 | }) 23 | -------------------------------------------------------------------------------- /test/clients.mjs: -------------------------------------------------------------------------------- 1 | import ligtweight from '../lightweight/index.js' 2 | import node from '../src/node.mjs' 3 | 4 | export default [ 5 | { constructor: node, target: 'node' }, 6 | { constructor: ligtweight, target: 'lightweight' } 7 | ] 8 | -------------------------------------------------------------------------------- /test/index.mjs: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import test from 'ava' 4 | 5 | import clients from './clients.mjs' 6 | 7 | clients.forEach(({ constructor: microlink, target }) => { 8 | test(`${target} » interact with the page`, async t => { 9 | const getTitle = ({ page }) => page.title() 10 | 11 | const myFn = microlink(getTitle) 12 | 13 | const result = await myFn('https://example.com', { force: true }) 14 | 15 | t.deepEqual(result, { 16 | isFulfilled: true, 17 | isRejected: false, 18 | value: 'Example Domain' 19 | }) 20 | }) 21 | 22 | test(`${target} » interact with the response`, async t => { 23 | const getTitle = ({ response }) => response.status() 24 | 25 | const myFn = microlink(getTitle) 26 | 27 | const result = await myFn('https://example.com', { force: true }) 28 | 29 | t.deepEqual(result, { 30 | isFulfilled: true, 31 | isRejected: false, 32 | value: 200 33 | }) 34 | }) 35 | 36 | test(`${target} » interact with user specific parameters`, async t => { 37 | const getTitle = ({ greetings }) => greetings 38 | 39 | const myFn = microlink(getTitle) 40 | 41 | const result = await myFn('https://example.com', { 42 | greetings: 'hello world', 43 | force: true 44 | }) 45 | 46 | t.deepEqual(result, { 47 | isFulfilled: true, 48 | isRejected: false, 49 | value: 'hello world' 50 | }) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /test/lightweight.test-d.ts: -------------------------------------------------------------------------------- 1 | import microlinkFn from '../lightweight' 2 | 3 | /** definition */ 4 | 5 | { 6 | const fn = microlinkFn(({ page }) => page.title()) 7 | const data = await fn('https://microlink.io', { meta: false }) 8 | console.log(data.value) 9 | console.log(data.isFulfilled) 10 | console.log(data.isRejected) 11 | } 12 | 13 | /** interaction */ 14 | 15 | microlinkFn(() => document.getElementsByTagName('*').length) 16 | microlinkFn(({ page }) => page.title()) 17 | microlinkFn(() => 420) 18 | microlinkFn(({ response }) => response.ok()) 19 | microlinkFn(({ name }) => `Greetings, ${name}`) 20 | --------------------------------------------------------------------------------