• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

microlinkhq / mql / 15450443311

04 Jun 2025 06:57PM UTC coverage: 69.918%. First build
15450443311

Pull #163

github

web-flow
Merge 6c4d60209 into 8bf2dac63
Pull Request #163: feat: retry as client parameter

168 of 223 branches covered (75.34%)

Branch coverage included in aggregate %.

0 of 2 new or added lines in 1 file covered. (0.0%)

857 of 1243 relevant lines covered (68.95%)

7.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.08
/src/factory.js
1
const ENDPOINT = {
2✔
2
  FREE: 'https://api.microlink.io/',
2✔
3
  PRO: 'https://pro.microlink.io/'
2✔
4
}
2✔
5

2✔
6
const isObject = input => input !== null && typeof input === 'object'
2✔
7

2✔
8
const isBuffer = input =>
2✔
9
  input != null &&
×
10
  input.constructor != null &&
×
11
  typeof input.constructor.isBuffer === 'function' &&
×
12
  input.constructor.isBuffer(input)
×
13

2✔
14
const parseBody = (input, error, url) => {
2✔
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

2✔
31
const isURL = url => {
2✔
32
  try {
×
33
    return /^https?:\/\//i.test(new URL(url).href)
×
34
  } catch (_) {
×
35
    return false
×
36
  }
×
37
}
×
38

2✔
39
const factory = streamResponseType => ({
2✔
40
  VERSION,
2✔
41
  MicrolinkError,
2✔
42
  got,
2✔
43
  flatten
2✔
44
}) => {
2✔
45
  const assertUrl = (url = '') => {
2✔
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

2✔
59
  const mapRules = rules => {
2✔
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

2✔
68
  const fetchFromApi = async (apiUrl, opts = {}) => {
2✔
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

2✔
99
  const getApiUrl = (
2✔
100
    url,
×
NEW
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
    }
×
NEW
120
    return [apiUrl, { ...gotOpts, responseType, headers }]
×
121
  }
×
122

2✔
123
  const createMql = defaultOpts => async (url, opts, gotOpts) => {
2✔
124
    assertUrl(url)
×
125
    const [apiUrl, fetchOpts] = getApiUrl(url, opts, {
×
126
      ...defaultOpts,
×
127
      ...gotOpts
×
128
    })
×
129
    return fetchFromApi(apiUrl, fetchOpts)
×
130
  }
×
131

2✔
132
  const mql = createMql()
2✔
133
  mql.extend = createMql
2✔
134
  mql.MicrolinkError = MicrolinkError
2✔
135
  mql.getApiUrl = getApiUrl
2✔
136
  mql.fetchFromApi = fetchFromApi
2✔
137
  mql.mapRules = mapRules
2✔
138
  mql.version = VERSION
2✔
139
  mql.stream = got.stream
2✔
140

2✔
141
  return mql
2✔
142
}
2✔
143

2✔
144
module.exports = factory
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc