ednl-liftstatus-web-components 1.61.2 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/api-BDbCaWHW.js +796 -0
- package/dist/cjs/debounce-DUdTuYyk.js +306 -0
- package/dist/cjs/ednl-liftstatus-web-components.cjs.js +1 -1
- package/dist/cjs/em-dash-BaIXt_2W.js +6 -0
- package/dist/cjs/error-message-DHsnNSTO.js +67 -0
- package/dist/cjs/icons-AUFyHyZx.js +81 -0
- package/dist/cjs/init-B8WotsHH.js +12 -0
- package/dist/cjs/is-empty-object-Cr9p07dP.js +7 -0
- package/dist/cjs/isEmpty-C46AwMJT.js +686 -0
- package/dist/cjs/isNil-B-fGcnNC.js +27 -0
- package/dist/cjs/isObjectLike-Bhr7FCs9.js +138 -0
- package/dist/cjs/isSymbol-1eHA2e9E.js +30 -0
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/locale-state-D434QK1o.js +60 -0
- package/dist/cjs/{ls-3d-scene_14.cjs.entry.js → ls-3d-scene.cjs.entry.js} +2059 -24361
- package/dist/cjs/ls-counters.cjs.entry.js +505 -0
- package/dist/cjs/ls-data.cjs.entry.js +4474 -0
- package/dist/cjs/ls-date-picker.cjs.entry.js +3298 -0
- package/dist/cjs/ls-energy-usage.cjs.entry.js +220 -206
- package/dist/cjs/ls-history-swimlane.cjs.entry.js +1786 -0
- package/dist/cjs/ls-indicator.cjs.entry.js +84 -0
- package/dist/cjs/ls-recent-stops.cjs.entry.js +2179 -0
- package/dist/cjs/ls-reset-steering.cjs.entry.js +208 -0
- package/dist/cjs/ls-status-count.cjs.entry.js +211 -0
- package/dist/cjs/ls-status-history.cjs.entry.js +488 -0
- package/dist/cjs/ls-status-item.cjs.entry.js +241 -0
- package/dist/cjs/ls-status-messages.cjs.entry.js +245 -0
- package/dist/cjs/ls-status.cjs.entry.js +156 -0
- package/dist/cjs/ls-swimlane.cjs.entry.js +820 -0
- package/dist/cjs/nl-CxoXyGvE.js +20 -0
- package/dist/cjs/nodrag-DdOgffWc.js +489 -0
- package/dist/cjs/period-Bqvedndf.js +63 -0
- package/dist/cjs/range-RkYbFtor.js +17 -0
- package/dist/cjs/safe-relative-time-DJTmYfc4.js +47 -0
- package/dist/cjs/sensorInfo-DN3WW3kt.js +51 -0
- package/dist/cjs/sensors-DqBjrPzl.js +321 -0
- package/dist/cjs/sortBy-BxklLsbW.js +2370 -0
- package/dist/cjs/status-codes.store-CxSiaNxt.js +158 -0
- package/dist/cjs/{init-DTU-5DzQ.js → store-ByFQQL9z.js} +89 -2599
- package/dist/cjs/store-error-CjlXhka5.js +23 -0
- package/dist/cjs/swimlane-constants-DRNSr6Ai.js +238 -0
- package/dist/cjs/timestamps-BIjmQUZ_.js +29 -0
- package/dist/cjs/transform-CXJtL0ob.js +4273 -0
- package/dist/cjs/values-Cm898VVc.js +190 -0
- package/dist/collection/collection-manifest.json +7 -1
- package/dist/collection/components/ls-counters/ls-counters.js +4 -3
- package/dist/collection/components/ls-counters/ls-counters.utils.js +0 -1
- package/dist/collection/components/ls-status-history/ls-status-history.css +9 -4
- package/dist/collection/components/ls-status-history/ls-status-history.js +14 -6
- package/dist/collection/components/ls-status-history/ls-status-history.utils.js +3 -1
- package/dist/collection/utils/em-dash.js +2 -0
- package/dist/collection/utils/translations.js +4 -0
- package/dist/components/em-dash.js +1 -0
- package/dist/components/ls-counters.js +1 -1
- package/dist/components/ls-status-history.js +1 -1
- package/dist/components/store.js +1 -1
- package/dist/ednl-liftstatus-web-components/ednl-liftstatus-web-components.esm.js +1 -1
- package/dist/ednl-liftstatus-web-components/p-1833ab57.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-1ede7002.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-25d4fbe9.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-45d22b78.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-49dec6f7.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-565b648d.entry.js +12 -0
- package/dist/ednl-liftstatus-web-components/p-566b122a.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-59ed0f4c.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-71a443d6.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-833ca3b7.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-B9avPOKf.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-BGkoB2Fp.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-BNLlCAGL.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-BRcAanmR.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-BXzXRhF2.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-BuFJl4bx.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-Bw7PDNGZ.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-BwePdsnC.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-C2wsufGp.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-CPEl--Uc.js +1 -0
- package/dist/ednl-liftstatus-web-components/{p-BsQE35C8.js → p-CqIIZZwb.js} +1 -1
- package/dist/ednl-liftstatus-web-components/p-CqapRXVk.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-D6stZ-hq.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-DFTN3X9p.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-DLuZqxqb.js +2 -0
- package/dist/ednl-liftstatus-web-components/p-DZFB7QnF.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-Di-aPGj-.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-DjSNdVAB.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-GHMPnNk2.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-MFjd05op.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-UIJuKZgx.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-Zo7BqT5S.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-bXk7HZ2Z.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-bcfac6cf.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-c9888cfa.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-dbxvlVVS.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-f272fab3.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-f4b51684.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-f9ef29c8.entry.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-gYSXSXh4.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-nKqbk1fp.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-udS2Cuut.js +1 -0
- package/dist/ednl-liftstatus-web-components/p-zpY4DTin.js +1 -0
- package/dist/esm/api-UfFwgR8t.js +787 -0
- package/dist/esm/debounce-Bab2sXAi.js +304 -0
- package/dist/esm/ednl-liftstatus-web-components.js +3 -3
- package/dist/esm/em-dash-CqapRXVk.js +4 -0
- package/dist/esm/error-message-CeSJc06I.js +62 -0
- package/dist/esm/icons-D5SXjqxY.js +76 -0
- package/dist/esm/{index-BsQE35C8.js → index-CqIIZZwb.js} +1 -1
- package/dist/esm/init-zpY4DTin.js +10 -0
- package/dist/esm/is-empty-object-BNLlCAGL.js +5 -0
- package/dist/esm/isEmpty-CyFPxYUf.js +670 -0
- package/dist/esm/isNil-DjSNdVAB.js +25 -0
- package/dist/esm/isObjectLike-CPEl--Uc.js +132 -0
- package/dist/esm/isSymbol-BqXpHTHW.js +28 -0
- package/dist/esm/loader.js +3 -3
- package/dist/esm/locale-state-CWnIr7Tx.js +58 -0
- package/dist/esm/{ls-3d-scene_14.entry.js → ls-3d-scene.entry.js} +2066 -24355
- package/dist/esm/ls-counters.entry.js +503 -0
- package/dist/esm/ls-data.entry.js +4472 -0
- package/dist/esm/ls-date-picker.entry.js +3296 -0
- package/dist/esm/ls-energy-usage.entry.js +185 -171
- package/dist/esm/ls-history-swimlane.entry.js +1784 -0
- package/dist/esm/ls-indicator.entry.js +82 -0
- package/dist/esm/ls-recent-stops.entry.js +2177 -0
- package/dist/esm/ls-reset-steering.entry.js +206 -0
- package/dist/esm/ls-status-count.entry.js +209 -0
- package/dist/esm/ls-status-history.entry.js +486 -0
- package/dist/esm/ls-status-item.entry.js +239 -0
- package/dist/esm/ls-status-messages.entry.js +243 -0
- package/dist/esm/ls-status.entry.js +154 -0
- package/dist/esm/ls-swimlane.entry.js +818 -0
- package/dist/esm/nl-DnseJVT7.js +18 -0
- package/dist/esm/nodrag-SvS3YAgi.js +484 -0
- package/dist/esm/period-ETScFoSl.js +60 -0
- package/dist/esm/range-BRcAanmR.js +15 -0
- package/dist/esm/safe-relative-time-B4Au03u7.js +44 -0
- package/dist/esm/sensorInfo-C6-8bOVj.js +49 -0
- package/dist/esm/sensors-DFTN3X9p.js +298 -0
- package/dist/esm/sortBy-CkXKwZ1N.js +2357 -0
- package/dist/esm/status-codes.store-DAFOLojD.js +154 -0
- package/dist/esm/{init-LFKAglbp.js → store-DaB-RvVn.js} +90 -2538
- package/dist/esm/store-error-BIwzy5fm.js +20 -0
- package/dist/esm/swimlane-constants-Bw6I6ZqC.js +222 -0
- package/dist/esm/timestamps-zpfoEaEE.js +25 -0
- package/dist/esm/transform-B-QWH-7l.js +4254 -0
- package/dist/esm/values-CmHpsdW5.js +185 -0
- package/dist/types/components/ls-counters/ls-counters.utils.d.ts +0 -1
- package/dist/types/components/ls-status-history/ls-status-history.d.ts +5 -0
- package/dist/types/utils/em-dash.d.ts +2 -0
- package/dist/types/utils/translations.d.ts +4 -0
- package/dist/types/utils/types.d.ts +6 -0
- package/package.json +1 -1
- package/dist/ednl-liftstatus-web-components/p-85e27496.entry.js +0 -1
- package/dist/ednl-liftstatus-web-components/p-BIAdTj7v.js +0 -2
- package/dist/ednl-liftstatus-web-components/p-c1ca83a1.entry.js +0 -12
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var store = require('./store-ByFQQL9z.js');
|
|
4
|
+
var isEmpty = require('./isEmpty-C46AwMJT.js');
|
|
5
|
+
|
|
6
|
+
class HTTPError extends Error {
|
|
7
|
+
response;
|
|
8
|
+
request;
|
|
9
|
+
options;
|
|
10
|
+
constructor(response, request, options) {
|
|
11
|
+
const code = (response.status || response.status === 0) ? response.status : '';
|
|
12
|
+
const title = response.statusText || '';
|
|
13
|
+
const status = `${code} ${title}`.trim();
|
|
14
|
+
const reason = status ? `status code ${status}` : 'an unknown error';
|
|
15
|
+
super(`Request failed with ${reason}: ${request.method} ${request.url}`);
|
|
16
|
+
this.name = 'HTTPError';
|
|
17
|
+
this.response = response;
|
|
18
|
+
this.request = request;
|
|
19
|
+
this.options = options;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class TimeoutError extends Error {
|
|
24
|
+
request;
|
|
25
|
+
constructor(request) {
|
|
26
|
+
super(`Request timed out: ${request.method} ${request.url}`);
|
|
27
|
+
this.name = 'TimeoutError';
|
|
28
|
+
this.request = request;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const supportsRequestStreams = (() => {
|
|
33
|
+
let duplexAccessed = false;
|
|
34
|
+
let hasContentType = false;
|
|
35
|
+
const supportsReadableStream = typeof globalThis.ReadableStream === 'function';
|
|
36
|
+
const supportsRequest = typeof globalThis.Request === 'function';
|
|
37
|
+
if (supportsReadableStream && supportsRequest) {
|
|
38
|
+
try {
|
|
39
|
+
hasContentType = new globalThis.Request('https://empty.invalid', {
|
|
40
|
+
body: new globalThis.ReadableStream(),
|
|
41
|
+
method: 'POST',
|
|
42
|
+
// @ts-expect-error - Types are outdated.
|
|
43
|
+
get duplex() {
|
|
44
|
+
duplexAccessed = true;
|
|
45
|
+
return 'half';
|
|
46
|
+
},
|
|
47
|
+
}).headers.has('Content-Type');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// QQBrowser on iOS throws "unsupported BodyInit type" error (see issue #581)
|
|
51
|
+
if (error instanceof Error && error.message === 'unsupported BodyInit type') {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return duplexAccessed && !hasContentType;
|
|
58
|
+
})();
|
|
59
|
+
const supportsAbortController = typeof globalThis.AbortController === 'function';
|
|
60
|
+
const supportsAbortSignal = typeof globalThis.AbortSignal === 'function' && typeof globalThis.AbortSignal.any === 'function';
|
|
61
|
+
const supportsResponseStreams = typeof globalThis.ReadableStream === 'function';
|
|
62
|
+
const supportsFormData = typeof globalThis.FormData === 'function';
|
|
63
|
+
const requestMethods = ['get', 'post', 'put', 'patch', 'head', 'delete'];
|
|
64
|
+
const responseTypes = {
|
|
65
|
+
json: 'application/json',
|
|
66
|
+
text: 'text/*',
|
|
67
|
+
formData: 'multipart/form-data',
|
|
68
|
+
arrayBuffer: '*/*',
|
|
69
|
+
blob: '*/*',
|
|
70
|
+
// Supported in modern Fetch implementations (for example, browsers and recent Node.js/undici).
|
|
71
|
+
// We still feature-check at runtime before exposing the shortcut.
|
|
72
|
+
bytes: '*/*',
|
|
73
|
+
};
|
|
74
|
+
// The maximum value of a 32bit int (see issue #117)
|
|
75
|
+
const maxSafeTimeout = 2_147_483_647;
|
|
76
|
+
// Size in bytes of a typical form boundary, used to help estimate upload size
|
|
77
|
+
const usualFormBoundarySize = new TextEncoder().encode('------WebKitFormBoundaryaxpyiPgbbPti10Rw').length;
|
|
78
|
+
const stop = Symbol('stop');
|
|
79
|
+
const kyOptionKeys = {
|
|
80
|
+
json: true,
|
|
81
|
+
parseJson: true,
|
|
82
|
+
stringifyJson: true,
|
|
83
|
+
searchParams: true,
|
|
84
|
+
prefixUrl: true,
|
|
85
|
+
retry: true,
|
|
86
|
+
timeout: true,
|
|
87
|
+
hooks: true,
|
|
88
|
+
throwHttpErrors: true,
|
|
89
|
+
onDownloadProgress: true,
|
|
90
|
+
onUploadProgress: true,
|
|
91
|
+
fetch: true,
|
|
92
|
+
};
|
|
93
|
+
const requestOptionsRegistry = {
|
|
94
|
+
method: true,
|
|
95
|
+
headers: true,
|
|
96
|
+
body: true,
|
|
97
|
+
mode: true,
|
|
98
|
+
credentials: true,
|
|
99
|
+
cache: true,
|
|
100
|
+
redirect: true,
|
|
101
|
+
referrer: true,
|
|
102
|
+
referrerPolicy: true,
|
|
103
|
+
integrity: true,
|
|
104
|
+
keepalive: true,
|
|
105
|
+
signal: true,
|
|
106
|
+
window: true,
|
|
107
|
+
dispatcher: true,
|
|
108
|
+
duplex: true,
|
|
109
|
+
priority: true,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
113
|
+
const getBodySize = (body) => {
|
|
114
|
+
if (!body) {
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
if (body instanceof FormData) {
|
|
118
|
+
// This is an approximation, as FormData size calculation is not straightforward
|
|
119
|
+
let size = 0;
|
|
120
|
+
for (const [key, value] of body) {
|
|
121
|
+
size += usualFormBoundarySize;
|
|
122
|
+
size += new TextEncoder().encode(`Content-Disposition: form-data; name="${key}"`).length;
|
|
123
|
+
size += typeof value === 'string'
|
|
124
|
+
? new TextEncoder().encode(value).length
|
|
125
|
+
: value.size;
|
|
126
|
+
}
|
|
127
|
+
return size;
|
|
128
|
+
}
|
|
129
|
+
if (body instanceof Blob) {
|
|
130
|
+
return body.size;
|
|
131
|
+
}
|
|
132
|
+
if (body instanceof ArrayBuffer) {
|
|
133
|
+
return body.byteLength;
|
|
134
|
+
}
|
|
135
|
+
if (typeof body === 'string') {
|
|
136
|
+
return new TextEncoder().encode(body).length;
|
|
137
|
+
}
|
|
138
|
+
if (body instanceof URLSearchParams) {
|
|
139
|
+
return new TextEncoder().encode(body.toString()).length;
|
|
140
|
+
}
|
|
141
|
+
if ('byteLength' in body) {
|
|
142
|
+
return (body).byteLength;
|
|
143
|
+
}
|
|
144
|
+
if (typeof body === 'object' && body !== null) {
|
|
145
|
+
try {
|
|
146
|
+
const jsonString = JSON.stringify(body);
|
|
147
|
+
return new TextEncoder().encode(jsonString).length;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return 0; // Default case, unable to determine size
|
|
154
|
+
};
|
|
155
|
+
const streamResponse = (response, onDownloadProgress) => {
|
|
156
|
+
const totalBytes = Number(response.headers.get('content-length')) || 0;
|
|
157
|
+
let transferredBytes = 0;
|
|
158
|
+
if (response.status === 204) {
|
|
159
|
+
if (onDownloadProgress) {
|
|
160
|
+
onDownloadProgress({ percent: 1, totalBytes, transferredBytes }, new Uint8Array());
|
|
161
|
+
}
|
|
162
|
+
return new Response(null, {
|
|
163
|
+
status: response.status,
|
|
164
|
+
statusText: response.statusText,
|
|
165
|
+
headers: response.headers,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return new Response(new ReadableStream({
|
|
169
|
+
async start(controller) {
|
|
170
|
+
const reader = response.body.getReader();
|
|
171
|
+
if (onDownloadProgress) {
|
|
172
|
+
onDownloadProgress({ percent: 0, transferredBytes: 0, totalBytes }, new Uint8Array());
|
|
173
|
+
}
|
|
174
|
+
async function read() {
|
|
175
|
+
const { done, value } = await reader.read();
|
|
176
|
+
if (done) {
|
|
177
|
+
controller.close();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (onDownloadProgress) {
|
|
181
|
+
transferredBytes += value.byteLength;
|
|
182
|
+
const percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
|
|
183
|
+
onDownloadProgress({ percent, transferredBytes, totalBytes }, value);
|
|
184
|
+
}
|
|
185
|
+
controller.enqueue(value);
|
|
186
|
+
await read();
|
|
187
|
+
}
|
|
188
|
+
await read();
|
|
189
|
+
},
|
|
190
|
+
}), {
|
|
191
|
+
status: response.status,
|
|
192
|
+
statusText: response.statusText,
|
|
193
|
+
headers: response.headers,
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
197
|
+
const streamRequest = (request, onUploadProgress, originalBody) => {
|
|
198
|
+
// Use original body for size calculation since request.body is already a stream
|
|
199
|
+
const totalBytes = getBodySize(originalBody ?? request.body);
|
|
200
|
+
let transferredBytes = 0;
|
|
201
|
+
return new Request(request, {
|
|
202
|
+
// @ts-expect-error - Types are outdated.
|
|
203
|
+
duplex: 'half',
|
|
204
|
+
body: new ReadableStream({
|
|
205
|
+
async start(controller) {
|
|
206
|
+
const reader = request.body instanceof ReadableStream ? request.body.getReader() : new Response('').body.getReader();
|
|
207
|
+
async function read() {
|
|
208
|
+
const { done, value } = await reader.read();
|
|
209
|
+
if (done) {
|
|
210
|
+
// Ensure 100% progress is reported when the upload is complete
|
|
211
|
+
if (onUploadProgress) {
|
|
212
|
+
onUploadProgress({ percent: 1, transferredBytes, totalBytes: Math.max(totalBytes, transferredBytes) }, new Uint8Array());
|
|
213
|
+
}
|
|
214
|
+
controller.close();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
transferredBytes += value.byteLength;
|
|
218
|
+
let percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
|
|
219
|
+
if (totalBytes < transferredBytes || percent === 1) {
|
|
220
|
+
percent = 0.99;
|
|
221
|
+
}
|
|
222
|
+
if (onUploadProgress) {
|
|
223
|
+
onUploadProgress({ percent: Number(percent.toFixed(2)), transferredBytes, totalBytes }, value);
|
|
224
|
+
}
|
|
225
|
+
controller.enqueue(value);
|
|
226
|
+
await read();
|
|
227
|
+
}
|
|
228
|
+
await read();
|
|
229
|
+
},
|
|
230
|
+
}),
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
235
|
+
const isObject = (value) => value !== null && typeof value === 'object';
|
|
236
|
+
|
|
237
|
+
const validateAndMerge = (...sources) => {
|
|
238
|
+
for (const source of sources) {
|
|
239
|
+
if ((!isObject(source) || Array.isArray(source)) && source !== undefined) {
|
|
240
|
+
throw new TypeError('The `options` argument must be an object');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return deepMerge({}, ...sources);
|
|
244
|
+
};
|
|
245
|
+
const mergeHeaders = (source1 = {}, source2 = {}) => {
|
|
246
|
+
const result = new globalThis.Headers(source1);
|
|
247
|
+
const isHeadersInstance = source2 instanceof globalThis.Headers;
|
|
248
|
+
const source = new globalThis.Headers(source2);
|
|
249
|
+
for (const [key, value] of source.entries()) {
|
|
250
|
+
if ((isHeadersInstance && value === 'undefined') || value === undefined) {
|
|
251
|
+
result.delete(key);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
result.set(key, value);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
};
|
|
259
|
+
function newHookValue(original, incoming, property) {
|
|
260
|
+
return (Object.hasOwn(incoming, property) && incoming[property] === undefined)
|
|
261
|
+
? []
|
|
262
|
+
: deepMerge(original[property] ?? [], incoming[property] ?? []);
|
|
263
|
+
}
|
|
264
|
+
const mergeHooks = (original = {}, incoming = {}) => ({
|
|
265
|
+
beforeRequest: newHookValue(original, incoming, 'beforeRequest'),
|
|
266
|
+
beforeRetry: newHookValue(original, incoming, 'beforeRetry'),
|
|
267
|
+
afterResponse: newHookValue(original, incoming, 'afterResponse'),
|
|
268
|
+
beforeError: newHookValue(original, incoming, 'beforeError'),
|
|
269
|
+
});
|
|
270
|
+
// TODO: Make this strongly-typed (no `any`).
|
|
271
|
+
const deepMerge = (...sources) => {
|
|
272
|
+
let returnValue = {};
|
|
273
|
+
let headers = {};
|
|
274
|
+
let hooks = {};
|
|
275
|
+
for (const source of sources) {
|
|
276
|
+
if (Array.isArray(source)) {
|
|
277
|
+
if (!Array.isArray(returnValue)) {
|
|
278
|
+
returnValue = [];
|
|
279
|
+
}
|
|
280
|
+
returnValue = [...returnValue, ...source];
|
|
281
|
+
}
|
|
282
|
+
else if (isObject(source)) {
|
|
283
|
+
for (let [key, value] of Object.entries(source)) {
|
|
284
|
+
if (isObject(value) && key in returnValue) {
|
|
285
|
+
value = deepMerge(returnValue[key], value);
|
|
286
|
+
}
|
|
287
|
+
returnValue = { ...returnValue, [key]: value };
|
|
288
|
+
}
|
|
289
|
+
if (isObject(source.hooks)) {
|
|
290
|
+
hooks = mergeHooks(hooks, source.hooks);
|
|
291
|
+
returnValue.hooks = hooks;
|
|
292
|
+
}
|
|
293
|
+
if (isObject(source.headers)) {
|
|
294
|
+
headers = mergeHeaders(headers, source.headers);
|
|
295
|
+
returnValue.headers = headers;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return returnValue;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const normalizeRequestMethod = (input) => requestMethods.includes(input) ? input.toUpperCase() : input;
|
|
303
|
+
const retryMethods = ['get', 'put', 'head', 'delete', 'options', 'trace'];
|
|
304
|
+
const retryStatusCodes = [408, 413, 429, 500, 502, 503, 504];
|
|
305
|
+
const retryAfterStatusCodes = [413, 429, 503];
|
|
306
|
+
const defaultRetryOptions = {
|
|
307
|
+
limit: 2,
|
|
308
|
+
methods: retryMethods,
|
|
309
|
+
statusCodes: retryStatusCodes,
|
|
310
|
+
afterStatusCodes: retryAfterStatusCodes,
|
|
311
|
+
maxRetryAfter: Number.POSITIVE_INFINITY,
|
|
312
|
+
backoffLimit: Number.POSITIVE_INFINITY,
|
|
313
|
+
delay: attemptCount => 0.3 * (2 ** (attemptCount - 1)) * 1000,
|
|
314
|
+
};
|
|
315
|
+
const normalizeRetryOptions = (retry = {}) => {
|
|
316
|
+
if (typeof retry === 'number') {
|
|
317
|
+
return {
|
|
318
|
+
...defaultRetryOptions,
|
|
319
|
+
limit: retry,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
if (retry.methods && !Array.isArray(retry.methods)) {
|
|
323
|
+
throw new Error('retry.methods must be an array');
|
|
324
|
+
}
|
|
325
|
+
if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {
|
|
326
|
+
throw new Error('retry.statusCodes must be an array');
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
...defaultRetryOptions,
|
|
330
|
+
...retry,
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
// `Promise.race()` workaround (#91)
|
|
335
|
+
async function timeout(request, init, abortController, options) {
|
|
336
|
+
return new Promise((resolve, reject) => {
|
|
337
|
+
const timeoutId = setTimeout(() => {
|
|
338
|
+
if (abortController) {
|
|
339
|
+
abortController.abort();
|
|
340
|
+
}
|
|
341
|
+
reject(new TimeoutError(request));
|
|
342
|
+
}, options.timeout);
|
|
343
|
+
void options
|
|
344
|
+
.fetch(request, init)
|
|
345
|
+
.then(resolve)
|
|
346
|
+
.catch(reject)
|
|
347
|
+
.then(() => {
|
|
348
|
+
clearTimeout(timeoutId);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// https://github.com/sindresorhus/delay/tree/ab98ae8dfcb38e1593286c94d934e70d14a4e111
|
|
354
|
+
async function delay(ms, { signal }) {
|
|
355
|
+
return new Promise((resolve, reject) => {
|
|
356
|
+
if (signal) {
|
|
357
|
+
signal.throwIfAborted();
|
|
358
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
359
|
+
}
|
|
360
|
+
function abortHandler() {
|
|
361
|
+
clearTimeout(timeoutId);
|
|
362
|
+
reject(signal.reason);
|
|
363
|
+
}
|
|
364
|
+
const timeoutId = setTimeout(() => {
|
|
365
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
366
|
+
resolve();
|
|
367
|
+
}, ms);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const findUnknownOptions = (request, options) => {
|
|
372
|
+
const unknownOptions = {};
|
|
373
|
+
for (const key in options) {
|
|
374
|
+
if (!(key in requestOptionsRegistry) && !(key in kyOptionKeys) && !(key in request)) {
|
|
375
|
+
unknownOptions[key] = options[key];
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return unknownOptions;
|
|
379
|
+
};
|
|
380
|
+
const hasSearchParameters = (search) => {
|
|
381
|
+
if (search === undefined) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
// The `typeof array` still gives "object", so we need different checking for array.
|
|
385
|
+
if (Array.isArray(search)) {
|
|
386
|
+
return search.length > 0;
|
|
387
|
+
}
|
|
388
|
+
if (search instanceof URLSearchParams) {
|
|
389
|
+
return search.size > 0;
|
|
390
|
+
}
|
|
391
|
+
// Record
|
|
392
|
+
if (typeof search === 'object') {
|
|
393
|
+
return Object.keys(search).length > 0;
|
|
394
|
+
}
|
|
395
|
+
if (typeof search === 'string') {
|
|
396
|
+
return search.trim().length > 0;
|
|
397
|
+
}
|
|
398
|
+
return Boolean(search);
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
class Ky {
|
|
402
|
+
static create(input, options) {
|
|
403
|
+
const ky = new Ky(input, options);
|
|
404
|
+
const function_ = async () => {
|
|
405
|
+
if (typeof ky._options.timeout === 'number' && ky._options.timeout > maxSafeTimeout) {
|
|
406
|
+
throw new RangeError(`The \`timeout\` option cannot be greater than ${maxSafeTimeout}`);
|
|
407
|
+
}
|
|
408
|
+
// Delay the fetch so that body method shortcuts can set the Accept header
|
|
409
|
+
await Promise.resolve();
|
|
410
|
+
// Before using ky.request, _fetch clones it and saves the clone for future retries to use.
|
|
411
|
+
// If retry is not needed, close the cloned request's ReadableStream for memory safety.
|
|
412
|
+
let response = await ky._fetch();
|
|
413
|
+
for (const hook of ky._options.hooks.afterResponse) {
|
|
414
|
+
// eslint-disable-next-line no-await-in-loop
|
|
415
|
+
const modifiedResponse = await hook(ky.request, ky._options, ky._decorateResponse(response.clone()));
|
|
416
|
+
if (modifiedResponse instanceof globalThis.Response) {
|
|
417
|
+
response = modifiedResponse;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
ky._decorateResponse(response);
|
|
421
|
+
if (!response.ok && ky._options.throwHttpErrors) {
|
|
422
|
+
let error = new HTTPError(response, ky.request, ky._options);
|
|
423
|
+
for (const hook of ky._options.hooks.beforeError) {
|
|
424
|
+
// eslint-disable-next-line no-await-in-loop
|
|
425
|
+
error = await hook(error);
|
|
426
|
+
}
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
// If `onDownloadProgress` is passed, it uses the stream API internally
|
|
430
|
+
if (ky._options.onDownloadProgress) {
|
|
431
|
+
if (typeof ky._options.onDownloadProgress !== 'function') {
|
|
432
|
+
throw new TypeError('The `onDownloadProgress` option must be a function');
|
|
433
|
+
}
|
|
434
|
+
if (!supportsResponseStreams) {
|
|
435
|
+
throw new Error('Streams are not supported in your environment. `ReadableStream` is missing.');
|
|
436
|
+
}
|
|
437
|
+
return streamResponse(response.clone(), ky._options.onDownloadProgress);
|
|
438
|
+
}
|
|
439
|
+
return response;
|
|
440
|
+
};
|
|
441
|
+
const isRetriableMethod = ky._options.retry.methods.includes(ky.request.method.toLowerCase());
|
|
442
|
+
const result = (isRetriableMethod ? ky._retry(function_) : function_())
|
|
443
|
+
.finally(async () => {
|
|
444
|
+
// Now that we know a retry is not needed, close the ReadableStream of the cloned request.
|
|
445
|
+
if (!ky.request.bodyUsed) {
|
|
446
|
+
await ky.request.body?.cancel();
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
for (const [type, mimeType] of Object.entries(responseTypes)) {
|
|
450
|
+
// Only expose `.bytes()` when the environment implements it.
|
|
451
|
+
if (type === 'bytes'
|
|
452
|
+
&& typeof globalThis.Response?.prototype?.bytes !== 'function') {
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
result[type] = async () => {
|
|
456
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
457
|
+
ky.request.headers.set('accept', ky.request.headers.get('accept') || mimeType);
|
|
458
|
+
const response = await result;
|
|
459
|
+
if (type === 'json') {
|
|
460
|
+
if (response.status === 204) {
|
|
461
|
+
return '';
|
|
462
|
+
}
|
|
463
|
+
const text = await response.text();
|
|
464
|
+
if (text === '') {
|
|
465
|
+
return '';
|
|
466
|
+
}
|
|
467
|
+
if (options.parseJson) {
|
|
468
|
+
return options.parseJson(text);
|
|
469
|
+
}
|
|
470
|
+
return JSON.parse(text);
|
|
471
|
+
}
|
|
472
|
+
return response[type]();
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
478
|
+
static #normalizeSearchParams(searchParams) {
|
|
479
|
+
// Filter out undefined values from plain objects
|
|
480
|
+
if (searchParams && typeof searchParams === 'object' && !Array.isArray(searchParams) && !(searchParams instanceof URLSearchParams)) {
|
|
481
|
+
return Object.fromEntries(Object.entries(searchParams).filter(([, value]) => value !== undefined));
|
|
482
|
+
}
|
|
483
|
+
return searchParams;
|
|
484
|
+
}
|
|
485
|
+
request;
|
|
486
|
+
abortController;
|
|
487
|
+
_retryCount = 0;
|
|
488
|
+
_input;
|
|
489
|
+
_options;
|
|
490
|
+
// eslint-disable-next-line complexity
|
|
491
|
+
constructor(input, options = {}) {
|
|
492
|
+
this._input = input;
|
|
493
|
+
this._options = {
|
|
494
|
+
...options,
|
|
495
|
+
headers: mergeHeaders(this._input.headers, options.headers),
|
|
496
|
+
hooks: mergeHooks({
|
|
497
|
+
beforeRequest: [],
|
|
498
|
+
beforeRetry: [],
|
|
499
|
+
beforeError: [],
|
|
500
|
+
afterResponse: [],
|
|
501
|
+
}, options.hooks),
|
|
502
|
+
method: normalizeRequestMethod(options.method ?? this._input.method ?? 'GET'),
|
|
503
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
504
|
+
prefixUrl: String(options.prefixUrl || ''),
|
|
505
|
+
retry: normalizeRetryOptions(options.retry),
|
|
506
|
+
throwHttpErrors: options.throwHttpErrors !== false,
|
|
507
|
+
timeout: options.timeout ?? 10_000,
|
|
508
|
+
fetch: options.fetch ?? globalThis.fetch.bind(globalThis),
|
|
509
|
+
};
|
|
510
|
+
if (typeof this._input !== 'string' && !(this._input instanceof URL || this._input instanceof globalThis.Request)) {
|
|
511
|
+
throw new TypeError('`input` must be a string, URL, or Request');
|
|
512
|
+
}
|
|
513
|
+
if (this._options.prefixUrl && typeof this._input === 'string') {
|
|
514
|
+
if (this._input.startsWith('/')) {
|
|
515
|
+
throw new Error('`input` must not begin with a slash when using `prefixUrl`');
|
|
516
|
+
}
|
|
517
|
+
if (!this._options.prefixUrl.endsWith('/')) {
|
|
518
|
+
this._options.prefixUrl += '/';
|
|
519
|
+
}
|
|
520
|
+
this._input = this._options.prefixUrl + this._input;
|
|
521
|
+
}
|
|
522
|
+
if (supportsAbortController && supportsAbortSignal) {
|
|
523
|
+
const originalSignal = this._options.signal ?? this._input.signal;
|
|
524
|
+
this.abortController = new globalThis.AbortController();
|
|
525
|
+
this._options.signal = originalSignal ? AbortSignal.any([originalSignal, this.abortController.signal]) : this.abortController.signal;
|
|
526
|
+
}
|
|
527
|
+
if (supportsRequestStreams) {
|
|
528
|
+
// @ts-expect-error - Types are outdated.
|
|
529
|
+
this._options.duplex = 'half';
|
|
530
|
+
}
|
|
531
|
+
if (this._options.json !== undefined) {
|
|
532
|
+
this._options.body = this._options.stringifyJson?.(this._options.json) ?? JSON.stringify(this._options.json);
|
|
533
|
+
this._options.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
|
|
534
|
+
}
|
|
535
|
+
this.request = new globalThis.Request(this._input, this._options);
|
|
536
|
+
if (hasSearchParameters(this._options.searchParams)) {
|
|
537
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
538
|
+
const textSearchParams = typeof this._options.searchParams === 'string'
|
|
539
|
+
? this._options.searchParams.replace(/^\?/, '')
|
|
540
|
+
: new URLSearchParams(Ky.#normalizeSearchParams(this._options.searchParams)).toString();
|
|
541
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
542
|
+
const searchParams = '?' + textSearchParams;
|
|
543
|
+
const url = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, searchParams);
|
|
544
|
+
// To provide correct form boundary, Content-Type header should be deleted each time when new Request instantiated from another one
|
|
545
|
+
if (((supportsFormData && this._options.body instanceof globalThis.FormData)
|
|
546
|
+
|| this._options.body instanceof URLSearchParams) && !(this._options.headers && this._options.headers['content-type'])) {
|
|
547
|
+
this.request.headers.delete('content-type');
|
|
548
|
+
}
|
|
549
|
+
// The spread of `this.request` is required as otherwise it misses the `duplex` option for some reason and throws.
|
|
550
|
+
this.request = new globalThis.Request(new globalThis.Request(url, { ...this.request }), this._options);
|
|
551
|
+
}
|
|
552
|
+
// If `onUploadProgress` is passed, it uses the stream API internally
|
|
553
|
+
if (this._options.onUploadProgress) {
|
|
554
|
+
if (typeof this._options.onUploadProgress !== 'function') {
|
|
555
|
+
throw new TypeError('The `onUploadProgress` option must be a function');
|
|
556
|
+
}
|
|
557
|
+
if (!supportsRequestStreams) {
|
|
558
|
+
throw new Error('Request streams are not supported in your environment. The `duplex` option for `Request` is not available.');
|
|
559
|
+
}
|
|
560
|
+
const originalBody = this.request.body;
|
|
561
|
+
if (originalBody) {
|
|
562
|
+
// Pass original body to calculate size correctly (before it becomes a stream)
|
|
563
|
+
this.request = streamRequest(this.request, this._options.onUploadProgress, this._options.body);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
_calculateRetryDelay(error) {
|
|
568
|
+
this._retryCount++;
|
|
569
|
+
if (this._retryCount > this._options.retry.limit || error instanceof TimeoutError) {
|
|
570
|
+
throw error;
|
|
571
|
+
}
|
|
572
|
+
if (error instanceof HTTPError) {
|
|
573
|
+
if (!this._options.retry.statusCodes.includes(error.response.status)) {
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
const retryAfter = error.response.headers.get('Retry-After')
|
|
577
|
+
?? error.response.headers.get('RateLimit-Reset')
|
|
578
|
+
?? error.response.headers.get('X-RateLimit-Reset') // GitHub
|
|
579
|
+
?? error.response.headers.get('X-Rate-Limit-Reset'); // Twitter
|
|
580
|
+
if (retryAfter && this._options.retry.afterStatusCodes.includes(error.response.status)) {
|
|
581
|
+
let after = Number(retryAfter) * 1000;
|
|
582
|
+
if (Number.isNaN(after)) {
|
|
583
|
+
after = Date.parse(retryAfter) - Date.now();
|
|
584
|
+
}
|
|
585
|
+
else if (after >= Date.parse('2024-01-01')) {
|
|
586
|
+
// A large number is treated as a timestamp (fixed threshold protects against clock skew)
|
|
587
|
+
after -= Date.now();
|
|
588
|
+
}
|
|
589
|
+
const max = this._options.retry.maxRetryAfter ?? after;
|
|
590
|
+
return after < max ? after : max;
|
|
591
|
+
}
|
|
592
|
+
if (error.response.status === 413) {
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
const retryDelay = this._options.retry.delay(this._retryCount);
|
|
597
|
+
return Math.min(this._options.retry.backoffLimit, retryDelay);
|
|
598
|
+
}
|
|
599
|
+
_decorateResponse(response) {
|
|
600
|
+
if (this._options.parseJson) {
|
|
601
|
+
response.json = async () => this._options.parseJson(await response.text());
|
|
602
|
+
}
|
|
603
|
+
return response;
|
|
604
|
+
}
|
|
605
|
+
async _retry(function_) {
|
|
606
|
+
try {
|
|
607
|
+
return await function_();
|
|
608
|
+
}
|
|
609
|
+
catch (error) {
|
|
610
|
+
const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout);
|
|
611
|
+
if (this._retryCount < 1) {
|
|
612
|
+
throw error;
|
|
613
|
+
}
|
|
614
|
+
await delay(ms, { signal: this._options.signal });
|
|
615
|
+
for (const hook of this._options.hooks.beforeRetry) {
|
|
616
|
+
// eslint-disable-next-line no-await-in-loop
|
|
617
|
+
const hookResult = await hook({
|
|
618
|
+
request: this.request,
|
|
619
|
+
options: this._options,
|
|
620
|
+
error: error,
|
|
621
|
+
retryCount: this._retryCount,
|
|
622
|
+
});
|
|
623
|
+
// If `stop` is returned from the hook, the retry process is stopped
|
|
624
|
+
if (hookResult === stop) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return this._retry(function_);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
async _fetch() {
|
|
632
|
+
for (const hook of this._options.hooks.beforeRequest) {
|
|
633
|
+
// eslint-disable-next-line no-await-in-loop
|
|
634
|
+
const result = await hook(this.request, this._options);
|
|
635
|
+
if (result instanceof Request) {
|
|
636
|
+
this.request = result;
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
if (result instanceof Response) {
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
const nonRequestOptions = findUnknownOptions(this.request, this._options);
|
|
644
|
+
// Cloning is done here to prepare in advance for retries
|
|
645
|
+
const mainRequest = this.request;
|
|
646
|
+
this.request = mainRequest.clone();
|
|
647
|
+
if (this._options.timeout === false) {
|
|
648
|
+
return this._options.fetch(mainRequest, nonRequestOptions);
|
|
649
|
+
}
|
|
650
|
+
return timeout(mainRequest, nonRequestOptions, this.abortController, this._options);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/*! MIT License © Sindre Sorhus */
|
|
655
|
+
const createInstance = (defaults) => {
|
|
656
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
657
|
+
const ky = (input, options) => Ky.create(input, validateAndMerge(defaults, options));
|
|
658
|
+
for (const method of requestMethods) {
|
|
659
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
660
|
+
ky[method] = (input, options) => Ky.create(input, validateAndMerge(defaults, options, { method }));
|
|
661
|
+
}
|
|
662
|
+
ky.create = (newDefaults) => createInstance(validateAndMerge(newDefaults));
|
|
663
|
+
ky.extend = (newDefaults) => {
|
|
664
|
+
if (typeof newDefaults === 'function') {
|
|
665
|
+
newDefaults = newDefaults(defaults ?? {});
|
|
666
|
+
}
|
|
667
|
+
return createInstance(validateAndMerge(defaults, newDefaults));
|
|
668
|
+
};
|
|
669
|
+
ky.stop = stop;
|
|
670
|
+
return ky;
|
|
671
|
+
};
|
|
672
|
+
const ky = createInstance();
|
|
673
|
+
|
|
674
|
+
const REQUEST_TIMEOUT_MS = 60000;
|
|
675
|
+
const authHeader = (accessToken) => ({
|
|
676
|
+
Authorization: `Bearer ${accessToken}`,
|
|
677
|
+
});
|
|
678
|
+
class MissingApiConfigError extends Error {
|
|
679
|
+
constructor(message) {
|
|
680
|
+
super(message);
|
|
681
|
+
this.name = 'MissingApiConfigError';
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async function authenticate({ apiUrl, accessToken }) {
|
|
685
|
+
return ky
|
|
686
|
+
.post(`${apiUrl}/liftstatus/auth`, {
|
|
687
|
+
headers: authHeader(accessToken),
|
|
688
|
+
json: { accessToken },
|
|
689
|
+
throwHttpErrors: true,
|
|
690
|
+
})
|
|
691
|
+
.json();
|
|
692
|
+
}
|
|
693
|
+
async function fetchSensorSummary({ apiUrl, accessToken, objectType, objectId, sensorId, from, }) {
|
|
694
|
+
return ky
|
|
695
|
+
.get(`${apiUrl}/liftstatus/${objectType}/${objectId}/sensor/${sensorId}/summary`, {
|
|
696
|
+
headers: authHeader(accessToken),
|
|
697
|
+
searchParams: { from },
|
|
698
|
+
throwHttpErrors: true,
|
|
699
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
700
|
+
})
|
|
701
|
+
.json();
|
|
702
|
+
}
|
|
703
|
+
async function fetchSensorData({ apiUrl, accessToken, objectType, objectId, from, to, sensors, }) {
|
|
704
|
+
return ky
|
|
705
|
+
.post(`${apiUrl}/liftstatus/${objectType}/${objectId}/sensor`, {
|
|
706
|
+
headers: authHeader(accessToken),
|
|
707
|
+
searchParams: {
|
|
708
|
+
from,
|
|
709
|
+
to,
|
|
710
|
+
sensors: sensors.map(String).join(),
|
|
711
|
+
},
|
|
712
|
+
throwHttpErrors: true,
|
|
713
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
714
|
+
})
|
|
715
|
+
.json();
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Fetches the status codes of the given impact levels that were active in the
|
|
719
|
+
* given period. Only concrete levels can be asked for: the API has a level for
|
|
720
|
+
* every code it returns, so it has no "unknown" to filter on. An empty `levels`
|
|
721
|
+
* reads as "no filter" server side, so pass at least one level.
|
|
722
|
+
*/
|
|
723
|
+
async function fetchStatusCodeHistory({ apiUrl, accessToken, objectType, objectId, from, to, levels, }) {
|
|
724
|
+
return ky
|
|
725
|
+
.get(`${apiUrl}/liftstatus/${objectType}/${objectId}/status-code`, {
|
|
726
|
+
headers: authHeader(accessToken),
|
|
727
|
+
searchParams: { from, to, levels: levels.join() },
|
|
728
|
+
throwHttpErrors: true,
|
|
729
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
730
|
+
})
|
|
731
|
+
.json();
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Fetches the reference (description and impact level) of every status code
|
|
735
|
+
* whose code starts with `controller`. The API needs at least 4 characters.
|
|
736
|
+
*/
|
|
737
|
+
async function fetchStatusCodeReference({ apiUrl, accessToken, controller, }) {
|
|
738
|
+
return ky
|
|
739
|
+
.get(`${apiUrl}/liftstatus/status-codes/reference`, {
|
|
740
|
+
headers: authHeader(accessToken),
|
|
741
|
+
searchParams: { controller },
|
|
742
|
+
throwHttpErrors: true,
|
|
743
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
744
|
+
})
|
|
745
|
+
.json();
|
|
746
|
+
}
|
|
747
|
+
async function fetchSensorSummaries({ apiUrl, accessToken, objectType, objectId, from, to, sensors, }) {
|
|
748
|
+
return ky
|
|
749
|
+
.post(`${apiUrl}/liftstatus/${objectType}/${objectId}/sensor/summary`, {
|
|
750
|
+
headers: authHeader(accessToken),
|
|
751
|
+
searchParams: {
|
|
752
|
+
from,
|
|
753
|
+
to,
|
|
754
|
+
sensors: sensors.map(String).join(),
|
|
755
|
+
},
|
|
756
|
+
throwHttpErrors: true,
|
|
757
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
758
|
+
})
|
|
759
|
+
.json();
|
|
760
|
+
}
|
|
761
|
+
/** A sensor series over the given period, bucketed by `resolution`. */
|
|
762
|
+
async function fetchSensorSeries({ apiUrl, accessToken, objectType, objectId, from, to, sensors, resolution, }) {
|
|
763
|
+
return ky
|
|
764
|
+
.post(`${apiUrl}/liftstatus/${objectType}/${objectId}/sensor/series`, {
|
|
765
|
+
headers: authHeader(accessToken),
|
|
766
|
+
searchParams: {
|
|
767
|
+
from,
|
|
768
|
+
to,
|
|
769
|
+
sensors: sensors.map(String).join(),
|
|
770
|
+
resolution,
|
|
771
|
+
},
|
|
772
|
+
throwHttpErrors: true,
|
|
773
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
774
|
+
})
|
|
775
|
+
.json();
|
|
776
|
+
}
|
|
777
|
+
async function sendResetCommand({ idKey, command }) {
|
|
778
|
+
const store$1 = await store.getStore(idKey);
|
|
779
|
+
const { accessToken, apiUrl, externalIdentifier, objectType } = store$1.state;
|
|
780
|
+
if (apiUrl === undefined || accessToken === undefined || objectType === undefined || isEmpty.isEmpty(apiUrl) || isEmpty.isEmpty(accessToken) || isEmpty.isEmpty(objectType)) {
|
|
781
|
+
throw new MissingApiConfigError('Cannot send reset command: missing API URL, access token, or object type.');
|
|
782
|
+
}
|
|
783
|
+
await ky.post(`${apiUrl}/liftstatus/command/${objectType}/${externalIdentifier}/${command}`, {
|
|
784
|
+
headers: authHeader(accessToken),
|
|
785
|
+
throwHttpErrors: true,
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
exports.authenticate = authenticate;
|
|
790
|
+
exports.fetchSensorData = fetchSensorData;
|
|
791
|
+
exports.fetchSensorSeries = fetchSensorSeries;
|
|
792
|
+
exports.fetchSensorSummaries = fetchSensorSummaries;
|
|
793
|
+
exports.fetchSensorSummary = fetchSensorSummary;
|
|
794
|
+
exports.fetchStatusCodeHistory = fetchStatusCodeHistory;
|
|
795
|
+
exports.fetchStatusCodeReference = fetchStatusCodeReference;
|
|
796
|
+
exports.sendResetCommand = sendResetCommand;
|