aves-sdk 1.6.0 → 1.8.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/CHANGELOG.md +239 -0
- package/README.md +231 -88
- package/dist/index.d.mts +5016 -749
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/docs/guida-implementazione-booking-ops.md +0 -528
- package/docs/spike-api-aves-analisi.md +0 -196
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AVES SDK
|
|
2
2
|
|
|
3
|
-
Type-safe TypeScript SDK for the AVES XML REST API. Handles XML parsing, Valibot validation, camelCase ↔ PascalCase, and returns `Result` instead of throwing.
|
|
3
|
+
Type-safe TypeScript SDK for the AVES XML REST API. Handles XML parsing, Valibot validation, camelCase ↔ PascalCase / `@` attrs, and returns `Result` instead of throwing.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ pnpm add aves-sdk
|
|
|
14
14
|
bun add aves-sdk
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
## Quick
|
|
17
|
+
## Quick start
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
20
|
import { AvesClient } from 'aves-sdk';
|
|
@@ -27,67 +27,99 @@ const client = new AvesClient({
|
|
|
27
27
|
timeoutMs: 30_000, // optional
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const result = await client.search({
|
|
31
31
|
searchType: 'CODE',
|
|
32
32
|
recordCode: '508558',
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
if (
|
|
36
|
-
console.log(
|
|
35
|
+
if (result.success) {
|
|
36
|
+
console.log(result.data.masterRecordList);
|
|
37
37
|
} else {
|
|
38
|
-
console.error(
|
|
39
|
-
searchResult.error.kind,
|
|
40
|
-
searchResult.error.message,
|
|
41
|
-
searchResult.error.code,
|
|
42
|
-
);
|
|
38
|
+
console.error(result.error.kind, result.error.message, result.error.code);
|
|
43
39
|
}
|
|
44
40
|
```
|
|
45
41
|
|
|
46
|
-
##
|
|
42
|
+
## Client shape
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
`AvesClient` is a facade over domain clients. **Prefer namespaces.** Flat methods are auto-bound from domain prototypes (no hand-maintained forwarders).
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
```typescript
|
|
47
|
+
// canonical
|
|
48
|
+
await client.booking.createBooking(params);
|
|
49
|
+
await client.packages.searchPackages(params);
|
|
50
|
+
await client.master.search({ searchType: 'CODE', recordCode: '508558' });
|
|
51
|
+
|
|
52
|
+
// flat compat (same implementations)
|
|
53
|
+
await client.createBooking(params);
|
|
54
|
+
await client.searchPackages(params);
|
|
55
|
+
await client.search({ searchType: 'CODE', recordCode: '508558' });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| Namespace | Methods |
|
|
59
|
+
| --------- | ------- |
|
|
60
|
+
| `master` | `search`, `upsertRecord` |
|
|
61
|
+
| `booking` | `createBooking`, `modBookingServices`, `modBookingHeader`, `cancelBooking`, `setBookingStatus`, `setBookingServiceStatus`, `insertFilePaymentList`, `searchBookingFiles` |
|
|
62
|
+
| `packages` | `searchPackages`, `searchTopServices`, `getPackageDetail`, `commitPackage` |
|
|
63
|
+
|
|
64
|
+
### Constructor
|
|
51
65
|
|
|
52
66
|
```typescript
|
|
53
|
-
new AvesClient(options: AvesClientOptions)
|
|
67
|
+
new AvesClient(options: AvesClientOptions, deps?: AvesClientDeps)
|
|
54
68
|
```
|
|
55
69
|
|
|
56
|
-
| Option
|
|
57
|
-
|
|
|
58
|
-
| `baseURL`
|
|
59
|
-
| `hostID`
|
|
60
|
-
| `xtoken`
|
|
70
|
+
| Option | Description |
|
|
71
|
+
| ------ | ----------- |
|
|
72
|
+
| `baseURL` | AVES API base URL |
|
|
73
|
+
| `hostID` | 6-digit host id |
|
|
74
|
+
| `xtoken` | Auth token |
|
|
61
75
|
| `languageCode` | Optional 2-digit language code |
|
|
62
|
-
| `timeoutMs`
|
|
76
|
+
| `timeoutMs` | Optional request timeout (default 30000) |
|
|
63
77
|
|
|
64
|
-
|
|
78
|
+
Optional DI (tests / custom transport):
|
|
65
79
|
|
|
66
80
|
```typescript
|
|
67
|
-
|
|
81
|
+
import {
|
|
82
|
+
AvesClient,
|
|
83
|
+
AvesTransport,
|
|
84
|
+
BookingClient,
|
|
85
|
+
} from 'aves-sdk';
|
|
86
|
+
|
|
87
|
+
const transport = new AvesTransport(options);
|
|
88
|
+
new AvesClient(options, {
|
|
89
|
+
transport,
|
|
90
|
+
booking: new BookingClient(transport),
|
|
91
|
+
});
|
|
68
92
|
```
|
|
69
93
|
|
|
70
|
-
|
|
94
|
+
### Result type
|
|
95
|
+
|
|
96
|
+
All methods return `Result<T, AvesError>` — they do **not** throw.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
type Result<T, E> =
|
|
100
|
+
| { success: true; data: T }
|
|
101
|
+
| { success: false; error: E };
|
|
102
|
+
```
|
|
71
103
|
|
|
72
|
-
|
|
104
|
+
---
|
|
73
105
|
|
|
74
|
-
|
|
106
|
+
## Master records
|
|
75
107
|
|
|
76
|
-
|
|
108
|
+
### `search(params)` / `client.master.search`
|
|
77
109
|
|
|
78
|
-
| `searchType`
|
|
79
|
-
|
|
|
80
|
-
| `'CODE'`
|
|
81
|
-
| `'NAME'`
|
|
82
|
-
| `'VATCODE'`
|
|
83
|
-
| `'ZONE'`
|
|
84
|
-
| `'CATEGORY'`
|
|
85
|
-
| `'EMAIL'`
|
|
86
|
-
| `'LASTMODDATE'`
|
|
87
|
-
| `'SEARCH_FIELD'` / `'EXTERNAL_REF_CODE'` | `searchFieldValue`
|
|
110
|
+
| `searchType` | Required fields |
|
|
111
|
+
| ------------ | --------------- |
|
|
112
|
+
| `'CODE'` | `recordCode` |
|
|
113
|
+
| `'NAME'` | `name` (+ optional `city`) |
|
|
114
|
+
| `'VATCODE'` | `vatCode` (+ optional `phoneNumber`) |
|
|
115
|
+
| `'ZONE'` | `zipCode`, `countyCode` (+ optional `city`) |
|
|
116
|
+
| `'CATEGORY'` | `categoryCode` |
|
|
117
|
+
| `'EMAIL'` | `email` |
|
|
118
|
+
| `'LASTMODDATE'` | `lastModificationDate: { minDate, maxDate }` |
|
|
119
|
+
| `'SEARCH_FIELD'` / `'EXTERNAL_REF_CODE'` | `searchFieldValue` |
|
|
88
120
|
|
|
89
121
|
```typescript
|
|
90
|
-
const byCode = await client.search({
|
|
122
|
+
const byCode = await client.master.search({
|
|
91
123
|
searchType: 'CODE',
|
|
92
124
|
recordCode: '508558',
|
|
93
125
|
});
|
|
@@ -98,23 +130,14 @@ const byEmail = await client.search({
|
|
|
98
130
|
});
|
|
99
131
|
```
|
|
100
132
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
Insert or update a master record. `insertCriteria` defaults to `'T'`.
|
|
133
|
+
### `upsertRecord(record)` / `client.master.upsertRecord`
|
|
104
134
|
|
|
105
|
-
|
|
106
|
-
- `'N'` — do not update if exists
|
|
107
|
-
- `'T'` — update all fields if exists (default)
|
|
108
|
-
- `'M'` — update secondary fields only
|
|
135
|
+
`insertCriteria`: `'S'` always insert · `'N'` skip if exists · `'T'` update all (default) · `'M'` secondary fields only.
|
|
109
136
|
|
|
110
137
|
```typescript
|
|
111
138
|
const result = await client.upsertRecord({
|
|
112
139
|
name: 'Jane Smith',
|
|
113
140
|
email: 'jane@example.com',
|
|
114
|
-
address: '456 Oak Ave',
|
|
115
|
-
zipCode: '67890',
|
|
116
|
-
cityName: 'Los Angeles',
|
|
117
|
-
stateCode: 'USA',
|
|
118
141
|
languageCode: '02',
|
|
119
142
|
insertCriteria: 'T',
|
|
120
143
|
});
|
|
@@ -126,24 +149,25 @@ if (result.success) {
|
|
|
126
149
|
|
|
127
150
|
---
|
|
128
151
|
|
|
129
|
-
|
|
152
|
+
## Booking
|
|
130
153
|
|
|
131
|
-
`*List` request fields are **flat arrays of Detail objects**. The SDK wraps them to AVES List/Detail XML
|
|
154
|
+
`*List` request fields are **flat arrays of Detail objects**. The SDK wraps them to AVES List/Detail XML.
|
|
132
155
|
|
|
133
|
-
| Method
|
|
134
|
-
|
|
|
135
|
-
| `createBooking`
|
|
136
|
-
| `modBookingServices`
|
|
137
|
-
| `modBookingHeader`
|
|
138
|
-
| `cancelBooking`
|
|
139
|
-
| `setBookingStatus`
|
|
140
|
-
| `setBookingServiceStatus` | Nullify a single service line
|
|
141
|
-
| `insertFilePaymentList`
|
|
156
|
+
| Method | Purpose |
|
|
157
|
+
| ------ | ------- |
|
|
158
|
+
| `createBooking` | Create booking file |
|
|
159
|
+
| `modBookingServices` | Add/replace services, assign package, delete/nullify lines |
|
|
160
|
+
| `modBookingHeader` | Header only (pax, notes, billing) — no costs |
|
|
161
|
+
| `cancelBooking` | Delete booking file |
|
|
162
|
+
| `setBookingStatus` | Change file status (`CANCELED` / `NULLIFIED` / …) |
|
|
163
|
+
| `setBookingServiceStatus` | Nullify a single service line |
|
|
164
|
+
| `insertFilePaymentList` | Register payments |
|
|
165
|
+
| `searchBookingFiles` | Search practices (`FILE_CODE`, `PAX_NAME`, `PACKAGE_CODE`, `OTHER`) |
|
|
142
166
|
|
|
143
|
-
|
|
167
|
+
### Create
|
|
144
168
|
|
|
145
169
|
```typescript
|
|
146
|
-
const created = await client.createBooking({
|
|
170
|
+
const created = await client.booking.createBooking({
|
|
147
171
|
customerDetail: { recordCode: '138311' },
|
|
148
172
|
bookingFileStatus: { value: 'QUOTATION' },
|
|
149
173
|
startDate: '2015-01-22T00:00:00',
|
|
@@ -178,10 +202,10 @@ if (created.success) {
|
|
|
178
202
|
}
|
|
179
203
|
```
|
|
180
204
|
|
|
181
|
-
|
|
205
|
+
### Modify services / package / overwrite lines
|
|
182
206
|
|
|
183
207
|
```typescript
|
|
184
|
-
|
|
208
|
+
await client.booking.modBookingServices({
|
|
185
209
|
customerRecordCode: '138311',
|
|
186
210
|
bookingFileCode: '14/036654',
|
|
187
211
|
selectedPackageDetail: {
|
|
@@ -213,13 +237,16 @@ const result = await client.modBookingServices({
|
|
|
213
237
|
});
|
|
214
238
|
```
|
|
215
239
|
|
|
216
|
-
|
|
240
|
+
### Payments
|
|
217
241
|
|
|
218
242
|
Requires `bookingFileCode` **or** `bookingFileRefCode`.
|
|
219
243
|
|
|
244
|
+
`paymentUser` is serialized as an XML **attribute** on `FilePaymentListRQ` (`PaymentUser="…"`), not as a child element.
|
|
245
|
+
|
|
220
246
|
```typescript
|
|
221
|
-
|
|
247
|
+
await client.booking.insertFilePaymentList({
|
|
222
248
|
bookingFileCode: '18/000172',
|
|
249
|
+
paymentUser: 'MLDN',
|
|
223
250
|
enableMultiplePayments: true,
|
|
224
251
|
operationType: 'AbsoluteAmountsInsertion',
|
|
225
252
|
filePaymentList: [
|
|
@@ -233,38 +260,91 @@ const paid = await client.insertFilePaymentList({
|
|
|
233
260
|
});
|
|
234
261
|
```
|
|
235
262
|
|
|
236
|
-
|
|
263
|
+
### Header, status, cancel, search practices
|
|
237
264
|
|
|
238
265
|
```typescript
|
|
239
|
-
await client.modBookingHeader({
|
|
266
|
+
await client.booking.modBookingHeader({
|
|
240
267
|
bookingFileCode: '14/000043',
|
|
241
268
|
bookingFileStartDate: '2014-04-28',
|
|
242
269
|
customerRecordCode: '103737',
|
|
243
270
|
passengerList: [{ rph: '001', name: 'ADULTI 001', sex: 'M' }],
|
|
244
271
|
});
|
|
245
272
|
|
|
246
|
-
await client.setBookingStatus({
|
|
273
|
+
await client.booking.setBookingStatus({
|
|
247
274
|
customerRecordCode: '000170',
|
|
248
275
|
bookingFileCode: '14/000081',
|
|
249
276
|
fileStatus: { value: 'CANCELED' },
|
|
250
277
|
});
|
|
251
278
|
|
|
252
|
-
await client.setBookingServiceStatus({
|
|
279
|
+
await client.booking.setBookingServiceStatus({
|
|
253
280
|
customerRecordCode: '000001',
|
|
254
281
|
bookingFileCode: '18/000252',
|
|
255
282
|
bookingServiceRef: '002',
|
|
256
283
|
bookingFileServiceStatus: 'NULLIFIED',
|
|
257
284
|
});
|
|
258
285
|
|
|
259
|
-
await client.cancelBooking({
|
|
286
|
+
await client.booking.cancelBooking({
|
|
260
287
|
bookingFileCode: '14/000081',
|
|
261
288
|
customerRecordCode: '000170',
|
|
262
289
|
});
|
|
290
|
+
|
|
291
|
+
await client.booking.searchBookingFiles({
|
|
292
|
+
searchType: 'PACKAGE_CODE',
|
|
293
|
+
customerRecordCode: '138311',
|
|
294
|
+
packageCode: '2014MDE0000010',
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Package / Program catalog
|
|
301
|
+
|
|
302
|
+
There is **no** Create Package API in AVES XML 1.8.0. Search, detail, and commit (publish) are supported.
|
|
303
|
+
|
|
304
|
+
| Method | Purpose |
|
|
305
|
+
| ------ | ------- |
|
|
306
|
+
| `searchPackages` | Search programs (defaults `avesSearchType: 'PACKAGE'`) |
|
|
307
|
+
| `searchTopServices` | Search TOP services (defaults `avesSearchType: 'SERVICE'`) |
|
|
308
|
+
| `getPackageDetail` | Package base info + service list |
|
|
309
|
+
| `commitPackage` | Publish existing package (`packageCode` only) |
|
|
310
|
+
|
|
311
|
+
`paxQty` defaults to `passengerList.length`; `paxQtyCriteria` defaults to `GREATER_OR_EQUAL`. `languageCode` can be omitted when set on `AvesClient` options.
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
const packages = await client.packages.searchPackages({
|
|
315
|
+
customerRecordCode: '138311',
|
|
316
|
+
languageCode: '01',
|
|
317
|
+
currencyCode: 'EUR',
|
|
318
|
+
startDate: '2014-12-27T00:00:00',
|
|
319
|
+
endDate: '2015-01-03T00:00:00',
|
|
320
|
+
passengerList: [
|
|
321
|
+
{
|
|
322
|
+
rph: '001',
|
|
323
|
+
roomRph: '001',
|
|
324
|
+
name: 'ADULTI 001',
|
|
325
|
+
categoryCode: 'AD',
|
|
326
|
+
sex: 'M',
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
servOrPackCode: '2014MDE0000010',
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const detail = await client.packages.getPackageDetail({
|
|
333
|
+
customerRecordCode: '001692',
|
|
334
|
+
packageCode: '2015F042',
|
|
335
|
+
startDate: '2015-05-02T00:00:00',
|
|
336
|
+
endDate: '2015-05-05T00:00:00',
|
|
337
|
+
selectedServiceList: [
|
|
338
|
+
{ serviceCode: 'PFRM04 PAR', packageRow: '01' },
|
|
339
|
+
],
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
await client.packages.commitPackage({ packageCode: '14/PACKAGE001' });
|
|
263
343
|
```
|
|
264
344
|
|
|
265
345
|
---
|
|
266
346
|
|
|
267
|
-
##
|
|
347
|
+
## Errors
|
|
268
348
|
|
|
269
349
|
```typescript
|
|
270
350
|
import { AvesClient, AvesError } from 'aves-sdk';
|
|
@@ -275,38 +355,100 @@ const result = await client.search({
|
|
|
275
355
|
});
|
|
276
356
|
|
|
277
357
|
if (!result.success) {
|
|
278
|
-
//
|
|
358
|
+
// kind: 'validation' | 'api' | 'unknown'
|
|
279
359
|
console.error(result.error.kind, result.error.message, result.error.code);
|
|
280
360
|
}
|
|
281
361
|
```
|
|
282
362
|
|
|
283
|
-
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Case transformation & wire shapes
|
|
284
366
|
|
|
285
|
-
- **Input**: camelCase (`recordCode`, `selectedServiceList`)
|
|
286
|
-
- **Wire**: PascalCase
|
|
367
|
+
- **Input**: camelCase (`recordCode`, `selectedServiceList`, `paymentUser`)
|
|
368
|
+
- **Wire**: PascalCase keys; `@`-prefixed keys become XML attributes
|
|
287
369
|
- **Output**: camelCase again
|
|
288
370
|
|
|
289
|
-
You do not handle XML attribute prefixes yourself.
|
|
371
|
+
You do not handle XML attribute prefixes yourself. Attr vs element is decided by a **per-request `WireShape`** (`src/utils/wire-shapes.ts`), not a global field set.
|
|
372
|
+
|
|
373
|
+
### Pipeline
|
|
374
|
+
|
|
375
|
+
One outbound path for all ops:
|
|
376
|
+
|
|
377
|
+
1. Valibot validates camelCase input
|
|
378
|
+
2. `createApiSchema(schema, shape, wrap?)` → `toWireBody` (optional list wrap + empty `paxAssociated` normalize + `camelToPascalKeys`)
|
|
379
|
+
3. `AvesTransport.invokeOp` adds `RqHeader`, optional `bodyKey` nest, POSTs XML
|
|
380
|
+
|
|
381
|
+
Element-only roots use `elementOnlyWire` (`{}`). Master upsert nests under `bodyKey: "MasterRecordDetail"`; master search and booking spread fields at the RQ root.
|
|
382
|
+
|
|
383
|
+
### Request shapes (one family per op)
|
|
384
|
+
|
|
385
|
+
| Shape | Used by |
|
|
386
|
+
| ----- | ------- |
|
|
387
|
+
| `masterRecordWire` / `searchMasterWire` | Upsert / Search master |
|
|
388
|
+
| `bookingFileWire` | CreateBooking, ModFileServices, ModFileHeader |
|
|
389
|
+
| `filePaymentListRequestWire` | InsertFilePaymentList (`paymentUser` root attr) |
|
|
390
|
+
| `searchFileWire` | SearchBookingFiles (date ranges / insurance attrs) |
|
|
391
|
+
| `setFileStatusWire` | SetBookingFileStatus |
|
|
392
|
+
| `packageDetailRequestWire` | GetPackageDetail |
|
|
393
|
+
| `baseSearchWire` + `avesSearchWire` | SearchAvesPackages / SearchTopServices |
|
|
394
|
+
| `elementOnlyWire` | CancelFile, SetFileServiceStatus, CommitPackage |
|
|
395
|
+
|
|
396
|
+
Editing CreateBooking shapes does not affect SearchFile or AvesSearch.
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Architecture
|
|
401
|
+
|
|
402
|
+
`AvesClient` (`src/client.ts`) is a thin facade over DI-friendly domain clients:
|
|
403
|
+
|
|
404
|
+
| Module | Role |
|
|
405
|
+
| ------ | ---- |
|
|
406
|
+
| `AvesTransport` | HTTP + XML encode/decode + `invokeOp` (optional `bodyKey`) |
|
|
407
|
+
| `MasterRecordsClient` | search / upsert |
|
|
408
|
+
| `BookingClient` | booking file ops + search practices |
|
|
409
|
+
| `PackageCatalogClient` | package/program catalog |
|
|
410
|
+
| `client/types.ts` | `AvesClientDeps` / `AvesClientFlat` |
|
|
411
|
+
| `client/flat-aliases.ts` | bind flat compat methods from domain prototypes |
|
|
412
|
+
| `src/xml/` | XML root helpers + JSON ↔ XML |
|
|
413
|
+
|
|
414
|
+
Flat aliases (`client.createBooking`, …) are attached in the constructor — add a domain method once and both surfaces work.
|
|
415
|
+
|
|
416
|
+
Outbound path: validate → `createApiSchema` / `toWireBody` → `invokeOp` → XML POST.
|
|
417
|
+
|
|
418
|
+
---
|
|
290
419
|
|
|
291
420
|
## Types
|
|
292
421
|
|
|
293
422
|
```typescript
|
|
294
423
|
import type {
|
|
295
424
|
AvesClientOptions,
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
MasterRecordDetail,
|
|
299
|
-
ManageMasterRecordRS,
|
|
425
|
+
AvesClientDeps,
|
|
426
|
+
AvesSearchRQ,
|
|
300
427
|
BookingFileRQ,
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
428
|
+
SearchMasterRecord,
|
|
429
|
+
} from 'aves-sdk';
|
|
430
|
+
|
|
431
|
+
import {
|
|
432
|
+
AvesClient,
|
|
433
|
+
AvesTransport,
|
|
434
|
+
MasterRecordsClient,
|
|
435
|
+
BookingClient,
|
|
436
|
+
PackageCatalogClient,
|
|
437
|
+
AvesError,
|
|
438
|
+
// object enums
|
|
439
|
+
AvesSearchType,
|
|
440
|
+
BookingFileStatus,
|
|
441
|
+
InsertCriteria,
|
|
442
|
+
PassengerCategory,
|
|
443
|
+
PaxQtyCriteria,
|
|
444
|
+
PaymentType,
|
|
445
|
+
SearchMasterType,
|
|
309
446
|
} from 'aves-sdk';
|
|
447
|
+
|
|
448
|
+
PaxQtyCriteria.GREATER_OR_EQUAL
|
|
449
|
+
AvesSearchType.PACKAGE
|
|
450
|
+
PaymentType.B
|
|
451
|
+
InsertCriteria.T
|
|
310
452
|
```
|
|
311
453
|
|
|
312
454
|
## License
|
|
@@ -315,6 +457,7 @@ MIT
|
|
|
315
457
|
|
|
316
458
|
## Links
|
|
317
459
|
|
|
460
|
+
- [Changelog](./CHANGELOG.md)
|
|
318
461
|
- [GitHub Repository](https://github.com/simoneguglielmi/aves-sdk)
|
|
319
462
|
- [NPM Package](https://npmjs.com/package/aves-sdk)
|
|
320
463
|
- [Issue Tracker](https://github.com/simoneguglielmi/aves-sdk/issues)
|