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 CHANGED
@@ -1,14 +1,6 @@
1
1
  # AVES SDK
2
2
 
3
- A type-safe TypeScript SDK for the AVES XML REST API. Automatically handles XML parsing, validation, case transformation, and provides full TypeScript support.
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', // Base URL
32
- 'hostid', // 6-digit HostID
33
- 'TOKEN', // Xtoken
34
- '02' // Optional: 2-digit language code (01=Italian, 02=English)
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); // SearchMasterRecordRS
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
- upsertResult.error.errorCode,
66
- upsertResult.error.errorDescription
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(baseURL: string, hostID: string, xtoken: string, languageCode?: string)
53
+ new AvesClient(options: AvesClientOptions)
79
54
  ```
80
55
 
81
- - `baseURL` - Base URL of the AVES API
82
- - `hostID` - 6-digit identification code
83
- - `xtoken` - Unique validation string
84
- - `languageCode` - Optional: 2-digit language code (01=Italian, 02=English, etc.)
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
- #### Methods
64
+ All methods return `Result<T, AvesError>`:
87
65
 
88
- ##### `search(params)`
66
+ ```typescript
67
+ type Result<T, E> = { success: true; data: T } | { success: false; error: E };
68
+ ```
89
69
 
90
- Search for master records by various criteria. The required fields depend on the `searchType` - TypeScript will enforce the correct fields for each search type.
70
+ ---
91
71
 
92
- **Search Types and Required Fields:**
72
+ ### Master records
93
73
 
94
- - **`'CODE'`** - Requires `recordCode` (6 digits)
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
- All search types accept an optional `languageCode` (2-digit code).
76
+ Search by `searchType`. TypeScript enforces the required fields per variant.
105
77
 
106
- **Examples:**
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
- if (byEmail.success) {
126
- console.log('Found:', byEmail.data.masterRecordList);
127
- } else {
128
- console.error('Error:', byEmail.error.message);
129
- }
101
+ #### `upsertRecord(record)`
130
102
 
131
- // Search by name (with optional city)
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
- // Search by zone (requires zipCode and countyCode)
139
- const byZone = await client.search({
140
- searchType: 'ZONE',
141
- zipCode: '47841',
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
- // Search by last modification date
147
- const byDate = await client.search({
148
- searchType: 'LASTMODDATE',
149
- lastModificationDate: {
150
- minDate: '2024-01-01',
151
- maxDate: '2024-12-31',
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
- ##### `upsertRecord(record)`
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
- Insert or update a master record. The `insertCriteria` defaults to `'T'` (update all fields if exists) but can be overridden by including it in the record.
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 result = await client.upsertRecord({
162
- name: string,
163
- email: string,
164
- address: string,
165
- zipCode: string,
166
- cityName: string,
167
- countyCode: string,
168
- stateCode: string,
169
- firstPhoneNumber: string,
170
- mobilePhoneNumber: string,
171
- fiscalCode: string,
172
- birthDate: string,
173
- gender: string,
174
- languageCode: string, // Required
175
- categoryCode: string,
176
- recordCode: string, // Optional: 6-digit code
177
- insertCriteria: 'S' | 'N' | 'T' | 'M', // Optional: defaults to 'T'
178
- // ... see types for full list
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
- // Result is Result<ManageMasterRecordRS, AvesError>
182
- if (result.success) {
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
- **Insert Criteria:**
181
+ #### `modBookingServices(params)`
190
182
 
191
- - `'S'` - Insert always new record
192
- - `'N'` - If record exists, do not update
193
- - `'T'` - If record exists, update all fields (default)
194
- - `'M'` - If record exists, update only secondary fields
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
- **Example:**
218
+ Requires `bookingFileCode` **or** `bookingFileRefCode`.
197
219
 
198
220
  ```typescript
199
- // Default behavior (update all fields if exists)
200
- const response = await client.upsertRecord({
201
- name: 'Jane Smith',
202
- email: 'jane@example.com',
203
- address: '456 Oak Ave',
204
- zipCode: '67890',
205
- cityName: 'Los Angeles',
206
- stateCode: 'USA',
207
- firstPhoneNumber: '+1234567890',
208
- languageCode: '02',
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
- if (response.success) {
212
- console.log(response.data.customerRecordRS?.customerRecordCode);
213
- } else {
214
- console.error('Failed:', response.error.message);
215
- }
236
+ #### Other booking ops
216
237
 
217
- // Override insertCriteria
218
- const newRecord = await client.upsertRecord({
219
- name: 'John Doe',
220
- insertCriteria: 'S', // Always insert new
221
- email: 'john@example.com',
222
- languageCode: '02',
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
- if (newRecord.success) {
227
- console.log('Created:', newRecord.data.customerRecordRS?.customerRecordCode);
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
- ## Error Handling
265
+ ---
232
266
 
233
- The SDK uses a functional `Result` pattern for type-safe error handling. All methods return `Result<Success, AvesError>` instead of throwing exceptions:
267
+ ## Error Handling
234
268
 
235
269
  ```typescript
236
- import { AvesClient, AvesError, type Result } from 'aves-sdk';
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
- // TypeScript knows result.data is SearchMasterRecordRS
245
- console.log(result.data.masterRecordList);
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
- The SDK automatically handles case transformation between your code and the API:
285
+ - **Input**: camelCase (`recordCode`, `selectedServiceList`)
286
+ - **Wire**: PascalCase / `@` attributes for XML
287
+ - **Output**: camelCase again
269
288
 
270
- - **Input**: Use camelCase (e.g., `recordCode`, `zipCode`)
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
- You never need to worry about case conversion or XML attribute prefixes - the SDK handles it all.
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