@softwear/latestcollectioncore 1.0.161 → 1.0.163
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/articleStatus.js +35 -24
- package/dist/lcAxios.d.ts +5 -1
- package/dist/lcAxios.js +97 -2
- package/package.json +1 -1
- package/src/articleStatus.ts +39 -25
- package/src/lcAxios.ts +54 -3
- package/test/lcAxios.spec.ts +52 -0
package/dist/articleStatus.js
CHANGED
|
@@ -99,6 +99,28 @@ function buildAggregationEvaluator(aggregationExpression) {
|
|
|
99
99
|
function prepareSubTotalAggKey(aggKey) {
|
|
100
100
|
return aggKey.split('\t').slice(0, -1).join('\t').concat(' Σ');
|
|
101
101
|
}
|
|
102
|
+
/** Same as filtrex std.coerceBoolean(customProp(...)) for bare join keys on the transaction */
|
|
103
|
+
function coerceJoinKeyValue(v) {
|
|
104
|
+
return typeof v === 'boolean' ? +v : v;
|
|
105
|
+
}
|
|
106
|
+
function getTrieLeaf(root, transaction, keys) {
|
|
107
|
+
const nrKeys = keys.length;
|
|
108
|
+
if (nrKeys === 0)
|
|
109
|
+
return root;
|
|
110
|
+
let node = root;
|
|
111
|
+
for (let i = 0; i < nrKeys; i++) {
|
|
112
|
+
const k = coerceJoinKeyValue(transaction[keys[i]]);
|
|
113
|
+
if (!node.children)
|
|
114
|
+
node.children = new Map();
|
|
115
|
+
let next = node.children.get(k);
|
|
116
|
+
if (!next) {
|
|
117
|
+
next = {};
|
|
118
|
+
node.children.set(k, next);
|
|
119
|
+
}
|
|
120
|
+
node = next;
|
|
121
|
+
}
|
|
122
|
+
return node;
|
|
123
|
+
}
|
|
102
124
|
/*
|
|
103
125
|
* A factory function that returns a function that can be used to aggregate transactions
|
|
104
126
|
* The factory function is called once for each aggregationExpression
|
|
@@ -122,47 +144,36 @@ function prepareSubTotalAggKey(aggKey) {
|
|
|
122
144
|
* @returns {Function} - The aggregator function
|
|
123
145
|
*/
|
|
124
146
|
function aggregator({ beginTimestamp, endTimestamp, filterExpression, aggregationExpression, rawAggregations, maxRows, totals, subtotalsForOuterGrouper, parentGroupTotals, }) {
|
|
125
|
-
const filterExpressionCache = {};
|
|
126
147
|
let filter;
|
|
127
|
-
let
|
|
148
|
+
let filterGranularity = [];
|
|
149
|
+
const filterTrieRoot = {};
|
|
128
150
|
if (filterExpression) {
|
|
129
151
|
filter = (0, filtrex_1.compileExpression)(filterExpression, filtrexOptions);
|
|
130
|
-
|
|
131
|
-
// The granularity of the cache is determined by the joined tables in the filterExpression
|
|
132
|
-
const filterGranularity = Object.entries(globalJoinableTables)
|
|
152
|
+
filterGranularity = Object.entries(globalJoinableTables)
|
|
133
153
|
.filter((join) => filterExpression.includes(join[0] + '.'))
|
|
134
154
|
.map((join) => join[1]);
|
|
135
|
-
filterDependencyEvaluator = (0, filtrex_1.compileExpression)(filterGranularity.join('+'), filtrexOptions);
|
|
136
155
|
}
|
|
137
156
|
const aggregationEvaluator = buildAggregationEvaluator(aggregationExpression);
|
|
138
|
-
// Maintain a cache of evaluated aggregationExpressions
|
|
139
|
-
// The granularity of the cache is determined by the joined tables in the aggregationExpression
|
|
140
|
-
const aggregationExpressionCache = {};
|
|
141
157
|
const aggregationGranularity = Object.entries(globalJoinableTables)
|
|
142
158
|
.filter((join) => aggregationExpression.includes(join[0] + '.'))
|
|
143
159
|
.map((join) => join[1]);
|
|
144
|
-
|
|
145
|
-
if (!aggregationDependencyExpression)
|
|
146
|
-
aggregationDependencyExpression = '"N.A."';
|
|
147
|
-
const aggregationDependencyEvaluator = (0, filtrex_1.compileExpression)(aggregationDependencyExpression, filtrexOptions);
|
|
160
|
+
const aggregationTrieRoot = {};
|
|
148
161
|
return function (transaction) {
|
|
149
162
|
if (filter) {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
if (filterExpression == -1)
|
|
163
|
+
const filterLeaf = getTrieLeaf(filterTrieRoot, transaction, filterGranularity);
|
|
164
|
+
if (filterLeaf.filterResult === -1)
|
|
153
165
|
return;
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
if (
|
|
166
|
+
if (filterLeaf.filterResult === undefined) {
|
|
167
|
+
filterLeaf.filterResult = filter(transaction) ? 1 : -1;
|
|
168
|
+
if (filterLeaf.filterResult === -1)
|
|
157
169
|
return;
|
|
158
170
|
}
|
|
159
171
|
}
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
aggregateKey = aggregationEvaluator(transaction);
|
|
164
|
-
aggregationExpressionCache[aggregationDependency] = aggregateKey;
|
|
172
|
+
const aggregateKeyLeaf = getTrieLeaf(aggregationTrieRoot, transaction, aggregationGranularity);
|
|
173
|
+
if (!aggregateKeyLeaf.aggregateKey) {
|
|
174
|
+
aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction);
|
|
165
175
|
}
|
|
176
|
+
const aggregateKey = aggregateKeyLeaf.aggregateKey;
|
|
166
177
|
// Prepare joined values for derived fields
|
|
167
178
|
if (transaction.type == types_1.transactionTypeE.SALE) {
|
|
168
179
|
const sku = globalRelations['sku'][transaction.ean];
|
package/dist/lcAxios.d.ts
CHANGED
|
@@ -13,11 +13,15 @@ export interface AxiosRequestConfig<D = any> {
|
|
|
13
13
|
params?: Record<string, any>;
|
|
14
14
|
headers?: Record<string, string | undefined> | any;
|
|
15
15
|
timeout?: number;
|
|
16
|
-
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
16
|
+
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer' | 'stream';
|
|
17
17
|
validateStatus?: (status: number) => boolean;
|
|
18
18
|
transformRequest?: AxiosTransformer | AxiosTransformer[];
|
|
19
19
|
transformResponse?: AxiosTransformer | AxiosTransformer[];
|
|
20
20
|
withCredentials?: boolean;
|
|
21
|
+
auth?: {
|
|
22
|
+
username?: string;
|
|
23
|
+
password?: string;
|
|
24
|
+
};
|
|
21
25
|
/** Axios-only; ignored — fetch handles Content-Encoding when reading the body */
|
|
22
26
|
decompress?: boolean;
|
|
23
27
|
}
|
package/dist/lcAxios.js
CHANGED
|
@@ -15,6 +15,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
15
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
16
|
});
|
|
17
17
|
};
|
|
18
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
19
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
20
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
21
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
22
|
+
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
23
|
+
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
24
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
25
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
26
|
+
function fulfill(value) { resume("next", value); }
|
|
27
|
+
function reject(value) { resume("throw", value); }
|
|
28
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
29
|
+
};
|
|
30
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
31
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
32
|
+
var m = o[Symbol.asyncIterator], i;
|
|
33
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
34
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
35
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
36
|
+
};
|
|
18
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
38
|
exports.isAxiosError = exports.lcAxios = exports.createAxiosInstance = exports.axiosRetry = exports.exponentialDelay = void 0;
|
|
20
39
|
function isAxiosError(payload) {
|
|
@@ -113,6 +132,72 @@ function flattenHeaders(h, method) {
|
|
|
113
132
|
}
|
|
114
133
|
return out;
|
|
115
134
|
}
|
|
135
|
+
function encodeBase64(input) {
|
|
136
|
+
if (typeof Buffer !== 'undefined')
|
|
137
|
+
return Buffer.from(input, 'utf8').toString('base64');
|
|
138
|
+
if (typeof btoa !== 'undefined')
|
|
139
|
+
return btoa(input);
|
|
140
|
+
throw new Error('Base64 encoding unavailable');
|
|
141
|
+
}
|
|
142
|
+
function applyAuthHeader(headers, auth) {
|
|
143
|
+
if (!auth)
|
|
144
|
+
return;
|
|
145
|
+
const username = auth.username || '';
|
|
146
|
+
const password = auth.password || '';
|
|
147
|
+
headers['Authorization'] = `Basic ${encodeBase64(`${username}:${password}`)}`;
|
|
148
|
+
}
|
|
149
|
+
function createPipeableStream(body) {
|
|
150
|
+
return {
|
|
151
|
+
[Symbol.asyncIterator]() {
|
|
152
|
+
return __asyncGenerator(this, arguments, function* _a() {
|
|
153
|
+
if (!body)
|
|
154
|
+
return yield __await(void 0);
|
|
155
|
+
const reader = body.getReader();
|
|
156
|
+
try {
|
|
157
|
+
while (true) {
|
|
158
|
+
const { done, value } = yield __await(reader.read());
|
|
159
|
+
if (done)
|
|
160
|
+
break;
|
|
161
|
+
if (value)
|
|
162
|
+
yield yield __await(value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
reader.releaseLock();
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
pipe(destination) {
|
|
171
|
+
;
|
|
172
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
var _a, e_1, _b, _c;
|
|
174
|
+
try {
|
|
175
|
+
for (var _d = true, _e = __asyncValues(this), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
176
|
+
_c = _f.value;
|
|
177
|
+
_d = false;
|
|
178
|
+
try {
|
|
179
|
+
const chunk = _c;
|
|
180
|
+
destination.write(chunk);
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
_d = true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
188
|
+
finally {
|
|
189
|
+
try {
|
|
190
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
191
|
+
}
|
|
192
|
+
finally { if (e_1) throw e_1.error; }
|
|
193
|
+
}
|
|
194
|
+
if (destination.end)
|
|
195
|
+
destination.end();
|
|
196
|
+
}))();
|
|
197
|
+
return destination;
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
116
201
|
function applyTransformRequest(fns, data, headers) {
|
|
117
202
|
return __awaiter(this, void 0, void 0, function* () {
|
|
118
203
|
if (!fns)
|
|
@@ -176,7 +261,11 @@ exports.axiosRetry = axiosRetry;
|
|
|
176
261
|
const defaultValidateStatus = (status) => status >= 200 && status < 300;
|
|
177
262
|
function getDefaultDefaults() {
|
|
178
263
|
return {
|
|
179
|
-
headers: {
|
|
264
|
+
headers: {
|
|
265
|
+
common: {
|
|
266
|
+
Accept: 'application/json, text/plain, */*',
|
|
267
|
+
},
|
|
268
|
+
},
|
|
180
269
|
transformRequest: [
|
|
181
270
|
function defaultTransformRequest(data, headers) {
|
|
182
271
|
var _a, _b;
|
|
@@ -221,6 +310,7 @@ function createAxiosInstance(initialDefaults) {
|
|
|
221
310
|
const method = (merged.method || 'get').toUpperCase();
|
|
222
311
|
const url = buildURL(merged.baseURL, merged.url, merged.params);
|
|
223
312
|
const headers = Object.assign({}, flattenHeaders(merged.headers, method));
|
|
313
|
+
applyAuthHeader(headers, merged.auth);
|
|
224
314
|
let data = merged.data;
|
|
225
315
|
data = yield applyTransformRequest(merged.transformRequest, data, headers);
|
|
226
316
|
const validateStatus = merged.validateStatus || defaultValidateStatus;
|
|
@@ -266,6 +356,9 @@ function createAxiosInstance(initialDefaults) {
|
|
|
266
356
|
else if (rt === 'arraybuffer') {
|
|
267
357
|
parsed = yield res.arrayBuffer();
|
|
268
358
|
}
|
|
359
|
+
else if (rt === 'stream') {
|
|
360
|
+
parsed = createPipeableStream(res.body || null);
|
|
361
|
+
}
|
|
269
362
|
else if (rt === 'text') {
|
|
270
363
|
parsed = yield res.text();
|
|
271
364
|
}
|
|
@@ -289,7 +382,9 @@ function createAxiosInstance(initialDefaults) {
|
|
|
289
382
|
parsed = text;
|
|
290
383
|
}
|
|
291
384
|
}
|
|
292
|
-
|
|
385
|
+
if (rt !== 'stream') {
|
|
386
|
+
parsed = applyTransformResponse(merged.transformResponse, parsed, resHeaders);
|
|
387
|
+
}
|
|
293
388
|
const response = {
|
|
294
389
|
data: parsed,
|
|
295
390
|
status: res.status,
|
package/package.json
CHANGED
package/src/articleStatus.ts
CHANGED
|
@@ -167,6 +167,31 @@ function prepareSubTotalAggKey(aggKey) {
|
|
|
167
167
|
return aggKey.split('\t').slice(0, -1).join('\t').concat(' Σ')
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/** Same as filtrex std.coerceBoolean(customProp(...)) for bare join keys on the transaction */
|
|
171
|
+
function coerceJoinKeyValue(v: unknown): unknown {
|
|
172
|
+
return typeof v === 'boolean' ? +v : v
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
type AggregateKeyTrieNode = { aggregateKey?: string; children?: Map<unknown, AggregateKeyTrieNode> }
|
|
176
|
+
type FilterResultTrieNode = { filterResult?: 1 | -1; children?: Map<unknown, FilterResultTrieNode> }
|
|
177
|
+
|
|
178
|
+
function getTrieLeaf<T extends { children?: Map<unknown, T> }>(root: T, transaction: TransactionI, keys: string[]): T {
|
|
179
|
+
const nrKeys = keys.length
|
|
180
|
+
if (nrKeys === 0) return root
|
|
181
|
+
let node = root
|
|
182
|
+
for (let i = 0; i < nrKeys; i++) {
|
|
183
|
+
const k = coerceJoinKeyValue(transaction[keys[i] as keyof TransactionI] as unknown)
|
|
184
|
+
if (!node.children) node.children = new Map()
|
|
185
|
+
let next = node.children.get(k) as T | undefined
|
|
186
|
+
if (!next) {
|
|
187
|
+
next = {} as T
|
|
188
|
+
node.children.set(k, next)
|
|
189
|
+
}
|
|
190
|
+
node = next
|
|
191
|
+
}
|
|
192
|
+
return node
|
|
193
|
+
}
|
|
194
|
+
|
|
170
195
|
/*
|
|
171
196
|
* A factory function that returns a function that can be used to aggregate transactions
|
|
172
197
|
* The factory function is called once for each aggregationExpression
|
|
@@ -200,46 +225,35 @@ function aggregator({
|
|
|
200
225
|
subtotalsForOuterGrouper,
|
|
201
226
|
parentGroupTotals,
|
|
202
227
|
}: AggregatorFnI) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
let filterDependencyEvaluator
|
|
228
|
+
let filter: ((transaction: TransactionI) => unknown) | undefined
|
|
229
|
+
let filterGranularity: string[] = []
|
|
230
|
+
const filterTrieRoot: FilterResultTrieNode = {}
|
|
207
231
|
if (filterExpression) {
|
|
208
232
|
filter = compileExpression(filterExpression, filtrexOptions)
|
|
209
|
-
|
|
210
|
-
// The granularity of the cache is determined by the joined tables in the filterExpression
|
|
211
|
-
const filterGranularity = Object.entries(globalJoinableTables)
|
|
233
|
+
filterGranularity = Object.entries(globalJoinableTables)
|
|
212
234
|
.filter((join) => filterExpression.includes(join[0] + '.'))
|
|
213
235
|
.map((join) => join[1])
|
|
214
|
-
filterDependencyEvaluator = compileExpression(filterGranularity.join('+'), filtrexOptions)
|
|
215
236
|
}
|
|
216
237
|
const aggregationEvaluator = buildAggregationEvaluator(aggregationExpression)
|
|
217
|
-
// Maintain a cache of evaluated aggregationExpressions
|
|
218
|
-
// The granularity of the cache is determined by the joined tables in the aggregationExpression
|
|
219
|
-
const aggregationExpressionCache = {}
|
|
220
238
|
const aggregationGranularity = Object.entries(globalJoinableTables)
|
|
221
239
|
.filter((join) => aggregationExpression.includes(join[0] + '.'))
|
|
222
240
|
.map((join) => join[1])
|
|
241
|
+
const aggregationTrieRoot: AggregateKeyTrieNode = {}
|
|
223
242
|
|
|
224
|
-
let aggregationDependencyExpression = aggregationGranularity.join('+')
|
|
225
|
-
if (!aggregationDependencyExpression) aggregationDependencyExpression = '"N.A."'
|
|
226
|
-
const aggregationDependencyEvaluator = compileExpression(aggregationDependencyExpression, filtrexOptions)
|
|
227
243
|
return function (transaction: TransactionI): void {
|
|
228
244
|
if (filter) {
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (filterExpressionCache[filterDependency] == -1) return
|
|
245
|
+
const filterLeaf = getTrieLeaf<FilterResultTrieNode>(filterTrieRoot, transaction, filterGranularity)
|
|
246
|
+
if (filterLeaf.filterResult === -1) return
|
|
247
|
+
if (filterLeaf.filterResult === undefined) {
|
|
248
|
+
filterLeaf.filterResult = filter(transaction) ? 1 : -1
|
|
249
|
+
if (filterLeaf.filterResult === -1) return
|
|
235
250
|
}
|
|
236
251
|
}
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
aggregateKey = aggregationEvaluator(transaction)
|
|
241
|
-
aggregationExpressionCache[aggregationDependency] = aggregateKey
|
|
252
|
+
const aggregateKeyLeaf = getTrieLeaf<AggregateKeyTrieNode>(aggregationTrieRoot, transaction, aggregationGranularity)
|
|
253
|
+
if (!aggregateKeyLeaf.aggregateKey) {
|
|
254
|
+
aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction) as string
|
|
242
255
|
}
|
|
256
|
+
const aggregateKey = aggregateKeyLeaf.aggregateKey as string
|
|
243
257
|
// Prepare joined values for derived fields
|
|
244
258
|
if (transaction.type == transactionTypeE.SALE) {
|
|
245
259
|
const sku = globalRelations['sku'][transaction.ean]
|
package/src/lcAxios.ts
CHANGED
|
@@ -14,11 +14,15 @@ export interface AxiosRequestConfig<D = any> {
|
|
|
14
14
|
params?: Record<string, any>
|
|
15
15
|
headers?: Record<string, string | undefined> | any
|
|
16
16
|
timeout?: number
|
|
17
|
-
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer'
|
|
17
|
+
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer' | 'stream'
|
|
18
18
|
validateStatus?: (status: number) => boolean
|
|
19
19
|
transformRequest?: AxiosTransformer | AxiosTransformer[]
|
|
20
20
|
transformResponse?: AxiosTransformer | AxiosTransformer[]
|
|
21
21
|
withCredentials?: boolean
|
|
22
|
+
auth?: {
|
|
23
|
+
username?: string
|
|
24
|
+
password?: string
|
|
25
|
+
}
|
|
22
26
|
/** Axios-only; ignored — fetch handles Content-Encoding when reading the body */
|
|
23
27
|
decompress?: boolean
|
|
24
28
|
}
|
|
@@ -129,6 +133,44 @@ function flattenHeaders(h: any, method: string): Record<string, string> {
|
|
|
129
133
|
return out
|
|
130
134
|
}
|
|
131
135
|
|
|
136
|
+
function encodeBase64(input: string): string {
|
|
137
|
+
if (typeof Buffer !== 'undefined') return Buffer.from(input, 'utf8').toString('base64')
|
|
138
|
+
if (typeof btoa !== 'undefined') return btoa(input)
|
|
139
|
+
throw new Error('Base64 encoding unavailable')
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function applyAuthHeader(headers: Record<string, string>, auth: AxiosRequestConfig['auth']) {
|
|
143
|
+
if (!auth) return
|
|
144
|
+
const username = auth.username || ''
|
|
145
|
+
const password = auth.password || ''
|
|
146
|
+
headers['Authorization'] = `Basic ${encodeBase64(`${username}:${password}`)}`
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function createPipeableStream(body: ReadableStream<Uint8Array> | null) {
|
|
150
|
+
return {
|
|
151
|
+
async *[Symbol.asyncIterator]() {
|
|
152
|
+
if (!body) return
|
|
153
|
+
const reader = body.getReader()
|
|
154
|
+
try {
|
|
155
|
+
while (true) {
|
|
156
|
+
const { done, value } = await reader.read()
|
|
157
|
+
if (done) break
|
|
158
|
+
if (value) yield value
|
|
159
|
+
}
|
|
160
|
+
} finally {
|
|
161
|
+
reader.releaseLock()
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
pipe(destination: { write: (chunk: Uint8Array) => any; end?: () => any }) {
|
|
165
|
+
;(async () => {
|
|
166
|
+
for await (const chunk of this) destination.write(chunk)
|
|
167
|
+
if (destination.end) destination.end()
|
|
168
|
+
})()
|
|
169
|
+
return destination
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
132
174
|
async function applyTransformRequest(fns: AxiosTransformer | AxiosTransformer[] | undefined, data: any, headers: any): Promise<any> {
|
|
133
175
|
if (!fns) return data
|
|
134
176
|
const list = Array.isArray(fns) ? fns : [fns]
|
|
@@ -193,7 +235,11 @@ const defaultValidateStatus = (status: number) => status >= 200 && status < 300
|
|
|
193
235
|
|
|
194
236
|
function getDefaultDefaults(): AxiosRequestConfig {
|
|
195
237
|
return {
|
|
196
|
-
headers: {
|
|
238
|
+
headers: {
|
|
239
|
+
common: {
|
|
240
|
+
Accept: 'application/json, text/plain, */*',
|
|
241
|
+
},
|
|
242
|
+
},
|
|
197
243
|
transformRequest: [
|
|
198
244
|
function defaultTransformRequest(data: any, headers: any) {
|
|
199
245
|
if (data == null) return data
|
|
@@ -231,6 +277,7 @@ export function createAxiosInstance(initialDefaults?: AxiosRequestConfig): any {
|
|
|
231
277
|
const method = (merged.method || 'get').toUpperCase()
|
|
232
278
|
const url = buildURL(merged.baseURL, merged.url, merged.params)
|
|
233
279
|
const headers: any = { ...flattenHeaders(merged.headers, method) }
|
|
280
|
+
applyAuthHeader(headers, merged.auth)
|
|
234
281
|
|
|
235
282
|
let data = merged.data
|
|
236
283
|
data = await applyTransformRequest(merged.transformRequest, data, headers)
|
|
@@ -279,6 +326,8 @@ export function createAxiosInstance(initialDefaults?: AxiosRequestConfig): any {
|
|
|
279
326
|
parsed = await res.blob()
|
|
280
327
|
} else if (rt === 'arraybuffer') {
|
|
281
328
|
parsed = await res.arrayBuffer()
|
|
329
|
+
} else if (rt === 'stream') {
|
|
330
|
+
parsed = createPipeableStream((res.body as ReadableStream<Uint8Array> | null) || null)
|
|
282
331
|
} else if (rt === 'text') {
|
|
283
332
|
parsed = await res.text()
|
|
284
333
|
} else if (ct.includes('application/json')) {
|
|
@@ -299,7 +348,9 @@ export function createAxiosInstance(initialDefaults?: AxiosRequestConfig): any {
|
|
|
299
348
|
}
|
|
300
349
|
}
|
|
301
350
|
|
|
302
|
-
|
|
351
|
+
if (rt !== 'stream') {
|
|
352
|
+
parsed = applyTransformResponse(merged.transformResponse, parsed, resHeaders)
|
|
353
|
+
}
|
|
303
354
|
|
|
304
355
|
const response: AxiosResponse = {
|
|
305
356
|
data: parsed,
|
package/test/lcAxios.spec.ts
CHANGED
|
@@ -10,6 +10,14 @@ function jsonResponse(body: unknown, status = 200) {
|
|
|
10
10
|
})
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
function textResponse(body: string, status = 200) {
|
|
14
|
+
return new Response(body, {
|
|
15
|
+
status,
|
|
16
|
+
statusText: status === 200 ? 'OK' : 'Error',
|
|
17
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
describe('lcAxios', () => {
|
|
14
22
|
beforeEach(() => {
|
|
15
23
|
vi.stubGlobal(
|
|
@@ -34,6 +42,26 @@ describe('lcAxios', () => {
|
|
|
34
42
|
expect(init?.body).toBeUndefined()
|
|
35
43
|
})
|
|
36
44
|
|
|
45
|
+
it('GET sends axios-style default Accept header', async () => {
|
|
46
|
+
const client = axios.create()
|
|
47
|
+
await client.get('https://api.example.com/accept')
|
|
48
|
+
|
|
49
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
50
|
+
const headers = init?.headers as Record<string, string>
|
|
51
|
+
expect(headers.Accept).toBe('application/json, text/plain, */*')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('auth config sets Authorization basic header', async () => {
|
|
55
|
+
const client = axios.create()
|
|
56
|
+
await client.get('https://api.example.com/auth', {
|
|
57
|
+
auth: { username: 'aladdin', password: 'opensesame' },
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
61
|
+
const headers = init?.headers as Record<string, string>
|
|
62
|
+
expect(headers.Authorization).toBe('Basic YWxhZGRpbjpvcGVuc2VzYW1l')
|
|
63
|
+
})
|
|
64
|
+
|
|
37
65
|
it('GET with decompress: true (axios compat) still works; option not passed to fetch', async () => {
|
|
38
66
|
const client = axios.create()
|
|
39
67
|
await client.get('https://api.example.com/x', { decompress: true })
|
|
@@ -131,6 +159,30 @@ describe('lcAxios', () => {
|
|
|
131
159
|
expect(res.data).toEqual({ missing: true })
|
|
132
160
|
})
|
|
133
161
|
|
|
162
|
+
it('responseType stream returns a pipeable async iterable body', async () => {
|
|
163
|
+
vi.mocked(fetch).mockResolvedValueOnce(textResponse('hello stream'))
|
|
164
|
+
|
|
165
|
+
const client = axios.create()
|
|
166
|
+
const response = await client.get('https://api.example.com/stream', {
|
|
167
|
+
responseType: 'stream',
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const chunks: Uint8Array[] = []
|
|
171
|
+
await new Promise<void>((resolve) => {
|
|
172
|
+
response.data.pipe({
|
|
173
|
+
write(chunk: Uint8Array) {
|
|
174
|
+
chunks.push(chunk)
|
|
175
|
+
},
|
|
176
|
+
end() {
|
|
177
|
+
resolve()
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
const text = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString('utf8')
|
|
183
|
+
expect(text).toBe('hello stream')
|
|
184
|
+
})
|
|
185
|
+
|
|
134
186
|
it('axiosRetry retries when retryCondition passes and fetch then succeeds', async () => {
|
|
135
187
|
vi.mocked(fetch).mockReset()
|
|
136
188
|
vi.mocked(fetch).mockRejectedValueOnce(new TypeError('Failed to fetch'))
|