aves-sdk 1.2.3 → 1.2.4

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,15 +1,14 @@
1
- # Aves SDK
1
+ # AVES SDK
2
2
 
3
- TypeScript SDK for integrating with the Aves
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
4
 
5
5
  ## Features
6
6
 
7
- - **100% Aves XML 1.8.0 Compliant** - Exact implementation of official spec
8
- - **Full Type Safety** - Discriminated unions, type narrowing, zero `any` types
9
- - **Smart Interfaces** - Type-safe search with discriminated unions
10
- - **Zod Validation** - Runtime validation for all requests/responses
11
- - **NestJS Native** - Proper module with DI support
12
- - **Production Ready** - Tested, validated, optimized bundle
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
+ - **Error handling** - Custom error types with detailed error information
13
12
 
14
13
  ## Installation
15
14
 
@@ -25,384 +24,231 @@ bun add aves-sdk
25
24
 
26
25
  ## Quick Start
27
26
 
28
- ### 1. Configure Environment
27
+ ```typescript
28
+ import { AvesClient } from 'aves-sdk';
29
+
30
+ const client = new AvesClient(
31
+ 'https://api.example.com', // Base URL
32
+ '025706', // 6-digit HostID
33
+ 'TOKEN002756', // Xtoken
34
+ '02' // Optional: 2-digit language code (01=Italian, 02=English)
35
+ );
36
+
37
+ // Search for records (camelCase input)
38
+ const results = await client.search({
39
+ searchType: 'CODE',
40
+ recordCode: '508558',
41
+ });
29
42
 
30
- ```env
31
- AVES_BASE_URL=https://your-aves-instance.com
32
- AVES_HOST_ID=123456
33
- AVES_XTOKEN=your_token_here
34
- AVES_LANGUAGE_CODE=01
43
+ // Insert or update a record (camelCase input)
44
+ const response = await client.upsertRecord({
45
+ name: 'John Doe',
46
+ email: 'john@example.com',
47
+ address: '123 Main St',
48
+ zipCode: '12345',
49
+ cityName: 'New York',
50
+ stateCode: 'USA',
51
+ // ... other fields
52
+ });
35
53
  ```
36
54
 
37
- ### 2. Import Module
55
+ ## API Reference
38
56
 
39
- ```typescript
40
- import { Module } from '@nestjs/common';
41
- import { ConfigModule, ConfigService } from '@nestjs/config';
42
- import { AvesModule } from 'aves-sdk';
43
-
44
- @Module({
45
- imports: [
46
- ConfigModule.forRoot({ isGlobal: true }),
47
- AvesModule.forRootAsync({
48
- imports: [ConfigModule],
49
- useFactory: (config: ConfigService) => ({
50
- baseUrl: config.get('AVES_BASE_URL')!,
51
- hostId: config.get('AVES_HOST_ID')!,
52
- xtoken: config.get('AVES_XTOKEN')!,
53
- languageCode: config.get('AVES_LANGUAGE_CODE'),
54
- }),
55
- inject: [ConfigService],
56
- }),
57
- ],
58
- })
59
- export class AppModule {}
60
- ```
57
+ ### `AvesClient`
61
58
 
62
- ### 3. Use the Service
59
+ #### Constructor
63
60
 
64
61
  ```typescript
