bump package version to 1.4.2
[squeep-indieauth-helper] / lib / common.js
1 'use strict';
2
3 /**
4 * @typedef {object} GotResponse
5 * @property {Buffer|string} body response body
6 * @property {Array} redirectUrls followed redirect urls
7 * @property {number=} retryCount retries
8 * @property {object=} timings timings object
9 * @property {object=} timings.phases timing phases object
10 * @property {number=} timings.phases.total timing total ms
11 */
12 /**
13 * Pick out useful got response fields.
14 * @param {GotResponse} res response
15 * @returns {object} filtered response
16 */
17 const gotResponseLogData = (res) => {
18 const data = pick(res, [
19 'statusCode',
20 'statusMessage',
21 'headers',
22 'body',
23 'url',
24 'error',
25 ]);
26 if (typeof res.body === 'string') {
27 data.body = logTruncate(data.body, 100);
28 } else if (res.body instanceof Buffer) {
29 data.body = `<Buffer ${res.body.byteLength} bytes>`;
30 }
31 data.elapsedTimeMs = res?.timings?.phases?.total;
32 if (res?.redirectUrls?.length) {
33 data.redirectUrls = res.redirectUrls;
34 }
35 if (res?.retryCount) {
36 data.retryCount = res.retryCount;
37 }
38 return data;
39 };
40
41
42 /**
43 * Limit length of string to keep logs sane
44 * @param {string} str string
45 * @param {number} len length
46 * @returns {string} truncated string
47 */
48 const logTruncate = (str, len) => {
49 if (typeof str !== 'string' || str.toString().length <= len) {
50 return str;
51 }
52 return str.toString().slice(0, len) + `... (${str.toString().length} bytes)`;
53 };
54
55
56 /**
57 * Return a new object with selected props.
58 * @param {object} obj object
59 * @param {string[]} props list of properties
60 * @returns {object} filtered object
61 */
62 const pick = (obj, props) => {
63 return props.reduce((acc, prop) => {
64 if (prop in obj) {
65 acc[prop] = obj[prop]; // eslint-disable-line security/detect-object-injection
66 }
67 return acc;
68 }, {});
69 };
70
71
72 /**
73 * Return a set containing non-shared items between two sets.
74 * @param {Set} a set a
75 * @param {Set} b set b
76 * @returns {Set} set difference
77 */
78 const setSymmetricDifference = (a, b) => {
79 const d = new Set(a);
80 for (const x of b) {
81 if (d.has(x)) {
82 d.delete(x);
83 } else {
84 d.add(x);
85 }
86 }
87 return d;
88 };
89
90
91 /**
92 * URL objects have weird names.
93 * @param {string} component url component name
94 * @returns {string} translated url component name
95 */
96 const properURLComponentName = (component) => {
97 // eslint-disable-next-line security/detect-object-injection
98 return {
99 hash: 'fragment',
100 protocol: 'scheme',
101 }[component] || component;
102 };
103
104
105 module.exports = {
106 gotResponseLogData,
107 logTruncate,
108 pick,
109 setSymmetricDifference,
110 properURLComponentName,
111 };