aspi 2.7.0 → 2.9.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/README.md +50 -12
- package/dist/index.cjs +151 -29
- package/dist/index.d.cts +80 -1
- package/dist/index.d.ts +80 -1
- package/dist/index.js +151 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Zero runtime dependencies. Three response modes. Full error-union types.
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
14
|
- **Zero dependencies** — thin wrapper around the platform `fetch` API
|
|
15
|
-
- **Three response modes** — tuple `[data, error]`, `Result` monad, or `throwable` (your choice per call)
|
|
15
|
+
- **Three response modes** — tuple `[data, error]`, `Result` monad, or `throwable` (your choice per call, plus explicit `.withTuple()` to reset)
|
|
16
16
|
- **Typed error unions** — every error variant is tagged and narrowable at compile time
|
|
17
17
|
- **Custom error mapping** — map any HTTP status code to a structured, typed error object
|
|
18
18
|
- **Retry with back-off** — fixed or dynamic delay, status-code filtering, custom predicates
|
|
@@ -65,7 +65,7 @@ if (data) console.log(data.title);
|
|
|
65
65
|
|
|
66
66
|
## Response modes
|
|
67
67
|
|
|
68
|
-
Every request can be consumed in one of three modes. Switch mode by calling `.withResult()
|
|
68
|
+
Every request can be consumed in one of three modes. Switch mode by calling `.withResult()`, `.throwable()`, or `.withTuple()` before the body-parser method.
|
|
69
69
|
|
|
70
70
|
### 1. Tuple mode (default)
|
|
71
71
|
|
|
@@ -106,7 +106,7 @@ try {
|
|
|
106
106
|
}
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
> `throwable()` and `
|
|
109
|
+
> `throwable()`, `withResult()`, and `withTuple()` are mutually exclusive — the **last one called wins**. Use `.withTuple()` to explicitly reset back to the default tuple mode after a previous `.withResult()` or `.throwable()`.
|
|
110
110
|
|
|
111
111
|
---
|
|
112
112
|
|
|
@@ -116,12 +116,12 @@ try {
|
|
|
116
116
|
|
|
117
117
|
Every response mode surfaces the same tagged error variants:
|
|
118
118
|
|
|
119
|
-
| Tag
|
|
120
|
-
|
|
|
121
|
-
| `aspiError`
|
|
122
|
-
| `jsonParseError`
|
|
123
|
-
| `
|
|
124
|
-
| _custom_
|
|
119
|
+
| Tag | When |
|
|
120
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| `aspiError` | Any non-2xx response with no matching custom handler |
|
|
122
|
+
| `jsonParseError` | Response body could not be parsed as JSON |
|
|
123
|
+
| `schemaParseError` | Response, request body, or query params failed schema validation (when `.schema()`, `.bodySchema()`, or `.querySchema()` is used) |
|
|
124
|
+
| _custom_ | Any tag you define via `.error()` or a convenience shortcut |
|
|
125
125
|
|
|
126
126
|
### Custom error mapping
|
|
127
127
|
|
|
@@ -228,7 +228,7 @@ const [data, error] = await api
|
|
|
228
228
|
.bodyJson({ name: 'Alice', email: 'alice@example.com' })
|
|
229
229
|
.json<User>();
|
|
230
230
|
|
|
231
|
-
// If bodyJson fails validation, error.tag === '
|
|
231
|
+
// If bodyJson fails validation, error.tag === 'schemaParseError'
|
|
232
232
|
```
|
|
233
233
|
|
|
234
234
|
### Query parameters
|
|
@@ -250,6 +250,39 @@ console.log(api.get('/todos').setQueryParams({ page: '2' }).url());
|
|
|
250
250
|
// → https://api.example.com/todos?page=2
|
|
251
251
|
```
|
|
252
252
|
|
|
253
|
+
#### Query schema validation
|
|
254
|
+
|
|
255
|
+
Just like request bodies, query parameters can be validated with `.querySchema()`. The schema transforms the input and `setQueryParams()` is typed to accept only the schema's input shape.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { z } from 'zod';
|
|
259
|
+
|
|
260
|
+
const ListTodosQuery = z.object({
|
|
261
|
+
page: z.number().default(1),
|
|
262
|
+
limit: z.number().default(10),
|
|
263
|
+
sort: z.enum(['asc', 'desc']).default('asc'),
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const result = await api
|
|
267
|
+
.get('/todos')
|
|
268
|
+
.querySchema(ListTodosQuery)
|
|
269
|
+
.setQueryParams({ page: 1, limit: 20 })
|
|
270
|
+
.withResult()
|
|
271
|
+
.json();
|
|
272
|
+
|
|
273
|
+
// If validation fails, error.tag === 'schemaParseError' and no network call is made
|
|
274
|
+
Result.match(result, {
|
|
275
|
+
onOk: ({ data }) => console.log(data),
|
|
276
|
+
onErr: (err) => {
|
|
277
|
+
if (err.tag === 'schemaParseError') {
|
|
278
|
+
console.error('Invalid query params:', err.data);
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
If the schema transforms values (e.g. applying defaults or coercion), the transformed output is what gets serialized into the URL. Async schema validators are also supported.
|
|
285
|
+
|
|
253
286
|
### Headers
|
|
254
287
|
|
|
255
288
|
```ts
|
|
@@ -309,6 +342,8 @@ Aspi integrates with any library that implements the [StandardSchemaV1](https://
|
|
|
309
342
|
|
|
310
343
|
Attach a schema with `.schema()` before the body-parser. The inferred output type is used automatically — you don't need to pass a generic.
|
|
311
344
|
|
|
345
|
+
Aspi supports both **synchronous and asynchronous** `validate` implementations, so schema libraries that return `Promise<Result>` work out of the box.
|
|
346
|
+
|
|
312
347
|
```ts
|
|
313
348
|
import { z } from 'zod';
|
|
314
349
|
|
|
@@ -323,13 +358,15 @@ const result = await api.get('/todos/1').withResult().schema(TodoSchema).json();
|
|
|
323
358
|
Result.match(result, {
|
|
324
359
|
onOk: ({ data }) => console.log(data.title), // data: { id: number; title: string; completed: boolean }
|
|
325
360
|
onErr: (err) => {
|
|
326
|
-
if (err.tag === '
|
|
361
|
+
if (err.tag === 'schemaParseError') {
|
|
327
362
|
console.error('Validation failed:', err.data); // StandardSchemaV1 issue list
|
|
328
363
|
}
|
|
329
364
|
},
|
|
330
365
|
});
|
|
331
366
|
```
|
|
332
367
|
|
|
368
|
+
> `.querySchema()` and `.bodySchema()` work the same way — they validate at the edge of the request builder and short-circuit the network call on failure, producing a `schemaParseError` in the error union.
|
|
369
|
+
|
|
333
370
|
---
|
|
334
371
|
|
|
335
372
|
## Middleware
|
|
@@ -530,9 +567,10 @@ These methods are available on the `Aspi` instance and affect all requests creat
|
|
|
530
567
|
| `useCapability(cap)` | Register a capability |
|
|
531
568
|
| `withResult()` | Switch all requests to Result mode |
|
|
532
569
|
| `throwable()` | Switch all requests to throwable mode |
|
|
570
|
+
| `withTuple()` | Switch all requests back to tuple mode |
|
|
533
571
|
| `.error(tag, status, cb)` | Map an HTTP status to a typed error |
|
|
534
572
|
|
|
535
|
-
Per-request methods (`api.get('/…').setQueryParams(…)`, `.schema(…)`, `.bodyJson(…)`, etc.) override the global config for that call only.
|
|
573
|
+
Per-request methods (`api.get('/…').setQueryParams(…)`, `.schema(…)`, `.querySchema(…)`, `.bodyJson(…)`, etc.) override the global config for that call only.
|
|
536
574
|
|
|
537
575
|
---
|
|
538
576
|
|
package/dist/index.cjs
CHANGED
|
@@ -20,7 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
Aspi: () =>
|
|
23
|
+
Aspi: () => Aspi2,
|
|
24
24
|
AspiError: () => AspiError,
|
|
25
25
|
CustomError: () => CustomError,
|
|
26
26
|
Request: () => Request,
|
|
@@ -325,6 +325,12 @@ var Request = class {
|
|
|
325
325
|
#timeoutMs;
|
|
326
326
|
#shouldBeResult = false;
|
|
327
327
|
#bodySchemaIssues = [];
|
|
328
|
+
#bodySchemaAsyncResult = null;
|
|
329
|
+
#bodySchemaAsyncBody = null;
|
|
330
|
+
#querySchema = null;
|
|
331
|
+
#querySchemaIssues = [];
|
|
332
|
+
#querySchemaAsyncResult = null;
|
|
333
|
+
#querySchemaAsyncParams = null;
|
|
328
334
|
#throwOnError = false;
|
|
329
335
|
#capabilities = [];
|
|
330
336
|
constructor(method, path, requestOptions, capabilities = []) {
|
|
@@ -478,9 +484,9 @@ var Request = class {
|
|
|
478
484
|
if (this.#bodySchema) {
|
|
479
485
|
const data = this.#bodySchema["~standard"].validate(body);
|
|
480
486
|
if (data instanceof Promise) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if (data.issues) {
|
|
487
|
+
this.#bodySchemaAsyncResult = data;
|
|
488
|
+
this.#bodySchemaAsyncBody = body;
|
|
489
|
+
} else if (data.issues) {
|
|
484
490
|
this.#bodySchemaIssues = data.issues;
|
|
485
491
|
} else {
|
|
486
492
|
this.#localRequestInit.body = JSON.stringify(data.value);
|
|
@@ -677,6 +683,26 @@ var Request = class {
|
|
|
677
683
|
};
|
|
678
684
|
return this;
|
|
679
685
|
}
|
|
686
|
+
/**
|
|
687
|
+
* Sets a validation schema for the query parameters using a StandardSchemaV1 schema.
|
|
688
|
+
* @template TSchema Type parameter extending StandardSchemaV1
|
|
689
|
+
* @param schema The schema to validate query parameters against
|
|
690
|
+
* @returns The request instance for chaining with updated error type
|
|
691
|
+
* @example
|
|
692
|
+
* const querySchema = z.object({
|
|
693
|
+
* page: z.number(),
|
|
694
|
+
* limit: z.number()
|
|
695
|
+
* });
|
|
696
|
+
*
|
|
697
|
+
* const request = new Request('/users', config);
|
|
698
|
+
* request
|
|
699
|
+
* .querySchema(querySchema)
|
|
700
|
+
* .setQueryParams({ page: 1, limit: 10 });
|
|
701
|
+
*/
|
|
702
|
+
querySchema(schema) {
|
|
703
|
+
this.#querySchema = schema;
|
|
704
|
+
return this;
|
|
705
|
+
}
|
|
680
706
|
/**
|
|
681
707
|
* Sets the query parameters for the request URL.
|
|
682
708
|
*
|
|
@@ -711,29 +737,19 @@ var Request = class {
|
|
|
711
737
|
* request.setQueryParams(qp);
|
|
712
738
|
*/
|
|
713
739
|
setQueryParams(params) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
qp.append(String(entry[0]), String(entry[1]));
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
} else if (typeof params === "object" && params !== null) {
|
|
727
|
-
qp = new URLSearchParams();
|
|
728
|
-
for (const [key, value] of Object.entries(
|
|
729
|
-
params
|
|
730
|
-
)) {
|
|
731
|
-
qp.append(key, String(value));
|
|
740
|
+
if (this.#querySchema) {
|
|
741
|
+
const data = this.#querySchema["~standard"].validate(params);
|
|
742
|
+
if (data instanceof Promise) {
|
|
743
|
+
this.#querySchemaAsyncResult = data;
|
|
744
|
+
this.#querySchemaAsyncParams = params;
|
|
745
|
+
} else if (data.issues) {
|
|
746
|
+
this.#querySchemaIssues = data.issues;
|
|
747
|
+
} else {
|
|
748
|
+
this.#queryParams = this.#valueToQueryParams(data.value);
|
|
732
749
|
}
|
|
733
750
|
} else {
|
|
734
|
-
|
|
751
|
+
this.#queryParams = this.#valueToQueryParams(params);
|
|
735
752
|
}
|
|
736
|
-
this.#queryParams = qp;
|
|
737
753
|
return this;
|
|
738
754
|
}
|
|
739
755
|
/**
|
|
@@ -1059,6 +1075,33 @@ var Request = class {
|
|
|
1059
1075
|
);
|
|
1060
1076
|
return this.#mapResponse(output);
|
|
1061
1077
|
}
|
|
1078
|
+
#valueToQueryParams(value) {
|
|
1079
|
+
if (value instanceof URLSearchParams) {
|
|
1080
|
+
return new URLSearchParams(value);
|
|
1081
|
+
}
|
|
1082
|
+
if (typeof value === "string") {
|
|
1083
|
+
return new URLSearchParams(value);
|
|
1084
|
+
}
|
|
1085
|
+
if (Array.isArray(value)) {
|
|
1086
|
+
const qp = new URLSearchParams();
|
|
1087
|
+
for (const entry of value) {
|
|
1088
|
+
if (Array.isArray(entry) && entry.length === 2) {
|
|
1089
|
+
qp.append(String(entry[0]), String(entry[1]));
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return qp;
|
|
1093
|
+
}
|
|
1094
|
+
if (typeof value === "object" && value !== null) {
|
|
1095
|
+
const qp = new URLSearchParams();
|
|
1096
|
+
for (const [key, val] of Object.entries(
|
|
1097
|
+
value
|
|
1098
|
+
)) {
|
|
1099
|
+
qp.append(key, String(val));
|
|
1100
|
+
}
|
|
1101
|
+
return qp;
|
|
1102
|
+
}
|
|
1103
|
+
return new URLSearchParams();
|
|
1104
|
+
}
|
|
1062
1105
|
#url() {
|
|
1063
1106
|
if (this.#path.startsWith("http://") || this.#path.startsWith("https://")) {
|
|
1064
1107
|
const absolute = new URL(this.#path);
|
|
@@ -1158,6 +1201,49 @@ var Request = class {
|
|
|
1158
1201
|
this.#shouldBeResult = true;
|
|
1159
1202
|
return this;
|
|
1160
1203
|
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Switches the request into **tuple** mode (the default).
|
|
1206
|
+
*
|
|
1207
|
+
* In tuple mode the response helpers (`json`, `text`, `blob`, …) resolve to a
|
|
1208
|
+
* tuple `[value, error]` where exactly one element is non‑null. This is useful
|
|
1209
|
+
* when you want an explicit opt‑in method to reset from `withResult()` or
|
|
1210
|
+
* `throwable()` back to the default tuple behaviour.
|
|
1211
|
+
*
|
|
1212
|
+
* Calling `withTuple` disables both Result mode and throwable mode.
|
|
1213
|
+
*
|
|
1214
|
+
* @returns {Request<
|
|
1215
|
+
* Method,
|
|
1216
|
+
* TRequest,
|
|
1217
|
+
* Merge<
|
|
1218
|
+
* Omit<Opts, 'withResult' | 'throwable'>,
|
|
1219
|
+
* {
|
|
1220
|
+
* withResult: false;
|
|
1221
|
+
* throwable: false;
|
|
1222
|
+
* }
|
|
1223
|
+
* >
|
|
1224
|
+
* >} The same {@link Request} instance, now typed with `withResult: false` and
|
|
1225
|
+
* `throwable: false` for fluent chaining.
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```ts
|
|
1229
|
+
* const request = new Request('/users', config);
|
|
1230
|
+
*
|
|
1231
|
+
* const [user, err] = await request
|
|
1232
|
+
* .withTuple() // explicitly use tuple mode
|
|
1233
|
+
* .json<User>();
|
|
1234
|
+
*
|
|
1235
|
+
* if (err) {
|
|
1236
|
+
* console.error(err);
|
|
1237
|
+
* } else {
|
|
1238
|
+
* console.log(user);
|
|
1239
|
+
* }
|
|
1240
|
+
* ```
|
|
1241
|
+
*/
|
|
1242
|
+
withTuple() {
|
|
1243
|
+
this.#throwOnError = false;
|
|
1244
|
+
this.#shouldBeResult = false;
|
|
1245
|
+
return this;
|
|
1246
|
+
}
|
|
1161
1247
|
#mapResponse(value) {
|
|
1162
1248
|
if (this.#shouldBeResult) {
|
|
1163
1249
|
return value;
|
|
@@ -1175,11 +1261,36 @@ var Request = class {
|
|
|
1175
1261
|
return response.ok || response.status >= 300 && response.status < 400;
|
|
1176
1262
|
}
|
|
1177
1263
|
async #makeRequest(responseParser, isJson = false) {
|
|
1264
|
+
if (this.#bodySchemaAsyncResult) {
|
|
1265
|
+
const data = await this.#bodySchemaAsyncResult;
|
|
1266
|
+
if (data.issues) {
|
|
1267
|
+
this.#bodySchemaIssues = data.issues;
|
|
1268
|
+
} else {
|
|
1269
|
+
this.#localRequestInit.body = JSON.stringify(data.value);
|
|
1270
|
+
}
|
|
1271
|
+
this.#bodySchemaAsyncResult = null;
|
|
1272
|
+
this.#bodySchemaAsyncBody = null;
|
|
1273
|
+
}
|
|
1178
1274
|
if (this.#bodySchemaIssues.length) {
|
|
1179
1275
|
return err(
|
|
1180
1276
|
new CustomError("schemaParseError", this.#bodySchemaIssues)
|
|
1181
1277
|
);
|
|
1182
1278
|
}
|
|
1279
|
+
if (this.#querySchemaAsyncResult) {
|
|
1280
|
+
const data = await this.#querySchemaAsyncResult;
|
|
1281
|
+
if (data.issues) {
|
|
1282
|
+
this.#querySchemaIssues = data.issues;
|
|
1283
|
+
} else {
|
|
1284
|
+
this.#queryParams = this.#valueToQueryParams(data.value);
|
|
1285
|
+
}
|
|
1286
|
+
this.#querySchemaAsyncResult = null;
|
|
1287
|
+
this.#querySchemaAsyncParams = null;
|
|
1288
|
+
}
|
|
1289
|
+
if (this.#querySchemaIssues.length) {
|
|
1290
|
+
return err(
|
|
1291
|
+
new CustomError("schemaParseError", this.#querySchemaIssues)
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1183
1294
|
const request = this.#request();
|
|
1184
1295
|
const { retries, retryDelay, retryOn, retryWhile, onRetry } = this.#sanitisedRetryConfig();
|
|
1185
1296
|
try {
|
|
@@ -1312,10 +1423,7 @@ var Request = class {
|
|
|
1312
1423
|
);
|
|
1313
1424
|
}
|
|
1314
1425
|
if (isJson && this.#schema) {
|
|
1315
|
-
const data = this.#schema["~standard"].validate(responseData);
|
|
1316
|
-
if (data instanceof Promise) {
|
|
1317
|
-
throw new Error("Schema validation should not return a promise");
|
|
1318
|
-
}
|
|
1426
|
+
const data = await this.#schema["~standard"].validate(responseData);
|
|
1319
1427
|
if (data.issues) {
|
|
1320
1428
|
return err(new CustomError("schemaParseError", data.issues));
|
|
1321
1429
|
}
|
|
@@ -1527,7 +1635,7 @@ var Request = class {
|
|
|
1527
1635
|
};
|
|
1528
1636
|
|
|
1529
1637
|
// src/aspi.ts
|
|
1530
|
-
var
|
|
1638
|
+
var Aspi2 = class {
|
|
1531
1639
|
#globalRequestInit;
|
|
1532
1640
|
#middlewares = [];
|
|
1533
1641
|
#retryConfig;
|
|
@@ -1887,6 +1995,20 @@ var Aspi = class {
|
|
|
1887
1995
|
this.#throwOnError = false;
|
|
1888
1996
|
return this;
|
|
1889
1997
|
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Configures all subsequent requests to return the default tuple `[value, error]`.
|
|
2000
|
+
*
|
|
2001
|
+
* This is the default behaviour, but `withTuple()` is provided as an explicit
|
|
2002
|
+
* reset when you have previously called {@link withResult} or {@link throwable}
|
|
2003
|
+
* on the {@link Aspi} instance.
|
|
2004
|
+
*
|
|
2005
|
+
* @returns The Aspi instance with tuple handling enabled.
|
|
2006
|
+
*/
|
|
2007
|
+
withTuple() {
|
|
2008
|
+
this.#shouldBeResult = false;
|
|
2009
|
+
this.#throwOnError = false;
|
|
2010
|
+
return this;
|
|
2011
|
+
}
|
|
1890
2012
|
/**
|
|
1891
2013
|
* Registers a capability on this {@link Aspi} instance.
|
|
1892
2014
|
*
|
package/dist/index.d.cts
CHANGED
|
@@ -1139,6 +1139,28 @@ declare class Request<Method extends HttpMethods, TRequest extends AspiRequestIn
|
|
|
1139
1139
|
error<Tag extends string, A extends {}>(tag: Tag, status: HttpErrorStatus, cb: CustomErrorCb<TRequest, A>): Request<Method, TRequest, Merge<Omit<Opts, "error">, {
|
|
1140
1140
|
error: { [K in Tag | keyof Opts["error"]]: K extends Tag ? CustomError<Tag, A> : Opts["error"][K]; };
|
|
1141
1141
|
}>>;
|
|
1142
|
+
/**
|
|
1143
|
+
* Sets a validation schema for the query parameters using a StandardSchemaV1 schema.
|
|
1144
|
+
* @template TSchema Type parameter extending StandardSchemaV1
|
|
1145
|
+
* @param schema The schema to validate query parameters against
|
|
1146
|
+
* @returns The request instance for chaining with updated error type
|
|
1147
|
+
* @example
|
|
1148
|
+
* const querySchema = z.object({
|
|
1149
|
+
* page: z.number(),
|
|
1150
|
+
* limit: z.number()
|
|
1151
|
+
* });
|
|
1152
|
+
*
|
|
1153
|
+
* const request = new Request('/users', config);
|
|
1154
|
+
* request
|
|
1155
|
+
* .querySchema(querySchema)
|
|
1156
|
+
* .setQueryParams({ page: 1, limit: 10 });
|
|
1157
|
+
*/
|
|
1158
|
+
querySchema<TSchema extends StandardSchemaV1>(schema: TSchema): Request<Method, TRequest, Omit<Opts, "querySchema"> & {
|
|
1159
|
+
querySchema: TSchema;
|
|
1160
|
+
error: Opts["error"] & {
|
|
1161
|
+
schemaParseError: CustomError<"schemaParseError", StandardSchemaV1.FailureResult["issues"]>;
|
|
1162
|
+
};
|
|
1163
|
+
}>;
|
|
1142
1164
|
/**
|
|
1143
1165
|
* Sets the query parameters for the request URL.
|
|
1144
1166
|
*
|
|
@@ -1172,7 +1194,9 @@ declare class Request<Method extends HttpMethods, TRequest extends AspiRequestIn
|
|
|
1172
1194
|
* const qp = new URLSearchParams({ page: '1' });
|
|
1173
1195
|
* request.setQueryParams(qp);
|
|
1174
1196
|
*/
|
|
1175
|
-
setQueryParams<T
|
|
1197
|
+
setQueryParams<T extends Opts extends {
|
|
1198
|
+
querySchema: infer S extends StandardSchemaV1;
|
|
1199
|
+
} ? StandardSchemaV1.InferInput<S> : any>(params: T): Request<Method, TRequest, Merge<Omit<Opts, "queryParams">, {
|
|
1176
1200
|
queryParams: T;
|
|
1177
1201
|
}>>;
|
|
1178
1202
|
/**
|
|
@@ -1564,6 +1588,48 @@ declare class Request<Method extends HttpMethods, TRequest extends AspiRequestIn
|
|
|
1564
1588
|
withResult: true;
|
|
1565
1589
|
throwable: false;
|
|
1566
1590
|
}>>;
|
|
1591
|
+
/**
|
|
1592
|
+
* Switches the request into **tuple** mode (the default).
|
|
1593
|
+
*
|
|
1594
|
+
* In tuple mode the response helpers (`json`, `text`, `blob`, …) resolve to a
|
|
1595
|
+
* tuple `[value, error]` where exactly one element is non‑null. This is useful
|
|
1596
|
+
* when you want an explicit opt‑in method to reset from `withResult()` or
|
|
1597
|
+
* `throwable()` back to the default tuple behaviour.
|
|
1598
|
+
*
|
|
1599
|
+
* Calling `withTuple` disables both Result mode and throwable mode.
|
|
1600
|
+
*
|
|
1601
|
+
* @returns {Request<
|
|
1602
|
+
* Method,
|
|
1603
|
+
* TRequest,
|
|
1604
|
+
* Merge<
|
|
1605
|
+
* Omit<Opts, 'withResult' | 'throwable'>,
|
|
1606
|
+
* {
|
|
1607
|
+
* withResult: false;
|
|
1608
|
+
* throwable: false;
|
|
1609
|
+
* }
|
|
1610
|
+
* >
|
|
1611
|
+
* >} The same {@link Request} instance, now typed with `withResult: false` and
|
|
1612
|
+
* `throwable: false` for fluent chaining.
|
|
1613
|
+
*
|
|
1614
|
+
* @example
|
|
1615
|
+
* ```ts
|
|
1616
|
+
* const request = new Request('/users', config);
|
|
1617
|
+
*
|
|
1618
|
+
* const [user, err] = await request
|
|
1619
|
+
* .withTuple() // explicitly use tuple mode
|
|
1620
|
+
* .json<User>();
|
|
1621
|
+
*
|
|
1622
|
+
* if (err) {
|
|
1623
|
+
* console.error(err);
|
|
1624
|
+
* } else {
|
|
1625
|
+
* console.log(user);
|
|
1626
|
+
* }
|
|
1627
|
+
* ```
|
|
1628
|
+
*/
|
|
1629
|
+
withTuple(): Request<Method, TRequest, Merge<Omit<Opts, "withResult" | "throwable">, {
|
|
1630
|
+
withResult: false;
|
|
1631
|
+
throwable: false;
|
|
1632
|
+
}>>;
|
|
1567
1633
|
/**
|
|
1568
1634
|
* Returns the underlying {@link AspiRequest} object that will be used for the fetch call.
|
|
1569
1635
|
*
|
|
@@ -1967,6 +2033,19 @@ declare class Aspi<TRequest extends AspiRequestInit = AspiRequestInit, Opts exte
|
|
|
1967
2033
|
withResult: true;
|
|
1968
2034
|
throwable: false;
|
|
1969
2035
|
}>>;
|
|
2036
|
+
/**
|
|
2037
|
+
* Configures all subsequent requests to return the default tuple `[value, error]`.
|
|
2038
|
+
*
|
|
2039
|
+
* This is the default behaviour, but `withTuple()` is provided as an explicit
|
|
2040
|
+
* reset when you have previously called {@link withResult} or {@link throwable}
|
|
2041
|
+
* on the {@link Aspi} instance.
|
|
2042
|
+
*
|
|
2043
|
+
* @returns The Aspi instance with tuple handling enabled.
|
|
2044
|
+
*/
|
|
2045
|
+
withTuple(): Aspi<TRequest, Merge<Omit<Opts, "withResult" | "throwable">, {
|
|
2046
|
+
withResult: false;
|
|
2047
|
+
throwable: false;
|
|
2048
|
+
}>>;
|
|
1970
2049
|
/**
|
|
1971
2050
|
* Registers a capability on this {@link Aspi} instance.
|
|
1972
2051
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1139,6 +1139,28 @@ declare class Request<Method extends HttpMethods, TRequest extends AspiRequestIn
|
|
|
1139
1139
|
error<Tag extends string, A extends {}>(tag: Tag, status: HttpErrorStatus, cb: CustomErrorCb<TRequest, A>): Request<Method, TRequest, Merge<Omit<Opts, "error">, {
|
|
1140
1140
|
error: { [K in Tag | keyof Opts["error"]]: K extends Tag ? CustomError<Tag, A> : Opts["error"][K]; };
|
|
1141
1141
|
}>>;
|
|
1142
|
+
/**
|
|
1143
|
+
* Sets a validation schema for the query parameters using a StandardSchemaV1 schema.
|
|
1144
|
+
* @template TSchema Type parameter extending StandardSchemaV1
|
|
1145
|
+
* @param schema The schema to validate query parameters against
|
|
1146
|
+
* @returns The request instance for chaining with updated error type
|
|
1147
|
+
* @example
|
|
1148
|
+
* const querySchema = z.object({
|
|
1149
|
+
* page: z.number(),
|
|
1150
|
+
* limit: z.number()
|
|
1151
|
+
* });
|
|
1152
|
+
*
|
|
1153
|
+
* const request = new Request('/users', config);
|
|
1154
|
+
* request
|
|
1155
|
+
* .querySchema(querySchema)
|
|
1156
|
+
* .setQueryParams({ page: 1, limit: 10 });
|
|
1157
|
+
*/
|
|
1158
|
+
querySchema<TSchema extends StandardSchemaV1>(schema: TSchema): Request<Method, TRequest, Omit<Opts, "querySchema"> & {
|
|
1159
|
+
querySchema: TSchema;
|
|
1160
|
+
error: Opts["error"] & {
|
|
1161
|
+
schemaParseError: CustomError<"schemaParseError", StandardSchemaV1.FailureResult["issues"]>;
|
|
1162
|
+
};
|
|
1163
|
+
}>;
|
|
1142
1164
|
/**
|
|
1143
1165
|
* Sets the query parameters for the request URL.
|
|
1144
1166
|
*
|
|
@@ -1172,7 +1194,9 @@ declare class Request<Method extends HttpMethods, TRequest extends AspiRequestIn
|
|
|
1172
1194
|
* const qp = new URLSearchParams({ page: '1' });
|
|
1173
1195
|
* request.setQueryParams(qp);
|
|
1174
1196
|
*/
|
|
1175
|
-
setQueryParams<T
|
|
1197
|
+
setQueryParams<T extends Opts extends {
|
|
1198
|
+
querySchema: infer S extends StandardSchemaV1;
|
|
1199
|
+
} ? StandardSchemaV1.InferInput<S> : any>(params: T): Request<Method, TRequest, Merge<Omit<Opts, "queryParams">, {
|
|
1176
1200
|
queryParams: T;
|
|
1177
1201
|
}>>;
|
|
1178
1202
|
/**
|
|
@@ -1564,6 +1588,48 @@ declare class Request<Method extends HttpMethods, TRequest extends AspiRequestIn
|
|
|
1564
1588
|
withResult: true;
|
|
1565
1589
|
throwable: false;
|
|
1566
1590
|
}>>;
|
|
1591
|
+
/**
|
|
1592
|
+
* Switches the request into **tuple** mode (the default).
|
|
1593
|
+
*
|
|
1594
|
+
* In tuple mode the response helpers (`json`, `text`, `blob`, …) resolve to a
|
|
1595
|
+
* tuple `[value, error]` where exactly one element is non‑null. This is useful
|
|
1596
|
+
* when you want an explicit opt‑in method to reset from `withResult()` or
|
|
1597
|
+
* `throwable()` back to the default tuple behaviour.
|
|
1598
|
+
*
|
|
1599
|
+
* Calling `withTuple` disables both Result mode and throwable mode.
|
|
1600
|
+
*
|
|
1601
|
+
* @returns {Request<
|
|
1602
|
+
* Method,
|
|
1603
|
+
* TRequest,
|
|
1604
|
+
* Merge<
|
|
1605
|
+
* Omit<Opts, 'withResult' | 'throwable'>,
|
|
1606
|
+
* {
|
|
1607
|
+
* withResult: false;
|
|
1608
|
+
* throwable: false;
|
|
1609
|
+
* }
|
|
1610
|
+
* >
|
|
1611
|
+
* >} The same {@link Request} instance, now typed with `withResult: false` and
|
|
1612
|
+
* `throwable: false` for fluent chaining.
|
|
1613
|
+
*
|
|
1614
|
+
* @example
|
|
1615
|
+
* ```ts
|
|
1616
|
+
* const request = new Request('/users', config);
|
|
1617
|
+
*
|
|
1618
|
+
* const [user, err] = await request
|
|
1619
|
+
* .withTuple() // explicitly use tuple mode
|
|
1620
|
+
* .json<User>();
|
|
1621
|
+
*
|
|
1622
|
+
* if (err) {
|
|
1623
|
+
* console.error(err);
|
|
1624
|
+
* } else {
|
|
1625
|
+
* console.log(user);
|
|
1626
|
+
* }
|
|
1627
|
+
* ```
|
|
1628
|
+
*/
|
|
1629
|
+
withTuple(): Request<Method, TRequest, Merge<Omit<Opts, "withResult" | "throwable">, {
|
|
1630
|
+
withResult: false;
|
|
1631
|
+
throwable: false;
|
|
1632
|
+
}>>;
|
|
1567
1633
|
/**
|
|
1568
1634
|
* Returns the underlying {@link AspiRequest} object that will be used for the fetch call.
|
|
1569
1635
|
*
|
|
@@ -1967,6 +2033,19 @@ declare class Aspi<TRequest extends AspiRequestInit = AspiRequestInit, Opts exte
|
|
|
1967
2033
|
withResult: true;
|
|
1968
2034
|
throwable: false;
|
|
1969
2035
|
}>>;
|
|
2036
|
+
/**
|
|
2037
|
+
* Configures all subsequent requests to return the default tuple `[value, error]`.
|
|
2038
|
+
*
|
|
2039
|
+
* This is the default behaviour, but `withTuple()` is provided as an explicit
|
|
2040
|
+
* reset when you have previously called {@link withResult} or {@link throwable}
|
|
2041
|
+
* on the {@link Aspi} instance.
|
|
2042
|
+
*
|
|
2043
|
+
* @returns The Aspi instance with tuple handling enabled.
|
|
2044
|
+
*/
|
|
2045
|
+
withTuple(): Aspi<TRequest, Merge<Omit<Opts, "withResult" | "throwable">, {
|
|
2046
|
+
withResult: false;
|
|
2047
|
+
throwable: false;
|
|
2048
|
+
}>>;
|
|
1970
2049
|
/**
|
|
1971
2050
|
* Registers a capability on this {@link Aspi} instance.
|
|
1972
2051
|
*
|
package/dist/index.js
CHANGED
|
@@ -295,6 +295,12 @@ var Request = class {
|
|
|
295
295
|
#timeoutMs;
|
|
296
296
|
#shouldBeResult = false;
|
|
297
297
|
#bodySchemaIssues = [];
|
|
298
|
+
#bodySchemaAsyncResult = null;
|
|
299
|
+
#bodySchemaAsyncBody = null;
|
|
300
|
+
#querySchema = null;
|
|
301
|
+
#querySchemaIssues = [];
|
|
302
|
+
#querySchemaAsyncResult = null;
|
|
303
|
+
#querySchemaAsyncParams = null;
|
|
298
304
|
#throwOnError = false;
|
|
299
305
|
#capabilities = [];
|
|
300
306
|
constructor(method, path, requestOptions, capabilities = []) {
|
|
@@ -448,9 +454,9 @@ var Request = class {
|
|
|
448
454
|
if (this.#bodySchema) {
|
|
449
455
|
const data = this.#bodySchema["~standard"].validate(body);
|
|
450
456
|
if (data instanceof Promise) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
if (data.issues) {
|
|
457
|
+
this.#bodySchemaAsyncResult = data;
|
|
458
|
+
this.#bodySchemaAsyncBody = body;
|
|
459
|
+
} else if (data.issues) {
|
|
454
460
|
this.#bodySchemaIssues = data.issues;
|
|
455
461
|
} else {
|
|
456
462
|
this.#localRequestInit.body = JSON.stringify(data.value);
|
|
@@ -647,6 +653,26 @@ var Request = class {
|
|
|
647
653
|
};
|
|
648
654
|
return this;
|
|
649
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* Sets a validation schema for the query parameters using a StandardSchemaV1 schema.
|
|
658
|
+
* @template TSchema Type parameter extending StandardSchemaV1
|
|
659
|
+
* @param schema The schema to validate query parameters against
|
|
660
|
+
* @returns The request instance for chaining with updated error type
|
|
661
|
+
* @example
|
|
662
|
+
* const querySchema = z.object({
|
|
663
|
+
* page: z.number(),
|
|
664
|
+
* limit: z.number()
|
|
665
|
+
* });
|
|
666
|
+
*
|
|
667
|
+
* const request = new Request('/users', config);
|
|
668
|
+
* request
|
|
669
|
+
* .querySchema(querySchema)
|
|
670
|
+
* .setQueryParams({ page: 1, limit: 10 });
|
|
671
|
+
*/
|
|
672
|
+
querySchema(schema) {
|
|
673
|
+
this.#querySchema = schema;
|
|
674
|
+
return this;
|
|
675
|
+
}
|
|
650
676
|
/**
|
|
651
677
|
* Sets the query parameters for the request URL.
|
|
652
678
|
*
|
|
@@ -681,29 +707,19 @@ var Request = class {
|
|
|
681
707
|
* request.setQueryParams(qp);
|
|
682
708
|
*/
|
|
683
709
|
setQueryParams(params) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
qp.append(String(entry[0]), String(entry[1]));
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
} else if (typeof params === "object" && params !== null) {
|
|
697
|
-
qp = new URLSearchParams();
|
|
698
|
-
for (const [key, value] of Object.entries(
|
|
699
|
-
params
|
|
700
|
-
)) {
|
|
701
|
-
qp.append(key, String(value));
|
|
710
|
+
if (this.#querySchema) {
|
|
711
|
+
const data = this.#querySchema["~standard"].validate(params);
|
|
712
|
+
if (data instanceof Promise) {
|
|
713
|
+
this.#querySchemaAsyncResult = data;
|
|
714
|
+
this.#querySchemaAsyncParams = params;
|
|
715
|
+
} else if (data.issues) {
|
|
716
|
+
this.#querySchemaIssues = data.issues;
|
|
717
|
+
} else {
|
|
718
|
+
this.#queryParams = this.#valueToQueryParams(data.value);
|
|
702
719
|
}
|
|
703
720
|
} else {
|
|
704
|
-
|
|
721
|
+
this.#queryParams = this.#valueToQueryParams(params);
|
|
705
722
|
}
|
|
706
|
-
this.#queryParams = qp;
|
|
707
723
|
return this;
|
|
708
724
|
}
|
|
709
725
|
/**
|
|
@@ -1029,6 +1045,33 @@ var Request = class {
|
|
|
1029
1045
|
);
|
|
1030
1046
|
return this.#mapResponse(output);
|
|
1031
1047
|
}
|
|
1048
|
+
#valueToQueryParams(value) {
|
|
1049
|
+
if (value instanceof URLSearchParams) {
|
|
1050
|
+
return new URLSearchParams(value);
|
|
1051
|
+
}
|
|
1052
|
+
if (typeof value === "string") {
|
|
1053
|
+
return new URLSearchParams(value);
|
|
1054
|
+
}
|
|
1055
|
+
if (Array.isArray(value)) {
|
|
1056
|
+
const qp = new URLSearchParams();
|
|
1057
|
+
for (const entry of value) {
|
|
1058
|
+
if (Array.isArray(entry) && entry.length === 2) {
|
|
1059
|
+
qp.append(String(entry[0]), String(entry[1]));
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return qp;
|
|
1063
|
+
}
|
|
1064
|
+
if (typeof value === "object" && value !== null) {
|
|
1065
|
+
const qp = new URLSearchParams();
|
|
1066
|
+
for (const [key, val] of Object.entries(
|
|
1067
|
+
value
|
|
1068
|
+
)) {
|
|
1069
|
+
qp.append(key, String(val));
|
|
1070
|
+
}
|
|
1071
|
+
return qp;
|
|
1072
|
+
}
|
|
1073
|
+
return new URLSearchParams();
|
|
1074
|
+
}
|
|
1032
1075
|
#url() {
|
|
1033
1076
|
if (this.#path.startsWith("http://") || this.#path.startsWith("https://")) {
|
|
1034
1077
|
const absolute = new URL(this.#path);
|
|
@@ -1128,6 +1171,49 @@ var Request = class {
|
|
|
1128
1171
|
this.#shouldBeResult = true;
|
|
1129
1172
|
return this;
|
|
1130
1173
|
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Switches the request into **tuple** mode (the default).
|
|
1176
|
+
*
|
|
1177
|
+
* In tuple mode the response helpers (`json`, `text`, `blob`, …) resolve to a
|
|
1178
|
+
* tuple `[value, error]` where exactly one element is non‑null. This is useful
|
|
1179
|
+
* when you want an explicit opt‑in method to reset from `withResult()` or
|
|
1180
|
+
* `throwable()` back to the default tuple behaviour.
|
|
1181
|
+
*
|
|
1182
|
+
* Calling `withTuple` disables both Result mode and throwable mode.
|
|
1183
|
+
*
|
|
1184
|
+
* @returns {Request<
|
|
1185
|
+
* Method,
|
|
1186
|
+
* TRequest,
|
|
1187
|
+
* Merge<
|
|
1188
|
+
* Omit<Opts, 'withResult' | 'throwable'>,
|
|
1189
|
+
* {
|
|
1190
|
+
* withResult: false;
|
|
1191
|
+
* throwable: false;
|
|
1192
|
+
* }
|
|
1193
|
+
* >
|
|
1194
|
+
* >} The same {@link Request} instance, now typed with `withResult: false` and
|
|
1195
|
+
* `throwable: false` for fluent chaining.
|
|
1196
|
+
*
|
|
1197
|
+
* @example
|
|
1198
|
+
* ```ts
|
|
1199
|
+
* const request = new Request('/users', config);
|
|
1200
|
+
*
|
|
1201
|
+
* const [user, err] = await request
|
|
1202
|
+
* .withTuple() // explicitly use tuple mode
|
|
1203
|
+
* .json<User>();
|
|
1204
|
+
*
|
|
1205
|
+
* if (err) {
|
|
1206
|
+
* console.error(err);
|
|
1207
|
+
* } else {
|
|
1208
|
+
* console.log(user);
|
|
1209
|
+
* }
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
withTuple() {
|
|
1213
|
+
this.#throwOnError = false;
|
|
1214
|
+
this.#shouldBeResult = false;
|
|
1215
|
+
return this;
|
|
1216
|
+
}
|
|
1131
1217
|
#mapResponse(value) {
|
|
1132
1218
|
if (this.#shouldBeResult) {
|
|
1133
1219
|
return value;
|
|
@@ -1145,11 +1231,36 @@ var Request = class {
|
|
|
1145
1231
|
return response.ok || response.status >= 300 && response.status < 400;
|
|
1146
1232
|
}
|
|
1147
1233
|
async #makeRequest(responseParser, isJson = false) {
|
|
1234
|
+
if (this.#bodySchemaAsyncResult) {
|
|
1235
|
+
const data = await this.#bodySchemaAsyncResult;
|
|
1236
|
+
if (data.issues) {
|
|
1237
|
+
this.#bodySchemaIssues = data.issues;
|
|
1238
|
+
} else {
|
|
1239
|
+
this.#localRequestInit.body = JSON.stringify(data.value);
|
|
1240
|
+
}
|
|
1241
|
+
this.#bodySchemaAsyncResult = null;
|
|
1242
|
+
this.#bodySchemaAsyncBody = null;
|
|
1243
|
+
}
|
|
1148
1244
|
if (this.#bodySchemaIssues.length) {
|
|
1149
1245
|
return err(
|
|
1150
1246
|
new CustomError("schemaParseError", this.#bodySchemaIssues)
|
|
1151
1247
|
);
|
|
1152
1248
|
}
|
|
1249
|
+
if (this.#querySchemaAsyncResult) {
|
|
1250
|
+
const data = await this.#querySchemaAsyncResult;
|
|
1251
|
+
if (data.issues) {
|
|
1252
|
+
this.#querySchemaIssues = data.issues;
|
|
1253
|
+
} else {
|
|
1254
|
+
this.#queryParams = this.#valueToQueryParams(data.value);
|
|
1255
|
+
}
|
|
1256
|
+
this.#querySchemaAsyncResult = null;
|
|
1257
|
+
this.#querySchemaAsyncParams = null;
|
|
1258
|
+
}
|
|
1259
|
+
if (this.#querySchemaIssues.length) {
|
|
1260
|
+
return err(
|
|
1261
|
+
new CustomError("schemaParseError", this.#querySchemaIssues)
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1153
1264
|
const request = this.#request();
|
|
1154
1265
|
const { retries, retryDelay, retryOn, retryWhile, onRetry } = this.#sanitisedRetryConfig();
|
|
1155
1266
|
try {
|
|
@@ -1282,10 +1393,7 @@ var Request = class {
|
|
|
1282
1393
|
);
|
|
1283
1394
|
}
|
|
1284
1395
|
if (isJson && this.#schema) {
|
|
1285
|
-
const data = this.#schema["~standard"].validate(responseData);
|
|
1286
|
-
if (data instanceof Promise) {
|
|
1287
|
-
throw new Error("Schema validation should not return a promise");
|
|
1288
|
-
}
|
|
1396
|
+
const data = await this.#schema["~standard"].validate(responseData);
|
|
1289
1397
|
if (data.issues) {
|
|
1290
1398
|
return err(new CustomError("schemaParseError", data.issues));
|
|
1291
1399
|
}
|
|
@@ -1497,7 +1605,7 @@ var Request = class {
|
|
|
1497
1605
|
};
|
|
1498
1606
|
|
|
1499
1607
|
// src/aspi.ts
|
|
1500
|
-
var
|
|
1608
|
+
var Aspi2 = class {
|
|
1501
1609
|
#globalRequestInit;
|
|
1502
1610
|
#middlewares = [];
|
|
1503
1611
|
#retryConfig;
|
|
@@ -1857,6 +1965,20 @@ var Aspi = class {
|
|
|
1857
1965
|
this.#throwOnError = false;
|
|
1858
1966
|
return this;
|
|
1859
1967
|
}
|
|
1968
|
+
/**
|
|
1969
|
+
* Configures all subsequent requests to return the default tuple `[value, error]`.
|
|
1970
|
+
*
|
|
1971
|
+
* This is the default behaviour, but `withTuple()` is provided as an explicit
|
|
1972
|
+
* reset when you have previously called {@link withResult} or {@link throwable}
|
|
1973
|
+
* on the {@link Aspi} instance.
|
|
1974
|
+
*
|
|
1975
|
+
* @returns The Aspi instance with tuple handling enabled.
|
|
1976
|
+
*/
|
|
1977
|
+
withTuple() {
|
|
1978
|
+
this.#shouldBeResult = false;
|
|
1979
|
+
this.#throwOnError = false;
|
|
1980
|
+
return this;
|
|
1981
|
+
}
|
|
1860
1982
|
/**
|
|
1861
1983
|
* Registers a capability on this {@link Aspi} instance.
|
|
1862
1984
|
*
|
|
@@ -1900,7 +2022,7 @@ var Aspi = class {
|
|
|
1900
2022
|
}
|
|
1901
2023
|
};
|
|
1902
2024
|
export {
|
|
1903
|
-
Aspi,
|
|
2025
|
+
Aspi2 as Aspi,
|
|
1904
2026
|
AspiError,
|
|
1905
2027
|
CustomError,
|
|
1906
2028
|
Request,
|
package/package.json
CHANGED