@randajan/api-kit 1.2.0 → 3.0.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/LICENSE +22 -0
- package/README.md +351 -66
- package/dist/cjs/client/index.cjs +255 -165
- package/dist/cjs/client/index.cjs.map +4 -4
- package/dist/cjs/index.cjs +285 -173
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/cjs/server/index.cjs +109 -46
- package/dist/cjs/server/index.cjs.map +4 -4
- package/dist/esm/chunk-4NYBELZF.js +309 -0
- package/dist/esm/chunk-4NYBELZF.js.map +7 -0
- package/dist/esm/{chunk-R2VELUR6.js → chunk-IUVT7Q4N.js} +26 -4
- package/dist/esm/chunk-IUVT7Q4N.js.map +7 -0
- package/dist/esm/{chunk-HYSF3GMO.js → chunk-K7ZQO3VB.js} +102 -79
- package/dist/esm/chunk-K7ZQO3VB.js.map +7 -0
- package/dist/esm/client/index.mjs +4 -4
- package/dist/esm/index.mjs +7 -5
- package/dist/esm/server/index.mjs +4 -4
- package/package.json +1 -1
- package/dist/esm/chunk-C737ZROD.js +0 -240
- package/dist/esm/chunk-C737ZROD.js.map +0 -7
- package/dist/esm/chunk-HYSF3GMO.js.map +0 -7
- package/dist/esm/chunk-R2VELUR6.js.map +0 -7
package/dist/cjs/index.cjs
CHANGED
|
@@ -20,17 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
22
|
Api: () => Api,
|
|
23
|
-
ApiError: () => ApiError,
|
|
24
23
|
Fetch: () => Fetch,
|
|
24
|
+
FetchError: () => FetchError,
|
|
25
|
+
HttpError: () => HttpError,
|
|
25
26
|
createApi: () => server_default,
|
|
26
27
|
createFetch: () => client_default
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
29
30
|
|
|
30
31
|
// <define:__slib_info>
|
|
31
|
-
var define_slib_info_default = { isBuild: true, name: "@randajan/api-kit", description: "A lightweight wrapper around fetch that always returns a structured JSON response, handling errors and network issues gracefully", version: "
|
|
32
|
+
var define_slib_info_default = { isBuild: true, name: "@randajan/api-kit", description: "A lightweight wrapper around fetch that always returns a structured JSON response, handling errors and network issues gracefully", version: "2.0.0", author: { name: "Jan Randa", email: "jnranda@gmail.com", url: "https://www.linkedin.com/in/randajan/" }, env: "development", mode: "web", port: 3e3, dir: { root: "C:\\dev\\lib\\api-kit", dist: "dist" } };
|
|
32
33
|
|
|
33
|
-
// src/arc/class/
|
|
34
|
+
// src/arc/class/FetchError.js
|
|
34
35
|
var import_props = require("@randajan/props");
|
|
35
36
|
|
|
36
37
|
// src/arc/tool.js
|
|
@@ -57,34 +58,36 @@ var doFn = (any) => isFn(any) ? any() : any;
|
|
|
57
58
|
var isProm = (any) => any instanceof Promise;
|
|
58
59
|
var isErr = (any) => any instanceof Error;
|
|
59
60
|
|
|
60
|
-
// src/arc/class/
|
|
61
|
-
var
|
|
62
|
-
static create(code, message) {
|
|
63
|
-
return new _ApiError(code, message);
|
|
64
|
-
}
|
|
61
|
+
// src/arc/class/FetchError.js
|
|
62
|
+
var FetchError = class _FetchError extends Error {
|
|
65
63
|
static is(any) {
|
|
66
|
-
return any instanceof
|
|
64
|
+
return any && any instanceof _FetchError;
|
|
67
65
|
}
|
|
68
|
-
static
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
const msg = toStr(any?.message || any) || "Unknown";
|
|
73
|
-
const apierr = _ApiError.create(code, msg);
|
|
74
|
-
return (0, import_props.solid)(apierr, "stack", any.stack, false);
|
|
66
|
+
static code(code, message, opt = {}) {
|
|
67
|
+
opt.code = code;
|
|
68
|
+
return new _FetchError(message, opt);
|
|
75
69
|
}
|
|
76
|
-
constructor(
|
|
77
|
-
|
|
70
|
+
constructor(message, options = {}) {
|
|
71
|
+
const { code, ...opt } = options || {};
|
|
72
|
+
super(message, opt);
|
|
78
73
|
(0, import_props.safe)(this, {}, "code", (t, f) => mrgStr(t, f, "."));
|
|
79
74
|
this.rise(code);
|
|
80
75
|
}
|
|
81
|
-
rise(code
|
|
82
|
-
|
|
76
|
+
rise(code) {
|
|
77
|
+
if (code == null) {
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
this.code = code;
|
|
83
81
|
return this;
|
|
84
82
|
}
|
|
85
83
|
toJSON() {
|
|
86
|
-
const { message } = this;
|
|
87
|
-
|
|
84
|
+
const { message, cause } = this;
|
|
85
|
+
const body = { message, ...this };
|
|
86
|
+
if (cause) {
|
|
87
|
+
const { message: message2, stack } = cause;
|
|
88
|
+
body.cause = { message: message2, stack };
|
|
89
|
+
}
|
|
90
|
+
return body;
|
|
88
91
|
}
|
|
89
92
|
toString() {
|
|
90
93
|
const { message, code } = this;
|
|
@@ -92,8 +95,47 @@ var ApiError = class _ApiError extends Error {
|
|
|
92
95
|
}
|
|
93
96
|
};
|
|
94
97
|
|
|
98
|
+
// src/arc/class/HttpError.js
|
|
99
|
+
var import_props2 = require("@randajan/props");
|
|
100
|
+
var HttpError = class _HttpError extends FetchError {
|
|
101
|
+
static is(any) {
|
|
102
|
+
return any && any instanceof _HttpError;
|
|
103
|
+
}
|
|
104
|
+
static code(code, message, httpStatusCode = 400, opt = {}) {
|
|
105
|
+
opt.code = code;
|
|
106
|
+
return new _HttpError(message, httpStatusCode, opt);
|
|
107
|
+
}
|
|
108
|
+
constructor(message, httpStatusCode = 400, options = {}) {
|
|
109
|
+
const { detail, exposeCause, ...opt } = options || {};
|
|
110
|
+
const http = httpStatusCode ?? 400;
|
|
111
|
+
const msg = message || `HTTP:${http}`;
|
|
112
|
+
super(msg, opt);
|
|
113
|
+
(0, import_props2.safe)(this, {}, "_exposeCause", (t) => !!t, void 0, false);
|
|
114
|
+
this.detail = detail;
|
|
115
|
+
this.httpStatusCode = http;
|
|
116
|
+
this._exposeCause = exposeCause;
|
|
117
|
+
}
|
|
118
|
+
exposeCause(exposeCause = true) {
|
|
119
|
+
this._exposeCause = exposeCause;
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
toJSON() {
|
|
123
|
+
const { message, cause, _exposeCause } = this;
|
|
124
|
+
const body = { message, ...this };
|
|
125
|
+
if (_exposeCause && cause) {
|
|
126
|
+
const { message: message2, stack } = cause;
|
|
127
|
+
body.cause = { message: message2, stack, ...cause };
|
|
128
|
+
}
|
|
129
|
+
return body;
|
|
130
|
+
}
|
|
131
|
+
toString() {
|
|
132
|
+
const { httpStatusCode } = this;
|
|
133
|
+
return super.toString() + ` [${httpStatusCode}]`;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
95
137
|
// src/server/class/Api.js
|
|
96
|
-
var
|
|
138
|
+
var import_props4 = require("@randajan/props");
|
|
97
139
|
|
|
98
140
|
// src/arc/class/Functionable.js
|
|
99
141
|
var Functionable = class extends Function {
|
|
@@ -125,10 +167,10 @@ var lockObject = (o) => {
|
|
|
125
167
|
var info = lockObject(define_slib_info_default);
|
|
126
168
|
var info_default = info;
|
|
127
169
|
|
|
128
|
-
// src/arc/
|
|
129
|
-
var
|
|
170
|
+
// src/arc/opt.js
|
|
171
|
+
var import_props3 = require("@randajan/props");
|
|
130
172
|
var start = (opt) => {
|
|
131
|
-
if (opt.
|
|
173
|
+
if (opt.timetrack) {
|
|
132
174
|
return opt.startAt = Date.now();
|
|
133
175
|
}
|
|
134
176
|
};
|
|
@@ -147,10 +189,12 @@ var endTime = (body, startAt) => {
|
|
|
147
189
|
time.netIn = body.time.startAt - startAt;
|
|
148
190
|
time.netOut = endAt - body.time.endAt;
|
|
149
191
|
}
|
|
150
|
-
body.time = (0,
|
|
192
|
+
body.time = (0, import_props3.solids)({}, time);
|
|
151
193
|
};
|
|
152
194
|
var end = (body, opt) => {
|
|
153
|
-
|
|
195
|
+
const hasError = !!body.error;
|
|
196
|
+
endTime(body, opt.startAt);
|
|
197
|
+
if (!hasError) {
|
|
154
198
|
if (isFn(opt.onOk)) {
|
|
155
199
|
opt.onOk(body, opt);
|
|
156
200
|
}
|
|
@@ -162,26 +206,19 @@ var end = (body, opt) => {
|
|
|
162
206
|
throw body.error;
|
|
163
207
|
}
|
|
164
208
|
}
|
|
165
|
-
|
|
166
|
-
return opt.resultOnly ? body.result : Object.freeze(body);
|
|
209
|
+
return Object.freeze(body);
|
|
167
210
|
};
|
|
168
|
-
var
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (v1 === v2) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const f1 = v1.split(".");
|
|
175
|
-
const f2 = v2.split(".");
|
|
176
|
-
if (f1[0] !== f2[0]) {
|
|
177
|
-
return "major";
|
|
178
|
-
}
|
|
179
|
-
if (f1[1] !== f2[1]) {
|
|
180
|
-
return "minor";
|
|
211
|
+
var createTrait = (trait) => {
|
|
212
|
+
if (!trait) {
|
|
213
|
+
return (opt) => opt;
|
|
181
214
|
}
|
|
182
|
-
if (
|
|
183
|
-
return
|
|
215
|
+
if (isFn(trait)) {
|
|
216
|
+
return trait;
|
|
184
217
|
}
|
|
218
|
+
throw new Error("config.trait should be a function");
|
|
219
|
+
};
|
|
220
|
+
var configTrait = (config) => {
|
|
221
|
+
config.trait = createTrait(config.trait);
|
|
185
222
|
};
|
|
186
223
|
|
|
187
224
|
// src/server/tool.js
|
|
@@ -208,11 +245,32 @@ var tryFn = (any) => {
|
|
|
208
245
|
}
|
|
209
246
|
return r.result.then(wrapResult).catch(wrapError);
|
|
210
247
|
};
|
|
248
|
+
var normalizeServerError = (any, opt) => {
|
|
249
|
+
let err = any;
|
|
250
|
+
if (!HttpError.is(err)) {
|
|
251
|
+
let custom = isFn(opt.normalizeError);
|
|
252
|
+
if (custom) {
|
|
253
|
+
try {
|
|
254
|
+
err = opt.normalizeError(err, opt);
|
|
255
|
+
} catch {
|
|
256
|
+
custom = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!custom || !HttpError.is(err)) {
|
|
260
|
+
err = HttpError.code(0, "Unknown", 500, { cause: any });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return err.rise(1).rise(opt.code);
|
|
264
|
+
};
|
|
211
265
|
|
|
212
266
|
// src/server/class/static.js
|
|
213
267
|
var apiExit = (resp, opt) => {
|
|
268
|
+
const { exposeCause } = opt;
|
|
269
|
+
resp.statusCode = 200;
|
|
214
270
|
if (resp.error) {
|
|
215
|
-
resp.error =
|
|
271
|
+
resp.error = normalizeServerError(resp.error, opt);
|
|
272
|
+
resp.statusCode = resp.error.httpStatusCode;
|
|
273
|
+
resp.error.exposeCause(!!exposeCause);
|
|
216
274
|
}
|
|
217
275
|
resp[info_default.name] = info_default.version;
|
|
218
276
|
return end(resp, opt);
|
|
@@ -231,20 +289,6 @@ var apiResolve = (exe, opt) => {
|
|
|
231
289
|
return resp.then((resp2) => apiExit(resp2, opt));
|
|
232
290
|
};
|
|
233
291
|
|
|
234
|
-
// src/arc/opt.js
|
|
235
|
-
var createTrait = (trait) => {
|
|
236
|
-
if (!trait) {
|
|
237
|
-
return (opt) => opt;
|
|
238
|
-
}
|
|
239
|
-
if (isFn(trait)) {
|
|
240
|
-
return trait;
|
|
241
|
-
}
|
|
242
|
-
throw new Error("config.trait should be a function");
|
|
243
|
-
};
|
|
244
|
-
var configTrait = (config) => {
|
|
245
|
-
config.trait = createTrait(config.trait);
|
|
246
|
-
};
|
|
247
|
-
|
|
248
292
|
// src/server/class/Api.js
|
|
249
293
|
var Api = class _Api extends Functionable {
|
|
250
294
|
static create(config = {}) {
|
|
@@ -254,7 +298,7 @@ var Api = class _Api extends Functionable {
|
|
|
254
298
|
configTrait(config);
|
|
255
299
|
super((exe, opt) => apiResolve(exe, mrgObj(config, opt)));
|
|
256
300
|
Object.freeze(config);
|
|
257
|
-
(0,
|
|
301
|
+
(0, import_props4.solid)(this, "config", config);
|
|
258
302
|
}
|
|
259
303
|
code(code, exe, opt = {}) {
|
|
260
304
|
opt.code = code;
|
|
@@ -270,25 +314,7 @@ var createApi = Api.create;
|
|
|
270
314
|
var server_default = createApi;
|
|
271
315
|
|
|
272
316
|
// src/client/class/static.js
|
|
273
|
-
var
|
|
274
|
-
|
|
275
|
-
// src/arc/url.js
|
|
276
|
-
var _regexp = /^https?:\/\//i;
|
|
277
|
-
var buildUrl = (inputUrl, params) => {
|
|
278
|
-
if (!params) {
|
|
279
|
-
return inputUrl;
|
|
280
|
-
}
|
|
281
|
-
const hasHost = _regexp.test(inputUrl);
|
|
282
|
-
const url = new URL(inputUrl, hasHost ? void 0 : "http://thisisonlyplaceholder.xyz");
|
|
283
|
-
url.hash = "";
|
|
284
|
-
for (const [key, value] of Object.entries(params)) {
|
|
285
|
-
if (value != null) {
|
|
286
|
-
url.searchParams.append(key, value);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
;
|
|
290
|
-
return hasHost ? url.toString() : url.pathname + url.search;
|
|
291
|
-
};
|
|
317
|
+
var import_props5 = require("@randajan/props");
|
|
292
318
|
|
|
293
319
|
// src/arc/types/kinds/json.js
|
|
294
320
|
var json_exports = {};
|
|
@@ -313,32 +339,141 @@ var decode2 = (body) => Object.fromEntries(new URLSearchParams(body));
|
|
|
313
339
|
var encode2 = (body) => new URLSearchParams(body);
|
|
314
340
|
|
|
315
341
|
// src/arc/types/index.js
|
|
316
|
-
var
|
|
317
|
-
var
|
|
318
|
-
|
|
342
|
+
var _types = { json: json_exports, form: form_exports };
|
|
343
|
+
var joinTypeNames = (types = {}) => {
|
|
344
|
+
const native = Object.keys(_types);
|
|
345
|
+
const custom = typeof types === "object" ? Object.keys(types) : [];
|
|
346
|
+
return `'${[.../* @__PURE__ */ new Set([...native, ...custom])].join("', '")}'`;
|
|
347
|
+
};
|
|
348
|
+
var getType = (propertyName, reqFnName, opt) => {
|
|
349
|
+
const tn = opt[propertyName] || opt.type;
|
|
350
|
+
if (!tn) {
|
|
319
351
|
return json_exports;
|
|
320
352
|
}
|
|
321
|
-
const
|
|
322
|
-
|
|
353
|
+
const customType = opt.types?.[tn];
|
|
354
|
+
const type = customType || _types[tn];
|
|
355
|
+
if (!type) {
|
|
356
|
+
throw new Error(`Unknown config.${propertyName} '${tn}'. Must be one of: ${joinTypeNames(opt.types)}`);
|
|
357
|
+
}
|
|
358
|
+
if (!customType) {
|
|
323
359
|
return type;
|
|
324
360
|
}
|
|
325
|
-
|
|
361
|
+
if (!type.mime || typeof type.mime !== "string") {
|
|
362
|
+
throw new Error(`Type definition '${tn}' requires 'mime' to be a string`);
|
|
363
|
+
}
|
|
364
|
+
if (!isFn(type[reqFnName])) {
|
|
365
|
+
throw new Error(`Type definition '${tn}' requires '${reqFnName}' to be a function`);
|
|
366
|
+
}
|
|
367
|
+
return type;
|
|
326
368
|
};
|
|
327
369
|
var encodeBody = (opt) => {
|
|
328
|
-
const type = getType(
|
|
370
|
+
const type = getType("requestType", "encode", opt);
|
|
329
371
|
opt.headers["Content-Type"] = type.mime;
|
|
330
372
|
opt.body = type.encode(opt.body);
|
|
331
373
|
};
|
|
332
374
|
var attachBodyDecoder = (opt) => {
|
|
333
|
-
const type = getType(
|
|
375
|
+
const type = getType("responseType", "decode", opt);
|
|
334
376
|
opt.headers["Accept"] = type.mime;
|
|
335
377
|
opt.decodeBody = type.decode;
|
|
336
378
|
};
|
|
337
379
|
|
|
338
|
-
// src/client/
|
|
380
|
+
// src/client/url.js
|
|
381
|
+
var _regexp = /^https?:\/\//i;
|
|
382
|
+
var buildUrl = (inputUrl, params) => {
|
|
383
|
+
if (!params) {
|
|
384
|
+
return inputUrl;
|
|
385
|
+
}
|
|
386
|
+
const hasHost = _regexp.test(inputUrl);
|
|
387
|
+
const url = new URL(inputUrl, hasHost ? void 0 : "http://thisisonlyplaceholder.xyz");
|
|
388
|
+
url.hash = "";
|
|
389
|
+
for (const [key, value] of Object.entries(params)) {
|
|
390
|
+
if (value != null) {
|
|
391
|
+
url.searchParams.append(key, value);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
;
|
|
395
|
+
return hasHost ? url.toString() : url.pathname + url.search;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// src/client/tool.js
|
|
399
|
+
var diffVersion = (version) => {
|
|
400
|
+
const v1 = toStr(info.version);
|
|
401
|
+
const v2 = toStr(version);
|
|
402
|
+
if (v1 === v2) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const f1 = v1.split(".");
|
|
406
|
+
const f2 = v2.split(".");
|
|
407
|
+
if (f1[0] !== f2[0]) {
|
|
408
|
+
return "major";
|
|
409
|
+
}
|
|
410
|
+
if (f1[1] !== f2[1]) {
|
|
411
|
+
return "minor";
|
|
412
|
+
}
|
|
413
|
+
if (f1[2] !== f2[2]) {
|
|
414
|
+
return "patch";
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
var failedError = (cause) => FetchError.code(1, "Failed", { cause });
|
|
418
|
+
var timeoutError = (_) => FetchError.code(2, "Timeout");
|
|
419
|
+
var abortError = (_) => FetchError.code(3, "Aborted");
|
|
420
|
+
var statusError = (resp) => HttpError.code(4, resp.statusText, resp.status, { exposeCause: true });
|
|
421
|
+
var unreadableError = (resp, cause) => resp.ok ? FetchError.code(5, "Unreadable", { cause }) : statusError(resp);
|
|
422
|
+
var undecodableError = (resp, cause, detail) => resp.ok ? FetchError.code(6, "Undecodable", { cause, detail }) : statusError(resp);
|
|
423
|
+
var parseHeaders = (resp, opt) => {
|
|
424
|
+
if (!resp || !opt.parseHeaders) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
return Object.freeze(Object.fromEntries(resp.headers.entries()));
|
|
428
|
+
};
|
|
429
|
+
var readText = async (resp) => {
|
|
430
|
+
try {
|
|
431
|
+
return await resp.text();
|
|
432
|
+
} catch (err) {
|
|
433
|
+
throw unreadableError(resp, err);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
var decodeText = (resp, opt, text) => {
|
|
437
|
+
try {
|
|
438
|
+
return opt.decodeBody(text);
|
|
439
|
+
} catch (err) {
|
|
440
|
+
throw undecodableError(resp, err, text);
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
var normalizeClientError = (any, opt) => {
|
|
444
|
+
let err = any;
|
|
445
|
+
if (!FetchError.is(err)) {
|
|
446
|
+
let custom = isFn(opt.normalizeError);
|
|
447
|
+
if (custom) {
|
|
448
|
+
try {
|
|
449
|
+
err = opt.normalizeError(err, opt);
|
|
450
|
+
} catch {
|
|
451
|
+
custom = false;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (!custom || !FetchError.is(err)) {
|
|
455
|
+
err = FetchError.code(0, "Unknown", { cause: any });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return err.rise(0).rise(0);
|
|
459
|
+
};
|
|
460
|
+
var reconstructApiError = (remoteErr) => {
|
|
461
|
+
if (!remoteErr) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const { message, code, httpStatusCode, cause, detail } = remoteErr;
|
|
465
|
+
return HttpError.code(code, message, httpStatusCode, { cause, detail, exposeCause: true });
|
|
466
|
+
};
|
|
467
|
+
var mrgOpt = (a, b) => {
|
|
468
|
+
const opt = mrgObj(a, b);
|
|
469
|
+
opt.body = mrgObj(a?.body, b?.body);
|
|
470
|
+
opt.params = mrgObj(a?.params, b?.params);
|
|
471
|
+
opt.headers = mrgObj(a?.headers, b?.headers, {});
|
|
472
|
+
return opt;
|
|
473
|
+
};
|
|
339
474
|
var prepareOpt = (url, opt, method) => {
|
|
340
475
|
start(opt);
|
|
341
|
-
opt.url = buildUrl(mrgStr(opt.url, url), opt.
|
|
476
|
+
opt.url = buildUrl(mrgStr(opt.url, url), opt.params);
|
|
342
477
|
if (method) {
|
|
343
478
|
opt.method = method;
|
|
344
479
|
}
|
|
@@ -347,101 +482,79 @@ var prepareOpt = (url, opt, method) => {
|
|
|
347
482
|
}
|
|
348
483
|
attachBodyDecoder(opt);
|
|
349
484
|
const hasTimeout = opt.timeout > 0;
|
|
350
|
-
if (opt.
|
|
485
|
+
if (opt.isAbortable || hasTimeout) {
|
|
351
486
|
opt.abortController = new AbortController();
|
|
352
487
|
opt.signal = opt.abortController.signal;
|
|
353
488
|
}
|
|
354
489
|
if (hasTimeout) {
|
|
355
|
-
opt.timeoutId = setTimeout(() => opt.abortController?.abort(
|
|
490
|
+
opt.timeoutId = setTimeout(() => opt.abortController?.abort(timeoutError()), opt.timeout);
|
|
356
491
|
}
|
|
357
492
|
if (isFn(opt.trait)) {
|
|
358
493
|
opt = opt.trait(opt) || opt;
|
|
359
494
|
}
|
|
360
495
|
return opt;
|
|
361
496
|
};
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
http = 415;
|
|
372
|
-
} else if (!http) {
|
|
373
|
-
http = 400;
|
|
374
|
-
}
|
|
375
|
-
error.rise(0).rise(opt.code || 0);
|
|
376
|
-
return end({ ok: false, http, error }, opt);
|
|
377
|
-
};
|
|
378
|
-
var fetchExe = async (_fetch, opt) => {
|
|
379
|
-
let resp, raw, body;
|
|
380
|
-
try {
|
|
381
|
-
resp = await _fetch(opt.url, opt);
|
|
382
|
-
} catch (err) {
|
|
383
|
-
return localReject(opt, ApiError.is(err) ? err : ApiError.to(0, "Failed"));
|
|
384
|
-
}
|
|
385
|
-
const { ok, status, headers, statusText } = resp;
|
|
386
|
-
try {
|
|
387
|
-
raw = opt.decodeBody(await resp.text());
|
|
388
|
-
} catch {
|
|
389
|
-
return localReject(opt, new ApiError(ok ? 3 : 4, ok ? "Unreadable" : statusText || status), status);
|
|
390
|
-
}
|
|
391
|
-
const apv = raw[info_default.name];
|
|
392
|
-
if (apv) {
|
|
393
|
-
body = raw;
|
|
394
|
-
const diff = diffVersion(apv);
|
|
395
|
-
const msg = `Detected @randajan/api-kit ${diff} version difference at '${opt.url}'. Server '${apv}' vs. client '${info_default.version}'`;
|
|
396
|
-
if (diff === "major") {
|
|
397
|
-
console.error(msg);
|
|
398
|
-
}
|
|
399
|
-
if (diff === "minor") {
|
|
400
|
-
console.warn(msg);
|
|
401
|
-
}
|
|
402
|
-
} else {
|
|
403
|
-
body = {};
|
|
404
|
-
try {
|
|
405
|
-
body.result = opt.parseBody(raw);
|
|
406
|
-
} catch (err) {
|
|
407
|
-
body.error = err.message || err;
|
|
497
|
+
|
|
498
|
+
// src/client/class/static.js
|
|
499
|
+
var localReject = (err, opt) => ({ error: normalizeClientError(FetchError.is(err) ? err : failedError(err), opt) });
|
|
500
|
+
var remoteReject = (err, opt) => ({ isRemote: true, error: normalizeClientError(err, opt) });
|
|
501
|
+
var remoteResolve = async (resp, opt) => {
|
|
502
|
+
const text = await readText(resp);
|
|
503
|
+
if (!text) {
|
|
504
|
+
if (resp.ok || resp.status === 304) {
|
|
505
|
+
return { isRemote: true };
|
|
408
506
|
}
|
|
507
|
+
throw statusError(resp);
|
|
409
508
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
509
|
+
const body = decodeText(resp, opt, text);
|
|
510
|
+
const ver = body?.[info_default.name];
|
|
511
|
+
if (!ver) {
|
|
512
|
+
if (resp.ok) {
|
|
513
|
+
return { isRemote: true, result: body };
|
|
514
|
+
}
|
|
515
|
+
throw statusError(resp);
|
|
413
516
|
}
|
|
414
|
-
body.
|
|
415
|
-
body.
|
|
416
|
-
|
|
417
|
-
|
|
517
|
+
body.isRemote = true;
|
|
518
|
+
body.isApiKit = true;
|
|
519
|
+
body.apiKitDiff = diffVersion(ver);
|
|
520
|
+
body.error = reconstructApiError(body.error);
|
|
521
|
+
return body;
|
|
522
|
+
};
|
|
523
|
+
var fetchBody = async (_fetch, opt) => {
|
|
524
|
+
let resp, body;
|
|
525
|
+
try {
|
|
526
|
+
resp = await _fetch(opt.url, opt);
|
|
527
|
+
} catch (err2) {
|
|
528
|
+
body = localReject(err2, opt);
|
|
418
529
|
}
|
|
419
|
-
|
|
530
|
+
try {
|
|
531
|
+
body = body || await remoteResolve(resp, opt);
|
|
532
|
+
} catch (err2) {
|
|
533
|
+
body = remoteReject(err2, opt);
|
|
534
|
+
}
|
|
535
|
+
const err = body.error;
|
|
536
|
+
body.isOk = !err;
|
|
537
|
+
body.isRemote = !!body.isRemote;
|
|
538
|
+
body.isApiKit = !!body.isApiKit;
|
|
539
|
+
body.statusCode = err?.httpStatusCode || resp?.status;
|
|
540
|
+
body.headers = parseHeaders(resp, opt);
|
|
541
|
+
body = end(body, opt);
|
|
542
|
+
return opt.resultOnly ? body.result : body;
|
|
420
543
|
};
|
|
421
|
-
var
|
|
422
|
-
|
|
544
|
+
var executeFetch = (_fetch, url, opt, method) => {
|
|
545
|
+
opt = prepareOpt(url, opt, method);
|
|
546
|
+
const prom = fetchBody(_fetch, opt);
|
|
423
547
|
if (opt.timeoutId) {
|
|
424
548
|
prom.finally((_) => clearTimeout(opt.timeoutId));
|
|
425
549
|
}
|
|
426
|
-
if (!opt.
|
|
550
|
+
if (!opt.isAbortable) {
|
|
427
551
|
return prom;
|
|
428
552
|
}
|
|
429
|
-
return (0,
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
// src/client/class/Fetch.js
|
|
433
|
-
var import_props5 = require("@randajan/props");
|
|
434
|
-
|
|
435
|
-
// src/client/tool.js
|
|
436
|
-
var mrgOpt = (a, b) => {
|
|
437
|
-
const opt = mrgObj(a, b);
|
|
438
|
-
opt.body = mrgObj(a?.body, b?.body);
|
|
439
|
-
opt.params = mrgObj(a?.params, b?.params);
|
|
440
|
-
opt.headers = mrgObj(a?.headers, b?.headers, {});
|
|
441
|
-
return opt;
|
|
553
|
+
return (0, import_props5.solid)(prom, "abort", (_) => opt.abortController?.abort(abortError()));
|
|
442
554
|
};
|
|
443
555
|
|
|
444
556
|
// src/client/class/Fetch.js
|
|
557
|
+
var import_props6 = require("@randajan/props");
|
|
445
558
|
var Fetch = class _Fetch extends Functionable {
|
|
446
559
|
static create(config = {}) {
|
|
447
560
|
return new _Fetch(config);
|
|
@@ -449,37 +562,36 @@ var Fetch = class _Fetch extends Functionable {
|
|
|
449
562
|
constructor(config = {}) {
|
|
450
563
|
const _fetch = config.fetch || globalThis.fetch;
|
|
451
564
|
if (!_fetch) {
|
|
452
|
-
throw new Error("Missing fetch function. Please provide it
|
|
565
|
+
throw new Error("Missing fetch function. Please provide it in config");
|
|
453
566
|
}
|
|
454
567
|
configTrait(config);
|
|
455
|
-
config.parseBody = createTrait(config.parseBody);
|
|
456
568
|
delete config.fetch;
|
|
457
|
-
super((url, opt, method) =>
|
|
569
|
+
super((url, opt, method) => executeFetch(_fetch, url, mrgOpt(config, opt), method));
|
|
458
570
|
Object.freeze(config);
|
|
459
|
-
(0,
|
|
571
|
+
(0, import_props6.solid)(this, "config", config);
|
|
460
572
|
}
|
|
461
573
|
extend(config) {
|
|
462
574
|
return new _Fetch(mrgOpt(this.config, config));
|
|
463
575
|
}
|
|
464
|
-
|
|
576
|
+
get(url, opt) {
|
|
465
577
|
return this(url, opt, "GET");
|
|
466
578
|
}
|
|
467
|
-
|
|
579
|
+
post(url, opt) {
|
|
468
580
|
return this(url, opt, "POST");
|
|
469
581
|
}
|
|
470
|
-
|
|
582
|
+
put(url, opt) {
|
|
471
583
|
return this(url, opt, "PUT");
|
|
472
584
|
}
|
|
473
|
-
|
|
585
|
+
delete(url, opt) {
|
|
474
586
|
return this(url, opt, "DELETE");
|
|
475
587
|
}
|
|
476
|
-
|
|
588
|
+
patch(url, opt) {
|
|
477
589
|
return this(url, opt, "PATCH");
|
|
478
590
|
}
|
|
479
|
-
|
|
591
|
+
head(url, opt) {
|
|
480
592
|
return this(url, opt, "HEAD");
|
|
481
593
|
}
|
|
482
|
-
|
|
594
|
+
options(url, opt) {
|
|
483
595
|
return this(url, opt, "OPTIONS");
|
|
484
596
|
}
|
|
485
597
|
};
|