65
- import { Injectable } from '@nestjs/common';
66
- import { AvesService, SearchCustomerRequest } from 'aves-sdk';
67
-
68
- @Injectable()
69
- export class BookingService {
70
- constructor(private readonly aves: AvesService) {}
71
-
72
- async findCustomer(code: string) {
73
- // Type-safe discriminated union
74
- const request: SearchCustomerRequest = {
75
- type: 'code',
76
- code: code,
77
- pagination: { pages: 50, page: 1 },
78
- };
79
-
80
- const result = await this.aves.searchCustomers(request);
81
- return result.customers; // Fully typed Customer[]
82
- }
83
- }
62
+ new AvesClient(baseURL: string, hostID: string, xtoken: string, languageCode?: string)
84
63
  ```
85
64
 
86
- ## Type-Safe Search (Discriminated Union)
65
+ - `baseURL` - Base URL of the AVES API
66
+ - `hostID` - 6-digit identification code
67
+ - `xtoken` - Unique validation string
68
+ - `languageCode` - Optional: 2-digit language code (01=Italian, 02=English, etc.)
87
69
 
88
- The search interface uses **discriminated unions** for perfect type safety:
70
+ #### Methods
89
71
 
90
- ```typescript
91
- // Search by customer code - TypeScript knows only 'code' is available
92
- const searchByCode: SearchCustomerRequest = {
93
- type: 'code',
94
- code: '123456',
95
- // Only 'code' property available - type-safe!
96
- };
97
-
98
- // Search by name - different fields available
99
- const searchByName: SearchCustomerRequest = {
100
- type: 'name',
101
- name: 'Smith',
102
- city: 'New York', // Optional for 'name' type
103
- };
104
-
105
- // Search by VAT code
106
- const searchByVat: SearchCustomerRequest = {
107
- type: 'vat_code',
108
- vatCode: 'IT12345678',
109
- phoneNumber: '+39123456', // Optional for 'vat_code' type
110
- };
72
+ ##### `search(params)`
111
73
 
112
- // Search by last modification date
113
- const searchByDate: SearchCustomerRequest = {
114
- type: 'last_mod_date',
115
- from: '2025-01-01',
116
- to: '2025-12-31',
117
- // 'from' and 'to' are required for this type
118
- };
119
- ```
74
+ Search for master records by various criteria. The required fields depend on the `searchType` - TypeScript will enforce the correct fields for each search type.
120
75
 
121
- ### Available Search Types
76
+ **Search Types and Required Fields:**
122
77
 
123
- | Type | Required Fields | Optional Fields |
124
- | ------------------- | ----------------- | ---------------------------------- |
125
- | `code` | `code` | `pagination` |
126
- | `name` | `name` | `city`, `pagination` |
127
- | `vat_code` | `vatCode` | `phoneNumber`, `pagination` |
128
- | `zone` | `zipCode` | `city`, `countyCode`, `pagination` |
129
- | `category` | `categoryCode` | `pagination` |
130
- | `email` | `email` | `pagination` |
131
- | `last_mod_date` | `from`, `to` | `pagination` |
132
- | `search_field` | `searchField` | `pagination` |
133
- | `external_ref_code` | `externalRefCode` | `pagination` |
78
+ - **`'CODE'`** - Requires `recordCode` (6 digits)
79
+ - **`'NAME'`** - Requires `name`, optionally `city`
80
+ - **`'VATCODE'`** - Requires `vatCode`, optionally `phoneNumber`
81
+ - **`'ZONE'`** - Requires `zipCode` and `countyCode`, optionally `city`
82
+ - **`'CATEGORY'`** - Requires `categoryCode`
83
+ - **`'EMAIL'`** - Requires `email`
84
+ - **`'LASTMODDATE'`** - Requires `lastModificationDate` with `minDate` and `maxDate`
85
+ - **`'SEARCH_FIELD'`** - Requires `searchFieldValue`
86
+ - **`'EXTERNAL_REF_CODE'`** - Requires `searchFieldValue`
134
87
 
135
- ## API Methods
88
+ All search types accept an optional `languageCode` (2-digit code).
136
89
 
137
- ### Customer Management
90
+ **Examples:**
138
91
 
139
92
  ```typescript
