sabre-client 0.3.0 → 0.4.1

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.es.md CHANGED
@@ -12,8 +12,9 @@ SDK de TypeScript para las APIs de Sabre.
12
12
 
13
13
  ## Estado
14
14
 
15
- `0.3.0` es la primera versión publicada de la reescritura. Cubre el Tier 1 y el Tier 2 del
16
- flujo de Air Booking por REST, y el Tier 3 (sesiones SOAP y colas).
15
+ `0.4.0` es la versión actual de la reescritura. Cubre el Tier 1 y el Tier 2 del flujo de Air
16
+ Booking por REST, y el Tier 3 (sesiones SOAP y colas). Sobre la `0.3.0` agrega `buildCredentials`
17
+ y los comandos de host (`session.command`), sin cambios incompatibles.
17
18
 
18
19
  ```sh
19
20
  npm install sabre-client
@@ -46,8 +47,9 @@ El Tier 3 agrega el cliente SOAP `SabreLegacy`, con una sesión stateful y Queue
46
47
  | Sesión | `SessionCreateRQ` 2.0.0 / 1.0.0, `OTA_PingRQ`, `SessionCloseRQ` | `legacy.withSession`, `legacy.openSession` |
47
48
  | Colas | Get Queue Count, Access Queue, Place Queue Message | `session.queue.count`, `list`, `access`, `ignore`, `remove`, `place`, `exit`, `process` |
48
49
  | Párrafo de cola | — (función pura) | `parseQueueParagraph`, `resolveHostDate` |
50
+ | Comandos de host | `SabreCommandLLSRQ` 2.0.0 | `session.command` |
49
51
 
50
- Planeado después de `0.3.0`: Get Ancillaries (solo NDC).
52
+ Planeado después de `0.4.0`: Get Ancillaries (solo NDC).
51
53
 
52
54
  ## Requisitos
53
55
 
@@ -70,8 +72,8 @@ const sabre = new Sabre({
70
72
  credentials: {
71
73
  clientId: process.env.SABRE_CLIENT_ID!,
72
74
  clientSecret: process.env.SABRE_CLIENT_SECRET!,
73
- username: process.env.SABRE_EPR_USERNAME!, // usuario EPR, p. ej. `<user>-<PCC>-AA`
74
- password: process.env.SABRE_EPR_PASSWORD!,
75
+ username: '<user>-<PCC>-AA', // usuario EPR ya armado (ver Credenciales abajo)
76
+ password: process.env.SABRE_PASSWORD!,
75
77
  },
76
78
  });
77
79
  ```
