├── .gitattributes
├── test
├── snapshots
│ ├── opts.js.snap
│ ├── opts.mjs.snap
│ ├── get-api-url.js.snap
│ ├── get-api-url.mjs.snap
│ ├── opts.js.md
│ ├── opts.mjs.md
│ ├── get-api-url.js.md
│ └── get-api-url.mjs.md
├── clients.mjs
├── stream.mjs
├── error
│ ├── client.mjs
│ └── server.mjs
├── opts.mjs
├── get-api-url.mjs
├── build.mjs
├── node.test-d.ts
├── rules.mjs
└── lightweight.test-d.ts
├── lightweight
├── package.json
├── index.d.ts
└── index.umd.js
├── .npmrc
├── .github
├── dependabot.yml
└── workflows
│ ├── pull_request.yml
│ └── main.yml
├── .editorconfig
├── src
├── node.js
├── node.d.ts
├── lightweight.js
└── factory.js
├── .gitignore
├── README.md
├── LICENSE.md
├── rollup.config.js
├── index.html
├── package.json
└── CHANGELOG.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/test/snapshots/opts.js.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microlinkhq/mql/HEAD/test/snapshots/opts.js.snap
--------------------------------------------------------------------------------
/test/snapshots/opts.mjs.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microlinkhq/mql/HEAD/test/snapshots/opts.mjs.snap
--------------------------------------------------------------------------------
/lightweight/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js",
3 | "type": "module",
4 | "types": "index.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/test/snapshots/get-api-url.js.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microlinkhq/mql/HEAD/test/snapshots/get-api-url.js.snap
--------------------------------------------------------------------------------
/test/snapshots/get-api-url.mjs.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microlinkhq/mql/HEAD/test/snapshots/get-api-url.mjs.snap
--------------------------------------------------------------------------------
/test/clients.mjs:
--------------------------------------------------------------------------------
1 | import mqlLightweight from '../lightweight/index.js'
2 | import mqlNode from '../src/node.mjs'
3 |
4 | export default [
5 | { constructor: mqlNode, target: 'node' },
6 | { constructor: mqlLightweight, target: 'lightweight' }
7 | ]
8 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | audit=false
2 | fund=false
3 | package-lock=false
4 | prefer-dedupe=true
5 | prefer-offline=false
6 | save-prefix=~
7 | save=false
8 | strict-peer-dependencies=false
9 | unsafe-perm=true
10 | loglevel=error
11 | shamefully-hoist=true
12 | resolution-mode=highest
13 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://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 |
21 | [*.md]
22 | trim_trailing_whitespace = false
23 |
--------------------------------------------------------------------------------
/src/node.js:
--------------------------------------------------------------------------------
1 | const mql = require('./factory')('buffer')({
2 | MicrolinkError: require('whoops')('MicrolinkError'),
3 | got: require('got').extend({ headers: { 'user-agent': undefined } }),
4 | flatten: require('flattie').flattie,
5 | VERSION: require('../package.json').version
6 | })
7 |
8 | module.exports = mql
9 | module.exports.buffer = mql.extend({ responseType: 'buffer' })
10 | module.exports.render = (input, { width = '650px' } = {}) => {
11 | if (input && input.url && input.type) {
12 | return `
`
13 | }
14 | return input
15 | }
16 |
--------------------------------------------------------------------------------
/.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 | examples
39 | src/node.mjs
40 | lightweight/index.js
41 | lightweight/index.umd.js
42 |
--------------------------------------------------------------------------------
/test/stream.mjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import test from 'ava'
4 | import toPromise from 'stream-to-promise'
5 |
6 | import clients from './clients.mjs'
7 |
8 | clients
9 | .filter(({ target }) => target === 'node')
10 | .forEach(({ constructor: mql, target }) => {
11 | test(`${target} » pass headers`, async t => {
12 | let headers
13 |
14 | const stream = mql.stream('https://cdn.microlink.io/logo/logo.png', {
15 | headers: {
16 | accept: 'image/webp'
17 | }
18 | })
19 |
20 | stream.on('response', response => {
21 | headers = response.headers
22 | })
23 |
24 | await toPromise(stream)
25 |
26 | t.true(['image/webp', 'image/png'].includes(headers['content-type']))
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |

4 |
5 |
6 | ###### [Documentation](https://microlink.io/mql) | [CLI](https://github.com/microlinkhq/cli) | [Playground](https://mql.microlink.io)
7 |
8 | ## License
9 |
10 | **microlink** © [Microlink](https://microlink.io), Released under the [MIT](https://github.com/microlinkhq/sdk/blob/master/LICENSE.md) License.
11 | Authored and maintained by Kiko Beats with help from [contributors](https://github.com/microlinkhq/sdk/contributors).
12 |
13 | > [microlink.io](https://microlink.io) · GitHub [@MicrolinkHQ](https://github.com/microlinkhq) · X [@microlinkhq](https://x.com/microlinkhq)
14 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: pull_request
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | jobs:
12 | test:
13 | if: github.ref != 'refs/heads/master'
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v6
18 | with:
19 | token: ${{ secrets.GITHUB_TOKEN }}
20 | - name: Setup Node.js
21 | uses: actions/setup-node@v6
22 | with:
23 | node-version: lts/*
24 | - name: Setup PNPM
25 | uses: pnpm/action-setup@v4
26 | with:
27 | version: latest
28 | run_install: true
29 | - name: Test
30 | run: npm test
31 | - name: Report
32 | run: npx c8 report --reporter=text-lcov > coverage/lcov.info
33 | - name: Coverage
34 | uses: coverallsapp/github-action@main
35 | with:
36 | github-token: ${{ secrets.GITHUB_TOKEN }}
37 |
--------------------------------------------------------------------------------
/src/node.d.ts:
--------------------------------------------------------------------------------
1 | import { MqlPayload, MqlOptions } from '../lightweight';
2 |
3 | export {
4 | ColorScheme,
5 | MicrolinkApiOptions,
6 | MicrolinkError,
7 | MqlError,
8 | MqlOptions,
9 | MqlPayload,
10 | MqlResponseData,
11 | version
12 | } from '../lightweight';
13 |
14 | import { Response, Options as GotOpts } from 'got/dist/source/core'
15 |
16 | type HTTPResponseWithBody = Response & { body: MqlPayload };
17 |
18 | export type HTTPResponseRaw = Response & { body: Buffer };
19 |
20 | export type MqlResponse = MqlPayload & { response: HTTPResponseWithBody };
21 |
22 | interface Mql {
23 | (url: string, opts?: MqlOptions & { stream: string }, gotOpts?: GotOpts): Promise;
24 | (url: string, opts?: MqlOptions, gotOpts?: GotOpts): Promise;
25 | extend: (gotOpts?: GotOpts) => Mql;
26 | stream: (url: string, gotOpts?: GotOpts) => NodeJS.ReadableStream;
27 | buffer: (url: string, opts?: MqlOptions, gotOpts?: GotOpts) => Promise;
28 | version: string;
29 | }
30 |
31 | declare const mql: Mql;
32 |
33 | export default mql;
34 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2019 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 |
--------------------------------------------------------------------------------
/test/error/client.mjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import test from 'ava'
4 |
5 | import clients from '../clients.mjs'
6 |
7 | clients.forEach(({ constructor: mql, target }) => {
8 | test(`${target} » EINVALURLCLIENT`, async t => {
9 | const error = await t.throwsAsync(mql(), { instanceOf: mql.MicrolinkError })
10 |
11 | t.true(error.url === '')
12 | t.true(error.code === 'EINVALURLCLIENT')
13 | t.true(error.status === 'fail')
14 | t.true(error.more === 'https://microlink.io/einvalurlclient')
15 | t.true(error.statusCode === undefined)
16 | t.true(!!error.data)
17 | t.true(!!error.message)
18 | t.true(!!error.description)
19 | })
20 |
21 | test(`${target} » EFATALCLIENT`, async t => {
22 | let count = 0
23 |
24 | const hooks = {
25 | beforeRetry: [
26 | () => ++count
27 | ]
28 | }
29 |
30 | const error = await t.throwsAsync(
31 | mql('https://example.com', { endpoint: 'https://notexist.dev' }, { retry: 2, hooks }),
32 | { instanceOf: mql.MicrolinkError }
33 | )
34 |
35 | t.is(count, 2)
36 | t.true(error.url === 'https://notexist.dev?url=https%3A%2F%2Fexample.com')
37 | t.true(error.code === 'EFATALCLIENT')
38 | t.true(error.status === 'error')
39 | t.true(error.more === 'https://microlink.io/efatalclient')
40 | t.true(error.statusCode === undefined)
41 | t.true(!!error.data)
42 | t.true(!!error.message)
43 | t.true(!!error.description)
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/test/opts.mjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import test from 'ava'
4 |
5 | import clients from './clients.mjs'
6 |
7 | clients.forEach(({ constructor: mql, target }) => {
8 | test(`${target} » url`, async t => {
9 | const { status, data, response } = await mql(
10 | 'https://kikobeats.com?ref=mql'
11 | )
12 | const { date, ...restData } = data
13 |
14 | t.snapshot(status)
15 | t.snapshot(restData)
16 | t.snapshot(response.url)
17 | t.snapshot(response.statusCode)
18 | })
19 |
20 | test(`${target} » stream`, async t => {
21 | const response = await mql(
22 | 'https://kikobeats.com?ref=mql', {
23 | screenshot: { optimizedForSpeed: true },
24 | stream: 'screenshot'
25 | }
26 | )
27 |
28 | t.is(typeof response.headers, 'object')
29 | t.is(typeof response.statusCode, 'number')
30 | t.is(typeof response.url, 'string')
31 |
32 | if (target === 'node') {
33 | t.true(Buffer.isBuffer(response.body))
34 | t.is(typeof response.isFromCache, 'boolean')
35 | } else {
36 | t.true((response.body instanceof ArrayBuffer))
37 | }
38 | })
39 |
40 | if (target === 'node') {
41 | test('node » cache support', async t => {
42 | const cache = new Map()
43 | let data
44 | data = await mql('https://kikobeats.com?ref=mql', {}, { cache })
45 | t.is(data.response.isFromCache, false)
46 | data = await mql('https://kikobeats.com?ref=mql', {}, { cache })
47 | t.is(data.response.isFromCache, true)
48 | })
49 | }
50 | })
51 |
--------------------------------------------------------------------------------
/test/get-api-url.mjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import test from 'ava'
4 |
5 | import clients from './clients.mjs'
6 |
7 | clients.forEach(({ constructor: mql, target }) => {
8 | test(`${target} » url without query params`, t => {
9 | t.snapshot(mql.getApiUrl('https://kikobeats.com'))
10 | })
11 |
12 | test(`${target} » apiKey`, t => {
13 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { apiKey: 'foobar' }))
14 | })
15 |
16 | test(`${target} » flatten options`, t => {
17 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { overlay: { browser: 'dark' } }))
18 | })
19 |
20 | test(`${target} » don't pass null`, t => {
21 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { colorScheme: undefined }))
22 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { colorScheme: null }))
23 | })
24 |
25 | test(`${target} » don't pass undefined`, t => {
26 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { colorScheme: undefined }))
27 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { colorScheme: null }))
28 | })
29 |
30 | test(`${target} » timeout`, t => {
31 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { timeout: 15000 }))
32 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { timeout: 28000 }))
33 | })
34 |
35 | test(`${target} » waitUntil`, t => {
36 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { waitUntil: 'load' }))
37 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { waitUntil: ['load', 'networkidle0'] }))
38 | })
39 |
40 | test(`${target} » undefined`, t => {
41 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { waitUntil: undefined }))
42 | t.snapshot(mql.getApiUrl('https://kikobeats.com', { screenshot: { element: '#screenshot', type: undefined } }))
43 | })
44 | })
45 |
--------------------------------------------------------------------------------
/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]).then(({ stdout }) => stdout)
8 | evalScript.esm = code => evalScript(code, ['--input-type', 'module'])
9 |
10 | const sort = array => array.sort((a, b) => a.localeCompare(b))
11 |
12 | test('cjs', async t => {
13 | // eslint-disable-next-line no-template-curly-in-string
14 | t.is((await evalScript("console.log(`mql v${require('@microlink/mql').version}`)")), `mql v${pkg.version}`)
15 |
16 | const methods = sort(JSON.parse((await evalScript("console.log(JSON.stringify(Object.keys(require('@microlink/mql'))))"))))
17 | t.deepEqual(methods,
18 | [
19 | 'buffer',
20 | 'extend',
21 | 'fetchFromApi',
22 | 'getApiUrl',
23 | 'mapRules',
24 | 'MicrolinkError',
25 | 'render',
26 | 'stream',
27 | 'version'
28 | ])
29 | })
30 |
31 | test('esm', async t => {
32 | // eslint-disable-next-line no-template-curly-in-string
33 | t.is((await evalScript.esm("import {version} from '@microlink/mql'; console.log(`mql v${version}`)")), `mql v${pkg.version}`)
34 |
35 | const methods = sort(JSON.parse((await evalScript('import("@microlink/mql").then(mql => console.log(JSON.stringify(Object.keys(mql))))'))))
36 |
37 | t.deepEqual(methods,
38 | [
39 | 'arrayBuffer',
40 | 'default',
41 | 'extend',
42 | 'fetchFromApi',
43 | 'getApiUrl',
44 | 'mapRules',
45 | 'MicrolinkError',
46 | 'version'
47 | ]
48 | )
49 |
50 | t.is((await evalScript.esm("import {getApiUrl} from '@microlink/mql'; console.log(typeof getApiUrl)")), 'function')
51 | })
52 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: main
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | contributors:
10 | if: "${{ github.event.head_commit.message != 'build: contributors' }}"
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v6
15 | with:
16 | fetch-depth: 0
17 | token: ${{ secrets.GITHUB_TOKEN }}
18 | - name: Setup Node.js
19 | uses: actions/setup-node@v6
20 | with:
21 | node-version: lts/*
22 | - name: Contributors
23 | run: |
24 | git config --global user.email ${{ secrets.GIT_EMAIL }}
25 | git config --global user.name ${{ secrets.GIT_USERNAME }}
26 | npm run contributors
27 | - name: Push changes
28 | run: |
29 | git push origin ${{ github.head_ref }}
30 |
31 | test:
32 | if: |
33 | !startsWith(github.event.head_commit.message, 'chore(release):') &&
34 | !startsWith(github.event.head_commit.message, 'docs:') &&
35 | !startsWith(github.event.head_commit.message, 'ci:')
36 | needs: [contributors]
37 | runs-on: ubuntu-latest
38 | steps:
39 | - name: Checkout
40 | uses: actions/checkout@v6
41 | with:
42 | token: ${{ secrets.GITHUB_TOKEN }}
43 | - name: Setup Node.js
44 | uses: actions/setup-node@v6
45 | with:
46 | node-version: lts/*
47 | - name: Setup PNPM
48 | uses: pnpm/action-setup@v4
49 | with:
50 | version: latest
51 | run_install: true
52 | - name: Test
53 | run: npm test
54 | - name: Report
55 | run: npx c8 report --reporter=text-lcov > coverage/lcov.info
56 | - name: Coverage
57 | uses: coverallsapp/github-action@main
58 | with:
59 | github-token: ${{ secrets.GITHUB_TOKEN }}
60 |
--------------------------------------------------------------------------------
/src/lightweight.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { flattie: flatten } = require('flattie')
4 | const { default: ky } = require('ky')
5 |
6 | const factory = require('./factory')('arrayBuffer')
7 |
8 | class MicrolinkError extends Error {
9 | constructor (props) {
10 | super()
11 | this.name = 'MicrolinkError'
12 | Object.assign(this, props)
13 | this.description = this.message
14 | this.message = this.code
15 | ? `${this.code}, ${this.description}`
16 | : this.description
17 | }
18 | }
19 |
20 | const got = async (url, { responseType, ...opts }) => {
21 | try {
22 | if (opts.timeout === undefined) opts.timeout = false
23 | const response = await ky(url, opts)
24 | const body = await response[responseType]()
25 | const { headers, status: statusCode } = response
26 | return { url: response.url, body, headers, statusCode }
27 | } catch (error) {
28 | if (error.response) {
29 | const { response } = error
30 | error.response = {
31 | ...response,
32 | headers: Array.from(response.headers.entries()).reduce(
33 | (acc, [key, value]) => {
34 | acc[key] = value
35 | return acc
36 | },
37 | {}
38 | ),
39 | statusCode: response.status,
40 | body: await response.text()
41 | }
42 | }
43 | throw error
44 | }
45 | }
46 |
47 | got.stream = (...args) => ky(...args).then(res => res.body)
48 |
49 | const mql = factory({
50 | MicrolinkError,
51 | got,
52 | flatten,
53 | VERSION: '__MQL_VERSION__'
54 | })
55 |
56 | module.exports = mql
57 | module.exports.arrayBuffer = mql.extend({ responseType: 'arrayBuffer' })
58 | module.exports.extend = mql.extend
59 | module.exports.fetchFromApi = mql.fetchFromApi
60 | module.exports.getApiUrl = mql.getApiUrl
61 | module.exports.mapRules = mql.mapRules
62 | module.exports.MicrolinkError = mql.MicrolinkError
63 | module.exports.version = mql.version
64 |
--------------------------------------------------------------------------------
/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 rewrite from 'rollup-plugin-rewrite'
7 | import terser from '@rollup/plugin-terser'
8 |
9 | const rewriteFlattie = () =>
10 | rewrite({
11 | find: /.* from 'flattie'/gm,
12 | replace: match => match[0].replace('import', 'import * as')
13 | })
14 |
15 | const build = ({ input, output, plugins = [], compress }) => {
16 | return {
17 | input,
18 | output,
19 | plugins: [
20 | replace({
21 | values: {
22 | "require('../package.json').version": "'__MQL_VERSION__'",
23 | __MQL_VERSION__: require('./package.json').version
24 | }
25 | }),
26 | ...plugins,
27 | compress &&
28 | terser({
29 | format: {
30 | comments: false
31 | }
32 | }),
33 | filesize(),
34 | visualizer()
35 | ]
36 | }
37 | }
38 |
39 | const builds = [
40 | /* This build is just for testing using ESM interface */
41 | build({
42 | input: './src/node.js',
43 | output: { file: 'src/node.mjs', format: 'es' },
44 | plugins: [commonjs({ strictRequires: 'auto' }), rewriteFlattie()]
45 | }),
46 | build({
47 | compress: false,
48 | input: 'src/lightweight.js',
49 | output: { file: 'lightweight/index.js', format: 'es' },
50 | plugins: [
51 | nodeResolve({
52 | mainFields: ['browser', 'module', 'main']
53 | }),
54 | commonjs({ strictRequires: 'auto' })
55 | ]
56 | }),
57 | build({
58 | compress: false,
59 | input: 'src/lightweight.js',
60 | output: { name: 'mql', file: 'lightweight/index.umd.js', format: 'umd' },
61 | plugins: [
62 | nodeResolve({
63 | mainFields: ['browser', 'module', 'main']
64 | }),
65 | commonjs({ strictRequires: 'auto' })
66 | ]
67 | })
68 | ]
69 |
70 | export default builds
71 |
--------------------------------------------------------------------------------
/test/node.test-d.ts:
--------------------------------------------------------------------------------
1 | import mql, { MicrolinkError, version } from '../src/node'
2 | import type { MqlError } from '../lightweight'
3 |
4 | /** version */
5 |
6 | ;(async () => {
7 | console.log(version)
8 | })()
9 |
10 | /** error */
11 |
12 | ;({
13 | status: 'error',
14 | data: { url: 'fetch failed' },
15 | more: 'https://microlink.io/efatalclient',
16 | code: 'EFATALCLIENT',
17 | url: 'https://localhost.microlink.io?url=https%3A%2F%2Fexample.com%23t%3D1696503516588',
18 | statusCode: undefined,
19 | headers: {},
20 | name: 'MicrolinkError',
21 | message: 'EFATALCLIENT, fetch failed',
22 | description: 'fetch failed'
23 | } as MqlError)
24 |
25 | ;(async () => {
26 | const error = new MicrolinkError({
27 | status: 'fail',
28 | data: { url: 'something goes wrong' },
29 | more: 'https://microlink.io/einvalurlclient',
30 | code: 'EINVALURLCLIENT',
31 | message: 'something goes wrong',
32 | url: 'https://example.com'
33 | })
34 |
35 | console.log(error.status)
36 | console.log(error.data)
37 | console.log(error.more)
38 | console.log(error.code)
39 | console.log(error.url)
40 | console.log(error.description)
41 | })()
42 |
43 | /** mql */
44 |
45 | ;(async () => {
46 | const result = await mql('https://example.com', {
47 | endpoint: 'https://pro.microlink.io',
48 | apiKey: '123',
49 | retry: 2,
50 | cache: new Map()
51 | })
52 |
53 | console.log(result.status)
54 | console.log(result.data)
55 | console.log(result.headers)
56 | console.log(result.response)
57 | console.log(result.response.isFromCache)
58 | })()
59 |
60 | ;(async () => {
61 | const response = await mql('https://example.com', {
62 | stream: 'screenshot',
63 | screenshot: true
64 | })
65 | console.log(response.url)
66 | console.log(response.body)
67 | console.log(response.headers)
68 | console.log(response.statusCode)
69 | })()
70 |
71 | /** got options */
72 |
73 | await mql(
74 | 'https://example.com',
75 | { meta: true },
76 | {
77 | timeout: 1000
78 | }
79 | )
80 |
81 | /** stream */
82 |
83 | mql.stream('https://cdn.microlink.io/logo/logo.png', {
84 | headers: {
85 | accept: 'image/webp'
86 | }
87 | })
88 |
--------------------------------------------------------------------------------
/test/snapshots/opts.js.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/opts.js`
2 |
3 | The actual snapshot is saved in `opts.js.snap`.
4 |
5 | Generated by [AVA](https://avajs.dev).
6 |
7 | ## node » url
8 |
9 | > Snapshot 1
10 |
11 | 'success'
12 |
13 | > Snapshot 2
14 |
15 | {
16 | author: 'kikobeats',
17 | description: 'A millennial doing stuff on internet that ships software every day and builds digital products.',
18 | image: {
19 | height: 1888,
20 | size: 620881,
21 | size_pretty: '621 kB',
22 | type: 'png',
23 | url: 'https://kikobeats.com/images/resume.png',
24 | width: 3838,
25 | },
26 | lang: 'en',
27 | logo: {
28 | height: 500,
29 | size: 30285,
30 | size_pretty: '30.3 kB',
31 | type: 'jpg',
32 | url: 'https://kikobeats.com/images/avatar-glitch.jpg',
33 | width: 500,
34 | },
35 | publisher: 'kikobeats',
36 | title: 'Kikobeats',
37 | url: 'https://kikobeats.com/',
38 | }
39 |
40 | > Snapshot 3
41 |
42 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com%3Fref%3Dmql'
43 |
44 | > Snapshot 4
45 |
46 | 200
47 |
48 | ## lightweight » url
49 |
50 | > Snapshot 1
51 |
52 | 'success'
53 |
54 | > Snapshot 2
55 |
56 | {
57 | author: 'kikobeats',
58 | description: 'A millennial doing stuff on internet that ships software every day and builds digital products.',
59 | image: {
60 | height: 1888,
61 | size: 620881,
62 | size_pretty: '621 kB',
63 | type: 'png',
64 | url: 'https://kikobeats.com/images/resume.png',
65 | width: 3838,
66 | },
67 | lang: 'en',
68 | logo: {
69 | height: 500,
70 | size: 30285,
71 | size_pretty: '30.3 kB',
72 | type: 'jpg',
73 | url: 'https://kikobeats.com/images/avatar-glitch.jpg',
74 | width: 500,
75 | },
76 | publisher: 'kikobeats',
77 | title: 'Kikobeats',
78 | url: 'https://kikobeats.com/',
79 | }
80 |
81 | > Snapshot 3
82 |
83 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com%3Fref%3Dmql'
84 |
85 | > Snapshot 4
86 |
87 | 200
88 |
--------------------------------------------------------------------------------
/test/snapshots/opts.mjs.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/opts.mjs`
2 |
3 | The actual snapshot is saved in `opts.mjs.snap`.
4 |
5 | Generated by [AVA](https://avajs.dev).
6 |
7 | ## node » url
8 |
9 | > Snapshot 1
10 |
11 | 'success'
12 |
13 | > Snapshot 2
14 |
15 | {
16 | author: 'kikobeats',
17 | description: 'A millennial doing stuff on internet that ships software every day and builds digital products.',
18 | image: {
19 | height: 1888,
20 | size: 620881,
21 | size_pretty: '621 kB',
22 | type: 'png',
23 | url: 'https://kikobeats.com/images/resume.png',
24 | width: 3838,
25 | },
26 | lang: 'en',
27 | logo: {
28 | height: 500,
29 | size: 30285,
30 | size_pretty: '30.3 kB',
31 | type: 'jpg',
32 | url: 'https://kikobeats.com/images/avatar-glitch.jpg',
33 | width: 500,
34 | },
35 | publisher: 'kikobeats',
36 | title: 'Kikobeats',
37 | url: 'https://kikobeats.com/',
38 | }
39 |
40 | > Snapshot 3
41 |
42 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com%3Fref%3Dmql'
43 |
44 | > Snapshot 4
45 |
46 | 200
47 |
48 | ## lightweight » url
49 |
50 | > Snapshot 1
51 |
52 | 'success'
53 |
54 | > Snapshot 2
55 |
56 | {
57 | author: 'kikobeats',
58 | description: 'A millennial doing stuff on internet that ships software every day and builds digital products.',
59 | image: {
60 | height: 1888,
61 | size: 620881,
62 | size_pretty: '621 kB',
63 | type: 'png',
64 | url: 'https://kikobeats.com/images/resume.png',
65 | width: 3838,
66 | },
67 | lang: 'en',
68 | logo: {
69 | height: 500,
70 | size: 30285,
71 | size_pretty: '30.3 kB',
72 | type: 'jpg',
73 | url: 'https://kikobeats.com/images/avatar-glitch.jpg',
74 | width: 500,
75 | },
76 | publisher: 'kikobeats',
77 | title: 'Kikobeats',
78 | url: 'https://kikobeats.com/',
79 | }
80 |
81 | > Snapshot 3
82 |
83 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com%3Fref%3Dmql'
84 |
85 | > Snapshot 4
86 |
87 | 200
88 |
--------------------------------------------------------------------------------
/test/error/server.mjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import { listen } from 'async-listen'
4 | import http from 'http'
5 | import test from 'ava'
6 |
7 | import clients from '../clients.mjs'
8 |
9 | clients.forEach(({ constructor: mql, target }) => {
10 | test(`${target} » server side unexpected`, async t => {
11 | const server = http.createServer((req, res) => {
12 | res.statusCode = 503
13 | res.end('503 Service Unavailable')
14 | })
15 |
16 | const endpoint = await listen(server)
17 |
18 | const error = await t.throwsAsync(
19 | mql('https://microlink.io', { endpoint, retry: 0 }),
20 | {
21 | instanceOf: mql.MicrolinkError
22 | }
23 | )
24 |
25 | t.true(!!error.url)
26 | t.true(!!error.code)
27 | t.true(!!error.status)
28 | t.true(!!error.more)
29 | t.true(!!error.statusCode)
30 | t.true(!!error.data)
31 | t.true(!!error.message)
32 | t.true(!!error.description)
33 | })
34 |
35 | test(`${target} » server side generic error`, async t => {
36 | const error = await t.throwsAsync(
37 | mql('https://microlink.io', { ttl: 100, retry: 0 }),
38 | {
39 | instanceOf: mql.MicrolinkError
40 | }
41 | )
42 |
43 | t.true(!!error.url)
44 | t.true(!!error.code)
45 | t.true(!!error.status)
46 | t.true(!!error.more)
47 | t.true(!!error.statusCode)
48 | t.true(!!error.data)
49 | t.true(!!error.message)
50 | t.true(!!error.description)
51 | })
52 |
53 | test(`${target} » server side timeout`, async t => {
54 | const error = await t.throwsAsync(
55 | mql('https://kikobeats.com', {
56 | timeout: 50,
57 | force: true,
58 | screenshot: true
59 | }, { retry: 0 }),
60 | { instanceOf: mql.MicrolinkError }
61 | )
62 |
63 | t.true(!!error.url)
64 | t.true(!!error.code)
65 | t.true(!!error.status)
66 | t.true(!!error.more)
67 | t.true(!!error.statusCode)
68 | t.true(!!error.data)
69 | t.true(!!error.message)
70 | t.true(!!error.description)
71 | })
72 |
73 | test(`${target} » EINVALURL`, async t => {
74 | const error = await t.throwsAsync(mql('https://invalid-link', {}), {
75 | instanceOf: mql.MicrolinkError
76 | })
77 |
78 | t.true(!!error.url)
79 | t.true(!!error.code)
80 | t.true(!!error.status)
81 | t.true(!!error.more)
82 | t.true(!!error.statusCode)
83 | t.true(!!error.data)
84 | t.true(!!error.message)
85 | t.true(!!error.description)
86 | })
87 | })
88 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Microlink Query Language
9 |
10 |
11 |
37 |
38 |
39 |
40 |
41 |
69 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/test/rules.mjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import test from 'ava'
4 |
5 | import clients from './clients.mjs'
6 |
7 | clients.forEach(({ constructor: mql, target }) => {
8 | test(`${target} » no rules`, t => {
9 | t.deepEqual(mql.mapRules(), undefined)
10 | t.deepEqual(mql.mapRules(false), undefined)
11 | t.deepEqual(mql.mapRules('false'), undefined)
12 | t.deepEqual(mql.mapRules({}), {})
13 | t.deepEqual(mql.mapRules([]), {})
14 | })
15 |
16 | test(`${target} » object selector`, t => {
17 | t.deepEqual(
18 | mql.mapRules({
19 | avatar: {
20 | type: 'image',
21 | selectors: {
22 | selector: '#avatar',
23 | attr: 'src'
24 | }
25 | }
26 | }),
27 | {
28 | 'data.avatar.selectors.selector': '#avatar',
29 | 'data.avatar.selectors.attr': 'src',
30 | 'data.avatar.type': 'image'
31 | }
32 | )
33 | })
34 |
35 | test(`${target} » single selector`, t => {
36 | t.deepEqual(
37 | mql.mapRules({
38 | avatar: {
39 | type: 'image',
40 | selectors: [
41 | {
42 | selector: '#avatar',
43 | attr: 'src'
44 | }
45 | ]
46 | }
47 | }),
48 | {
49 | 'data.avatar.selectors.0.selector': '#avatar',
50 | 'data.avatar.selectors.0.attr': 'src',
51 | 'data.avatar.type': 'image'
52 | }
53 | )
54 | })
55 |
56 | test(`${target} » multiple selector`, t => {
57 | t.deepEqual(
58 | mql.mapRules({
59 | avatar: {
60 | type: 'image',
61 | selectors: [
62 | {
63 | selector: '#avatar',
64 | attr: 'src'
65 | },
66 | {
67 | selector: '.avatar',
68 | attr: 'href'
69 | }
70 | ]
71 | }
72 | }),
73 | {
74 | 'data.avatar.selectors.0.selector': '#avatar',
75 | 'data.avatar.selectors.0.attr': 'src',
76 | 'data.avatar.selectors.1.selector': '.avatar',
77 | 'data.avatar.selectors.1.attr': 'href',
78 | 'data.avatar.type': 'image'
79 | }
80 | )
81 | })
82 |
83 | test(`${target} » multiple rules`, t => {
84 | t.deepEqual(
85 | mql.mapRules({
86 | avatar: {
87 | type: 'image',
88 | selectors: [
89 | {
90 | selector: '#avatar',
91 | attr: 'src'
92 | },
93 | {
94 | selector: '.avatar',
95 | attr: 'href'
96 | }
97 | ]
98 | },
99 | logo: {
100 | type: 'image',
101 | selectors: [
102 | {
103 | selector: '#logo',
104 | attr: 'src'
105 | },
106 | {
107 | selector: '.logo',
108 | attr: 'href'
109 | }
110 | ]
111 | }
112 | }),
113 | {
114 | 'data.avatar.selectors.0.selector': '#avatar',
115 | 'data.avatar.selectors.0.attr': 'src',
116 | 'data.avatar.selectors.1.selector': '.avatar',
117 | 'data.avatar.selectors.1.attr': 'href',
118 | 'data.avatar.type': 'image',
119 | 'data.logo.selectors.0.selector': '#logo',
120 | 'data.logo.selectors.0.attr': 'src',
121 | 'data.logo.selectors.1.selector': '.logo',
122 | 'data.logo.selectors.1.attr': 'href',
123 | 'data.logo.type': 'image'
124 | }
125 | )
126 | })
127 | })
128 |
--------------------------------------------------------------------------------
/src/factory.js:
--------------------------------------------------------------------------------
1 | const ENDPOINT = {
2 | FREE: 'https://api.microlink.io/',
3 | PRO: 'https://pro.microlink.io/'
4 | }
5 |
6 | const isObject = input => input !== null && typeof input === 'object'
7 |
8 | const isBuffer = input =>
9 | input != null &&
10 | input.constructor != null &&
11 | typeof input.constructor.isBuffer === 'function' &&
12 | input.constructor.isBuffer(input)
13 |
14 | const parseBody = (input, error, url) => {
15 | try {
16 | return JSON.parse(input)
17 | } catch (_) {
18 | const message = input || error.message
19 |
20 | return {
21 | status: 'error',
22 | data: { url: message },
23 | more: 'https://microlink.io/efatalclient',
24 | code: 'EFATALCLIENT',
25 | message,
26 | url
27 | }
28 | }
29 | }
30 |
31 | const isURL = url => {
32 | try {
33 | return /^https?:\/\//i.test(new URL(url).href)
34 | } catch (_) {
35 | return false
36 | }
37 | }
38 |
39 | const factory = streamResponseType => ({
40 | VERSION,
41 | MicrolinkError,
42 | got,
43 | flatten
44 | }) => {
45 | const assertUrl = (url = '') => {
46 | if (!isURL(url)) {
47 | const message = `The \`url\` as \`${url}\` is not valid. Ensure it has protocol (http or https) and hostname.`
48 | throw new MicrolinkError({
49 | status: 'fail',
50 | data: { url: message },
51 | more: 'https://microlink.io/einvalurlclient',
52 | code: 'EINVALURLCLIENT',
53 | message,
54 | url
55 | })
56 | }
57 | }
58 |
59 | const mapRules = rules => {
60 | if (!isObject(rules)) return
61 | const flatRules = flatten(rules)
62 | return Object.keys(flatRules).reduce((acc, key) => {
63 | acc[`data.${key}`] = flatRules[key].toString()
64 | return acc
65 | }, {})
66 | }
67 |
68 | const fetchFromApi = async (apiUrl, opts = {}) => {
69 | try {
70 | const response = await got(apiUrl, opts)
71 | return opts.responseType === streamResponseType
72 | ? response
73 | : { ...response.body, response }
74 | } catch (error) {
75 | const { response = {} } = error
76 | const {
77 | statusCode,
78 | body: rawBody,
79 | headers = {},
80 | url: uri = apiUrl
81 | } = response
82 | const isBodyBuffer = isBuffer(rawBody)
83 |
84 | const body =
85 | isObject(rawBody) && !isBodyBuffer
86 | ? rawBody
87 | : parseBody(isBodyBuffer ? rawBody.toString() : rawBody, error, uri)
88 |
89 | throw new MicrolinkError({
90 | ...body,
91 | message: body.message,
92 | url: uri,
93 | statusCode,
94 | headers
95 | })
96 | }
97 | }
98 |
99 | const getApiUrl = (
100 | url,
101 | { data, apiKey, endpoint, ...opts } = {},
102 | { responseType = 'json', headers: gotHeaders, ...gotOpts } = {}
103 | ) => {
104 | const isPro = !!apiKey
105 | const apiEndpoint = endpoint || ENDPOINT[isPro ? 'PRO' : 'FREE']
106 |
107 | const apiUrl = `${apiEndpoint}?${new URLSearchParams({
108 | url,
109 | ...mapRules(data),
110 | ...flatten(opts)
111 | }).toString()}`
112 |
113 | const headers = isPro
114 | ? { ...gotHeaders, 'x-api-key': apiKey }
115 | : { ...gotHeaders }
116 |
117 | if (opts.stream) {
118 | responseType = streamResponseType
119 | }
120 | return [apiUrl, { ...gotOpts, responseType, headers }]
121 | }
122 |
123 | const createMql = defaultOpts => async (url, opts, gotOpts) => {
124 | assertUrl(url)
125 | const [apiUrl, fetchOpts] = getApiUrl(url, opts, {
126 | ...defaultOpts,
127 | ...gotOpts
128 | })
129 | return fetchFromApi(apiUrl, fetchOpts)
130 | }
131 |
132 | const mql = createMql()
133 | mql.extend = createMql
134 | mql.MicrolinkError = MicrolinkError
135 | mql.getApiUrl = getApiUrl
136 | mql.fetchFromApi = fetchFromApi
137 | mql.mapRules = mapRules
138 | mql.version = VERSION
139 | mql.stream = got.stream
140 |
141 | return mql
142 | }
143 |
144 | module.exports = factory
145 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@microlink/mql",
3 | "description": "Microlink Query Language. The official HTTP client to interact with Microlink API for Node.js, browsers & Deno.",
4 | "homepage": "https://microlink.io/mql",
5 | "version": "0.14.0",
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 | "contributors": [
17 | {
18 | "name": "Dani de la Cruz",
19 | "email": "5173869+delacruz-dev@users.noreply.github.com"
20 | },
21 | {
22 | "name": "ndom91",
23 | "email": "yo@ndo.dev"
24 | },
25 | {
26 | "name": "Askar Yusupov",
27 | "email": "devex.soft@gmail.com"
28 | },
29 | {
30 | "name": "Gabe O'Leary",
31 | "email": "oleary.gabe@gmail.com"
32 | }
33 | ],
34 | "repository": {
35 | "type": "git",
36 | "url": "git+https://github.com/microlinkhq/mql.git"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/microlinkhq/mql/issues"
40 | },
41 | "keywords": [
42 | "api",
43 | "language",
44 | "microlink",
45 | "mql",
46 | "query"
47 | ],
48 | "dependencies": {
49 | "flattie": "~1.1.1",
50 | "got": "~11.8.6",
51 | "whoops": "~5.0.1"
52 | },
53 | "devDependencies": {
54 | "@commitlint/cli": "latest",
55 | "@commitlint/config-conventional": "latest",
56 | "@ksmithut/prettier-standard": "latest",
57 | "@rollup/plugin-commonjs": "latest",
58 | "@rollup/plugin-node-resolve": "latest",
59 | "@rollup/plugin-replace": "latest",
60 | "@rollup/plugin-terser": "latest",
61 | "async-listen": "latest",
62 | "ava": "5",
63 | "c8": "latest",
64 | "ci-publish": "latest",
65 | "git-authors-cli": "latest",
66 | "github-generate-release": "latest",
67 | "ky": "latest",
68 | "nano-staged": "latest",
69 | "prettier-standard": "latest",
70 | "rollup": "latest",
71 | "rollup-plugin-filesize": "latest",
72 | "rollup-plugin-rewrite": "latest",
73 | "rollup-plugin-visualizer": "latest",
74 | "simple-git-hooks": "latest",
75 | "standard": "latest",
76 | "standard-markdown": "latest",
77 | "standard-version": "latest",
78 | "stream-to-promise": "latest",
79 | "tsd": "latest"
80 | },
81 | "engines": {
82 | "node": ">= 18"
83 | },
84 | "files": [
85 | "lightweight",
86 | "src/factory.js",
87 | "src/node.js"
88 | ],
89 | "scripts": {
90 | "build": "rollup -c rollup.config.js --bundleConfigAsCjs",
91 | "clean": "rm -rf node_modules",
92 | "clean:build": "rm -rf lightweight/index.js",
93 | "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
94 | "dev": "npm run build -- -w",
95 | "lint": "standard && tsd",
96 | "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
97 | "prebuild": "npm run clean:build",
98 | "prepublishOnly": "npm run build",
99 | "pretest": "npm run lint && npm run build",
100 | "release": "standard-version -a",
101 | "release:github": "github-generate-release",
102 | "release:tags": "git push --follow-tags origin HEAD:master",
103 | "test": "c8 ava --verbose"
104 | },
105 | "license": "MIT",
106 | "ava": {
107 | "files": [
108 | "test/**/*",
109 | "!test/clients.mjs"
110 | ],
111 | "timeout": "1m"
112 | },
113 | "commitlint": {
114 | "extends": [
115 | "@commitlint/config-conventional"
116 | ],
117 | "rules": {
118 | "body-max-line-length": [
119 | 0
120 | ]
121 | }
122 | },
123 | "nano-staged": {
124 | "*.js": [
125 | "prettier-standard",
126 | "standard --fix"
127 | ],
128 | "*.md": [
129 | "standard-markdown"
130 | ],
131 | "package.json": [
132 | "finepack"
133 | ]
134 | },
135 | "simple-git-hooks": {
136 | "commit-msg": "npx commitlint --edit",
137 | "pre-commit": "npx nano-staged"
138 | },
139 | "standard": {
140 | "ignore": [
141 | "lightweight/index.js",
142 | "lightweight/index.umd.js",
143 | "src/node.mjs"
144 | ]
145 | },
146 | "tsd": {
147 | "directory": "test"
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/test/snapshots/get-api-url.js.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/get-api-url.js`
2 |
3 | The actual snapshot is saved in `get-api-url.js.snap`.
4 |
5 | Generated by [AVA](https://avajs.dev).
6 |
7 | ## node » url without query params
8 |
9 | > Snapshot 1
10 |
11 | [
12 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
13 | {
14 | cache: undefined,
15 | headers: {},
16 | responseType: 'json',
17 | retry: undefined,
18 | },
19 | ]
20 |
21 | ## node » apiKey
22 |
23 | > Snapshot 1
24 |
25 | [
26 | 'https://pro.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
27 | {
28 | cache: undefined,
29 | headers: {
30 | 'x-api-key': 'foobar',
31 | },
32 | responseType: 'json',
33 | retry: undefined,
34 | },
35 | ]
36 |
37 | ## node » flatten options
38 |
39 | > Snapshot 1
40 |
41 | [
42 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&overlay.browser=dark',
43 | {
44 | cache: undefined,
45 | headers: {},
46 | responseType: 'json',
47 | retry: undefined,
48 | },
49 | ]
50 |
51 | ## node » don't pass null
52 |
53 | > Snapshot 1
54 |
55 | [
56 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
57 | {
58 | cache: undefined,
59 | headers: {},
60 | responseType: 'json',
61 | retry: undefined,
62 | },
63 | ]
64 |
65 | > Snapshot 2
66 |
67 | [
68 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
69 | {
70 | cache: undefined,
71 | headers: {},
72 | responseType: 'json',
73 | retry: undefined,
74 | },
75 | ]
76 |
77 | ## node » don't pass undefined
78 |
79 | > Snapshot 1
80 |
81 | [
82 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
83 | {
84 | cache: undefined,
85 | headers: {},
86 | responseType: 'json',
87 | retry: undefined,
88 | },
89 | ]
90 |
91 | > Snapshot 2
92 |
93 | [
94 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
95 | {
96 | cache: undefined,
97 | headers: {},
98 | responseType: 'json',
99 | retry: undefined,
100 | },
101 | ]
102 |
103 | ## node » timeout
104 |
105 | > Snapshot 1
106 |
107 | [
108 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=15000',
109 | {
110 | cache: undefined,
111 | headers: {},
112 | responseType: 'json',
113 | retry: undefined,
114 | },
115 | ]
116 |
117 | > Snapshot 2
118 |
119 | [
120 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=28000',
121 | {
122 | cache: undefined,
123 | headers: {},
124 | responseType: 'json',
125 | retry: undefined,
126 | },
127 | ]
128 |
129 | ## lightweight » url without query params
130 |
131 | > Snapshot 1
132 |
133 | [
134 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
135 | {
136 | cache: undefined,
137 | headers: {},
138 | responseType: 'json',
139 | retry: undefined,
140 | },
141 | ]
142 |
143 | ## lightweight » apiKey
144 |
145 | > Snapshot 1
146 |
147 | [
148 | 'https://pro.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
149 | {
150 | cache: undefined,
151 | headers: {
152 | 'x-api-key': 'foobar',
153 | },
154 | responseType: 'json',
155 | retry: undefined,
156 | },
157 | ]
158 |
159 | ## lightweight » flatten options
160 |
161 | > Snapshot 1
162 |
163 | [
164 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&overlay.browser=dark',
165 | {
166 | cache: undefined,
167 | headers: {},
168 | responseType: 'json',
169 | retry: undefined,
170 | },
171 | ]
172 |
173 | ## lightweight » don't pass null
174 |
175 | > Snapshot 1
176 |
177 | [
178 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
179 | {
180 | cache: undefined,
181 | headers: {},
182 | responseType: 'json',
183 | retry: undefined,
184 | },
185 | ]
186 |
187 | > Snapshot 2
188 |
189 | [
190 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
191 | {
192 | cache: undefined,
193 | headers: {},
194 | responseType: 'json',
195 | retry: undefined,
196 | },
197 | ]
198 |
199 | ## lightweight » don't pass undefined
200 |
201 | > Snapshot 1
202 |
203 | [
204 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
205 | {
206 | cache: undefined,
207 | headers: {},
208 | responseType: 'json',
209 | retry: undefined,
210 | },
211 | ]
212 |
213 | > Snapshot 2
214 |
215 | [
216 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
217 | {
218 | cache: undefined,
219 | headers: {},
220 | responseType: 'json',
221 | retry: undefined,
222 | },
223 | ]
224 |
225 | ## lightweight » timeout
226 |
227 | > Snapshot 1
228 |
229 | [
230 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=15000',
231 | {
232 | cache: undefined,
233 | headers: {},
234 | responseType: 'json',
235 | retry: undefined,
236 | },
237 | ]
238 |
239 | > Snapshot 2
240 |
241 | [
242 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=28000',
243 | {
244 | cache: undefined,
245 | headers: {},
246 | responseType: 'json',
247 | retry: undefined,
248 | },
249 | ]
250 |
--------------------------------------------------------------------------------
/test/lightweight.test-d.ts:
--------------------------------------------------------------------------------
1 | import mql, { MicrolinkError, version } from '../lightweight'
2 | import type { MqlError } from '../lightweight'
3 |
4 | /** version */
5 |
6 | ;(async () => {
7 | console.log(version)
8 | })()
9 |
10 |
11 | /** error */
12 |
13 | ;(async () => {
14 | const error = new MicrolinkError({
15 | status: 'fail',
16 | data: { url: 'something goes wrong' },
17 | more: 'https://microlink.io/einvalurlclient',
18 | code: 'EINVALURLCLIENT',
19 | message: 'something goes wrong',
20 | url: 'https://example.com'
21 | })
22 |
23 | console.log(error.status)
24 | console.log(error.data)
25 | console.log(error.more)
26 | console.log(error.code)
27 | console.log(error.url)
28 | console.log(error.description)
29 | })()
30 |
31 | /** mql */
32 |
33 | ;(async () => {
34 | const result = await mql('https://example.com', {
35 | endpoint: 'https://pro.microlink.io',
36 | apiKey: '123',
37 | retry: 2,
38 | cache: new Map()
39 | })
40 |
41 | console.log(result.status)
42 | console.log(result.data)
43 | console.log(result.headers)
44 | console.log(result.response)
45 | console.log(result.response.statusCode)
46 | })()
47 |
48 | ;(async () => {
49 | const response = await mql('https://example.com', {
50 | stream: 'screenshot',
51 | screenshot: true
52 | })
53 | console.log(response.url)
54 | console.log(response.body)
55 | console.log(response.headers)
56 | console.log(response.statusCode)
57 | })()
58 |
59 | /** data */
60 |
61 | mql('https://example.com', {
62 | data: {
63 | version: {
64 | evaluate: 'window.next.version',
65 | type: 'string'
66 | }
67 | }
68 | })
69 |
70 | mql('https://github.com/microlinkhq', {
71 | data: {
72 | stats: {
73 | selector: '.application-main',
74 | attr: {
75 | followers: {
76 | selector: '.js-profile-editable-area a[href*="tab=followers"] span',
77 | type: 'number'
78 | },
79 | following: {
80 | selector: '.js-profile-editable-area a[href*="tab=following"] span',
81 | type: 'number'
82 | },
83 | stars: {
84 | selector: '.js-responsive-underlinenav a[data-tab-item="stars"] span',
85 | type: 'number'
86 | }
87 | }
88 | }
89 | }
90 | })
91 |
92 | /** meta */
93 |
94 | mql('https://example.com')
95 | mql('https://example.com', { meta: true })
96 | mql('https://example.com', { meta: { logo: { square: true } } })
97 |
98 | /** pdf */
99 |
100 | mql('https://example.com', { pdf: true })
101 | mql('https://example.com', {
102 | pdf: {
103 | format: 'A4',
104 | width: '480px',
105 | margin: {
106 | top: '4mm',
107 | bottom: '4mm',
108 | left: '4mm',
109 | right: '4mm'
110 | }
111 | }
112 | })
113 |
114 | /** screenshot */
115 |
116 | mql('https://example.com', { screenshot: true })
117 | mql('https://example.com', {
118 | screenshot: {
119 | codeScheme: 'atom-dark',
120 | type: 'png',
121 | optimizeForSpeed: true,
122 | overlay: {
123 | background: '#000',
124 | browser: 'light'
125 | }
126 | }
127 | })
128 |
129 | /** others */
130 |
131 | mql('https://example.com', { click: ['div'] })
132 | mql('https://example.com', {
133 | adblock: true,
134 | animations: false,
135 | audio: true,
136 | video: true
137 | })
138 |
139 | console.log(MicrolinkError)
140 | console.log(mql.version)
141 |
142 | /** response */
143 |
144 | const result = await mql('https://example.com', { meta: true })
145 | console.log(result.status)
146 | console.log(result.data)
147 | console.log(result.statusCode)
148 | console.log(result.headers)
149 |
150 | /** error */
151 |
152 | ;({
153 | status: 'error',
154 | data: { url: 'fetch failed' },
155 | more: 'https://microlink.io/efatalclient',
156 | code: 'EFATALCLIENT',
157 | url: 'https://localhost.microlink.io?url=https%3A%2F%2Fexample.com%23t%3D1696503516588',
158 | statusCode: undefined,
159 | headers: {},
160 | name: 'MicrolinkError',
161 | message: 'EFATALCLIENT, fetch failed',
162 | description: 'fetch failed'
163 | } as MqlError)
164 |
165 | ;({
166 | status: 'fail',
167 | code: 'EAUTH',
168 | more: 'https://microlink.io/eauth',
169 | url: 'https://pro.microlink.io?url=https%3A%2F%2Fexample.com%23t%3D1696503754740',
170 | statusCode: 403,
171 | headers: {
172 | 'alt-svc': 'h3=":443"; ma=86400',
173 | 'cf-cache-status': 'BYPASS',
174 | 'cf-ray': '81152c548f405e54-MAD',
175 | connection: 'keep-alive',
176 | 'content-encoding': 'br',
177 | 'content-type': 'application/json',
178 | date: 'Thu, 05 Oct 2023 11:02:35 GMT',
179 | nel: '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}',
180 | 'report-to':
181 | '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=6tEv%2Fk7XkC0so782muCCxAfbFeaMusFvyv839c8Xv74aKQFy1jD%2Fd8hRrldtfntrhuzCi5HG8W%2FlBxk1a9qKqxHObl79FhxBnK6pAOF6gGXc9Vi0wHnXb1hayCkTxolfpR7yoH89el9W34r1T8E%3D"}],"group":"cf-nel","max_age":604800}',
182 | server: 'cloudflare',
183 | 'transfer-encoding': 'chunked',
184 | vary: 'Accept-Encoding',
185 | via: '1.1 2d741086cf4a760a29245ab77d5fa70a.cloudfront.net (CloudFront)',
186 | 'x-amz-apigw-id': 'MUynzHpvIAMEtpA=',
187 | 'x-amz-cf-id': 'YPxW5fWYSiPgHuOiocQyYkCFoxWDsuV4MtRBh1Yiym3m1b361Q2fgQ==',
188 | 'x-amz-cf-pop': 'MAD56-P2',
189 | 'x-amzn-errortype': 'ForbiddenException',
190 | 'x-amzn-requestid': '7990f38f-d004-49cc-a406-f7cd0cb7df07',
191 | 'x-cache': 'Error from cloudfront'
192 | },
193 | name: 'MicrolinkError',
194 | message:
195 | 'EAUTH, Invalid API key. Make sure you are attaching your API key as `x-api-key` header.',
196 | description:
197 | 'Invalid API key. Make sure you are attaching your API key as `x-api-key` header.'
198 | } as MqlError)
199 |
200 | /* extend */
201 |
202 | mql.extend({ responseType: 'text' })
203 |
204 | /* stream */
205 |
206 | mql.stream('https://example.com', { headers: { 'user-agent': 'foo' } })
207 |
208 | /* arrraBuffer */
209 |
210 | {
211 | const response = await mql.arrayBuffer('https://example.com', { meta: false })
212 | console.log(response.body)
213 | }
214 |
215 | /* redirects */
216 |
217 | {
218 | const response = await mql('https://example.com', { meta: false })
219 | console.log(response.redirects)
220 | }
221 |
--------------------------------------------------------------------------------
/lightweight/index.d.ts:
--------------------------------------------------------------------------------
1 | export type ColorScheme = 'dark' | 'light'
2 |
3 | type WaitUntilEvent =
4 | | 'load'
5 | | 'domcontentloaded'
6 | | 'networkidle0'
7 | | 'networkidle2'
8 |
9 | type PixelUnit = string | number
10 |
11 | type ScreenshotOverlay = {
12 | background?: string
13 | browser?: 'dark' | 'light'
14 | }
15 |
16 | type PdfMargin = {
17 | bottom?: string | number
18 | left?: string | number
19 | right?: string | number
20 | top?: string | number
21 | }
22 |
23 | type PdfOptions = {
24 | format?: string
25 | height?: PixelUnit
26 | landscape?: string
27 | margin?: string | PdfMargin
28 | pageRanges?: string
29 | scale?: number
30 | width?: PixelUnit
31 | }
32 |
33 | type ScreenshotOptions = {
34 | codeScheme?: string
35 | element?: string
36 | fullPage?: boolean
37 | omitBackground?: boolean
38 | optimizeForSpeed?: boolean
39 | overlay?: ScreenshotOverlay
40 | type?: 'jpeg' | 'png'
41 | }
42 |
43 | type MqlClientOptions = {
44 | apiKey?: string
45 | cache?: Map
46 | endpoint?: string
47 | retry?: number
48 | }
49 |
50 | type MqlQuery = {
51 | [field: string]: MqlQueryOptions
52 | }
53 |
54 | type MqlQueryOptions = {
55 | attr?: string | string[] | MqlQuery
56 | evaluate?: string
57 | selector?: string | string[]
58 | selectorAll?: string | string[]
59 | type?:
60 | | 'audio'
61 | | 'author'
62 | | 'auto'
63 | | 'boolean'
64 | | 'date'
65 | | 'description'
66 | | 'email'
67 | | 'image'
68 | | 'ip'
69 | | 'lang'
70 | | 'logo'
71 | | 'number'
72 | | 'object'
73 | | 'publisher'
74 | | 'regexp'
75 | | 'string'
76 | | 'title'
77 | | 'url'
78 | | 'video'
79 | }
80 |
81 | export type MicrolinkApiOptions = {
82 | adblock?: boolean
83 | animations?: boolean
84 | audio?: boolean
85 | click?: string | string[]
86 | colorScheme?: ColorScheme
87 | data?: MqlQuery
88 | device?: string
89 | embed?: string
90 | filename?: string
91 | filter?: string
92 | force?: boolean
93 | function?: string
94 | headers?: Record
95 | iframe?: boolean | { maxWidth?: number; maxHeight?: number }
96 | insights?: boolean | { lighthouse?: boolean | object; technologies?: boolean }
97 | javascript?: boolean
98 | mediaType?: string
99 | meta?: boolean | { logo: { square: boolean } }
100 | modules?: string | string[]
101 | palette?: boolean
102 | pdf?: boolean | PdfOptions
103 | ping?: boolean | object
104 | prerender?: boolean | 'auto'
105 | proxy?: string | { countryCode?: string }
106 | retry?: number
107 | screenshot?: boolean | ScreenshotOptions
108 | scripts?: string | string[]
109 | scroll?: string
110 | staleTtl?: string | number
111 | stream?: string
112 | styles?: string | string[]
113 | timeout?: string | number
114 | ttl?: string | number
115 | video?: boolean
116 | viewport?: object
117 | waitForSelector?: string
118 | waitForTimeout?: string | number
119 | waitUntil?: WaitUntilEvent | WaitUntilEvent[]
120 | }
121 |
122 | type IframeInfo = {
123 | html: string
124 | scripts: Record
125 | }
126 |
127 | type MediaInfo = {
128 | alternative_color?: string
129 | background_color?: string
130 | color?: string
131 | duration_pretty?: string
132 | duration?: number
133 | height?: number
134 | palette?: string[]
135 | size_pretty?: string
136 | size?: number
137 | type?: string
138 | url: string
139 | width?: number
140 | }
141 |
142 | export type MqlResponseData = {
143 | audio?: MediaInfo | null
144 | author?: string | null
145 | date?: string | null
146 | description?: string | null
147 | function?: MqlFunctionResult
148 | iframe?: IframeInfo | null
149 | image?: MediaInfo | null
150 | lang?: string | null
151 | logo?: MediaInfo | null
152 | publisher?: string | null
153 | screenshot?: MediaInfo | null
154 | title?: string | null
155 | url?: string
156 | video?: MediaInfo | null
157 | }
158 |
159 | type MqlFunctionResult = {
160 | isFulfilled: boolean
161 | isRejected: boolean
162 | value: any
163 | }
164 |
165 | type MqlStatus = 'success' | 'fail' | 'error'
166 |
167 | export type MqlPayload = {
168 | status: MqlStatus
169 | data: MqlResponseData
170 | statusCode?: number
171 | redirects: { statusCode: number; url: string }[]
172 | headers: { [key: string]: string }
173 | }
174 |
175 | type HTTPResponse = {
176 | url: string
177 | statusCode: number
178 | headers: Headers
179 | }
180 |
181 | type HTTPResponseWithBody = HTTPResponse & { body: MqlPayload }
182 |
183 | export type HTTPResponseRaw = HTTPResponse & { body: ArrayBuffer }
184 |
185 | export type MqlResponse = MqlPayload & { response: HTTPResponseWithBody }
186 |
187 | export type MqlOptions = MqlClientOptions & MicrolinkApiOptions
188 |
189 | type MqlErrorGeneratedProps = {
190 | description: string
191 | name: string
192 | }
193 |
194 | export type MqlErrorProps = {
195 | code: string
196 | status: MqlStatus
197 | message: string
198 | data?: MqlResponseData
199 | headers?: { [key: string]: string }
200 | more?: string
201 | statusCode?: number
202 | url?: string
203 | }
204 |
205 | export type MqlError = MqlErrorProps & MqlErrorGeneratedProps
206 |
207 | export declare class MicrolinkError extends Error {
208 | constructor(props: MqlErrorProps)
209 | readonly code: string
210 | readonly status: MqlStatus
211 | readonly message: string
212 | readonly description: string
213 | readonly name: string
214 | readonly data?: MqlResponseData
215 | readonly headers?: { [key: string]: string }
216 | readonly more?: string
217 | readonly statusCode?: number
218 | readonly url?: string
219 | }
220 |
221 | export const version: string
222 |
223 | interface mql {
224 | (
225 | url: string,
226 | opts?: MqlOptions & { stream: string },
227 | gotOpts?: object
228 | ): Promise
229 | (url: string, opts?: MqlOptions, gotOpts?: object): Promise
230 | arrayBuffer: (
231 | url: string,
232 | opts?: MqlOptions,
233 | gotOpts?: object
234 | ) => Promise
235 | extend: (gotOpts?: object) => mql
236 | stream: (input: RequestInfo, init?: RequestInit) => ReadableStream
237 | MicrolinkError: new (props: object) => MqlErrorProps
238 | version: string
239 | }
240 |
241 | declare const mql: mql
242 |
243 | export default mql
244 |
--------------------------------------------------------------------------------
/test/snapshots/get-api-url.mjs.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/get-api-url.mjs`
2 |
3 | The actual snapshot is saved in `get-api-url.mjs.snap`.
4 |
5 | Generated by [AVA](https://avajs.dev).
6 |
7 | ## node » url without query params
8 |
9 | > Snapshot 1
10 |
11 | [
12 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
13 | {
14 | headers: {},
15 | responseType: 'json',
16 | },
17 | ]
18 |
19 | ## node » apiKey
20 |
21 | > Snapshot 1
22 |
23 | [
24 | 'https://pro.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
25 | {
26 | headers: {
27 | 'x-api-key': 'foobar',
28 | },
29 | responseType: 'json',
30 | },
31 | ]
32 |
33 | ## node » flatten options
34 |
35 | > Snapshot 1
36 |
37 | [
38 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&overlay.browser=dark',
39 | {
40 | headers: {},
41 | responseType: 'json',
42 | },
43 | ]
44 |
45 | ## node » don't pass null
46 |
47 | > Snapshot 1
48 |
49 | [
50 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
51 | {
52 | headers: {},
53 | responseType: 'json',
54 | },
55 | ]
56 |
57 | > Snapshot 2
58 |
59 | [
60 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
61 | {
62 | headers: {},
63 | responseType: 'json',
64 | },
65 | ]
66 |
67 | ## node » don't pass undefined
68 |
69 | > Snapshot 1
70 |
71 | [
72 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
73 | {
74 | headers: {},
75 | responseType: 'json',
76 | },
77 | ]
78 |
79 | > Snapshot 2
80 |
81 | [
82 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
83 | {
84 | headers: {},
85 | responseType: 'json',
86 | },
87 | ]
88 |
89 | ## node » timeout
90 |
91 | > Snapshot 1
92 |
93 | [
94 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=15000',
95 | {
96 | headers: {},
97 | responseType: 'json',
98 | },
99 | ]
100 |
101 | > Snapshot 2
102 |
103 | [
104 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=28000',
105 | {
106 | headers: {},
107 | responseType: 'json',
108 | },
109 | ]
110 |
111 | ## node » waitUntil
112 |
113 | > Snapshot 1
114 |
115 | [
116 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&waitUntil=load',
117 | {
118 | headers: {},
119 | responseType: 'json',
120 | },
121 | ]
122 |
123 | > Snapshot 2
124 |
125 | [
126 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&waitUntil.0=load&waitUntil.1=networkidle0',
127 | {
128 | headers: {},
129 | responseType: 'json',
130 | },
131 | ]
132 |
133 | ## node » undefined
134 |
135 | > Snapshot 1
136 |
137 | [
138 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
139 | {
140 | headers: {},
141 | responseType: 'json',
142 | },
143 | ]
144 |
145 | > Snapshot 2
146 |
147 | [
148 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&screenshot.element=%23screenshot',
149 | {
150 | headers: {},
151 | responseType: 'json',
152 | },
153 | ]
154 |
155 | ## lightweight » url without query params
156 |
157 | > Snapshot 1
158 |
159 | [
160 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
161 | {
162 | headers: {},
163 | responseType: 'json',
164 | },
165 | ]
166 |
167 | ## lightweight » apiKey
168 |
169 | > Snapshot 1
170 |
171 | [
172 | 'https://pro.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
173 | {
174 | headers: {
175 | 'x-api-key': 'foobar',
176 | },
177 | responseType: 'json',
178 | },
179 | ]
180 |
181 | ## lightweight » flatten options
182 |
183 | > Snapshot 1
184 |
185 | [
186 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&overlay.browser=dark',
187 | {
188 | headers: {},
189 | responseType: 'json',
190 | },
191 | ]
192 |
193 | ## lightweight » don't pass null
194 |
195 | > Snapshot 1
196 |
197 | [
198 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
199 | {
200 | headers: {},
201 | responseType: 'json',
202 | },
203 | ]
204 |
205 | > Snapshot 2
206 |
207 | [
208 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
209 | {
210 | headers: {},
211 | responseType: 'json',
212 | },
213 | ]
214 |
215 | ## lightweight » don't pass undefined
216 |
217 | > Snapshot 1
218 |
219 | [
220 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
221 | {
222 | headers: {},
223 | responseType: 'json',
224 | },
225 | ]
226 |
227 | > Snapshot 2
228 |
229 | [
230 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
231 | {
232 | headers: {},
233 | responseType: 'json',
234 | },
235 | ]
236 |
237 | ## lightweight » timeout
238 |
239 | > Snapshot 1
240 |
241 | [
242 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=15000',
243 | {
244 | headers: {},
245 | responseType: 'json',
246 | },
247 | ]
248 |
249 | > Snapshot 2
250 |
251 | [
252 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&timeout=28000',
253 | {
254 | headers: {},
255 | responseType: 'json',
256 | },
257 | ]
258 |
259 | ## lightweight » waitUntil
260 |
261 | > Snapshot 1
262 |
263 | [
264 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&waitUntil=load',
265 | {
266 | headers: {},
267 | responseType: 'json',
268 | },
269 | ]
270 |
271 | > Snapshot 2
272 |
273 | [
274 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&waitUntil.0=load&waitUntil.1=networkidle0',
275 | {
276 | headers: {},
277 | responseType: 'json',
278 | },
279 | ]
280 |
281 | ## lightweight » undefined
282 |
283 | > Snapshot 1
284 |
285 | [
286 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com',
287 | {
288 | headers: {},
289 | responseType: 'json',
290 | },
291 | ]
292 |
293 | > Snapshot 2
294 |
295 | [
296 | 'https://api.microlink.io/?url=https%3A%2F%2Fkikobeats.com&screenshot.element=%23screenshot',
297 | {
298 | headers: {},
299 | responseType: 'json',
300 | },
301 | ]
302 |
--------------------------------------------------------------------------------
/lightweight/index.umd.js:
--------------------------------------------------------------------------------
1 | ;(function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined'
3 | ? factory(exports)
4 | : typeof define === 'function' && define.amd
5 | ? define(['exports'], factory)
6 | : ((global =
7 | typeof globalThis !== 'undefined' ? globalThis : global || self),
8 | factory((global.mql = {})))
9 | })(this, function (exports) {
10 | 'use strict'
11 |
12 | function getDefaultExportFromCjs (x) {
13 | return x &&
14 | x.__esModule &&
15 | Object.prototype.hasOwnProperty.call(x, 'default')
16 | ? x['default']
17 | : x
18 | }
19 |
20 | function getAugmentedNamespace (n) {
21 | if (n.__esModule) return n
22 | var f = n.default
23 | if (typeof f == 'function') {
24 | var a = function a () {
25 | if (this instanceof a) {
26 | return Reflect.construct(f, arguments, this.constructor)
27 | }
28 | return f.apply(this, arguments)
29 | }
30 | a.prototype = f.prototype
31 | } else a = {}
32 | Object.defineProperty(a, '__esModule', { value: true })
33 | Object.keys(n).forEach(function (k) {
34 | var d = Object.getOwnPropertyDescriptor(n, k)
35 | Object.defineProperty(
36 | a,
37 | k,
38 | d.get
39 | ? d
40 | : {
41 | enumerable: true,
42 | get: function () {
43 | return n[k]
44 | }
45 | }
46 | )
47 | })
48 | return a
49 | }
50 |
51 | var lightweight$1 = { exports: {} }
52 |
53 | var dist = {}
54 |
55 | function iter (output, nullish, sep, val, key) {
56 | var k,
57 | pfx = key ? key + sep : key
58 |
59 | if (val == null) {
60 | if (nullish) output[key] = val
61 | } else if (typeof val != 'object') {
62 | output[key] = val
63 | } else if (Array.isArray(val)) {
64 | for (k = 0; k < val.length; k++) {
65 | iter(output, nullish, sep, val[k], pfx + k)
66 | }
67 | } else {
68 | for (k in val) {
69 | iter(output, nullish, sep, val[k], pfx + k)
70 | }
71 | }
72 | }
73 |
74 | function flattie (input, glue, toNull) {
75 | var output = {}
76 | if (typeof input == 'object') {
77 | iter(output, !!toNull, glue || '.', input, '')
78 | }
79 | return output
80 | }
81 |
82 | dist.flattie = flattie
83 |
84 | class HTTPError extends Error {
85 | response
86 | request
87 | options
88 | constructor (response, request, options) {
89 | const code =
90 | response.status || response.status === 0 ? response.status : ''
91 | const title = response.statusText || ''
92 | const status = `${code} ${title}`.trim()
93 | const reason = status ? `status code ${status}` : 'an unknown error'
94 | super(`Request failed with ${reason}: ${request.method} ${request.url}`)
95 | this.name = 'HTTPError'
96 | this.response = response
97 | this.request = request
98 | this.options = options
99 | }
100 | }
101 |
102 | class TimeoutError extends Error {
103 | request
104 | constructor (request) {
105 | super(`Request timed out: ${request.method} ${request.url}`)
106 | this.name = 'TimeoutError'
107 | this.request = request
108 | }
109 | }
110 |
111 | // eslint-disable-next-line @typescript-eslint/ban-types
112 | const isObject$1 = value => value !== null && typeof value === 'object'
113 |
114 | const validateAndMerge = (...sources) => {
115 | for (const source of sources) {
116 | if (
117 | (!isObject$1(source) || Array.isArray(source)) &&
118 | source !== undefined
119 | ) {
120 | throw new TypeError('The `options` argument must be an object')
121 | }
122 | }
123 | return deepMerge({}, ...sources)
124 | }
125 | const mergeHeaders = (source1 = {}, source2 = {}) => {
126 | const result = new globalThis.Headers(source1)
127 | const isHeadersInstance = source2 instanceof globalThis.Headers
128 | const source = new globalThis.Headers(source2)
129 | for (const [key, value] of source.entries()) {
130 | if ((isHeadersInstance && value === 'undefined') || value === undefined) {
131 | result.delete(key)
132 | } else {
133 | result.set(key, value)
134 | }
135 | }
136 | return result
137 | }
138 | function newHookValue (original, incoming, property) {
139 | return Object.hasOwn(incoming, property) && incoming[property] === undefined
140 | ? []
141 | : deepMerge(original[property] ?? [], incoming[property] ?? [])
142 | }
143 | const mergeHooks = (original = {}, incoming = {}) => ({
144 | beforeRequest: newHookValue(original, incoming, 'beforeRequest'),
145 | beforeRetry: newHookValue(original, incoming, 'beforeRetry'),
146 | afterResponse: newHookValue(original, incoming, 'afterResponse'),
147 | beforeError: newHookValue(original, incoming, 'beforeError')
148 | })
149 | // TODO: Make this strongly-typed (no `any`).
150 | const deepMerge = (...sources) => {
151 | let returnValue = {}
152 | let headers = {}
153 | let hooks = {}
154 | for (const source of sources) {
155 | if (Array.isArray(source)) {
156 | if (!Array.isArray(returnValue)) {
157 | returnValue = []
158 | }
159 | returnValue = [...returnValue, ...source]
160 | } else if (isObject$1(source)) {
161 | for (let [key, value] of Object.entries(source)) {
162 | if (isObject$1(value) && key in returnValue) {
163 | value = deepMerge(returnValue[key], value)
164 | }
165 | returnValue = { ...returnValue, [key]: value }
166 | }
167 | if (isObject$1(source.hooks)) {
168 | hooks = mergeHooks(hooks, source.hooks)
169 | returnValue.hooks = hooks
170 | }
171 | if (isObject$1(source.headers)) {
172 | headers = mergeHeaders(headers, source.headers)
173 | returnValue.headers = headers
174 | }
175 | }
176 | }
177 | return returnValue
178 | }
179 |
180 | const supportsRequestStreams = (() => {
181 | let duplexAccessed = false
182 | let hasContentType = false
183 | const supportsReadableStream =
184 | typeof globalThis.ReadableStream === 'function'
185 | const supportsRequest = typeof globalThis.Request === 'function'
186 | if (supportsReadableStream && supportsRequest) {
187 | try {
188 | hasContentType = new globalThis.Request('https://empty.invalid', {
189 | body: new globalThis.ReadableStream(),
190 | method: 'POST',
191 | // @ts-expect-error - Types are outdated.
192 | get duplex () {
193 | duplexAccessed = true
194 | return 'half'
195 | }
196 | }).headers.has('Content-Type')
197 | } catch (error) {
198 | // QQBrowser on iOS throws "unsupported BodyInit type" error (see issue #581)
199 | if (
200 | error instanceof Error &&
201 | error.message === 'unsupported BodyInit type'
202 | ) {
203 | return false
204 | }
205 | throw error
206 | }
207 | }
208 | return duplexAccessed && !hasContentType
209 | })()
210 | const supportsAbortController =
211 | typeof globalThis.AbortController === 'function'
212 | const supportsResponseStreams =
213 | typeof globalThis.ReadableStream === 'function'
214 | const supportsFormData = typeof globalThis.FormData === 'function'
215 | const requestMethods = ['get', 'post', 'put', 'patch', 'head', 'delete']
216 | const responseTypes = {
217 | json: 'application/json',
218 | text: 'text/*',
219 | formData: 'multipart/form-data',
220 | arrayBuffer: '*/*',
221 | blob: '*/*'
222 | }
223 | // The maximum value of a 32bit int (see issue #117)
224 | const maxSafeTimeout = 2_147_483_647
225 | const stop = Symbol('stop')
226 | const kyOptionKeys = {
227 | json: true,
228 | parseJson: true,
229 | stringifyJson: true,
230 | searchParams: true,
231 | prefixUrl: true,
232 | retry: true,
233 | timeout: true,
234 | hooks: true,
235 | throwHttpErrors: true,
236 | onDownloadProgress: true,
237 | fetch: true
238 | }
239 | const requestOptionsRegistry = {
240 | method: true,
241 | headers: true,
242 | body: true,
243 | mode: true,
244 | credentials: true,
245 | cache: true,
246 | redirect: true,
247 | referrer: true,
248 | referrerPolicy: true,
249 | integrity: true,
250 | keepalive: true,
251 | signal: true,
252 | window: true,
253 | dispatcher: true,
254 | duplex: true,
255 | priority: true
256 | }
257 |
258 | const normalizeRequestMethod = input =>
259 | requestMethods.includes(input) ? input.toUpperCase() : input
260 | const retryMethods = ['get', 'put', 'head', 'delete', 'options', 'trace']
261 | const retryStatusCodes = [408, 413, 429, 500, 502, 503, 504]
262 | const retryAfterStatusCodes = [413, 429, 503]
263 | const defaultRetryOptions = {
264 | limit: 2,
265 | methods: retryMethods,
266 | statusCodes: retryStatusCodes,
267 | afterStatusCodes: retryAfterStatusCodes,
268 | maxRetryAfter: Number.POSITIVE_INFINITY,
269 | backoffLimit: Number.POSITIVE_INFINITY,
270 | delay: attemptCount => 0.3 * 2 ** (attemptCount - 1) * 1000
271 | }
272 | const normalizeRetryOptions = (retry = {}) => {
273 | if (typeof retry === 'number') {
274 | return {
275 | ...defaultRetryOptions,
276 | limit: retry
277 | }
278 | }
279 | if (retry.methods && !Array.isArray(retry.methods)) {
280 | throw new Error('retry.methods must be an array')
281 | }
282 | if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {
283 | throw new Error('retry.statusCodes must be an array')
284 | }
285 | return {
286 | ...defaultRetryOptions,
287 | ...retry
288 | }
289 | }
290 |
291 | // `Promise.race()` workaround (#91)
292 | async function timeout (request, init, abortController, options) {
293 | return new Promise((resolve, reject) => {
294 | const timeoutId = setTimeout(() => {
295 | if (abortController) {
296 | abortController.abort()
297 | }
298 | reject(new TimeoutError(request))
299 | }, options.timeout)
300 | void options
301 | .fetch(request, init)
302 | .then(resolve)
303 | .catch(reject)
304 | .then(() => {
305 | clearTimeout(timeoutId)
306 | })
307 | })
308 | }
309 |
310 | // https://github.com/sindresorhus/delay/tree/ab98ae8dfcb38e1593286c94d934e70d14a4e111
311 | async function delay (ms, { signal }) {
312 | return new Promise((resolve, reject) => {
313 | if (signal) {
314 | signal.throwIfAborted()
315 | signal.addEventListener('abort', abortHandler, { once: true })
316 | }
317 | function abortHandler () {
318 | clearTimeout(timeoutId)
319 | reject(signal.reason)
320 | }
321 | const timeoutId = setTimeout(() => {
322 | signal?.removeEventListener('abort', abortHandler)
323 | resolve()
324 | }, ms)
325 | })
326 | }
327 |
328 | const findUnknownOptions = (request, options) => {
329 | const unknownOptions = {}
330 | for (const key in options) {
331 | if (
332 | !(key in requestOptionsRegistry) &&
333 | !(key in kyOptionKeys) &&
334 | !(key in request)
335 | ) {
336 | unknownOptions[key] = options[key]
337 | }
338 | }
339 | return unknownOptions
340 | }
341 |
342 | class Ky {
343 | static create (input, options) {
344 | const ky = new Ky(input, options)
345 | const function_ = async () => {
346 | if (
347 | typeof ky._options.timeout === 'number' &&
348 | ky._options.timeout > maxSafeTimeout
349 | ) {
350 | throw new RangeError(
351 | `The \`timeout\` option cannot be greater than ${maxSafeTimeout}`
352 | )
353 | }
354 | // Delay the fetch so that body method shortcuts can set the Accept header
355 | await Promise.resolve()
356 | let response = await ky._fetch()
357 | for (const hook of ky._options.hooks.afterResponse) {
358 | // eslint-disable-next-line no-await-in-loop
359 | const modifiedResponse = await hook(
360 | ky.request,
361 | ky._options,
362 | ky._decorateResponse(response.clone())
363 | )
364 | if (modifiedResponse instanceof globalThis.Response) {
365 | response = modifiedResponse
366 | }
367 | }
368 | ky._decorateResponse(response)
369 | if (!response.ok && ky._options.throwHttpErrors) {
370 | let error = new HTTPError(response, ky.request, ky._options)
371 | for (const hook of ky._options.hooks.beforeError) {
372 | // eslint-disable-next-line no-await-in-loop
373 | error = await hook(error)
374 | }
375 | throw error
376 | }
377 | // If `onDownloadProgress` is passed, it uses the stream API internally
378 | /* istanbul ignore next */
379 | if (ky._options.onDownloadProgress) {
380 | if (typeof ky._options.onDownloadProgress !== 'function') {
381 | throw new TypeError(
382 | 'The `onDownloadProgress` option must be a function'
383 | )
384 | }
385 | if (!supportsResponseStreams) {
386 | throw new Error(
387 | 'Streams are not supported in your environment. `ReadableStream` is missing.'
388 | )
389 | }
390 | return ky._stream(response.clone(), ky._options.onDownloadProgress)
391 | }
392 | return response
393 | }
394 | const isRetriableMethod = ky._options.retry.methods.includes(
395 | ky.request.method.toLowerCase()
396 | )
397 | const result = isRetriableMethod ? ky._retry(function_) : function_()
398 | for (const [type, mimeType] of Object.entries(responseTypes)) {
399 | result[type] = async () => {
400 | // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
401 | ky.request.headers.set(
402 | 'accept',
403 | ky.request.headers.get('accept') || mimeType
404 | )
405 | const awaitedResult = await result
406 | const response = awaitedResult.clone()
407 | if (type === 'json') {
408 | if (response.status === 204) {
409 | return ''
410 | }
411 | const arrayBuffer = await response.clone().arrayBuffer()
412 | const responseSize = arrayBuffer.byteLength
413 | if (responseSize === 0) {
414 | return ''
415 | }
416 | if (options.parseJson) {
417 | return options.parseJson(await response.text())
418 | }
419 | }
420 | return response[type]()
421 | }
422 | }
423 | return result
424 | }
425 | request
426 | abortController
427 | _retryCount = 0
428 | _input
429 | _options
430 | // eslint-disable-next-line complexity
431 | constructor (input, options = {}) {
432 | this._input = input
433 | this._options = {
434 | ...options,
435 | headers: mergeHeaders(this._input.headers, options.headers),
436 | hooks: mergeHooks(
437 | {
438 | beforeRequest: [],
439 | beforeRetry: [],
440 | beforeError: [],
441 | afterResponse: []
442 | },
443 | options.hooks
444 | ),
445 | method: normalizeRequestMethod(options.method ?? this._input.method),
446 | // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
447 | prefixUrl: String(options.prefixUrl || ''),
448 | retry: normalizeRetryOptions(options.retry),
449 | throwHttpErrors: options.throwHttpErrors !== false,
450 | timeout: options.timeout ?? 10_000,
451 | fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
452 | }
453 | if (
454 | typeof this._input !== 'string' &&
455 | !(
456 | this._input instanceof URL ||
457 | this._input instanceof globalThis.Request
458 | )
459 | ) {
460 | throw new TypeError('`input` must be a string, URL, or Request')
461 | }
462 | if (this._options.prefixUrl && typeof this._input === 'string') {
463 | if (this._input.startsWith('/')) {
464 | throw new Error(
465 | '`input` must not begin with a slash when using `prefixUrl`'
466 | )
467 | }
468 | if (!this._options.prefixUrl.endsWith('/')) {
469 | this._options.prefixUrl += '/'
470 | }
471 | this._input = this._options.prefixUrl + this._input
472 | }
473 | if (supportsAbortController) {
474 | this.abortController = new globalThis.AbortController()
475 | const originalSignal = this._options.signal ?? this._input.signal
476 | originalSignal?.addEventListener('abort', () => {
477 | this.abortController.abort(originalSignal.reason)
478 | })
479 | this._options.signal = this.abortController.signal
480 | }
481 | if (supportsRequestStreams) {
482 | // @ts-expect-error - Types are outdated.
483 | this._options.duplex = 'half'
484 | }
485 | if (this._options.json !== undefined) {
486 | this._options.body =
487 | this._options.stringifyJson?.(this._options.json) ??
488 | JSON.stringify(this._options.json)
489 | this._options.headers.set(
490 | 'content-type',
491 | this._options.headers.get('content-type') ?? 'application/json'
492 | )
493 | }
494 | this.request = new globalThis.Request(this._input, this._options)
495 | if (this._options.searchParams) {
496 | // eslint-disable-next-line unicorn/prevent-abbreviations
497 | const textSearchParams =
498 | typeof this._options.searchParams === 'string'
499 | ? this._options.searchParams.replace(/^\?/, '')
500 | : new URLSearchParams(this._options.searchParams).toString()
501 | // eslint-disable-next-line unicorn/prevent-abbreviations
502 | const searchParams = '?' + textSearchParams
503 | const url = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, searchParams)
504 | // To provide correct form boundary, Content-Type header should be deleted each time when new Request instantiated from another one
505 | if (
506 | ((supportsFormData &&
507 | this._options.body instanceof globalThis.FormData) ||
508 | this._options.body instanceof URLSearchParams) &&
509 | !(this._options.headers && this._options.headers['content-type'])
510 | ) {
511 | this.request.headers.delete('content-type')
512 | }
513 | // The spread of `this.request` is required as otherwise it misses the `duplex` option for some reason and throws.
514 | this.request = new globalThis.Request(
515 | new globalThis.Request(url, { ...this.request }),
516 | this._options
517 | )
518 | }
519 | }
520 | _calculateRetryDelay (error) {
521 | this._retryCount++
522 | if (
523 | this._retryCount > this._options.retry.limit ||
524 | error instanceof TimeoutError
525 | ) {
526 | throw error
527 | }
528 | if (error instanceof HTTPError) {
529 | if (!this._options.retry.statusCodes.includes(error.response.status)) {
530 | throw error
531 | }
532 | const retryAfter =
533 | error.response.headers.get('Retry-After') ??
534 | error.response.headers.get('RateLimit-Reset') ??
535 | error.response.headers.get('X-RateLimit-Reset') ?? // GitHub
536 | error.response.headers.get('X-Rate-Limit-Reset') // Twitter
537 | if (
538 | retryAfter &&
539 | this._options.retry.afterStatusCodes.includes(error.response.status)
540 | ) {
541 | let after = Number(retryAfter) * 1000
542 | if (Number.isNaN(after)) {
543 | after = Date.parse(retryAfter) - Date.now()
544 | } else if (after >= Date.parse('2024-01-01')) {
545 | // A large number is treated as a timestamp (fixed threshold protects against clock skew)
546 | after -= Date.now()
547 | }
548 | const max = this._options.retry.maxRetryAfter ?? after
549 | return after < max ? after : max
550 | }
551 | if (error.response.status === 413) {
552 | throw error
553 | }
554 | }
555 | const retryDelay = this._options.retry.delay(this._retryCount)
556 | return Math.min(this._options.retry.backoffLimit, retryDelay)
557 | }
558 | _decorateResponse (response) {
559 | if (this._options.parseJson) {
560 | response.json = async () =>
561 | this._options.parseJson(await response.text())
562 | }
563 | return response
564 | }
565 | async _retry (function_) {
566 | try {
567 | return await function_()
568 | } catch (error) {
569 | const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout)
570 | if (this._retryCount < 1) {
571 | throw error
572 | }
573 | await delay(ms, { signal: this._options.signal })
574 | for (const hook of this._options.hooks.beforeRetry) {
575 | // eslint-disable-next-line no-await-in-loop
576 | const hookResult = await hook({
577 | request: this.request,
578 | options: this._options,
579 | error: error,
580 | retryCount: this._retryCount
581 | })
582 | // If `stop` is returned from the hook, the retry process is stopped
583 | if (hookResult === stop) {
584 | return
585 | }
586 | }
587 | return this._retry(function_)
588 | }
589 | }
590 | async _fetch () {
591 | for (const hook of this._options.hooks.beforeRequest) {
592 | // eslint-disable-next-line no-await-in-loop
593 | const result = await hook(this.request, this._options)
594 | if (result instanceof Request) {
595 | this.request = result
596 | break
597 | }
598 | if (result instanceof Response) {
599 | return result
600 | }
601 | }
602 | const nonRequestOptions = findUnknownOptions(this.request, this._options)
603 | // Cloning is done here to prepare in advance for retries
604 | const mainRequest = this.request
605 | this.request = mainRequest.clone()
606 | if (this._options.timeout === false) {
607 | return this._options.fetch(mainRequest, nonRequestOptions)
608 | }
609 | return timeout(
610 | mainRequest,
611 | nonRequestOptions,
612 | this.abortController,
613 | this._options
614 | )
615 | }
616 | /* istanbul ignore next */
617 | _stream (response, onDownloadProgress) {
618 | const totalBytes = Number(response.headers.get('content-length')) || 0
619 | let transferredBytes = 0
620 | if (response.status === 204) {
621 | if (onDownloadProgress) {
622 | onDownloadProgress(
623 | { percent: 1, totalBytes, transferredBytes },
624 | new Uint8Array()
625 | )
626 | }
627 | return new globalThis.Response(null, {
628 | status: response.status,
629 | statusText: response.statusText,
630 | headers: response.headers
631 | })
632 | }
633 | return new globalThis.Response(
634 | new globalThis.ReadableStream({
635 | async start (controller) {
636 | const reader = response.body.getReader()
637 | if (onDownloadProgress) {
638 | onDownloadProgress(
639 | { percent: 0, transferredBytes: 0, totalBytes },
640 | new Uint8Array()
641 | )
642 | }
643 | async function read () {
644 | const { done, value } = await reader.read()
645 | if (done) {
646 | controller.close()
647 | return
648 | }
649 | if (onDownloadProgress) {
650 | transferredBytes += value.byteLength
651 | const percent =
652 | totalBytes === 0 ? 0 : transferredBytes / totalBytes
653 | onDownloadProgress(
654 | { percent, transferredBytes, totalBytes },
655 | value
656 | )
657 | }
658 | controller.enqueue(value)
659 | await read()
660 | }
661 | await read()
662 | }
663 | }),
664 | {
665 | status: response.status,
666 | statusText: response.statusText,
667 | headers: response.headers
668 | }
669 | )
670 | }
671 | }
672 |
673 | /*! MIT License © Sindre Sorhus */
674 | const createInstance = defaults => {
675 | // eslint-disable-next-line @typescript-eslint/promise-function-async
676 | const ky = (input, options) =>
677 | Ky.create(input, validateAndMerge(defaults, options))
678 | for (const method of requestMethods) {
679 | // eslint-disable-next-line @typescript-eslint/promise-function-async
680 | ky[method] = (input, options) =>
681 | Ky.create(input, validateAndMerge(defaults, options, { method }))
682 | }
683 | ky.create = newDefaults => createInstance(validateAndMerge(newDefaults))
684 | ky.extend = newDefaults => {
685 | if (typeof newDefaults === 'function') {
686 | newDefaults = newDefaults(defaults ?? {})
687 | }
688 | return createInstance(validateAndMerge(defaults, newDefaults))
689 | }
690 | ky.stop = stop
691 | return ky
692 | }
693 | const ky$1 = createInstance()
694 |
695 | var distribution = /*#__PURE__*/ Object.freeze({
696 | __proto__: null,
697 | HTTPError: HTTPError,
698 | TimeoutError: TimeoutError,
699 | default: ky$1
700 | })
701 |
702 | var require$$1 = /*@__PURE__*/ getAugmentedNamespace(distribution)
703 |
704 | const ENDPOINT = {
705 | FREE: 'https://api.microlink.io/',
706 | PRO: 'https://pro.microlink.io/'
707 | }
708 |
709 | const isObject = input => input !== null && typeof input === 'object'
710 |
711 | const isBuffer = input =>
712 | input != null &&
713 | input.constructor != null &&
714 | typeof input.constructor.isBuffer === 'function' &&
715 | input.constructor.isBuffer(input)
716 |
717 | const parseBody = (input, error, url) => {
718 | try {
719 | return JSON.parse(input)
720 | } catch (_) {
721 | const message = input || error.message
722 |
723 | return {
724 | status: 'error',
725 | data: { url: message },
726 | more: 'https://microlink.io/efatalclient',
727 | code: 'EFATALCLIENT',
728 | message,
729 | url
730 | }
731 | }
732 | }
733 |
734 | const isURL = url => {
735 | try {
736 | return /^https?:\/\//i.test(new URL(url).href)
737 | } catch (_) {
738 | return false
739 | }
740 | }
741 |
742 | const factory$1 = streamResponseType => ({
743 | VERSION,
744 | MicrolinkError,
745 | got,
746 | flatten
747 | }) => {
748 | const assertUrl = (url = '') => {
749 | if (!isURL(url)) {
750 | const message = `The \`url\` as \`${url}\` is not valid. Ensure it has protocol (http or https) and hostname.`
751 | throw new MicrolinkError({
752 | status: 'fail',
753 | data: { url: message },
754 | more: 'https://microlink.io/einvalurlclient',
755 | code: 'EINVALURLCLIENT',
756 | message,
757 | url
758 | })
759 | }
760 | }
761 |
762 | const mapRules = rules => {
763 | if (!isObject(rules)) return
764 | const flatRules = flatten(rules)
765 | return Object.keys(flatRules).reduce((acc, key) => {
766 | acc[`data.${key}`] = flatRules[key].toString()
767 | return acc
768 | }, {})
769 | }
770 |
771 | const fetchFromApi = async (apiUrl, opts = {}) => {
772 | try {
773 | const response = await got(apiUrl, opts)
774 | return opts.responseType === streamResponseType
775 | ? response
776 | : { ...response.body, response }
777 | } catch (error) {
778 | const { response = {} } = error
779 | const {
780 | statusCode,
781 | body: rawBody,
782 | headers = {},
783 | url: uri = apiUrl
784 | } = response
785 | const isBodyBuffer = isBuffer(rawBody)
786 |
787 | const body =
788 | isObject(rawBody) && !isBodyBuffer
789 | ? rawBody
790 | : parseBody(isBodyBuffer ? rawBody.toString() : rawBody, error, uri)
791 |
792 | throw new MicrolinkError({
793 | ...body,
794 | message: body.message,
795 | url: uri,
796 | statusCode,
797 | headers
798 | })
799 | }
800 | }
801 |
802 | const getApiUrl = (
803 | url,
804 | { data, apiKey, endpoint, ...opts } = {},
805 | { responseType = 'json', headers: gotHeaders, ...gotOpts } = {}
806 | ) => {
807 | const isPro = !!apiKey
808 | const apiEndpoint = endpoint || ENDPOINT[isPro ? 'PRO' : 'FREE']
809 |
810 | const apiUrl = `${apiEndpoint}?${new URLSearchParams({
811 | url,
812 | ...mapRules(data),
813 | ...flatten(opts)
814 | }).toString()}`
815 |
816 | const headers = isPro
817 | ? { ...gotHeaders, 'x-api-key': apiKey }
818 | : { ...gotHeaders }
819 |
820 | if (opts.stream) {
821 | responseType = streamResponseType
822 | }
823 | return [apiUrl, { ...gotOpts, responseType, headers }]
824 | }
825 |
826 | const createMql = defaultOpts => async (url, opts, gotOpts) => {
827 | assertUrl(url)
828 | const [apiUrl, fetchOpts] = getApiUrl(url, opts, {
829 | ...defaultOpts,
830 | ...gotOpts
831 | })
832 | return fetchFromApi(apiUrl, fetchOpts)
833 | }
834 |
835 | const mql = createMql()
836 | mql.extend = createMql
837 | mql.MicrolinkError = MicrolinkError
838 | mql.getApiUrl = getApiUrl
839 | mql.fetchFromApi = fetchFromApi
840 | mql.mapRules = mapRules
841 | mql.version = VERSION
842 | mql.stream = got.stream
843 |
844 | return mql
845 | }
846 |
847 | var factory_1 = factory$1
848 |
849 | const { flattie: flatten } = dist
850 | const { default: ky } = require$$1
851 |
852 | const factory = factory_1('arrayBuffer')
853 |
854 | class MicrolinkError extends Error {
855 | constructor (props) {
856 | super()
857 | this.name = 'MicrolinkError'
858 | Object.assign(this, props)
859 | this.description = this.message
860 | this.message = this.code
861 | ? `${this.code}, ${this.description}`
862 | : this.description
863 | }
864 | }
865 |
866 | const got = async (url, { responseType, ...opts }) => {
867 | try {
868 | if (opts.timeout === undefined) opts.timeout = false
869 | const response = await ky(url, opts)
870 | const body = await response[responseType]()
871 | const { headers, status: statusCode } = response
872 | return { url: response.url, body, headers, statusCode }
873 | } catch (error) {
874 | if (error.response) {
875 | const { response } = error
876 | error.response = {
877 | ...response,
878 | headers: Array.from(response.headers.entries()).reduce(
879 | (acc, [key, value]) => {
880 | acc[key] = value
881 | return acc
882 | },
883 | {}
884 | ),
885 | statusCode: response.status,
886 | body: await response.text()
887 | }
888 | }
889 | throw error
890 | }
891 | }
892 |
893 | got.stream = (...args) => ky(...args).then(res => res.body)
894 |
895 | const mql = factory({
896 | MicrolinkError,
897 | got,
898 | flatten,
899 | VERSION: '0.13.20'
900 | })
901 |
902 | lightweight$1.exports = mql
903 | var arrayBuffer = (lightweight$1.exports.arrayBuffer = mql.extend({
904 | responseType: 'arrayBuffer'
905 | }))
906 | var extend = (lightweight$1.exports.extend = mql.extend)
907 | var fetchFromApi = (lightweight$1.exports.fetchFromApi = mql.fetchFromApi)
908 | var getApiUrl = (lightweight$1.exports.getApiUrl = mql.getApiUrl)
909 | var mapRules = (lightweight$1.exports.mapRules = mql.mapRules)
910 | var MicrolinkError_1 = (lightweight$1.exports.MicrolinkError =
911 | mql.MicrolinkError)
912 | var version = (lightweight$1.exports.version = mql.version)
913 |
914 | var lightweightExports = lightweight$1.exports
915 | var lightweight = /*@__PURE__*/ getDefaultExportFromCjs(lightweightExports)
916 |
917 | exports.MicrolinkError = MicrolinkError_1
918 | exports.arrayBuffer = arrayBuffer
919 | exports.default = lightweight
920 | exports.extend = extend
921 | exports.fetchFromApi = fetchFromApi
922 | exports.getApiUrl = getApiUrl
923 | exports.mapRules = mapRules
924 | exports.version = version
925 |
926 | Object.defineProperty(exports, '__esModule', { value: true })
927 | })
928 |
--------------------------------------------------------------------------------
/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.14.0](https://github.com/microlinkhq/mql/compare/v0.13.20...v0.14.0) (2025-06-04)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * retry as client parameter ([#163](https://github.com/microlinkhq/mql/issues/163)) ([36fbc5b](https://github.com/microlinkhq/mql/commit/36fbc5b1ac351eb619979d97c677be890b9daf38))
11 |
12 | ### [0.13.20](https://github.com/microlinkhq/mql/compare/v0.13.19...v0.13.20) (2025-05-21)
13 |
14 |
15 | ### Bug Fixes
16 |
17 | * rename type ([55f1870](https://github.com/microlinkhq/mql/commit/55f18708a3d415d02f4082137f91ac8057a81eb7))
18 |
19 | ### [0.13.19](https://github.com/microlinkhq/mql/compare/v0.13.18...v0.13.19) (2025-05-21)
20 |
21 |
22 | ### Bug Fixes
23 |
24 | * better error type ([aa44aa9](https://github.com/microlinkhq/mql/commit/aa44aa9d7b39fe7800a9405913e7cef28a9923dd))
25 |
26 | ### [0.13.18](https://github.com/microlinkhq/mql/compare/v0.13.17...v0.13.18) (2025-05-21)
27 |
28 |
29 | ### Bug Fixes
30 |
31 | * export missing types ([b55df1d](https://github.com/microlinkhq/mql/commit/b55df1d64a06b64c2311e355f90c3f459c8ce6aa))
32 |
33 | ### [0.13.17](https://github.com/microlinkhq/mql/compare/v0.13.16...v0.13.17) (2025-05-21)
34 |
35 |
36 | ### Bug Fixes
37 |
38 | * expose MicrolinkApiOptions for node ([fdad1b4](https://github.com/microlinkhq/mql/commit/fdad1b43ff5742f931258425bd80825c908d48e5))
39 |
40 | ### [0.13.16](https://github.com/microlinkhq/mql/compare/v0.13.15...v0.13.16) (2025-05-21)
41 |
42 |
43 | ### Bug Fixes
44 |
45 | * timeout/waitForTimeout as string ([48000ac](https://github.com/microlinkhq/mql/commit/48000ace4ba61922d2228bd4682f18c56186b698))
46 |
47 | ### [0.13.15](https://github.com/microlinkhq/mql/compare/v0.13.14...v0.13.15) (2025-05-21)
48 |
49 | ### [0.13.14](https://github.com/microlinkhq/mql/compare/v0.13.13...v0.13.14) (2025-01-28)
50 |
51 | ### [0.13.13](https://github.com/microlinkhq/mql/compare/v0.13.12...v0.13.13) (2025-01-28)
52 |
53 | ### [0.13.12](https://github.com/microlinkhq/mql/compare/v0.13.11...v0.13.12) (2024-12-08)
54 |
55 |
56 | ### Features
57 |
58 | * redirects ([#159](https://github.com/microlinkhq/mql/issues/159)) ([5b90fd7](https://github.com/microlinkhq/mql/commit/5b90fd7c5a9dc40d592e2709347cd9051a717c19))
59 |
60 | ### [0.13.11](https://github.com/microlinkhq/mql/compare/v0.13.10...v0.13.11) (2024-11-26)
61 |
62 |
63 | ### Bug Fixes
64 |
65 | * **types:** expose MqlResponseData ([9bd3b66](https://github.com/microlinkhq/mql/commit/9bd3b66e53c21d49bfc862040535a6e7a5086ee1))
66 |
67 | ### [0.13.10](https://github.com/microlinkhq/mql/compare/v0.13.9...v0.13.10) (2024-10-23)
68 |
69 |
70 | ### Bug Fixes
71 |
72 | * **types:** add size properties ([4e17fa4](https://github.com/microlinkhq/mql/commit/4e17fa4aee58abda929f051e27a2f7b74ce821a7))
73 |
74 | ### [0.13.9](https://github.com/microlinkhq/mql/compare/v0.13.8...v0.13.9) (2024-10-01)
75 |
76 | ### [0.13.8](https://github.com/microlinkhq/mql/compare/v0.13.7...v0.13.8) (2024-10-01)
77 |
78 |
79 | ### Bug Fixes
80 |
81 | * **build:** ensure exports are there ([f64896a](https://github.com/microlinkhq/mql/commit/f64896a654b83aa544198b76e706709aab6b95ec))
82 |
83 | ### [0.13.7](https://github.com/microlinkhq/mql/compare/v0.13.5...v0.13.7) (2024-09-30)
84 |
85 |
86 | ### Bug Fixes
87 |
88 | * **types:** statusCode can be null ([be503c7](https://github.com/microlinkhq/mql/commit/be503c7a6c97c3234586ddb906d85fe4419f8793))
89 |
90 | ### [0.13.6](https://github.com/microlinkhq/mql/compare/v0.13.5...v0.13.6) (2024-04-23)
91 |
92 |
93 | ### Bug Fixes
94 |
95 | * **types:** statusCode can be null ([be503c7](https://github.com/microlinkhq/mql/commit/be503c7a6c97c3234586ddb906d85fe4419f8793))
96 |
97 | ### [0.13.5](https://github.com/microlinkhq/mql/compare/v0.13.4...v0.13.5) (2024-04-04)
98 |
99 |
100 | ### Bug Fixes
101 |
102 | * update docs url ([a122de0](https://github.com/microlinkhq/mql/commit/a122de0f095913133fdb4563ee908233ab90d121))
103 |
104 | ### [0.13.4](https://github.com/microlinkhq/mql/compare/v0.13.3...v0.13.4) (2024-03-17)
105 |
106 |
107 | ### Bug Fixes
108 |
109 | * types ([#154](https://github.com/microlinkhq/mql/issues/154)) ([e8cfe09](https://github.com/microlinkhq/mql/commit/e8cfe092a5aaf24ea007cd00292954e79d030742))
110 |
111 | ### [0.13.3](https://github.com/microlinkhq/mql/compare/v0.13.2...v0.13.3) (2024-03-17)
112 |
113 |
114 | ### Bug Fixes
115 |
116 | * **types:** expose HTTPResponseRaw ([1ceff8f](https://github.com/microlinkhq/mql/commit/1ceff8f0091b5232043a01519b040764609a8cd6))
117 |
118 | ### [0.13.2](https://github.com/microlinkhq/mql/compare/v0.13.1...v0.13.2) (2024-03-17)
119 |
120 |
121 | ### Bug Fixes
122 |
123 | * **types:** expose some methods ([#153](https://github.com/microlinkhq/mql/issues/153)) ([980787e](https://github.com/microlinkhq/mql/commit/980787e0a4a3aa099fbf79a55d778099f8b60483))
124 |
125 | ### [0.13.1](https://github.com/microlinkhq/mql/compare/v0.13.0...v0.13.1) (2024-03-17)
126 |
127 |
128 | ### Bug Fixes
129 |
130 | * stream type ([b8a5f1b](https://github.com/microlinkhq/mql/commit/b8a5f1b6f71ad6ce6e862e79305b983ffcac2907))
131 |
132 | ## [0.13.0](https://github.com/microlinkhq/mql/compare/v0.12.3...v0.13.0) (2024-03-17)
133 |
134 |
135 | ### Features
136 |
137 | * add `stream` query parameter ([#152](https://github.com/microlinkhq/mql/issues/152)) ([7b74413](https://github.com/microlinkhq/mql/commit/7b74413ffc9602a4ed310368ff76c41301ebe939))
138 |
139 | ### [0.12.3](https://github.com/microlinkhq/mql/compare/v0.12.2...v0.12.3) (2024-03-01)
140 |
141 | ### [0.12.2](https://github.com/microlinkhq/mql/compare/v0.12.1...v0.12.2) (2024-01-07)
142 |
143 | ### [0.12.1](https://github.com/microlinkhq/mql/compare/v0.12.0...v0.12.1) (2023-11-30)
144 |
145 |
146 | ### Bug Fixes
147 |
148 | * **lightweight:** stream interface ([#144](https://github.com/microlinkhq/mql/issues/144)) ([9dcb280](https://github.com/microlinkhq/mql/commit/9dcb280a1bdac1fe7c3bee2fa1b735cd194abc28))
149 |
150 | ## [0.12.0](https://github.com/microlinkhq/mql/compare/v0.11.10...v0.12.0) (2023-11-30)
151 |
152 |
153 | ### Features
154 |
155 | * add .extend and buffer/arrayBuffer methods ([#143](https://github.com/microlinkhq/mql/issues/143)) ([3e49bf2](https://github.com/microlinkhq/mql/commit/3e49bf2051775508e9a99c3f79e27b0308e379f3))
156 |
157 | ### [0.11.10](https://github.com/microlinkhq/mql/compare/v0.11.9...v0.11.10) (2023-11-29)
158 |
159 |
160 | ### Bug Fixes
161 |
162 | * **esm:** expose fetchFromApi method ([#141](https://github.com/microlinkhq/mql/issues/141)) ([0ada023](https://github.com/microlinkhq/mql/commit/0ada0231b7e007b22d05c4d92cab53426d57463b))
163 |
164 | ### [0.11.9](https://github.com/microlinkhq/mql/compare/v0.11.8...v0.11.9) (2023-11-06)
165 |
166 |
167 | ### Bug Fixes
168 |
169 | * export MqlResponse type ([831b669](https://github.com/microlinkhq/mql/commit/831b669156e7531a7c88b29a5019fbec9f3471f7))
170 |
171 | ### [0.11.8](https://github.com/microlinkhq/mql/compare/v0.11.7...v0.11.8) (2023-11-05)
172 |
173 | ### [0.11.7](https://github.com/microlinkhq/mql/compare/v0.11.7-0...v0.11.7) (2023-11-03)
174 |
175 |
176 | ### Bug Fixes
177 |
178 | * sort fields using finepack ([061f3a8](https://github.com/microlinkhq/mql/commit/061f3a8c921e3c7c1aebdefda36619dccf34a2b9))
179 |
180 | ### [0.11.7-0](https://github.com/microlinkhq/mql/compare/v0.11.5...v0.11.7-0) (2023-11-02)
181 |
182 | ### [0.11.6](https://github.com/microlinkhq/mql/compare/v0.11.5...v0.11.6) (2023-11-02)
183 |
184 | ### [0.11.5](https://github.com/microlinkhq/mql/compare/v0.11.4...v0.11.5) (2023-11-01)
185 |
186 | ### [0.11.4](https://github.com/microlinkhq/mql/compare/v0.11.3...v0.11.4) (2023-10-05)
187 |
188 |
189 | ### Bug Fixes
190 |
191 | * **error:** add missing fields to type ([3066841](https://github.com/microlinkhq/mql/commit/306684144dc11f86360cfc08f8278a5032eb7d19))
192 |
193 | ### [0.11.3](https://github.com/microlinkhq/mql/compare/v0.11.2...v0.11.3) (2023-10-05)
194 |
195 |
196 | ### Bug Fixes
197 |
198 | * **types:** expose MqlError ([338cac7](https://github.com/microlinkhq/mql/commit/338cac70bc60895981299a167b04a2541dd89ed4))
199 |
200 | ### [0.11.2](https://github.com/microlinkhq/mql/compare/v0.11.1...v0.11.2) (2023-09-06)
201 |
202 |
203 | ### Bug Fixes
204 |
205 | * declare main for old node versions ([79560af](https://github.com/microlinkhq/mql/commit/79560af2dec2d263f44588d41d3dd88bb2041cfe))
206 |
207 | ### [0.11.1](https://github.com/microlinkhq/mql/compare/v0.11.0...v0.11.1) (2023-09-06)
208 |
209 |
210 | ### Bug Fixes
211 |
212 | * **esm:** ensure indvidual methods are exported ([#135](https://github.com/microlinkhq/mql/issues/135)) ([9212276](https://github.com/microlinkhq/mql/commit/9212276bae897dfed7279f7be6bb96a0572f6f8d))
213 |
214 | ## [0.11.0](https://github.com/microlinkhq/mql/compare/v0.10.39...v0.11.0) (2023-09-06)
215 |
216 | ### [0.10.39](https://github.com/microlinkhq/mql/compare/v0.10.38...v0.10.39) (2023-09-04)
217 |
218 |
219 | ### Bug Fixes
220 |
221 | * prefer exports over main ([bab451c](https://github.com/microlinkhq/mql/commit/bab451cb1715117b0905984d2b43cd92ec242ac1))
222 |
223 | ### [0.10.38](https://github.com/microlinkhq/mql/compare/v0.10.37...v0.10.38) (2023-09-03)
224 |
225 |
226 | ### Bug Fixes
227 |
228 | * add url type for media ([fb898dc](https://github.com/microlinkhq/mql/commit/fb898dcbb4df578657ec05266f8576e328f9e92c))
229 |
230 | ### [0.10.37](https://github.com/microlinkhq/mql/compare/v0.10.36...v0.10.37) (2023-09-03)
231 |
232 | ### [0.10.36](https://github.com/microlinkhq/mql/compare/v0.10.35...v0.10.36) (2023-09-03)
233 |
234 | ### [0.10.35](https://github.com/microlinkhq/mql/compare/v0.10.34...v0.10.35) (2023-09-03)
235 |
236 |
237 | ### Bug Fixes
238 |
239 | * add missing types ([#132](https://github.com/microlinkhq/mql/issues/132)) ([55a58f4](https://github.com/microlinkhq/mql/commit/55a58f4ca5a64e113b0727de478ef9ad85f0aa40))
240 |
241 | ### [0.10.34](https://github.com/microlinkhq/mql/compare/v0.10.33...v0.10.34) (2023-09-01)
242 |
243 |
244 | ### Bug Fixes
245 |
246 | * unify retry interface ([#130](https://github.com/microlinkhq/mql/issues/130)) ([64e4aff](https://github.com/microlinkhq/mql/commit/64e4aff438ece5f7c1ce3015fdc094950601f7b6))
247 |
248 | ### [0.10.33](https://github.com/microlinkhq/mql/compare/v0.10.32...v0.10.33) (2023-04-06)
249 |
250 | ### [0.10.32](https://github.com/microlinkhq/mql/compare/v0.10.31...v0.10.32) (2023-01-02)
251 |
252 | ### [0.10.31](https://github.com/microlinkhq/mql/compare/v0.10.30...v0.10.31) (2022-11-27)
253 |
254 |
255 | ### Bug Fixes
256 |
257 | * remove module field ([00efd9c](https://github.com/microlinkhq/mql/commit/00efd9cf64c882b5cc8849f967ad9336ff7ea754))
258 |
259 | ### [0.10.30](https://github.com/microlinkhq/mql/compare/v0.10.29...v0.10.30) (2022-11-13)
260 |
261 |
262 | ### Bug Fixes
263 |
264 | * avoid class field declaration ([070ef61](https://github.com/microlinkhq/mql/commit/070ef61cd6e40a41cf7b567fb36943984bc4a3a5))
265 |
266 | ### [0.10.29](https://github.com/microlinkhq/mql/compare/v0.10.28...v0.10.29) (2022-11-13)
267 |
268 |
269 | ### Features
270 |
271 | * add ES bundle ([8f0935c](https://github.com/microlinkhq/mql/commit/8f0935cabcc447e5cce33a3a4d22743f00cd5156))
272 |
273 | ### [0.10.28](https://github.com/microlinkhq/mql/compare/v0.10.27...v0.10.28) (2022-07-20)
274 |
275 | ### [0.10.27](https://github.com/microlinkhq/mql/compare/v0.10.26...v0.10.27) (2022-07-14)
276 |
277 | ### [0.10.26](https://github.com/microlinkhq/mql/compare/v0.10.25...v0.10.26) (2022-06-27)
278 |
279 |
280 | ### Bug Fixes
281 |
282 | * ensure headers is an object ([31fa807](https://github.com/microlinkhq/mql/commit/31fa8079015c4544a153e262a6a712587a3dfc26))
283 |
284 | ### [0.10.25](https://github.com/microlinkhq/mql/compare/v0.10.24...v0.10.25) (2022-06-14)
285 |
286 | ### [0.10.24](https://github.com/microlinkhq/mql/compare/v0.10.23...v0.10.24) (2022-06-14)
287 |
288 | ### [0.10.23](https://github.com/microlinkhq/mql/compare/v0.10.22...v0.10.23) (2022-06-14)
289 |
290 | ### [0.10.22](https://github.com/microlinkhq/mql/compare/v0.10.21...v0.10.22) (2022-05-27)
291 |
292 | ### [0.10.21](https://github.com/microlinkhq/mql/compare/v0.10.20...v0.10.21) (2022-05-27)
293 |
294 |
295 | ### Bug Fixes
296 |
297 | * typecheck Buffer without using Buffer ([69ee222](https://github.com/microlinkhq/mql/commit/69ee2222c4f23cfb9f703369cac7e69bc6b79bef))
298 |
299 | ### [0.10.20](https://github.com/microlinkhq/mql/compare/v0.10.19...v0.10.20) (2022-04-28)
300 |
301 | ### [0.10.19](https://github.com/microlinkhq/mql/compare/v0.10.18...v0.10.19) (2022-03-05)
302 |
303 | ### [0.10.18](https://github.com/microlinkhq/mql/compare/v0.10.17...v0.10.18) (2022-02-24)
304 |
305 | ### [0.10.17](https://github.com/microlinkhq/mql/compare/v0.10.15...v0.10.17) (2022-02-24)
306 |
307 | ### [0.10.16](https://github.com/microlinkhq/mql/compare/v0.10.15...v0.10.16) (2022-02-24)
308 |
309 | ### [0.10.15](https://github.com/microlinkhq/mql/compare/v0.10.14...v0.10.15) (2022-02-21)
310 |
311 | ### [0.10.14](https://github.com/microlinkhq/mql/compare/v0.10.13...v0.10.14) (2022-02-12)
312 |
313 | ### [0.10.13](https://github.com/microlinkhq/mql/compare/v0.10.12...v0.10.13) (2022-01-18)
314 |
315 | ### [0.10.12](https://github.com/microlinkhq/mql/compare/v0.10.11...v0.10.12) (2022-01-04)
316 |
317 | ### [0.10.11](https://github.com/microlinkhq/mql/compare/v0.10.10...v0.10.11) (2021-12-08)
318 |
319 | ### [0.10.10](https://github.com/microlinkhq/mql/compare/v0.10.9...v0.10.10) (2021-12-08)
320 |
321 |
322 | ### Bug Fixes
323 |
324 | * dependency name ([1b679a9](https://github.com/microlinkhq/mql/commit/1b679a96b2f90eefda521f7b3c64b37daafde58c))
325 |
326 | ### [0.10.9](https://github.com/microlinkhq/mql/compare/v0.10.7...v0.10.9) (2021-12-08)
327 |
328 | ### [0.10.8](https://github.com/microlinkhq/mql/compare/v0.10.7...v0.10.8) (2021-12-08)
329 |
330 | ### [0.10.7](https://github.com/microlinkhq/mql/compare/v0.10.6...v0.10.7) (2021-12-08)
331 |
332 |
333 | ### Bug Fixes
334 |
335 | * ensure to parseBody input is a string ([45e037d](https://github.com/microlinkhq/mql/commit/45e037de0260ba6b5298cb5207c6cb1d8f063c46))
336 |
337 | ### [0.10.6](https://github.com/microlinkhq/mql/compare/v0.10.5...v0.10.6) (2021-12-01)
338 |
339 | ### [0.10.5](https://github.com/microlinkhq/mql/compare/v0.10.4...v0.10.5) (2021-11-23)
340 |
341 |
342 | ### Features
343 |
344 | * expand types ([4be8564](https://github.com/microlinkhq/mql/commit/4be856405c683b077fefddf82d521ca5de71ff9a))
345 |
346 | ### [0.10.4](https://github.com/microlinkhq/mql/compare/v0.10.3...v0.10.4) (2021-10-13)
347 |
348 | ### [0.10.3](https://github.com/microlinkhq/mql/compare/v0.10.2...v0.10.3) (2021-10-13)
349 |
350 | ### [0.10.2](https://github.com/microlinkhq/mql/compare/v0.10.1...v0.10.2) (2021-10-13)
351 |
352 | ### [0.10.1](https://github.com/microlinkhq/mql/compare/v0.10.0...v0.10.1) (2021-10-12)
353 |
354 |
355 | ### Bug Fixes
356 |
357 | * remove duplicate type ([da98fce](https://github.com/microlinkhq/mql/commit/da98fce145ec96c944857b87a05d17d159530431))
358 |
359 | ## [0.10.0](https://github.com/microlinkhq/mql/compare/v0.9.13...v0.10.0) (2021-10-01)
360 |
361 |
362 | ### Features
363 |
364 | * add EFATALCLIENT error code ([2e77319](https://github.com/microlinkhq/mql/commit/2e77319df0864b2962e53113105c4eeb0ed07cf8))
365 |
366 | ### [0.9.13](https://github.com/microlinkhq/mql/compare/v0.9.12...v0.9.13) (2021-09-19)
367 |
368 | ### [0.9.12](https://github.com/microlinkhq/mql/compare/v0.9.11...v0.9.12) (2021-09-18)
369 |
370 |
371 | ### Bug Fixes
372 |
373 | * serialize values properly ([74e2dbb](https://github.com/microlinkhq/mql/commit/74e2dbb9f376cf4dbe5ef49afe0a27714d7765ce))
374 |
375 | ### [0.9.11](https://github.com/microlinkhq/mql/compare/v0.9.10...v0.9.11) (2021-09-12)
376 |
377 | ### [0.9.10](https://github.com/microlinkhq/mql/compare/v0.9.9...v0.9.10) (2021-09-12)
378 |
379 | ### [0.9.9](https://github.com/microlinkhq/mql/compare/v0.9.8...v0.9.9) (2021-08-09)
380 |
381 | ### [0.9.8](https://github.com/microlinkhq/mql/compare/v0.9.7...v0.9.8) (2021-06-28)
382 |
383 |
384 | ### Bug Fixes
385 |
386 | * ensure input exist before render ([7af11e1](https://github.com/microlinkhq/mql/commit/7af11e1eed5f73980b449c39f4a1f8cae8db09ec))
387 |
388 | ### [0.9.7](https://github.com/microlinkhq/mql/compare/v0.9.5...v0.9.7) (2021-06-26)
389 |
390 |
391 | ### Features
392 |
393 | * add api param types ([00ff9b7](https://github.com/microlinkhq/mql/commit/00ff9b705928697543282b47894a0110ba1ed3cf))
394 | * add types ([41cc61a](https://github.com/microlinkhq/mql/commit/41cc61ace94824d7b3814f93be34f8e1ccdb9c40))
395 |
396 |
397 | ### Bug Fixes
398 |
399 | * **build:** add missing dependency ([89b16a3](https://github.com/microlinkhq/mql/commit/89b16a31e2896bea752726ca7caae2a0f5f14f07))
400 |
401 | ### [0.9.5](https://github.com/microlinkhq/mql/compare/v0.9.4...v0.9.5) (2021-05-25)
402 |
403 |
404 | ### Bug Fixes
405 |
406 | * default parameters ([d5d788a](https://github.com/microlinkhq/mql/commit/d5d788ab486b070b41af0ed32491b65020657db2))
407 |
408 | ### [0.9.4](https://github.com/microlinkhq/mql/compare/v0.9.3...v0.9.4) (2021-05-25)
409 |
410 | ### [0.9.3](https://github.com/microlinkhq/mql/compare/v0.9.2...v0.9.3) (2021-03-21)
411 |
412 |
413 | ### Bug Fixes
414 |
415 | * setup mql version properly ([e5f9016](https://github.com/microlinkhq/mql/commit/e5f9016167e1a5aeb1ecfb9b8d2a0cd42b972742))
416 |
417 | ### [0.9.2](https://github.com/microlinkhq/mql/compare/v0.9.1...v0.9.2) (2021-03-20)
418 |
419 |
420 | ### Bug Fixes
421 |
422 | * browser dist file ([17aaecc](https://github.com/microlinkhq/mql/commit/17aaeccea629d3ca03f64139c8592fac32e9bd83))
423 |
424 | ### [0.9.1](https://github.com/microlinkhq/mql/compare/v0.9.0...v0.9.1) (2021-03-20)
425 |
426 |
427 | ### Bug Fixes
428 |
429 | * scripts ([e883dd0](https://github.com/microlinkhq/mql/commit/e883dd0c42abe8e1e527dc24d8ab847ff83fd7c4))
430 |
431 | ## [0.9.0](https://github.com/microlinkhq/mql/compare/v0.8.4...v0.9.0) (2021-03-20)
432 |
433 | ### [0.8.4](https://github.com/microlinkhq/mql/compare/v0.8.3...v0.8.4) (2021-03-20)
434 |
435 | ### [0.8.3](https://github.com/microlinkhq/mql/compare/v0.8.2...v0.8.3) (2021-03-03)
436 |
437 | ### [0.8.2](https://github.com/microlinkhq/mql/compare/v0.8.1...v0.8.2) (2021-02-24)
438 |
439 | ### [0.8.1](https://github.com/microlinkhq/mql/compare/v0.8.0...v0.8.1) (2021-01-17)
440 |
441 | ## [0.8.0](https://github.com/microlinkhq/mql/compare/v0.7.19...v0.8.0) (2020-12-18)
442 |
443 | ### [0.7.19](https://github.com/microlinkhq/mql/compare/v0.7.18...v0.7.19) (2020-11-29)
444 |
445 | ### [0.7.18](https://github.com/microlinkhq/mql/compare/v0.7.17...v0.7.18) (2020-11-29)
446 |
447 | ### [0.7.17](https://github.com/microlinkhq/mql/compare/v0.7.16...v0.7.17) (2020-11-29)
448 |
449 | ### [0.7.16](https://github.com/microlinkhq/mql/compare/v0.7.15...v0.7.16) (2020-11-16)
450 |
451 | ### [0.7.15](https://github.com/microlinkhq/mql/compare/v0.7.14...v0.7.15) (2020-10-31)
452 |
453 |
454 | ### Bug Fixes
455 |
456 | * linter ([031f98d](https://github.com/microlinkhq/mql/commit/031f98d561a056c175afdd659e517236867d39e4))
457 |
458 | ### [0.7.14](https://github.com/microlinkhq/mql/compare/v0.7.13...v0.7.14) (2020-10-21)
459 |
460 | ### [0.7.13](https://github.com/microlinkhq/mql/compare/v0.7.12...v0.7.13) (2020-10-13)
461 |
462 | ### [0.7.12](https://github.com/microlinkhq/mql/compare/v0.7.11...v0.7.12) (2020-10-13)
463 |
464 | ### [0.7.11](https://github.com/microlinkhq/mql/compare/v0.7.10...v0.7.11) (2020-10-12)
465 |
466 | ### [0.7.10](https://github.com/microlinkhq/mql/compare/v0.7.9...v0.7.10) (2020-09-29)
467 |
468 | ### [0.7.9](https://github.com/microlinkhq/mql/compare/v0.7.8...v0.7.9) (2020-09-20)
469 |
470 | ### [0.7.8](https://github.com/microlinkhq/mql/compare/v0.7.7...v0.7.8) (2020-09-10)
471 |
472 |
473 | ### Bug Fixes
474 |
475 | * remove unused dependency ([7b87935](https://github.com/microlinkhq/mql/commit/7b879351587f85234a08e05cc199150219ebb3cf))
476 |
477 | ### [0.7.7](https://github.com/microlinkhq/mql/compare/v0.7.6...v0.7.7) (2020-09-08)
478 |
479 | ### [0.7.6](https://github.com/microlinkhq/mql/compare/v0.7.5...v0.7.6) (2020-09-07)
480 |
481 | ### [0.7.5](https://github.com/microlinkhq/mql/compare/v0.7.4...v0.7.5) (2020-08-29)
482 |
483 | ### [0.7.4](https://github.com/microlinkhq/mql/compare/v0.7.3...v0.7.4) (2020-07-17)
484 |
485 | ### [0.7.3](https://github.com/microlinkhq/mql/compare/v0.7.2...v0.7.3) (2020-07-09)
486 |
487 | ### [0.7.2](https://github.com/microlinkhq/mql/compare/v0.7.1...v0.7.2) (2020-07-05)
488 |
489 | ### [0.7.1](https://github.com/microlinkhq/mql/compare/v0.7.0...v0.7.1) (2020-05-27)
490 |
491 |
492 | ### Bug Fixes
493 |
494 | * avoid undefined ([9feaec8](https://github.com/microlinkhq/mql/commit/9feaec8bdd1f826a6dd13064bf34b9564b999ef7))
495 |
496 | ## [0.7.0](https://github.com/microlinkhq/mql/compare/v0.6.15...v0.7.0) (2020-05-25)
497 |
498 |
499 | ### Features
500 |
501 | * customize http client as third argument ([b9cf7c7](https://github.com/microlinkhq/mql/commit/b9cf7c71ebb05a3e667ebb1b421ea1e874b8f472))
502 |
503 | ### [0.6.15](https://github.com/microlinkhq/mql/compare/v0.6.14...v0.6.15) (2020-05-19)
504 |
505 |
506 | ### Bug Fixes
507 |
508 | * ensure to parse buffer responses ([bf69ba9](https://github.com/microlinkhq/mql/commit/bf69ba9c1fd25a093442a1dab0431cd19be13bc6))
509 |
510 | ### [0.6.14](https://github.com/microlinkhq/mql/compare/v0.6.13...v0.6.14) (2020-05-17)
511 |
512 |
513 | ### Bug Fixes
514 |
515 | * ensure to parse body ([6d66e43](https://github.com/microlinkhq/mql/commit/6d66e43128b62065cf2868d3614e62cb1668d56c))
516 |
517 | ### [0.6.13](https://github.com/microlinkhq/mql/compare/v0.6.12...v0.6.13) (2020-05-04)
518 |
519 | ### [0.6.12](https://github.com/microlinkhq/mql/compare/v0.6.11...v0.6.12) (2020-04-21)
520 |
521 | ### [0.6.11](https://github.com/microlinkhq/mql/compare/v0.6.10...v0.6.11) (2020-04-03)
522 |
523 |
524 | ### Bug Fixes
525 |
526 | * client timeout ([ad4fadf](https://github.com/microlinkhq/mql/commit/ad4fadf1a699c9bc1bc1c8a7c435bc397a26758c))
527 |
528 | ### [0.6.10](https://github.com/microlinkhq/mql/compare/v0.6.9...v0.6.10) (2020-03-30)
529 |
530 | ### [0.6.9](https://github.com/microlinkhq/mql/compare/v0.6.8...v0.6.9) (2020-03-25)
531 |
532 | ### [0.6.8](https://github.com/microlinkhq/mql/compare/v0.6.7...v0.6.8) (2020-03-23)
533 |
534 | ### [0.6.7](https://github.com/microlinkhq/mql/compare/v0.6.6...v0.6.7) (2020-03-23)
535 |
536 | ### [0.6.6](https://github.com/microlinkhq/mql/compare/v0.6.5...v0.6.6) (2020-03-23)
537 |
538 | ### [0.6.5](https://github.com/microlinkhq/mql/compare/v0.6.4...v0.6.5) (2020-03-11)
539 |
540 |
541 | ### Bug Fixes
542 |
543 | * remove module field ([56e17d7](https://github.com/microlinkhq/mql/commit/56e17d71bdbb91c2ff8f4b2dc1ae3212e990f01a)), closes [#50](https://github.com/microlinkhq/mql/issues/50)
544 |
545 | ### [0.6.4](https://github.com/microlinkhq/mql/compare/v0.6.3...v0.6.4) (2020-03-09)
546 |
547 | ### [0.6.3](https://github.com/microlinkhq/mql/compare/v0.6.2...v0.6.3) (2020-03-04)
548 |
549 |
550 | ### Bug Fixes
551 |
552 | * remove isStream prop ([afe5f6f](https://github.com/microlinkhq/mql/commit/afe5f6f802d5f947011a2829ae51c3dc79ac0fe6))
553 |
554 | ### [0.6.2](https://github.com/microlinkhq/mql/compare/v0.6.1...v0.6.2) (2020-03-03)
555 |
556 |
557 | ### Bug Fixes
558 |
559 | * headers serialization on browser ([23fde59](https://github.com/microlinkhq/mql/commit/23fde599afbe700a94be9a522ab9dfdcfc6f31da))
560 |
561 | ### [0.6.1](https://github.com/microlinkhq/mql/compare/v0.6.0...v0.6.1) (2020-03-01)
562 |
563 |
564 | ### Bug Fixes
565 |
566 | * streaming ([a3d97c6](https://github.com/microlinkhq/mql/commit/a3d97c684dae1e66bec5b6e29498a7d7c22d8207))
567 |
568 | ## [0.6.0](https://github.com/microlinkhq/mql/compare/v0.5.23...v0.6.0) (2020-03-01)
569 |
570 |
571 | ### Features
572 |
573 | * better error handling ([17bee3b](https://github.com/microlinkhq/mql/commit/17bee3b051803f21ac761967439b2fcd4fe8d409))
574 |
575 | ### [0.5.23](https://github.com/microlinkhq/mql/compare/v0.5.22...v0.5.23) (2020-02-28)
576 |
577 | ### [0.5.22](https://github.com/microlinkhq/mql/compare/v0.5.21...v0.5.22) (2020-02-20)
578 |
579 | ### [0.5.21](https://github.com/microlinkhq/mql/compare/v0.5.20...v0.5.21) (2020-02-12)
580 |
581 | ### [0.5.20](https://github.com/microlinkhq/mql/compare/v0.5.19...v0.5.20) (2020-02-07)
582 |
583 | ### [0.5.19](https://github.com/microlinkhq/mql/compare/v0.5.18...v0.5.19) (2020-02-05)
584 |
585 | ### [0.5.18](https://github.com/microlinkhq/mql/compare/v0.5.17...v0.5.18) (2020-02-05)
586 |
587 |
588 | ### Bug Fixes
589 |
590 | * ensure ky is loaded properly ([9f44ee2](https://github.com/microlinkhq/mql/commit/9f44ee20e2ac99e23d258b3651fec66290949e4f))
591 |
592 | ### [0.5.17](https://github.com/microlinkhq/mql/compare/v0.5.16...v0.5.17) (2020-02-03)
593 |
594 |
595 | ### Features
596 |
597 | * update dependencies ([06e7ae2](https://github.com/microlinkhq/mql/commit/06e7ae2b8c195cbdb20e01f48d3ff3f551dd1cd6))
598 |
599 | ### [0.5.16](https://github.com/microlinkhq/mql/compare/v0.5.15...v0.5.16) (2020-01-18)
600 |
601 | ### [0.5.15](https://github.com/microlinkhq/mql/compare/v0.5.14...v0.5.15) (2019-12-20)
602 |
603 |
604 | ### Bug Fixes
605 |
606 | * only flatten data objects ([1867815](https://github.com/microlinkhq/mql/commit/1867815b9804d02f3f5ba7bda51a4dcb22712faa))
607 |
608 | ### [0.5.14](https://github.com/microlinkhq/mql/compare/v0.5.13...v0.5.14) (2019-12-04)
609 |
610 | ### [0.5.13](https://github.com/microlinkhq/mql/compare/v0.5.12...v0.5.13) (2019-11-25)
611 |
612 |
613 | ### Bug Fixes
614 |
615 | * ensure to flatten options passed ([3afeb3d](https://github.com/microlinkhq/mql/commit/3afeb3d930af220b312ca0be1a3048d0f2899114))
616 |
617 | ### [0.5.12](https://github.com/microlinkhq/mql/compare/v0.5.11...v0.5.12) (2019-11-18)
618 |
619 | ### [0.5.11](https://github.com/microlinkhq/mql/compare/v0.5.10...v0.5.11) (2019-11-09)
620 |
621 | ### [0.5.10](https://github.com/microlinkhq/mql/compare/v0.5.9...v0.5.10) (2019-10-23)
622 |
623 | ### [0.5.9](https://github.com/microlinkhq/mql/compare/v0.5.8...v0.5.9) (2019-10-18)
624 |
625 | ### [0.5.8](https://github.com/microlinkhq/mql/compare/v0.5.7...v0.5.8) (2019-10-18)
626 |
627 |
628 | ### Bug Fixes
629 |
630 | * timeout no more undefined ([0f81606](https://github.com/microlinkhq/mql/commit/0f81606))
631 |
632 | ### [0.5.7](https://github.com/microlinkhq/mql/compare/v0.5.6...v0.5.7) (2019-10-14)
633 |
634 | ### [0.5.6](https://github.com/microlinkhq/mql/compare/v0.5.5...v0.5.6) (2019-10-14)
635 |
636 | ### [0.5.5](https://github.com/microlinkhq/mql/compare/v0.5.4...v0.5.5) (2019-10-14)
637 |
638 | ### [0.5.4](https://github.com/microlinkhq/mql/compare/v0.5.3...v0.5.4) (2019-10-13)
639 |
640 | ### [0.5.3](https://github.com/microlinkhq/mql/compare/v0.5.2...v0.5.3) (2019-10-13)
641 |
642 |
643 | ### Bug Fixes
644 |
645 | * setup fetch default options ([81087d0](https://github.com/microlinkhq/mql/commit/81087d0))
646 |
647 | ### [0.5.2](https://github.com/microlinkhq/mql/compare/v0.5.1...v0.5.2) (2019-10-13)
648 |
649 |
650 | ### Bug Fixes
651 |
652 | * print timeout ([e829a4a](https://github.com/microlinkhq/mql/commit/e829a4a))
653 |
654 | ### [0.5.1](https://github.com/microlinkhq/mql/compare/v0.5.0...v0.5.1) (2019-10-13)
655 |
656 | ## [0.5.0](https://github.com/microlinkhq/mql/compare/v0.4.5...v0.5.0) (2019-10-08)
657 |
658 | ### [0.4.5](https://github.com/microlinkhq/mql/compare/v0.4.4...v0.4.5) (2019-09-28)
659 |
660 | ### [0.4.4](https://github.com/microlinkhq/mql/compare/v1.0.22...v0.4.4) (2019-09-26)
661 |
662 |
663 | ### Bug Fixes
664 |
665 | * pass headers ([d79f883](https://github.com/microlinkhq/mql/commit/d79f883))
666 |
667 | ### [0.4.3](https://github.com/microlinkhq/mql/compare/v0.4.2...v0.4.3) (2019-09-10)
668 |
669 | ### [0.4.2](https://github.com/microlinkhq/mql/compare/v1.0.19...v0.4.2) (2019-09-08)
670 |
671 | ### [0.4.1](https://github.com/microlinkhq/mql/compare/v0.4.0...v0.4.1) (2019-08-24)
672 |
673 | ## [0.4.0](https://github.com/microlinkhq/mql/compare/v0.3.16...v0.4.0) (2019-08-24)
674 |
675 |
676 | ### Bug Fixes
677 |
678 | * linter ([5f62d0f](https://github.com/microlinkhq/mql/commit/5f62d0f))
679 |
680 | ### [0.3.16](https://github.com/microlinkhq/mql/compare/v1.0.16...v0.3.16) (2019-08-13)
681 |
682 | ### [0.3.15](https://github.com/microlinkhq/mql/compare/v1.0.9...v0.3.15) (2019-07-31)
683 |
684 |
685 | ### Bug Fixes
686 |
687 | * linter ([f7f985b](https://github.com/microlinkhq/mql/commit/f7f985b))
688 |
689 | ### [0.3.14](https://github.com/microlinkhq/mql/compare/v1.0.7...v0.3.14) (2019-07-10)
690 |
691 |
692 | ### Build System
693 |
694 | * migrate lint-staged ([698e8e0](https://github.com/microlinkhq/mql/commit/698e8e0))
695 | * update dependencies ([d15b056](https://github.com/microlinkhq/mql/commit/d15b056))
696 |
697 |
698 |
699 | ### [0.3.13](https://github.com/microlinkhq/mql/compare/v0.3.12...v0.3.13) (2019-06-12)
700 |
701 |
702 | ### Bug Fixes
703 |
704 | * handle buffer ([e62c782](https://github.com/microlinkhq/mql/commit/e62c782))
705 |
706 |
707 | ### Build System
708 |
709 | * generate bundle ([2a6fa12](https://github.com/microlinkhq/mql/commit/2a6fa12))
710 |
711 |
712 |
713 | ### [0.3.12](https://github.com/microlinkhq/mql/compare/v0.3.11...v0.3.12) (2019-06-09)
714 |
715 |
716 | ### Bug Fixes
717 |
718 | * require ([2eb2416](https://github.com/microlinkhq/mql/commit/2eb2416))
719 |
720 |
721 | ### Build System
722 |
723 | * generate bundle ([37ec175](https://github.com/microlinkhq/mql/commit/37ec175))
724 |
725 |
726 |
727 | ### [0.3.11](https://github.com/microlinkhq/mql/compare/v0.3.10...v0.3.11) (2019-06-09)
728 |
729 |
730 | ### Bug Fixes
731 |
732 | * setup umd main file properly ([4804c27](https://github.com/microlinkhq/mql/commit/4804c27))
733 | * umd ([ac37de9](https://github.com/microlinkhq/mql/commit/ac37de9))
734 | * use default constructor ([ee75e1c](https://github.com/microlinkhq/mql/commit/ee75e1c))
735 |
736 |
737 | ### Build System
738 |
739 | * generate build after release ([4920073](https://github.com/microlinkhq/mql/commit/4920073))
740 | * ignore stats.html ([c43e0cc](https://github.com/microlinkhq/mql/commit/c43e0cc))
741 |
742 |
743 |
744 | ### [0.3.10](https://github.com/microlinkhq/mql/compare/v1.0.6...v0.3.10) (2019-06-08)
745 |
746 |
747 | ### Bug Fixes
748 |
749 | * just parse when the body is an string ([2612577](https://github.com/microlinkhq/mql/commit/2612577))
750 |
751 |
752 | ### Build System
753 |
754 | * update dependencies ([9e1a31c](https://github.com/microlinkhq/mql/commit/9e1a31c))
755 |
756 |
757 | ### Tests
758 |
759 | * update snapshot ([0caa920](https://github.com/microlinkhq/mql/commit/0caa920))
760 |
761 |
762 |
763 | ### [0.3.9](https://github.com/microlinkhq/mql/compare/v1.0.5...v0.3.9) (2019-05-28)
764 |
765 |
766 | ### Build System
767 |
768 | * associate url with the error ([605f913](https://github.com/microlinkhq/mql/commit/605f913))
769 |
770 |
771 | ### Tests
772 |
773 | * avoid date ([a21c21c](https://github.com/microlinkhq/mql/commit/a21c21c))
774 |
775 |
776 |
777 | ### [0.3.8](https://github.com/microlinkhq/mql/compare/v1.0.4...v0.3.8) (2019-05-28)
778 |
779 |
780 | ### Build System
781 |
782 | * update dependencies ([5047672](https://github.com/microlinkhq/mql/commit/5047672))
783 |
784 |
785 |
786 | ### [0.3.7](https://github.com/microlinkhq/mql/compare/v1.0.3...v0.3.7) (2019-05-20)
787 |
788 |
789 | ### Bug Fixes
790 |
791 | * **package:** update is-url-http to version 1.2.0 ([fb85fae](https://github.com/microlinkhq/mql/commit/fb85fae))
792 |
793 |
794 | ### Tests
795 |
796 | * update snapshots ([101c989](https://github.com/microlinkhq/mql/commit/101c989))
797 |
798 |
799 |
800 | ## [0.3.6](https://github.com/microlinkhq/mql/compare/v0.3.5...v0.3.6) (2019-04-25)
801 |
802 |
803 |
804 | ## [0.3.5](https://github.com/microlinkhq/mql/compare/v0.3.4...v0.3.5) (2019-04-25)
805 |
806 |
807 | ### Bug Fixes
808 |
809 | * **package:** update ky to version 0.10.0 ([9947a0e](https://github.com/microlinkhq/mql/commit/9947a0e))
810 | * **package:** update ky-universal to version 0.2.0 ([5cd3d89](https://github.com/microlinkhq/mql/commit/5cd3d89))
811 |
812 |
813 |
814 |
815 | ## [0.3.4](https://github.com/microlinkhq/mql/compare/v0.3.3...v0.3.4) (2019-04-08)
816 |
817 |
818 |
819 |
820 | ## [0.3.3](https://github.com/microlinkhq/mql/compare/v0.3.2...v0.3.3) (2019-03-29)
821 |
822 |
823 |
824 |
825 | ## [0.3.2](https://github.com/microlinkhq/mql/compare/v0.3.1...v0.3.2) (2019-03-29)
826 |
827 |
828 |
829 |
830 | ## [0.3.1](https://github.com/microlinkhq/mql/compare/v0.3.0...v0.3.1) (2019-03-29)
831 |
832 |
833 |
834 |
835 | # [0.3.0](https://github.com/microlinkhq/mql/compare/v0.2.12...v0.3.0) (2019-03-21)
836 |
837 |
838 | ### Features
839 |
840 | * add custom rules support ([f342dd3](https://github.com/microlinkhq/mql/commit/f342dd3))
841 |
842 |
843 |
844 |
845 | ## [0.2.12](https://github.com/microlinkhq/mql/compare/v0.2.11...v0.2.12) (2019-03-11)
846 |
847 |
848 |
849 |
850 | ## [0.2.11](https://github.com/microlinkhq/mql/compare/v0.2.6...v0.2.11) (2019-03-11)
851 |
852 |
853 | ### Bug Fixes
854 |
855 | * add missing browser dependency ([ec1ed09](https://github.com/microlinkhq/mql/commit/ec1ed09))
856 |
857 |
858 |
859 |
860 | ## 0.2.10 (2019-03-03)
861 |
862 |
863 |
864 |
865 | ## 0.2.9 (2019-03-03)
866 |
867 |
868 |
869 |
870 | ## 0.2.8 (2019-03-03)
871 |
872 |
873 |
874 |
875 | ## 0.2.7 (2019-03-03)
876 |
877 |
878 |
879 |
880 | ## 0.2.10 (2019-03-03)
881 |
882 | * build: update dependencies ([1998c50](https://github.com/microlinkhq/mql/commit/1998c50))
883 |
884 |
885 |
886 |
887 | ## 0.2.9 (2019-03-03)
888 |
889 | * test: improve ([f89a41f](https://github.com/microlinkhq/mql/commit/f89a41f))
890 |
891 |
892 |
893 |
894 | ## 0.2.8 (2019-03-03)
895 |
896 | * build: setup deps ([491e227](https://github.com/microlinkhq/mql/commit/491e227))
897 |
898 |
899 |
900 |
901 | ## 0.2.7 (2019-03-03)
902 |
903 | * build: add ky-universal as dependecy ([8570d8e](https://github.com/microlinkhq/mql/commit/8570d8e))
904 | * build: fix tests ([c9bddfd](https://github.com/microlinkhq/mql/commit/c9bddfd))
905 |
906 |
907 |
908 | # Change Log
909 |
910 | 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.
911 |
912 |
913 | ## [0.2.6](https://github.com/microlinkhq/mql/compare/v0.2.5...v0.2.6) (2019-02-24)
914 |
915 |
916 |
917 |
918 | ## [0.2.5](https://github.com/microlinkhq/mql/compare/v0.2.4...v0.2.5) (2019-02-24)
919 |
920 |
921 |
922 |
923 | ## [0.2.4](https://github.com/microlinkhq/mql/compare/v0.2.3...v0.2.4) (2019-02-24)
924 |
925 |
926 |
927 |
928 | ## [0.2.3](https://github.com/microlinkhq/mql/compare/v0.2.2...v0.2.3) (2019-02-24)
929 |
930 |
931 |
932 |
933 | ## [0.2.2](https://github.com/microlinkhq/mql/compare/v0.2.1...v0.2.2) (2019-02-24)
934 |
935 |
936 |
937 |
938 | ## [0.2.1](https://github.com/microlinkhq/mql/compare/v0.2.0...v0.2.1) (2019-02-24)
939 |
940 |
941 |
942 |
943 | # 0.2.0 (2019-02-24)
944 |
945 |
946 | ### Bug Fixes
947 |
948 | * linter ([92762fc](https://github.com/microlinkhq/mql/commit/92762fc))
949 | * **package:** update is-url-http to version 1.1.1 ([7d0d33a](https://github.com/microlinkhq/mql/commit/7d0d33a))
950 |
951 |
952 | ### Features
953 |
954 | * add browser support ([fdcfad5](https://github.com/microlinkhq/mql/commit/fdcfad5))
955 |
956 |
957 |
958 |
959 | # 0.1.0 (2019-02-03)
960 |
961 |
962 | ### Bug Fixes
963 |
964 | * better docs ([ea72b17](https://github.com/microlinkhq/mql/commit/ea72b17))
965 |
966 |
967 |
968 |
969 | # 0.1.0 (2019-02-03)
970 |
971 | * docs: add introduction ([2d30d5a](https://github.com/microlinkhq/mql/commit/2d30d5a))
972 | * test: fix snapshots ([ec78c1d](https://github.com/microlinkhq/mql/commit/ec78c1d))
973 | * build: first commit ([8cf91a9](https://github.com/microlinkhq/mql/commit/8cf91a9))
974 | * build: tweak meta ([bbf383c](https://github.com/microlinkhq/mql/commit/bbf383c))
975 | * fix: better docs ([ea72b17](https://github.com/microlinkhq/mql/commit/ea72b17))
976 | * add cache support ([f7f2414](https://github.com/microlinkhq/mql/commit/f7f2414))
977 | * add error handling ([7f56519](https://github.com/microlinkhq/mql/commit/7f56519))
978 |
--------------------------------------------------------------------------------