140
- // Search customers
141
- const result = await aves.searchCustomers({
142
- type: 'name',
143
- name: 'Rossi',
144
- pagination: { pages: 25, page: 1 },
93
+ // Search by code
94
+ const byCode = await client.search({
95
+ searchType: 'CODE',
96
+ recordCode: '508558',
145
97
  });
146
98
 
147
- // Create customer
148
- const customer = await aves.createCustomer({
149
- id: '123456',
150
- type: 'customer',
151
- status: 'enabled',
152
- personalInfo: {
153
- firstName: 'Mario',
154
- lastName: 'Rossi',
155
- dateOfBirth: '1990-01-01',
156
- gender: 'male',
157
- },
158
- contact: {
159
- email: { address: 'mario.rossi@example.com' },
160
- phone: { number: '+39123456789' },
161
- },
99
+ // Search by email
100
+ const byEmail = await client.search({
101
+ searchType: 'EMAIL',
102
+ email: 'user@example.com',
162
103
  });
163
104
 
164
- // Update customer
165
- await aves.updateCustomer(customer);
166
-
167
- // Upsert customer (insert or update secondary fields)
168
- await aves.upsertCustomer(customer);
169
- ```
170
-
171
- ### Booking Management
172
-
173
- ```typescript
174
- // Create booking
175
- const booking = await aves.createBooking({
176
- customerId: '123456',
177
- description: 'Summer vacation package',
178
- startDate: '2025-07-01',
179
- endDate: '2025-07-14',
180
- currency: 'EUR',
181
- passengers: [
182
- {
183
- id: '001',
184
- type: 'adult',
185
- firstName: 'Mario',
186
- lastName: 'Rossi',
187
- dateOfBirth: '1990-01-01',
188
- gender: 'male',
189
- },
190
- ],
191
- services: [
192
- {
193
- id: 'HTL001',
194
- type: 'hotel',
195
- status: 'pending',
196
- name: 'Hotel Paradise',
197
- startDate: '2025-07-01',
198
- endDate: '2025-07-14',
199
- },
200
- ],
201
- statisticCodes: {
202
- code2: 'USA',
203
- code3: 'GEN',
204
- },
205
- printDocument: false,
206
- sendDocumentViaEmail: false,
105
+ // Search by name (with optional city)
106
+ const byName = await client.search({
107
+ searchType: 'NAME',
108
+ name: 'John Doe',
109
+ city: 'New York', // Optional
207
110
  });
208
111
 
209
- // Update booking header
210
- await aves.updateBookingHeader('123456', 'BK/2025/001', '2025-07-01', {
211
- notes: 'Updated booking notes',
212
- passengers: [
213
- /* updated passengers */
214
- ],
112
+ // Search by zone (requires zipCode and countyCode)
113
+ const byZone = await client.search({
114
+ searchType: 'ZONE',
115
+ zipCode: '47841',
116
+ countyCode: 'RN',
117
+ city: 'Cattolica', // Optional
215
118
  });
216
119
 
217
- // Set booking status
218
- await aves.setBookingStatus('123456', 'BK/2025/001', 'confirmed');
219
-
220
- // Cancel booking
221
- await aves.cancelBooking({
222
- bookingId: 'BK/2025/001',
223
- customerId: '123456',
120
+ // Search by last modification date
121
+ const byDate = await client.search({
122
+ searchType: 'LASTMODDATE',
123
+ lastModificationDate: {
124
+ minDate: '2024-01-01',
125
+ maxDate: '2024-12-31',
126
+ },
224
127
  });
225
128
  ```
226
129
 
227
- ### Document Management
228
-
229
- ```typescript
230
- // Print booking documents
231
- const result = await aves.printDocument({
232
- bookingId: 'BK/2025/001',
233
- customerId: '123456',
234
- documentType: 'voucher',
235
- format: 'pdf',
236
- language: '01',
237
- });
130
+ ##### `upsertRecord(record)`
238
131
 
239
- // Access generated documents
240
- result.data.documents.forEach((doc) => {
241
- console.log(doc.fileName);
242
- console.log(doc.content); // Base64 content
243
- console.log(doc.contentSize);
244
- });
245
- ```
246
-
247
- ### Payment Management
132
+ 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.
248
133
 
249
134
  ```typescript
250
- // Add payment
251
- await aves.addPayment({
252
- bookingId: 'BK/2025/001',
253
- payments: [
254
- {
255
- id: 'PAY001',
256
- type: 'cash',
257
- status: 'confirmed',
258
- amount: {
259
- currency: 'EUR',
260
- amount: 500.0,
261
- },
262
- },
263
- ],
264
- enableMultiple: true,
265
- operationType: 'absolute',
135
+ const response = await client.upsertRecord({
136
+ name: string,
137
+ email: string,
138
+ address: string,
139
+ zipCode: string,
140
+ cityName: string,
141
+ countyCode: string,
142
+ stateCode: string,
143
+ firstPhoneNumber: string,
144
+ mobilePhoneNumber: string,
145
+ fiscalCode: string,
146
+ birthDate: string,
147
+ gender: string,
148
+ languageCode: string,
149
+ categoryCode: string,
150
+ recordCode: string, // Optional: 6-digit code
151
+ insertCriteria: 'S' | 'N' | 'T' | 'M', // Optional: defaults to 'T'
152
+ // ... see types for full list
266
153
  });
267
154
  ```
268
155
 
269
- ## Type Definitions
156
+ **Insert Criteria:**
270
157
 
271
- ### Customer Types
158
+ - `'S'` - Insert always new record
159
+ - `'N'` - If record exists, do not update
160
+ - `'T'` - If record exists, update all fields (default)
161
+ - `'M'` - If record exists, update only secondary fields
272
162
 
273
- ```typescript
274
- type CustomerType = 'customer' | 'supplier' | 'voucher' | 'supplier_voucher';
275
- type CustomerStatusType = 'enabled' | 'warning' | 'blacklisted' | 'disabled';
276
- type PassengerType = 'adult' | 'child' | 'infant' | 'senior';
277
- type GenderType = 'male' | 'female';
278
- ```
279
-
280
- ### Booking Types
163
+ **Example:**
281
164
 
282
165
  ```typescript
283
- type BookingStatusType =
284
- | 'quotation'
285
- | 'work_in_progress'
286
- | 'confirmed'
287
- | 'optioned'
288
- | 'nullified'
289
- | 'canceled';
290
- ```
166
+ // Default behavior (update all fields if exists)
167
+ const response = await client.upsertRecord({
168
+ name: 'Jane Smith',
169
+ email: 'jane@example.com',
170
+ address: '456 Oak Ave',
171
+ zipCode: '67890',
172
+ cityName: 'Los Angeles',
173
+ stateCode: 'USA',
174
+ firstPhoneNumber: '+1234567890',
175
+ languageCode: '02',
176
+ });
291
177
 
292
- ### Document Types
178
+ // Override insertCriteria
179
+ const newRecord = await client.upsertRecord({
180
+ name: 'John Doe',
181
+ insertCriteria: 'S', // Always insert new
182
+ email: 'john@example.com',
183
+ // ... other fields
184
+ });
293
185
 
294
- ```typescript
295
- type DocumentType =
296
- | 'visa_request'
297
- | 'travel_information'
298
- | 'voucher'
299
- | 'booking_contract'
300
- | 'booking_confirmation'
301
- | 'supplier_service_list'
302
- | 'invoice'
303
- | 'proforma_invoice'
304
- | 'adeguamento'
305
- | 'reservation_form'
306
- | 'open_xml'
307
- | 'sales_invoice'
308
- | 'ticketing_tmaster'
309
- | 'summary_form';
186
+ console.log(response.customerRecordRS?.customerRecordCode);
310
187
  ```
311
188
 
312
- ## Response Interfaces
313
-
314
- ### Search Response with Pagination
315
-
316
- ```typescript
317
- interface CustomerSearchResult {
318
- customers: Customer[];
319
- pagination: {
320
- page: number; // Current page
321
- pages: number; // Minimum known pages
322
- totalItems: number; // Items in this response
323
- hasMore: boolean; // More results available
324
- };
325
- }
326
- ```
189
+ ## Error Handling
327
190
 
328
- ### Document Print Result
191
+ The SDK throws `AvesError` for API errors and validation failures:
329
192
 
330
193
  ```typescript
331
- interface DocumentPrintResult {
332
- emailRecipient?: string;
333
- documents: PrintedDocument[];
334
- additionalDocuments?: {
335
- emailRecipient: string;
336
- documents: PrintedDocument[];
337
- }[];
338
- }
194
+ import { AvesError } from 'aves-sdk';
339
195
 
340
- interface PrintedDocument {
341
- fileName: string;
342
- content?: string; // Base64 content
343
- contentSize: number;
196
+ try {
197
+ await client.search({ searchType: 'CODE', recordCode: '123' });
198
+ } catch (error) {
199
+ if (error instanceof AvesError) {
200
+ console.error('Status:', error.status); // 'ERROR' | 'TIMEOUT' | 'WARNING'
201
+ console.error('Error Code:', error.errorCode);
202
+ console.error('Description:', error.errorDescription);
203
+ }
344
204
  }
345
205
  ```
346
206
 
347
- ## Validation
207
+ ## Case Transformation
348
208
 
349
- All requests are validated using Zod schemas:
209
+ The SDK automatically handles case transformation between your code and the API:
350
210
 
351
- ```typescript
352
- import { searchCustomerRequestSchema } from 'aves-sdk';
211
+ - **Input**: Use camelCase (e.g., `recordCode`, `zipCode`)
212
+ - **API**: Automatically converted to PascalCase with XML attributes (e.g., `@RecordCode`, `ZipCode`)
213
+ - **Output**: Automatically converted back to camelCase
353
214
 
354
- const result = searchCustomerRequestSchema.safeParse(request);
355
- if (!result.success) {
356
- console.error(result.error.issues);
357
- }
358
- ```
215
+ You never need to worry about case conversion or XML attribute prefixes - the SDK handles it all.
359
216
 
360
- ## Error Handling
217
+ ## Type Safety
361
218
 
362
- ```typescript
363
- import { AvesErrorHandler, AvesErrorCodes } from 'aves-sdk';
219
+ All types are exported and inferred from the validation schemas:
364
220
 
365
- try {
366
- const booking = await aves.createBooking(request);
367
- } catch (error) {
368
- const avesError = errorHandler.handleHttpError(error);
369
- console.error(avesError.code, avesError.message);
221
+ ```typescript
222
+ import type {
223
+ SearchMasterRecordRS,
224
+ ManageMasterRecordRS,
225
+ MasterRecordDetail,
226
+ } from 'aves-sdk';
227
+
228
+ // Use types for your functions
229
+ function processRecord(record: MasterRecordDetail) {
230
+ // TypeScript knows all available fields in camelCase
370
231
  }
371
232
  ```
372
233
 
373
- ## Bundle Size
374
-
375
- Optimized for production:
234
+ ## Validation
376
235
 
377
- - **ESM**: 51.75 KB (gzipped)
378
- - **CJS**: 55.13 KB (gzipped)
379
- - **DTS**: 137.03 KB
236
+ The SDK validates all inputs and outputs using Valibot schemas:
380
237
 
381
- ## Architecture
238
+ - **HostID**: Must be exactly 6 digits
239
+ - **RecordCode**: Must be exactly 6 characters
240
+ - **LanguageCode**: Must be exactly 2 digits (01=Italian, 02=English, etc.)
241
+ - **Search parameters**: Required fields are enforced based on `searchType` using discriminated unions
242
+ - All other fields follow the AVES API specification
382
243
 
383
- ```
384
- aves-sdk/
385
- ├── validation/
386
- │ └── api-schemas.ts # Zod schemas + inferred types (single source of truth)
387
- ├── types/
388
- │ ├── interfaces.ts # XML layer (Aves API)
389
- │ └── common.ts # Shared types
390
- ├── mappers/
391
- │ ├── request-mappers.ts # API → XML
392
- │ ├── response-mappers.ts # XML → API
393
- │ └── type-mappers.ts # Enum conversions
394
- ├── nest/
395
- │ ├── aves.module.ts # NestJS module
396
- │ └── aves.service.ts # Main service
397
- └── config/
398
- ├── endpoints.ts # API endpoints
399
- └── root-elements.ts # XML root elements
400
- ```
244
+ Invalid data will throw a validation error 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`.
401
245
 
402
246
  ## License
403
247
 
404
248
  MIT
405
249
 
406
- ## Credits
250
+ ## Links
407
251
 
408
- Built for the Aves XML 1.8.0 Booking CPX API specification.
252
+ - [GitHub Repository](https://github.com/simoneguglielmi/aves-sdk)
253
+ - [NPM Package](https://npmjs.com/package/aves-sdk)
254
+ - [Issue Tracker](https://github.com/simoneguglielmi/aves-sdk/issues)