@@ -86,6 +88,48 @@ const sabre = new Sabre({
86
88
  | `fetch` | `fetch` global | `fetch` propio (proxies, tests, otros runtimes) |
87
89
  | `tokenStore` | solo en memoria | Comparte el token entre procesos (ver [Reutilizar el token](#reutilizar-el-token)) |
88
90
 
91
+ > **`pcc` está deprecado** desde la `0.4.1` y se quita en la `0.5.0`. Era un campo reservado, y
92
+ > ningún cliente lo lee. El PCC con el que te autenticas va en `credentials` (ver
93
+ > [Credenciales](#credenciales) y `buildCredentials`). Para trabajar en otro PCC, pásalo en cada
94
+ > operación: `targetPcc` en REST y `pcc` en las operaciones de colas.
95
+
96
+ ### Credenciales
97
+
98
+ Hay **un solo juego de credenciales** para REST y SOAP: el mismo objeto `credentials` sirve para
99
+ `Sabre` y para `SabreLegacy`. Trae el usuario EPR, su PCC y su domain, el password del EPR y, de
100
+ forma opcional, el `clientId`/`clientSecret` de la app. La versión de OAuth solo cambia cómo se
101
+ escribe el `username` del EPR: `<user>-<PCC>-<domain>` (v3) o `V1:<user>:<PCC>:<domain>` (v2).
102
+
103
+ `buildCredentials` arma ese objeto a partir de las partes, así que no necesitas conocer ninguno de
104
+ los dos formatos. No lee variables de entorno y lanza un `TypeError` si algo no es válido:
105
+
106
+ ```ts
107
+ import { Sabre, SabreLegacy, buildCredentials } from 'sabre-client';
108
+
109
+ const credentials = buildCredentials({
110
+ authVersion: 'v3', // por defecto; 'v2' → `V1:<user>:<PCC>:<domain>`
111
+ user: process.env.SABRE_USERNAME!, // solo el usuario EPR
112
+ pcc: process.env.SABRE_PCC!, // el PCC al que pertenece el EPR
113
+ domain: process.env.SABRE_DOMAIN || undefined, // 'AA' por defecto
114
+ password: process.env.SABRE_PASSWORD!,
115
+ clientId: process.env.SABRE_CLIENT_ID!, // obligatorio con v3; con v2, los dos o ninguno
116
+ clientSecret: process.env.SABRE_CLIENT_SECRET!,
117
+ });
118
+
119
+ const sabre = new Sabre({ environment: 'sandbox', credentials });
120
+ const legacy = new SabreLegacy({ environment: 'sandbox', credentials });
121
+ ```
122
+
123
+ El objeto que devuelve `buildCredentials` lleva su `authVersion`, así que la config no necesita
124
+ repetirlo: con `authVersion: 'v2'` en `buildCredentials`, `{ environment, credentials }` ya es una
125
+ config v2. Si también pasas `authVersion` en la config, tiene que coincidir; si no, el cliente lanza
126
+ un `TypeError`. Las credenciales que armas a mano no llevan `authVersion`, así que con v2 la config
127
+ sigue necesitando `authVersion: 'v2'`.
128
+
129
+ El PCC de las credenciales es con el que te autenticas. Trabajar en otro PCC no requiere otro
130
+ juego de credenciales: se pasa en cada operación, como `targetPcc` en `booking.create`, `get` y
131
+ `cancel`, o como `pcc` en las operaciones de colas.
132
+
89
133
  ### Autenticación
90
134
 
91
135
  Nunca pides el token tú. El cliente lo obtiene en la primera llamada, lo cachea, lo renueva
@@ -256,9 +300,12 @@ A tener en cuenta:
256
300
  que llega como `SabreGatewayError`.
257
301
  - **Qué está comprobado.** `byReservationPayload` se probó en producción, en solo lectura, con
258
302
  un vuelo directo y una conexión. La reserva con asiento se probó en sandbox: el asiento llega
259
- al PNR y `sabre.booking.get` lo devuelve en `flights[].seats[]`. `byPnrLocator` todavía no se
260
- probó contra Sabre, porque las únicas reservas posibles en sandbox viven en otro PCC. Los
261
- precios llegan como número aunque el spec diga string, así que los tipos aceptan los dos.
303
+ al PNR y `sabre.booking.get` lo devuelve en `flights[].seats[]`. `byPnrLocator` se probó en
304
+ sandbox con una reserva hecha en el PCC con el que te autenticas: devuelve el mapa de los
305
+ segmentos del PNR, con ids propios de Sabre para pasajero y segmento (`pnr_pax_1`,
306
+ `segment_ancs_1`) en lugar de `P1` y `S1`. En sandbox ninguno de los dos endpoints refleja la
307
+ ocupación: todos los asientos vienen en `F`, también el que tiene el PNR. Los precios llegan
308
+ como número aunque el spec diga string, así que los tipos aceptan los dos.
262
309
 
263
310
  ## Sesiones SOAP y colas (`SabreLegacy`)
264
311
 
@@ -275,7 +322,7 @@ import { SabreLegacy } from 'sabre-client';
275
322
  const legacy = new SabreLegacy({
276
323
  environment: 'production',
277
324
  authVersion: 'v2',
278
- credentials: { username: 'V1:<user>:<PCC>:AA', password: process.env.SABRE_EPR_PASSWORD! },
325
+ credentials: { username: 'V1:<user>:<PCC>:AA', password: process.env.SABRE_PASSWORD! },
279
326
  });
280
327
 
281
328
  const counts = await legacy.withSession((session) => session.queue.count());
@@ -302,6 +349,45 @@ const counts = await legacy.withSession((session) => session.queue.count());
302
349
  `session unusable` sin red, y `close()` resuelve sin red. El SDK no la reabre, porque el cursor
303
350
  de la cola ya se perdió. Volver a empezar es decisión tuya.
304
351
 
352
+ ### Comandos de host
353
+
354
+ `session.command(command, options?)` manda un comando de host de Sabre (`SabreCommandLLSRQ` 2.0.0)
355
+ dentro de la sesión y devuelve la pantalla como texto. **Es una vía de escape**, sin tipos ni
356
+ garantías: el SDK no interpreta la pantalla, y un comando puede cambiar la configuración del PCC o
357
+ emitir boletos. El SDK no tiene una lista de comandos permitidos o bloqueados.
358
+
359
+ ```ts
360
+ const screen = await legacy.withSession((session) => session.command('W/PT¥*', { idempotent: true }));
361
+ // screen.text → 'PSGR TYPE - ON' (como lo manda Sabre, sin recortar)
362
+ // screen.warnings → los stl:Warning, si los hay
363
+ // screen.messageId → eb:MessageId, para soporte de Sabre
364
+ ```
365
+
366
+ - **El comando va tal cual.** En este servicio, el separador `‡` de Sabre se escribe `¥`
367
+ (`W/PT‡*` en Sabre Red es `W/PT¥*` aquí); el SDK no lo convierte.
368
+ - **La pantalla no se recorta.** Las pantallas del host van alineadas por columna y pueden empezar
369
+ con un espacio (` 17MAR WED…`), así que `text` es el contenido de `Response` tal cual. Si
370
+ necesitas recortarla, hazlo tú.
371
+ - **Hasta 1023 caracteres, contados como Sabre:** `!`, `%`, `$`, `&`, `¥` y `§` cuentan 2. Un
372
+ comando más largo lanza un `TypeError` sin llamar a la red (Sabre respondería
373
+ `REQUEST EXCEEDED MAXIMUM LENGTH`).
374
+ - **Sabre bloquea algunos comandos por su cuenta** (`SO`, `/@`, `¤¤`, según su whitelist), aunque
375
+ el SDK no tenga una lista propia.
376
+ - **Algunos comandos cuestan más.** `JR` y `WPNI` cuentan como búsquedas "Worldfare".
377
+ - **Las máscaras del host** se responden con los dos primeros caracteres de la máscara.
378
+ - **Prefiere una API estructurada.** Sabre pide no usar este servicio para lo que ya tiene una:
379
+ si el SDK tiene una operación para eso, úsala.
380
+ - **Sin reintentos por defecto**, porque el SDK no distingue una lectura de un cambio. Pasa
381
+ `{ idempotent: true }` en los comandos de solo lectura y siguen la
382
+ [política de reintentos](#reintentos).
383
+ - **Un mensaje del host no es un error.** `DUTY CODE 9 REQUIRED` o `FORMAT` llegan en `text`. Un
384
+ SOAP fault o un `stl:Error` lanzan, como en cualquier otra llamada de la sesión.
385
+ - Los comandos que dependen de la misma firma (`SI9` y luego `W/PT¥ON`) tienen que ir en la misma
386
+ sesión.
387
+ - El log de debug (`sabre.session.command`) lleva solo el primer token del comando, cortado a 4
388
+ caracteres (`W/PT`, `DC`, `*IM`), nunca el comando entero ni la pantalla. La respuesta completa
389
+ está disponible en `onRawResponse`.
390
+
305
391
  ### Colas
306
392
 
307
393
  Las operaciones de cola están en `session.queue`. `pcc` es opcional en cada llamada, y por defecto
@@ -490,7 +576,7 @@ const booking = await sabre.booking.get({ confirmationId }, { onRawResponse: (r)
490
576
  conserva el valor y escríbelo cuando la llamada vuelva.
491
577
 
492
578
  En `SabreLegacy`, `protocol` es `'soap'`, `body` es el sobre SOAP completo, y `operation` es
493
- `'openSession'`, `'close'`, `'ping'` o `'queue.<método>'`. El token de la sesión
579
+ `'openSession'`, `'close'`, `'ping'`, `'command'` o `'queue.<método>'`. El token de la sesión
494
580
  (`BinarySecurityToken`) se reemplaza por `[REDACTED]` donde aparezca. No se cambia nada más.
495
581
 
496
582
  > [!WARNING]
@@ -555,7 +641,7 @@ El SDK registra eventos estructurados (`sabre.request.start`, `sabre.request.end
555
641
  `sabre.request.retry`, `sabre.request.rawResponseHookFailed`, `sabre.auth.token.refresh`,
556
642
  `sabre.auth.token.store`, `sabre.booking.seat.priced`, `sabre.session.open`,
557
643
  `sabre.session.close`, `sabre.session.closeFailed`, `sabre.session.keepAliveFailed`,
558
- `sabre.queue.exitTolerated`, `sabre.queue.exitFailed`) y nunca los bodies
644
+ `sabre.session.command`, `sabre.queue.exitTolerated`, `sabre.queue.exitFailed`) y nunca los bodies
559
645
  crudos de request o response. Los secretos, el header `Authorization` y los datos de pasajeros
560
646
  se redactan siempre antes de llegar a tu logger.
561
647
 
package/README.md CHANGED
@@ -12,8 +12,9 @@ TypeScript SDK for the Sabre APIs.
12
12
 
13
13
  ## Status
14
14
 
15
- `0.3.0` is the first release of the rewrite. It covers Tier 1 and Tier 2 of the Air Booking
16
- flow over REST, and Tier 3 (SOAP sessions and queues).
15
+ `0.4.0` is the current release of the rewrite. It covers Tier 1 and Tier 2 of the Air Booking
16
+ flow over REST, and Tier 3 (SOAP sessions and queues). It adds `buildCredentials` and host
17
+ commands (`session.command`) to `0.3.0`, with no breaking changes.
17
18
 
18
19
  ```sh
19
20
  npm install sabre-client
@@ -46,8 +47,9 @@ Tier 3 adds the `SabreLegacy` SOAP client, with a stateful session and Queue Man
46
47
  | Session | `SessionCreateRQ` 2.0.0 / 1.0.0, `OTA_PingRQ`, `SessionCloseRQ` | `legacy.withSession`, `legacy.openSession` |
47
48
  | Queues | Get Queue Count, Access Queue, Place Queue Message | `session.queue.count`, `list`, `access`, `ignore`, `remove`, `place`, `exit`, `process` |
48
49
  | Queue paragraph | — (pure function) | `parseQueueParagraph`, `resolveHostDate` |
50
+ | Host commands | `SabreCommandLLSRQ` 2.0.0 | `session.command` |
49
51
 
50
- Planned after `0.3.0`: Get Ancillaries (NDC only).
52
+ Planned after `0.4.0`: Get Ancillaries (NDC only).
51
53
 
52
54
  ## Requirements
53
55
 
@@ -70,8 +72,8 @@ const sabre = new Sabre({
70
72
  credentials: {
71
73
  clientId: process.env.SABRE_CLIENT_ID!,
72
74
  clientSecret: process.env.SABRE_CLIENT_SECRET!,
73
- username: process.env.SABRE_EPR_USERNAME!, // EPR user, e.g. `<user>-<PCC>-AA`
74
- password: process.env.SABRE_EPR_PASSWORD!,
75
+ username: '<user>-<PCC>-AA', // EPR username, already built (see Credentials below)
76
+ password: process.env.SABRE_PASSWORD!,
75
77
  },
76
78
  });
77
79
  ```
@@ -86,6 +88,48 @@ const sabre = new Sabre({
86
88
  | `fetch` | global `fetch` | Custom `fetch` (proxies, tests, other runtimes) |
87
89
  | `tokenStore` | in-memory only | Shares the token between processes (see [Token reuse](#token-reuse)) |
88
90
 
91
+ > **`pcc` is deprecated** since `0.4.1` and will be removed in `0.5.0`. It was a reserved field,
92
+ > and no client reads it. The PCC you authenticate with goes in `credentials` (see
93
+ > [Credentials](#credentials) and `buildCredentials`). To work in another PCC, pass it per
94
+ > operation: `targetPcc` in REST, `pcc` in the queue operations.
95
+
96
+ ### Credentials
97
+
98
+ There is **one set of credentials** for REST and SOAP: the same `credentials` object works for
99
+ `Sabre` and for `SabreLegacy`. It holds the EPR user, its PCC and domain, the EPR password and,
100
+ optionally, the app's `clientId`/`clientSecret`. The OAuth version only changes how the EPR
101
+ `username` is written: `<user>-<PCC>-<domain>` (v3) or `V1:<user>:<PCC>:<domain>` (v2).
102
+
103
+ `buildCredentials` builds that object from the parts, so you don't have to know either format.
104
+ It does not read environment variables and throws a `TypeError` on invalid input:
105
+
106
+ ```ts
107
+ import { Sabre, SabreLegacy, buildCredentials } from 'sabre-client';
108
+
109
+ const credentials = buildCredentials({
110
+ authVersion: 'v3', // default; 'v2' → `V1:<user>:<PCC>:<domain>`
111
+ user: process.env.SABRE_USERNAME!, // the EPR user alone
112
+ pcc: process.env.SABRE_PCC!, // the PCC the EPR belongs to
113
+ domain: process.env.SABRE_DOMAIN || undefined, // 'AA' by default
114
+ password: process.env.SABRE_PASSWORD!,
115
+ clientId: process.env.SABRE_CLIENT_ID!, // required with v3; with v2, both or neither
116
+ clientSecret: process.env.SABRE_CLIENT_SECRET!,
117
+ });
118
+
119
+ const sabre = new Sabre({ environment: 'sandbox', credentials });
120
+ const legacy = new SabreLegacy({ environment: 'sandbox', credentials });
121
+ ```
122
+
123
+ The object that `buildCredentials` returns carries its `authVersion`, so the config does not
124
+ need to repeat it: with `authVersion: 'v2'` in `buildCredentials`, `{ environment, credentials }`
125
+ is already a v2 config. If you pass `authVersion` in the config too, it must match, or the client
126
+ throws a `TypeError`. Credentials you build by hand have no `authVersion`, so with v2 the config
127
+ still needs `authVersion: 'v2'`.
128
+
129
+ The PCC in the credentials is the one you authenticate with. Working in another PCC is not a
130
+ second set of credentials: pass it per operation, as `targetPcc` in `booking.create`, `get` and
131
+ `cancel`, or as `pcc` in the queue operations.
132
+
89
133
  ### Authentication
90
134
 
91
135
  You never request a token yourself. The client gets one on the first call, caches it, renews
@@ -255,9 +299,12 @@ Things to know:
255
299
  which surfaces as a `SabreGatewayError`.
256
300
  - **What has been checked.** `byReservationPayload` was checked read-only in production, for
257
301
  a nonstop and a connection. Booking with a seat was checked in sandbox: the seat reaches the
258
- PNR and `sabre.booking.get` returns it in `flights[].seats[]`. `byPnrLocator` has not been
259
- checked against Sabre yet, because the only sandbox bookings available live in another PCC.
260
- Prices arrive as numbers even though the spec says strings, so the types accept both.
302
+ PNR and `sabre.booking.get` returns it in `flights[].seats[]`. `byPnrLocator` was checked in
303
+ sandbox with a booking made in the PCC you authenticate with: it returns the map for the PNR's
304
+ segments, with Sabre's own passenger and segment ids (`pnr_pax_1`, `segment_ancs_1`) instead
305
+ of `P1` and `S1`. In sandbox neither endpoint reflects occupancy: every seat comes back as
306
+ `F`, including the one the PNR holds. Prices arrive as numbers even though the spec says
307
+ strings, so the types accept both.
261
308
 
262
309
  ## SOAP sessions and queues (`SabreLegacy`)
263
310
 
@@ -273,7 +320,7 @@ import { SabreLegacy } from 'sabre-client';
273
320
  const legacy = new SabreLegacy({
274
321
  environment: 'production',
275
322
  authVersion: 'v2',
276
- credentials: { username: 'V1:<user>:<PCC>:AA', password: process.env.SABRE_EPR_PASSWORD! },
323
+ credentials: { username: 'V1:<user>:<PCC>:AA', password: process.env.SABRE_PASSWORD! },
277
324
  });
278
325
 
279
326
  const counts = await legacy.withSession((session) => session.queue.count());
@@ -301,6 +348,42 @@ const counts = await legacy.withSession((session) => session.queue.count());
301
348
  calling the network, and `close()` resolves without calling it. The SDK does not reopen the
302
349
  session, because the queue cursor is already lost. Starting over is your decision.
303
350
 
351
+ ### Host commands
352
+
353
+ `session.command(command, options?)` sends a Sabre host command (`SabreCommandLLSRQ` 2.0.0)
354
+ inside the session and returns the screen as text. **It is an escape hatch**, with no types and
355
+ no guarantees: the SDK does not parse the screen, and a command can change the PCC configuration
356
+ or issue tickets. There is no list of allowed or blocked commands.
357
+
358
+ ```ts
359
+ const screen = await legacy.withSession((session) => session.command('W/PT¥*', { idempotent: true }));
360
+ // screen.text → 'PSGR TYPE - ON' (as Sabre sends it, not trimmed)
361
+ // screen.warnings → the stl:Warning entries, if any
362
+ // screen.messageId → eb:MessageId, for Sabre support
363
+ ```
364
+
365
+ - **The command is sent as is.** In this service Sabre's `‡` separator is written `¥`
366
+ (`W/PT‡*` in Sabre Red is `W/PT¥*` here); the SDK does not convert it.
367
+ - **The screen is not trimmed.** Host screens are aligned by column and can start with a space
368
+ (` 17MAR WED…`), so `text` is the content of `Response` as is. Trim it yourself if you need to.
369
+ - **Up to 1023 characters, counted as Sabre does:** `!`, `%`, `$`, `&`, `¥` and `§` count 2. A
370
+ longer command throws a `TypeError` without calling the network (Sabre would answer
371
+ `REQUEST EXCEEDED MAXIMUM LENGTH`).
372
+ - **Sabre blocks some commands on its own** (`SO`, `/@`, `¤¤`, per its whitelist), even though
373
+ the SDK has no list of its own.
374
+ - **Some commands cost more.** `JR` and `WPNI` count as "Worldfare" searches.
375
+ - **Host masks** are answered with the first two characters of the mask.
376
+ - **Prefer a structured API.** Sabre asks not to use this service for what already has one: when
377
+ the SDK has an operation for it, use that.
378
+ - **No retries by default**, because the SDK cannot tell a read from a change. Pass
379
+ `{ idempotent: true }` for read-only commands and they follow the [retry policy](#retries).
380
+ - **A host message is not an error.** `DUTY CODE 9 REQUIRED` or `FORMAT` come back in `text`. A
381
+ SOAP fault or an `stl:Error` throws, like any other session call.
382
+ - Commands that need the same sign-in (`SI9` followed by `W/PT¥ON`) must run in the same session.
383
+ - The debug log (`sabre.session.command`) carries only the first token of the command, cut to 4
384
+ characters (`W/PT`, `DC`, `*IM`), never the whole command or the screen. The full response is
385
+ available through `onRawResponse`.
386
+
304
387
  ### Queues
305
388
 
306
389
  The queue operations live in `session.queue`. `pcc` is optional in every call and defaults to the
@@ -486,7 +569,7 @@ const booking = await sabre.booking.get({ confirmationId }, { onRawResponse: (r)
486
569
  asynchronously, keep the value and write it after the call returns.
487
570
 
488
571
  In `SabreLegacy`, `protocol` is `'soap'`, `body` is the whole SOAP envelope, and `operation` is
489
- `'openSession'`, `'close'`, `'ping'` or `'queue.<method>'`. The session token
572
+ `'openSession'`, `'close'`, `'ping'`, `'command'` or `'queue.<method>'`. The session token
490
573
  (`BinarySecurityToken`) is replaced by `[REDACTED]` wherever it appears. Nothing else is changed.
491
574
 
492
575
  > [!WARNING]
@@ -552,7 +635,7 @@ The SDK logs structured events (`sabre.request.start`, `sabre.request.end`,
552
635
  `sabre.request.retry`, `sabre.request.rawResponseHookFailed`, `sabre.auth.token.refresh`,
553
636
  `sabre.auth.token.store`, `sabre.booking.seat.priced`, `sabre.session.open`,
554
637
  `sabre.session.close`, `sabre.session.closeFailed`, `sabre.session.keepAliveFailed`,
555
- `sabre.queue.exitTolerated`, `sabre.queue.exitFailed`), never raw
638
+ `sabre.session.command`, `sabre.queue.exitTolerated`, `sabre.queue.exitFailed`), never raw
556
639
  request or response bodies. Secrets, the `Authorization` header and passenger data are always
557
640
  redacted before they reach your logger.
558
641
 
package/dist/index.d.ts CHANGED
@@ -41,7 +41,7 @@ interface SabreLogger {
41
41
  }
42
42
  type SabreLogLevel = keyof SabreLogger;
43
43
  /** Eventos estables que emite el SDK como `message`. */
44
- type SabreLogEvent = 'sabre.request.start' | 'sabre.request.end' | 'sabre.request.retry' | 'sabre.request.rawResponseHookFailed' | 'sabre.auth.token.refresh' | 'sabre.auth.token.store' | 'sabre.booking.seat.priced' | 'sabre.session.open' | 'sabre.session.close' | 'sabre.session.closeFailed' | 'sabre.session.keepAliveFailed' | 'sabre.queue.exitTolerated' | 'sabre.queue.exitFailed';
44
+ type SabreLogEvent = 'sabre.request.start' | 'sabre.request.end' | 'sabre.request.retry' | 'sabre.request.rawResponseHookFailed' | 'sabre.auth.token.refresh' | 'sabre.auth.token.store' | 'sabre.booking.seat.priced' | 'sabre.session.open' | 'sabre.session.close' | 'sabre.session.closeFailed' | 'sabre.session.keepAliveFailed' | 'sabre.session.command' | 'sabre.queue.exitTolerated' | 'sabre.queue.exitFailed';
45
45
  /** Logger interno: redacta siempre el contexto y no hace nada si no hay logger. */
46
46
  declare class EventLogger {
47
47
  #private;
@@ -53,6 +53,11 @@ type SabreEnvironment = 'sandbox' | 'production';
53
53
  type SabreAuthVersion = 'v3' | 'v2';
54
54
  /** Credenciales para OAuth Token Create v3: Client ID/Secret más usuario EPR. */
55
55
  interface SabreCredentials {
56
+ /**
57
+ * Versión de OAuth para la que se armaron. `buildCredentials` la pone; la config la usa cuando
58
+ * no trae su propio `authVersion`.
59
+ */
60
+ authVersion?: 'v3';
56
61
  clientId: string;
57
62
  clientSecret: string;
58
63
  /** Usuario EPR. */
@@ -62,6 +67,11 @@ interface SabreCredentials {
62
67
  }
63
68
  /** Credenciales para OAuth Token Create v2: solo EPR; `clientId`/`clientSecret` se ignoran. */
64
69
  interface SabreCredentialsV2 {
70
+ /**
71
+ * Versión de OAuth para la que se armaron. `buildCredentials` la pone, y con ella la config no
72
+ * necesita repetir `authVersion: 'v2'`.
73
+ */
74
+ authVersion?: 'v2';
65
75
  clientId?: string;
66
76
  clientSecret?: string;
67
77
  /** Usuario EPR. */
@@ -71,7 +81,11 @@ interface SabreCredentialsV2 {
71
81
  }
72
82
  interface SabreBaseConfig {
73
83
  environment: SabreEnvironment;
74
- /** Campo reservado: PCC vs iPCC sigue sin resolver. */
84
+ /**
85
+ * @deprecated Desde 0.4.1; se quita en 0.5.0. Ningún cliente lo lee. El PCC con el que te
86
+ * autenticas va en `credentials` (ver `buildCredentials`). Para trabajar en otro PCC, se pasa en
87
+ * cada operación: `targetPcc` en REST, `pcc` en colas.
88
+ */
75
89
  pcc?: string;
76
90
  logger?: SabreLogger;
77
91
  /** Reintentos por defecto del cliente; cada request puede pisarlos. */
@@ -94,8 +108,21 @@ interface SabreConfigV2 extends SabreBaseConfig {
94
108
  authVersion: 'v2';
95
109
  credentials: SabreCredentialsV2;
96
110
  }
97
- /** Config del cliente, discriminada por `authVersion`. */
98
- type SabreConfig = SabreConfigV3 | SabreConfigV2;
111
+ /**
112
+ * OAuth Token Create v2 sin `authVersion` en la config: la versión sale de las credenciales,
113
+ * como las devuelve `buildCredentials({ authVersion: 'v2', … })`.
114
+ */
115
+ interface SabreConfigV2FromCredentials extends SabreBaseConfig {
116
+ authVersion?: never;
117
+ credentials: SabreCredentialsV2 & {
118
+ authVersion: 'v2';
119
+ };
120
+ }
121
+ /**
122
+ * Config del cliente, discriminada por `authVersion`: el de la config o, si falta, el de
123
+ * `credentials`. Sin ninguno de los dos, es v3.
124
+ */
125
+ type SabreConfig = SabreConfigV3 | SabreConfigV2 | SabreConfigV2FromCredentials;
99
126
  /** Config validada y con defaults aplicados. */
100
127
  interface ResolvedConfig {
101
128
  credentials: Readonly<SabreCredentials | SabreCredentialsV2>;
@@ -1893,6 +1920,27 @@ declare class QueueManagement {
1893
1920
  place(request: QueuePlaceRequest, options?: QueuePlaceOptions): Promise<QueuePlaceResponse>;
1894
1921
  }
1895
1922
 
1923
+ interface SabreCommandOptions extends RequestOptions {
1924
+ /**
1925
+ * `true` solo si el comando es una lectura (`W/PT¥*`, `DC¥…`): entra en la política de
1926
+ * reintentos. Por defecto `false`, porque el SDK no sabe si un comando cambia algo.
1927
+ */
1928
+ idempotent?: boolean;
1929
+ }
1930
+ interface SabreCommandResponse {
1931
+ /**
1932
+ * La pantalla tal como la devuelve Sabre (`Response`), sin interpretar y sin recortar: las
1933
+ * pantallas van alineadas por columna y pueden empezar con un espacio (` 17MAR WED…`). Recortar
1934
+ * es decisión de quien la lee. Un mensaje de host (`DUTY CODE 9 REQUIRED`, `FORMAT`) llega aquí:
1935
+ * no lanza.
1936
+ */
1937
+ text: string;
1938
+ /** Los `stl:Warning` de la respuesta. No lanzan. */
1939
+ warnings: SabreWarning[];
1940
+ /** `eb:MessageId` de la respuesta, el dato que pide soporte de Sabre. */
1941
+ messageId: string | undefined;
1942
+ }
1943
+
1896
1944
  /** Lo que una operación pide al transporte. La sesión agrega `CPAId`, `ConversationId` y el token. */
1897
1945
  type SessionRequest = Omit<SoapRequest, 'cpaId' | 'conversationId' | 'security'>;
1898
1946
  /**
@@ -1937,6 +1985,14 @@ declare class SabreSession {
1937
1985
  * recorrido de cola no hace falta: cada operación ya lo reinicia.
1938
1986
  */
1939
1987
  ping(options?: RequestOptions): Promise<void>;
1988
+ /**
1989
+ * Manda un comando de host (`SabreCommandLLSRQ` 2.0.0) y devuelve la pantalla como texto, sin
1990
+ * interpretarla. Es una vía de escape: sin tipos ni garantías, y un comando puede cambiar la
1991
+ * configuración del PCC o emitir. El comando va tal cual; el separador de Sabre Red (`‡`) se
1992
+ * escribe `¥`. Sin reintento salvo `{ idempotent: true }`, para comandos de solo lectura. La
1993
+ * pantalla llega sin recortar, y más de 1023 caracteres (contados como Sabre) lanza sin red.
1994
+ */
1995
+ command(command: string, options?: SabreCommandOptions): Promise<SabreCommandResponse>;
1940
1996
  /**
1941
1997
  * Cierra la sesión con `SessionCloseRQ`: Sabre descarta el AAA e invalida el token. Es
1942
1998
  * idempotente: las llamadas siguientes devuelven la misma promesa, sin volver a la red. Si el
@@ -1975,6 +2031,54 @@ declare class SabreLegacy {
1975
2031
  withSession<T>(callback: (session: SabreSession) => Promise<T>): Promise<T>;
1976
2032
  }
1977
2033
 
2034
+ interface BuildCredentialsBase {
2035
+ /** Usuario EPR, sin PCC ni domain. */
2036
+ user: string;
2037
+ /** PCC del EPR (el *group*): 3 o 4 caracteres alfanuméricos. */
2038
+ pcc: string;
2039
+ /** Domain del EPR. Default `'AA'`. */
2040
+ domain?: string;
2041
+ /** Contraseña EPR. */
2042
+ password: string;
2043
+ }
2044
+ /** Partes para OAuth Token Create v3 (default): `clientId` y `clientSecret` son obligatorios. */
2045
+ interface BuildCredentialsOptionsV3 extends BuildCredentialsBase {
2046
+ authVersion?: 'v3';
2047
+ clientId: string;
2048
+ clientSecret: string;
2049
+ }
2050
+ /**
2051
+ * Partes para OAuth Token Create v2: `clientId`/`clientSecret` son opcionales. REST los ignora,
2052
+ * pero si vienen los dos, `SabreLegacy` abre la sesión con `SessionCreateRQ` 2.0.0.
2053
+ */
2054
+ interface BuildCredentialsOptionsV2 extends BuildCredentialsBase {
2055
+ authVersion: 'v2';
2056
+ clientId?: string;
2057
+ clientSecret?: string;
2058
+ }
2059
+ type BuildCredentialsOptions = BuildCredentialsOptionsV3 | BuildCredentialsOptionsV2;
2060
+ /** Lo que devuelve `buildCredentials` para v3: lleva `authVersion: 'v3'`. */
2061
+ type BuiltCredentialsV3 = SabreCredentials & {
2062
+ authVersion: 'v3';
2063
+ };
2064
+ /**
2065
+ * Lo que devuelve `buildCredentials` para v2: lleva `authVersion: 'v2'`, así que la config no
2066
+ * necesita repetirlo (#148).
2067
+ */
2068
+ type BuiltCredentialsV2 = SabreCredentialsV2 & {
2069
+ authVersion: 'v2';
2070
+ };
2071
+ /**
2072
+ * Arma el `credentials` para `Sabre` y `SabreLegacy` a partir del usuario, el PCC, el domain y
2073
+ * la contraseña del EPR, más `clientId`/`clientSecret` cuando los hay. El username queda como
2074
+ * `<user>-<PCC>-<domain>` (v3) o `V1:<user>:<PCC>:<domain>` (v2). No lee variables de entorno
2075
+ * ni toca la red; un dato inválido lanza `TypeError` sin repetir secretos. El resultado lleva
2076
+ * `authVersion`, que la config usa si no trae el suyo.
2077
+ */
2078
+ declare function buildCredentials(options: BuildCredentialsOptionsV3): BuiltCredentialsV3;
2079
+ declare function buildCredentials(options: BuildCredentialsOptionsV2): BuiltCredentialsV2;
2080
+ declare function buildCredentials(options: BuildCredentialsOptions): BuiltCredentialsV3 | BuiltCredentialsV2;
2081
+
1978
2082
  /**
1979
2083
  * Cómo se elige el año cuando el texto no lo trae:
1980
2084
  *
@@ -2219,6 +2323,6 @@ interface BookingFlightDetailsSource {
2219
2323
  */
2220
2324
  declare function buildBookingFlightDetails(source: BookingFlightDetailsSource): FlightDetails;
2221
2325
 
2222
- declare const VERSION = "0.3.0";
2326
+ declare const VERSION = "0.4.1";
2223
2327
 
2224
- export { Air, type BaggageAllowanceDesc, type BaggageInformation, type BargainFinderMaxRequest, type BargainFinderMaxResponse, type BookContactInformation, type BookGenericSeat, type BookSeat, type BookTraveler, type Booking, type BookingAgency, type BookingFlightDetailsSource, type BookingItemReference, BookingManagement, type BookingResponseError, type BookingSeatSelection, type BookingSource, type BrandedFare, type CancelBookingErrorPolicy, type CancelBookingNotification, type CancelBookingOptions, type CancelBookingRequest, type CancelBookingResponse, type CancelSegmentReference, type CreateBookingErrorPolicy, type CreateBookingOptions, type CreateBookingRequest, type CreateBookingResponse, type CreateBookingResponseError, type CurrencyConversion, type Fare, type FareComponent, type FareComponentDesc, type FareComponentDescSegment, type FareComponentSegment, type FareComponentSegmentDetail, type FareMessage, type FlightDetails, type FlightStatusCode, type FlightTicketOperation, type FlightToBook, type GetBookingExtraFeatures, type GetBookingOptions, type GetBookingRequest, type GetBookingResponse, type GetBookingReturnOnly, type GetSeatsRequest, type GetSeatsResponse, type GroupedItineraryResponse, type HostDateDirection, type Itinerary, type ItineraryGroup, type ItineraryMessage, type Leg, type LegDesc, type LegDescription, type LegSchedule, type LegScheduleRef, type LowFareSearchFlight, type LowFareSearchLocation, type LowFareSearchOriginDestination, type LowFareSearchPassengerTypeQuantity, type LowFareSearchRequestorId, type LowFareSearchSource, type LowFareSearchTpaExtensions, type LowFareSearchTravelPreferences, type LowFareSearchTravelerInfoSummary, type ObFeeDesc, type OpenSessionOptions, type OtaAirLowFareSearchRq, type PassengerInfo, type PassengerPricing, type PassengerTotalFare, type PaymentMethod, type PriceComparison, type PriceComparisonType, type PricedSeat, type PricingDetails, type PricingInformation, type PricingQualifiers, type QueueAccessOptions, type QueueAccessRequest, type QueueCount, type QueueCountOptions, type QueueCountRequest, type QueueCountResponse, type QueueEndReason, type QueueItem, type QueueListEntry, type QueueListOptions, type QueueListRequest, type QueueListResponse, QueueManagement, type QueueNavigationOptions, type QueueParagraph, type QueueParagraphAirSegment, type QueueParagraphMessage, type QueueParagraphOptions, type QueueParagraphOtherSegment, type QueueParagraphPassenger, type QueueParagraphReceivedFrom, type QueueParagraphSegment, type QueueParagraphTicketing, type QueueParagraphTicketingEntry, type QueuePlaceOptions, type QueuePlaceRequest, type QueuePlaceResponse, type QueuePlaceResult, type QueuePlaceTarget, type QueuePlacement, type QueueProcessAction, type QueueProcessRequest, type QueueProcessResult, QueueRef, type QueueRemoveRequest, type QueueRemoveTarget, type QueueSelection, type QueueState, type QueueStep, type RawSeatAvailabilityRs, type Ref, type RefundDocumentsType, type RequestOptions, type ResolveHostDateOptions, type RetryOptions, type RevalidateItineraryRequest, type RevalidateItineraryRequestSource, type RevalidateItineraryResponse, Sabre, type SabreAuthVersion, SabreBusinessError, type SabreBusinessErrorOptions, type SabreConfig, type SabreConfigV2, type SabreConfigV3, type SabreCredentials, type SabreCredentialsV2, type SabreEnvironment, SabreError, type SabreErrorOptions, SabreGatewayError, type SabreGatewayErrorOptions, SabreLegacy, type SabreLogEvent, type SabreLogLevel, type SabreLogger, SabreOrchestrationError, type SabreOrchestrationErrorOptions, type SabreProtocol, type SabreRawResponse, type SabreRawResponseCallback, type SabreServiceErrorOptions, SabreSession, SabreSessionError, type SabreSessionErrorKind, type SabreSessionErrorOptions, type SabreTokenStore, SabreWarning, type ScheduleCarrier, type ScheduleDesc, type ScheduleEndpoint, type ScheduleEquipment, type Seat, type SeatAreaPreference, type SeatAvailabilityByPayloadRq, type SeatAvailabilityByPnrLocatorRq, type SeatAvailabilityIssue, type SeatAvailabilityRequestSource, type SeatAvailabilityResponse, type SeatCabinCompartment, type SeatCabinFacility, type SeatCabinLayout, type SeatCabinRowPosition, type SeatCharacteristic, type SeatDisplayOnlyItem, type SeatFareComponent, type SeatFareDetail, type SeatFareSegmentAssociation, type SeatFlightLeg, type SeatKeyValuePair, type SeatLoyaltyProgramAccount, type SeatMap, type SeatOfferItem, type SeatOfferItemDetails, type SeatPassenger, type SeatPassengerPayloadRq, type SeatPassengerRs, type SeatPriceBreakdown, type SeatPriceDefinition, type SeatRow, type SeatSegment, type SeatSegmentPayloadRq, type SeatSegmentRs, type SeatServiceDefinition, type SeatSpecialServiceRequest, type SeatTax, type SpecificFare, type StoredToken, type TaxDesc, type TaxSummaryDesc, type TicketingPolicy, type TotalFare, type TravelerPhone, type TravelerTitle, VERSION, type ValidatingCarrierDesc, buildBookingFlightDetails, buildRevalidateItineraryRequest, buildSeatAvailabilityRequest, parseQueueParagraph, resolveHostDate };
2328
+ export { Air, type BaggageAllowanceDesc, type BaggageInformation, type BargainFinderMaxRequest, type BargainFinderMaxResponse, type BookContactInformation, type BookGenericSeat, type BookSeat, type BookTraveler, type Booking, type BookingAgency, type BookingFlightDetailsSource, type BookingItemReference, BookingManagement, type BookingResponseError, type BookingSeatSelection, type BookingSource, type BrandedFare, type BuildCredentialsOptions, type BuildCredentialsOptionsV2, type BuildCredentialsOptionsV3, type BuiltCredentialsV2, type BuiltCredentialsV3, type CancelBookingErrorPolicy, type CancelBookingNotification, type CancelBookingOptions, type CancelBookingRequest, type CancelBookingResponse, type CancelSegmentReference, type CreateBookingErrorPolicy, type CreateBookingOptions, type CreateBookingRequest, type CreateBookingResponse, type CreateBookingResponseError, type CurrencyConversion, type Fare, type FareComponent, type FareComponentDesc, type FareComponentDescSegment, type FareComponentSegment, type FareComponentSegmentDetail, type FareMessage, type FlightDetails, type FlightStatusCode, type FlightTicketOperation, type FlightToBook, type GetBookingExtraFeatures, type GetBookingOptions, type GetBookingRequest, type GetBookingResponse, type GetBookingReturnOnly, type GetSeatsRequest, type GetSeatsResponse, type GroupedItineraryResponse, type HostDateDirection, type Itinerary, type ItineraryGroup, type ItineraryMessage, type Leg, type LegDesc, type LegDescription, type LegSchedule, type LegScheduleRef, type LowFareSearchFlight, type LowFareSearchLocation, type LowFareSearchOriginDestination, type LowFareSearchPassengerTypeQuantity, type LowFareSearchRequestorId, type LowFareSearchSource, type LowFareSearchTpaExtensions, type LowFareSearchTravelPreferences, type LowFareSearchTravelerInfoSummary, type ObFeeDesc, type OpenSessionOptions, type OtaAirLowFareSearchRq, type PassengerInfo, type PassengerPricing, type PassengerTotalFare, type PaymentMethod, type PriceComparison, type PriceComparisonType, type PricedSeat, type PricingDetails, type PricingInformation, type PricingQualifiers, type QueueAccessOptions, type QueueAccessRequest, type QueueCount, type QueueCountOptions, type QueueCountRequest, type QueueCountResponse, type QueueEndReason, type QueueItem, type QueueListEntry, type QueueListOptions, type QueueListRequest, type QueueListResponse, QueueManagement, type QueueNavigationOptions, type QueueParagraph, type QueueParagraphAirSegment, type QueueParagraphMessage, type QueueParagraphOptions, type QueueParagraphOtherSegment, type QueueParagraphPassenger, type QueueParagraphReceivedFrom, type QueueParagraphSegment, type QueueParagraphTicketing, type QueueParagraphTicketingEntry, type QueuePlaceOptions, type QueuePlaceRequest, type QueuePlaceResponse, type QueuePlaceResult, type QueuePlaceTarget, type QueuePlacement, type QueueProcessAction, type QueueProcessRequest, type QueueProcessResult, QueueRef, type QueueRemoveRequest, type QueueRemoveTarget, type QueueSelection, type QueueState, type QueueStep, type RawSeatAvailabilityRs, type Ref, type RefundDocumentsType, type RequestOptions, type ResolveHostDateOptions, type RetryOptions, type RevalidateItineraryRequest, type RevalidateItineraryRequestSource, type RevalidateItineraryResponse, Sabre, type SabreAuthVersion, SabreBusinessError, type SabreBusinessErrorOptions, type SabreCommandOptions, type SabreCommandResponse, type SabreConfig, type SabreConfigV2, type SabreConfigV2FromCredentials, type SabreConfigV3, type SabreCredentials, type SabreCredentialsV2, type SabreEnvironment, SabreError, type SabreErrorOptions, SabreGatewayError, type SabreGatewayErrorOptions, SabreLegacy, type SabreLogEvent, type SabreLogLevel, type SabreLogger, SabreOrchestrationError, type SabreOrchestrationErrorOptions, type SabreProtocol, type SabreRawResponse, type SabreRawResponseCallback, type SabreServiceErrorOptions, SabreSession, SabreSessionError, type SabreSessionErrorKind, type SabreSessionErrorOptions, type SabreTokenStore, SabreWarning, type ScheduleCarrier, type ScheduleDesc, type ScheduleEndpoint, type ScheduleEquipment, type Seat, type SeatAreaPreference, type SeatAvailabilityByPayloadRq, type SeatAvailabilityByPnrLocatorRq, type SeatAvailabilityIssue, type SeatAvailabilityRequestSource, type SeatAvailabilityResponse, type SeatCabinCompartment, type SeatCabinFacility, type SeatCabinLayout, type SeatCabinRowPosition, type SeatCharacteristic, type SeatDisplayOnlyItem, type SeatFareComponent, type SeatFareDetail, type SeatFareSegmentAssociation, type SeatFlightLeg, type SeatKeyValuePair, type SeatLoyaltyProgramAccount, type SeatMap, type SeatOfferItem, type SeatOfferItemDetails, type SeatPassenger, type SeatPassengerPayloadRq, type SeatPassengerRs, type SeatPriceBreakdown, type SeatPriceDefinition, type SeatRow, type SeatSegment, type SeatSegmentPayloadRq, type SeatSegmentRs, type SeatServiceDefinition, type SeatSpecialServiceRequest, type SeatTax, type SpecificFare, type StoredToken, type TaxDesc, type TaxSummaryDesc, type TicketingPolicy, type TotalFare, type TravelerPhone, type TravelerTitle, VERSION, type ValidatingCarrierDesc, buildBookingFlightDetails, buildCredentials, buildRevalidateItineraryRequest, buildSeatAvailabilityRequest, parseQueueParagraph, resolveHostDate };