aves-sdk 1.5.1 → 1.6.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 +201 -194
- package/dist/index.d.mts +369 -398
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/docs/guida-implementazione-booking-ops.md +227 -250
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# AVES SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Type-safe** - Full TypeScript support with inferred types
|
|
8
|
-
- **Runtime validation** - Input/output validation using Valibot
|
|
9
|
-
- **XML handling** - Automatic XML ↔ JSON conversion
|
|
10
|
-
- **Case transformation** - Automatic camelCase ↔ PascalCase conversion
|
|
11
|
-
- **Functional error handling** - Result pattern for type-safe error handling
|
|
3
|
+
Type-safe TypeScript SDK for the AVES XML REST API. Handles XML parsing, Valibot validation, camelCase ↔ PascalCase, and returns `Result` instead of throwing.
|
|
12
4
|
|
|
13
5
|
## Installation
|
|
14
6
|
|
|
@@ -27,43 +19,26 @@ bun add aves-sdk
|
|
|
27
19
|
```typescript
|
|
28
20
|
import { AvesClient } from 'aves-sdk';
|
|
29
21
|
|
|
30
|
-
const client = new AvesClient(
|
|
31
|
-
'https://api.example.com',
|
|
32
|
-
'
|
|
33
|
-
'TOKEN',
|
|
34
|
-
'02' //
|
|
35
|
-
|
|
22
|
+
const client = new AvesClient({
|
|
23
|
+
baseURL: 'https://api.example.com',
|
|
24
|
+
hostID: '000000', // 6 digits
|
|
25
|
+
xtoken: 'TOKEN',
|
|
26
|
+
languageCode: '02', // optional: 01=Italian, 02=English
|
|
27
|
+
timeoutMs: 30_000, // optional
|
|
28
|
+
});
|
|
36
29
|
|
|
37
|
-
// Search for records
|
|
38
30
|
const searchResult = await client.search({
|
|
39
31
|
searchType: 'CODE',
|
|
40
32
|
recordCode: '508558',
|
|
41
33
|
});
|
|
42
34
|
|
|
43
35
|
if (searchResult.success) {
|
|
44
|
-
console.log(searchResult.data);
|
|
45
|
-
} else {
|
|
46
|
-
console.error(searchResult.error); // AvesError
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Insert or update a record
|
|
50
|
-
const upsertResult = await client.upsertRecord({
|
|
51
|
-
name: 'John Doe',
|
|
52
|
-
email: 'john@example.com',
|
|
53
|
-
address: '123 Main St',
|
|
54
|
-
zipCode: '12345',
|
|
55
|
-
cityName: 'New York',
|
|
56
|
-
stateCode: 'USA',
|
|
57
|
-
languageCode: '02',
|
|
58
|
-
// ... other fields
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (upsertResult.success) {
|
|
62
|
-
console.log(upsertResult.data.customerRecordRS?.customerRecordCode);
|
|
36
|
+
console.log(searchResult.data.masterRecordList);
|
|
63
37
|
} else {
|
|
64
38
|
console.error(
|
|
65
|
-
|
|
66
|
-
|
|
39
|
+
searchResult.error.kind,
|
|
40
|
+
searchResult.error.message,
|
|
41
|
+
searchResult.error.code,
|
|
67
42
|
);
|
|
68
43
|
}
|
|
69
44
|
```
|
|
@@ -75,233 +50,265 @@ if (upsertResult.success) {
|
|
|
75
50
|
#### Constructor
|
|
76
51
|
|
|
77
52
|
```typescript
|
|
78
|
-
new AvesClient(
|
|
53
|
+
new AvesClient(options: AvesClientOptions)
|
|
79
54
|
```
|
|
80
55
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
56
|
+
| Option | Description |
|
|
57
|
+
| -------------- | ------------------------------ |
|
|
58
|
+
| `baseURL` | AVES API base URL |
|
|
59
|
+
| `hostID` | 6-digit host id |
|
|
60
|
+
| `xtoken` | Auth token |
|
|
61
|
+
| `languageCode` | Optional 2-digit language code |
|
|
62
|
+
| `timeoutMs` | Optional request timeout |
|
|
85
63
|
|
|
86
|
-
|
|
64
|
+
All methods return `Result<T, AvesError>`:
|
|
87
65
|
|
|
88
|
-
|
|
66
|
+
```typescript
|
|
67
|
+
type Result<T, E> = { success: true; data: T } | { success: false; error: E };
|
|
68
|
+
```
|
|
89
69
|
|
|
90
|
-
|
|
70
|
+
---
|
|
91
71
|
|
|
92
|
-
|
|
72
|
+
### Master records
|
|
93
73
|
|
|
94
|
-
|
|
95
|
-
- **`'NAME'`** - Requires `name`, optionally `city`
|
|
96
|
-
- **`'VATCODE'`** - Requires `vatCode`, optionally `phoneNumber`
|
|
97
|
-
- **`'ZONE'`** - Requires `zipCode` and `countyCode`, optionally `city`
|
|
98
|
-
- **`'CATEGORY'`** - Requires `categoryCode`
|
|
99
|
-
- **`'EMAIL'`** - Requires `email`
|
|
100
|
-
- **`'LASTMODDATE'`** - Requires `lastModificationDate` with `minDate` and `maxDate`
|
|
101
|
-
- **`'SEARCH_FIELD'`** - Requires `searchFieldValue`
|
|
102
|
-
- **`'EXTERNAL_REF_CODE'`** - Requires `searchFieldValue`
|
|
74
|
+
#### `search(params)`
|
|
103
75
|
|
|
104
|
-
|
|
76
|
+
Search by `searchType`. TypeScript enforces the required fields per variant.
|
|
105
77
|
|
|
106
|
-
|
|
78
|
+
| `searchType` | Required fields |
|
|
79
|
+
| ---------------------------------------- | -------------------------------------------- |
|
|
80
|
+
| `'CODE'` | `recordCode` |
|
|
81
|
+
| `'NAME'` | `name` (+ optional `city`) |
|
|
82
|
+
| `'VATCODE'` | `vatCode` (+ optional `phoneNumber`) |
|
|
83
|
+
| `'ZONE'` | `zipCode`, `countyCode` (+ optional `city`) |
|
|
84
|
+
| `'CATEGORY'` | `categoryCode` |
|
|
85
|
+
| `'EMAIL'` | `email` |
|
|
86
|
+
| `'LASTMODDATE'` | `lastModificationDate: { minDate, maxDate }` |
|
|
87
|
+
| `'SEARCH_FIELD'` / `'EXTERNAL_REF_CODE'` | `searchFieldValue` |
|
|
107
88
|
|
|
108
89
|
```typescript
|
|
109
|
-
// Search by code
|
|
110
90
|
const byCode = await client.search({
|
|
111
91
|
searchType: 'CODE',
|
|
112
92
|
recordCode: '508558',
|
|
113
93
|
});
|
|
114
94
|
|
|
115
|
-
if (byCode.success) {
|
|
116
|
-
console.log('Found records:', byCode.data.masterRecordList);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Search by email
|
|
120
95
|
const byEmail = await client.search({
|
|
121
96
|
searchType: 'EMAIL',
|
|
122
97
|
email: 'user@example.com',
|
|
123
98
|
});
|
|
99
|
+
```
|
|
124
100
|
|
|
125
|
-
|
|
126
|
-
console.log('Found:', byEmail.data.masterRecordList);
|
|
127
|
-
} else {
|
|
128
|
-
console.error('Error:', byEmail.error.message);
|
|
129
|
-
}
|
|
101
|
+
#### `upsertRecord(record)`
|
|
130
102
|
|
|
131
|
-
|
|
132
|
-
const byName = await client.search({
|
|
133
|
-
searchType: 'NAME',
|
|
134
|
-
name: 'John Doe',
|
|
135
|
-
city: 'New York', // Optional
|
|
136
|
-
});
|
|
103
|
+
Insert or update a master record. `insertCriteria` defaults to `'T'`.
|
|
137
104
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
countyCode: 'RN',
|
|
143
|
-
city: 'Cattolica', // Optional
|
|
144
|
-
});
|
|
105
|
+
- `'S'` — always insert
|
|
106
|
+
- `'N'` — do not update if exists
|
|
107
|
+
- `'T'` — update all fields if exists (default)
|
|
108
|
+
- `'M'` — update secondary fields only
|
|
145
109
|
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
110
|
+
```typescript
|
|
111
|
+
const result = await client.upsertRecord({
|
|
112
|
+
name: 'Jane Smith',
|
|
113
|
+
email: 'jane@example.com',
|
|
114
|
+
address: '456 Oak Ave',
|
|
115
|
+
zipCode: '67890',
|
|
116
|
+
cityName: 'Los Angeles',
|
|
117
|
+
stateCode: 'USA',
|
|
118
|
+
languageCode: '02',
|
|
119
|
+
insertCriteria: 'T',
|
|
153
120
|
});
|
|
121
|
+
|
|
122
|
+
if (result.success) {
|
|
123
|
+
console.log(result.data.masterRecordDetail?.recordCode);
|
|
124
|
+
}
|
|
154
125
|
```
|
|
155
126
|
|
|
156
|
-
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Booking
|
|
130
|
+
|
|
131
|
+
`*List` request fields are **flat arrays of Detail objects**. The SDK wraps them to AVES List/Detail XML automatically.
|
|
157
132
|
|
|
158
|
-
|
|
133
|
+
| Method | Purpose |
|
|
134
|
+
| ------------------------- | ---------------------------------------------------------- |
|
|
135
|
+
| `createBooking` | Create booking file |
|
|
136
|
+
| `modBookingServices` | Add/replace services, assign package, delete/nullify lines |
|
|
137
|
+
| `modBookingHeader` | Header only (pax, notes, billing) — no costs |
|
|
138
|
+
| `cancelBooking` | Delete booking file |
|
|
139
|
+
| `setBookingStatus` | Change file status (`CANCELED` / `NULLIFIED` / …) |
|
|
140
|
+
| `setBookingServiceStatus` | Nullify a single service line |
|
|
141
|
+
| `insertFilePaymentList` | Register payments on a booking |
|
|
142
|
+
|
|
143
|
+
#### `createBooking(params)`
|
|
159
144
|
|
|
160
145
|
```typescript
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
146
|
+
const created = await client.createBooking({
|
|
147
|
+
customerDetail: { recordCode: '138311' },
|
|
148
|
+
bookingFileStatus: { value: 'QUOTATION' },
|
|
149
|
+
startDate: '2015-01-22T00:00:00',
|
|
150
|
+
endDate: '2015-01-25T00:00:00',
|
|
151
|
+
selectedServiceList: [
|
|
152
|
+
{
|
|
153
|
+
sCode: 'HT00110840',
|
|
154
|
+
ssCode: 'DL',
|
|
155
|
+
avesServiceType: 'TOP',
|
|
156
|
+
toServiceType: 'RESIDENCE',
|
|
157
|
+
startDate: '2015-01-22T00:00:00',
|
|
158
|
+
endDate: '2015-01-25T00:00:00',
|
|
159
|
+
qty: '1',
|
|
160
|
+
pax: '2',
|
|
161
|
+
paxAssociated: [],
|
|
162
|
+
avesSession: '1',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
passengerList: [
|
|
166
|
+
{
|
|
167
|
+
rph: '001',
|
|
168
|
+
roomRph: '001',
|
|
169
|
+
name: 'ADULTI 001',
|
|
170
|
+
categoryCode: 'AD', // required on create
|
|
171
|
+
sex: 'M',
|
|
172
|
+
},
|
|
173
|
+
],
|
|
179
174
|
});
|
|
180
175
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// Access result.data
|
|
184
|
-
} else {
|
|
185
|
-
// Handle result.error
|
|
176
|
+
if (created.success) {
|
|
177
|
+
console.log(created.data.bookingFileDetail?.bookingFileCode);
|
|
186
178
|
}
|
|
187
179
|
```
|
|
188
180
|
|
|
189
|
-
|
|
181
|
+
#### `modBookingServices(params)`
|
|
190
182
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
183
|
+
```typescript
|
|
184
|
+
const result = await client.modBookingServices({
|
|
185
|
+
customerRecordCode: '138311',
|
|
186
|
+
bookingFileCode: '14/036654',
|
|
187
|
+
selectedPackageDetail: {
|
|
188
|
+
pCode: '2014MDE0000010',
|
|
189
|
+
startDate: '2015-01-22T00:00:00',
|
|
190
|
+
endDate: '2015-01-25T00:00:00',
|
|
191
|
+
},
|
|
192
|
+
cancellableBookedServiceList: [
|
|
193
|
+
{
|
|
194
|
+
cancelOperationType: 'DELETE', // or 'NULLIFY'
|
|
195
|
+
serviceRefType: 'RPH',
|
|
196
|
+
serviceRefValue: '001',
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
selectedServiceList: [
|
|
200
|
+
{
|
|
201
|
+
sCode: 'HT00110840',
|
|
202
|
+
avesServiceType: 'TOP',
|
|
203
|
+
toServiceType: 'RESIDENCE',
|
|
204
|
+
startDate: '2015-01-22T00:00:00',
|
|
205
|
+
endDate: '2015-01-25T00:00:00',
|
|
206
|
+
qty: '1',
|
|
207
|
+
pax: '2',
|
|
208
|
+
avesSession: '1',
|
|
209
|
+
bookedServiceRef: '001',
|
|
210
|
+
serviceFare: { currencyCode: 'EUR', cost: '100.00', price: '120.00' },
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### `insertFilePaymentList(params)`
|
|
195
217
|
|
|
196
|
-
**
|
|
218
|
+
Requires `bookingFileCode` **or** `bookingFileRefCode`.
|
|
197
219
|
|
|
198
220
|
```typescript
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
221
|
+
const paid = await client.insertFilePaymentList({
|
|
222
|
+
bookingFileCode: '18/000172',
|
|
223
|
+
enableMultiplePayments: true,
|
|
224
|
+
operationType: 'AbsoluteAmountsInsertion',
|
|
225
|
+
filePaymentList: [
|
|
226
|
+
{
|
|
227
|
+
paymentDate: '2018-09-08',
|
|
228
|
+
paymentNote: 'INCASSO',
|
|
229
|
+
amount: '100.00',
|
|
230
|
+
paymentType: 'B', // C cash | B bank | R card | …
|
|
231
|
+
},
|
|
232
|
+
],
|
|
209
233
|
});
|
|
234
|
+
```
|
|
210
235
|
|
|
211
|
-
|
|
212
|
-
console.log(response.data.customerRecordRS?.customerRecordCode);
|
|
213
|
-
} else {
|
|
214
|
-
console.error('Failed:', response.error.message);
|
|
215
|
-
}
|
|
236
|
+
#### Other booking ops
|
|
216
237
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
// ... other fields
|
|
238
|
+
```typescript
|
|
239
|
+
await client.modBookingHeader({
|
|
240
|
+
bookingFileCode: '14/000043',
|
|
241
|
+
bookingFileStartDate: '2014-04-28',
|
|
242
|
+
customerRecordCode: '103737',
|
|
243
|
+
passengerList: [{ rph: '001', name: 'ADULTI 001', sex: 'M' }],
|
|
224
244
|
});
|
|
225
245
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
246
|
+
await client.setBookingStatus({
|
|
247
|
+
customerRecordCode: '000170',
|
|
248
|
+
bookingFileCode: '14/000081',
|
|
249
|
+
fileStatus: { value: 'CANCELED' },
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await client.setBookingServiceStatus({
|
|
253
|
+
customerRecordCode: '000001',
|
|
254
|
+
bookingFileCode: '18/000252',
|
|
255
|
+
bookingServiceRef: '002',
|
|
256
|
+
bookingFileServiceStatus: 'NULLIFIED',
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await client.cancelBooking({
|
|
260
|
+
bookingFileCode: '14/000081',
|
|
261
|
+
customerRecordCode: '000170',
|
|
262
|
+
});
|
|
229
263
|
```
|
|
230
264
|
|
|
231
|
-
|
|
265
|
+
---
|
|
232
266
|
|
|
233
|
-
|
|
267
|
+
## Error Handling
|
|
234
268
|
|
|
235
269
|
```typescript
|
|
236
|
-
import { AvesClient, AvesError
|
|
270
|
+
import { AvesClient, AvesError } from 'aves-sdk';
|
|
237
271
|
|
|
238
272
|
const result = await client.search({
|
|
239
273
|
searchType: 'CODE',
|
|
240
274
|
recordCode: '508558',
|
|
241
275
|
});
|
|
242
276
|
|
|
243
|
-
if (result.success) {
|
|
244
|
-
//
|
|
245
|
-
console.
|
|
246
|
-
} else {
|
|
247
|
-
// TypeScript knows result.error is AvesError
|
|
248
|
-
console.error('Status:', result.error.status); // 'ERROR' | 'TIMEOUT' | 'WARNING'
|
|
249
|
-
console.error('Error Code:', result.error.errorCode);
|
|
250
|
-
console.error('Description:', result.error.errorDescription);
|
|
277
|
+
if (!result.success) {
|
|
278
|
+
// AvesError: kind ('validation' | 'api' | 'unknown'), message, status?, code?
|
|
279
|
+
console.error(result.error.kind, result.error.message, result.error.code);
|
|
251
280
|
}
|
|
252
281
|
```
|
|
253
282
|
|
|
254
|
-
**Result Type:**
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
type Result<T, E> = { success: true; data: T } | { success: false; error: E };
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
This pattern ensures:
|
|
261
|
-
|
|
262
|
-
- **Type safety**: TypeScript narrows the type based on `success`
|
|
263
|
-
- **No exceptions**: All errors are explicit in the return type
|
|
264
|
-
- **Functional style**: Easier to compose and chain operations
|
|
265
|
-
|
|
266
283
|
## Case Transformation
|
|
267
284
|
|
|
268
|
-
|
|
285
|
+
- **Input**: camelCase (`recordCode`, `selectedServiceList`)
|
|
286
|
+
- **Wire**: PascalCase / `@` attributes for XML
|
|
287
|
+
- **Output**: camelCase again
|
|
269
288
|
|
|
270
|
-
|
|
271
|
-
- **API**: Automatically converted to PascalCase with XML attributes (e.g., `@RecordCode`, `ZipCode`)
|
|
272
|
-
- **Output**: Automatically converted back to camelCase
|
|
289
|
+
You do not handle XML attribute prefixes yourself.
|
|
273
290
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
## Type Safety
|
|
277
|
-
|
|
278
|
-
All types are exported and inferred from the validation schemas:
|
|
291
|
+
## Types
|
|
279
292
|
|
|
280
293
|
```typescript
|
|
281
294
|
import type {
|
|
295
|
+
AvesClientOptions,
|
|
296
|
+
SearchMasterRecord,
|
|
282
297
|
SearchMasterRecordRS,
|
|
283
|
-
ManageMasterRecordRS,
|
|
284
298
|
MasterRecordDetail,
|
|
299
|
+
ManageMasterRecordRS,
|
|
300
|
+
BookingFileRQ,
|
|
301
|
+
BookingFileRS,
|
|
302
|
+
ModFileServicesRQ,
|
|
303
|
+
ModFileHeaderRQ,
|
|
304
|
+
CancelFileRQ,
|
|
305
|
+
SetFileStatusRQ,
|
|
306
|
+
SetFileServiceStatusRQ,
|
|
307
|
+
FilePaymentListRQ,
|
|
308
|
+
BookingStatusOnlyRS,
|
|
285
309
|
} from 'aves-sdk';
|
|
286
|
-
|
|
287
|
-
// Use types for your functions
|
|
288
|
-
function processRecord(record: MasterRecordDetail) {
|
|
289
|
-
// TypeScript knows all available fields in camelCase
|
|
290
|
-
}
|
|
291
310
|
```
|
|
292
311
|
|
|
293
|
-
## Validation
|
|
294
|
-
|
|
295
|
-
The SDK validates all inputs and outputs using Valibot schemas:
|
|
296
|
-
|
|
297
|
-
- **HostID**: Must be exactly 6 digits
|
|
298
|
-
- **RecordCode**: Must be exactly 6 characters
|
|
299
|
-
- **LanguageCode**: Must be exactly 2 digits (01=Italian, 02=English, etc.)
|
|
300
|
-
- **Search parameters**: Required fields are enforced based on `searchType` using discriminated unions
|
|
301
|
-
- All other fields follow the AVES API specification
|
|
302
|
-
|
|
303
|
-
Invalid data will return an error `Result` before making the API request. All validation happens on camelCase input, making it easy to use. TypeScript will also provide type checking and autocomplete based on the selected `searchType`.
|
|
304
|
-
|
|
305
312
|
## License
|
|
306
313
|
|
|
307
314
|
MIT
|