sabre-client 0.3.0-next.0 → 0.3.0-next.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
@@ -206,6 +206,35 @@ try {
206
206
  > `JSON.stringify` ni en un spread, pero sigue accesible como `error.raw`. Nunca lo mandes a un
207
207
  > logger, a un tracker de errores ni a un servicio de monitoreo sin sanitizarlo antes.
208
208
 
209
+ ## Respuesta cruda
210
+
211
+ Toda operación REST (`air.bargainFinderMax`, `air.revalidateItinerary`, `booking.create`,
212
+ `booking.get` y `booking.cancel`) acepta un callback `onRawResponse` en sus opciones, junto a
213
+ `signal`. Recibe la respuesta de Sabre tal cual llegó, por ejemplo para guardarla junto al
214
+ resultado tipado:
215
+
216
+ ```ts
217
+ import type { SabreRawResponse } from 'sabre-client';
218
+
219
+ let raw: SabreRawResponse | undefined;
220
+ const booking = await sabre.booking.get({ confirmationId }, { onRawResponse: (r) => (raw = r) });
221
+ // raw: { operation: 'booking.get', protocol: 'rest', status, headers, body, attempts }
222
+ ```
223
+
224
+ - Se llama **una vez**, con el último intento HTTP, antes de que la operación devuelva o lance.
225
+ También se llama cuando la operación lanza `SabreBusinessError` (un `200` con `errors[]`) o
226
+ `SabreGatewayError` (un no `2xx`). Si hubo reintentos, `attempts` cuenta todos los intentos HTTP.
227
+ - No se llama si ningún intento tuvo respuesta HTTP (error de red, abort), ni con las llamadas de
228
+ token. Tras un `401`, recibe la respuesta del reintento con el token nuevo.
229
+ - Es síncrono y su retorno se ignora. Si lanza, el SDK lo atrapa, registra
230
+ `sabre.request.rawResponseHookFailed` sin el body y la operación sigue: un callback que falla
231
+ nunca hace que `booking.create` pierda su `confirmationId`. Para guardar de forma asíncrona,
232
+ conserva el valor y escríbelo cuando la llamada vuelva.
233
+
234
+ > [!WARNING]
235
+ > `body` es la respuesta cruda y **trae datos de pasajeros**. El SDK nunca lo manda al logger.
236
+ > Dónde lo guardas es tu responsabilidad.
237
+
209
238
  ## Reintentos
210
239
 
211
240
  Solo se reintentan las operaciones idempotentes: Bargain Finder Max y Revalidate Itinerary
@@ -255,7 +284,8 @@ const sabre = new Sabre({
255
284
  ```
256
285
 
257
286
  El SDK registra eventos estructurados (`sabre.request.start`, `sabre.request.end`,
258
- `sabre.request.retry`, `sabre.auth.token.refresh`, `sabre.auth.token.store`) y nunca los bodies
287
+ `sabre.request.retry`, `sabre.request.rawResponseHookFailed`, `sabre.auth.token.refresh`,
288
+ `sabre.auth.token.store`) y nunca los bodies
259
289
  crudos de request o response. Los secretos, el header `Authorization` y los datos de pasajeros
260
290
  se redactan siempre antes de llegar a tu logger.
261
291
 
package/README.md CHANGED
@@ -205,6 +205,35 @@ try {
205
205
  > `JSON.stringify` or object spreads, but you can still read `error.raw`. Never send it to a
206
206
  > logger, error tracker or monitoring service without sanitizing it first.
207
207
 
208
+ ## Raw response
209
+
210
+ Every REST operation (`air.bargainFinderMax`, `air.revalidateItinerary`, `booking.create`,
211
+ `booking.get` and `booking.cancel`) accepts an `onRawResponse` callback in its options, next to
212
+ `signal`. It receives Sabre's response as it arrived, for example to store it next to the typed
213
+ result:
214
+
215
+ ```ts
216
+ import type { SabreRawResponse } from 'sabre-client';
217
+
218
+ let raw: SabreRawResponse | undefined;
219
+ const booking = await sabre.booking.get({ confirmationId }, { onRawResponse: (r) => (raw = r) });
220
+ // raw: { operation: 'booking.get', protocol: 'rest', status, headers, body, attempts }
221
+ ```
222
+
223
+ - It is called **once**, with the last HTTP attempt, before the operation returns or throws.
224
+ It is also called when the operation throws `SabreBusinessError` (a `200` with `errors[]`) or
225
+ `SabreGatewayError` (a non-`2xx`). After retries, `attempts` counts every HTTP attempt.
226
+ - It is not called if no attempt got an HTTP response (network error, abort), nor for token
227
+ requests. After a `401`, it gets the response of the retry with the new token.
228
+ - It is synchronous and its return value is ignored. If it throws, the SDK catches it, logs
229
+ `sabre.request.rawResponseHookFailed` without the body, and the operation carries on: a
230
+ failing callback never makes `booking.create` lose its `confirmationId`. To persist
231
+ asynchronously, keep the value and write it after the call returns.
232
+
233
+ > [!WARNING]
234
+ > `body` is the raw response and **contains passenger data**. The SDK never sends it to the
235
+ > logger. Where you store it is up to you.
236
+
208
237
  ## Retries
209
238
 
210
239
  Only idempotent operations are retried: Bargain Finder Max and Revalidate Itinerary (both
@@ -255,7 +284,8 @@ const sabre = new Sabre({
255
284
  ```
256
285
 
257
286
  The SDK logs structured events (`sabre.request.start`, `sabre.request.end`,
258
- `sabre.request.retry`, `sabre.auth.token.refresh`, `sabre.auth.token.store`), never raw
287
+ `sabre.request.retry`, `sabre.request.rawResponseHookFailed`, `sabre.auth.token.refresh`,
288
+ `sabre.auth.token.store`), never raw
259
289
  request or response bodies. Secrets, the `Authorization` header and passenger data are always
260
290
  redacted before they reach your logger.
261
291
 
package/dist/index.d.ts CHANGED
@@ -39,7 +39,7 @@ interface SabreLogger {
39
39
  }
40
40
  type SabreLogLevel = keyof SabreLogger;
41
41
  /** Eventos estables que emite el SDK como `message`. */
42
- type SabreLogEvent = 'sabre.request.start' | 'sabre.request.end' | 'sabre.request.retry' | 'sabre.auth.token.refresh' | 'sabre.auth.token.store';
42
+ type SabreLogEvent = 'sabre.request.start' | 'sabre.request.end' | 'sabre.request.retry' | 'sabre.request.rawResponseHookFailed' | 'sabre.auth.token.refresh' | 'sabre.auth.token.store';
43
43
 
44
44
  type SabreEnvironment = 'sandbox' | 'production';
45
45
  type SabreAuthVersion = 'v3' | 'v2';
@@ -195,6 +195,34 @@ declare class SabreWarning extends SabreError {
195
195
  constructor(message: string, options: SabreServiceErrorOptions);
196
196
  }
197
197
 
198
+ /**
199
+ * Respuesta tal cual llegó de Sabre, para guardarla junto al resultado tipado.
200
+ *
201
+ * ⚠️ El `body` trae datos de pasajeros (PII). El SDK nunca lo envía al logger; quien usa
202
+ * `onRawResponse` responde por dónde lo guarda.
203
+ */
204
+ interface SabreRawResponse {
205
+ /** Método público sin `sabre.`, p. ej. `'booking.get'` o `'air.bargainFinderMax'`. */
206
+ operation: string;
207
+ protocol: 'rest';
208
+ /** HTTP status del intento que se entrega. */
209
+ status: number;
210
+ headers: Headers;
211
+ /** Texto tal cual llegó, sin parsear. `''` si vino vacío. */
212
+ body: string;
213
+ /** Intentos HTTP hechos, contando los reintentos (1 si no hubo). */
214
+ attempts: number;
215
+ }
216
+ /**
217
+ * Se llama una sola vez por operación, con la respuesta del último intento HTTP, antes de
218
+ * devolver o de lanzar: también si termina en `SabreBusinessError` o `SabreGatewayError`. No
219
+ * se llama si ningún intento tuvo respuesta HTTP, ni con las llamadas de token.
220
+ *
221
+ * Es síncrono y su retorno se ignora. Si lanza, el SDK lo atrapa, emite
222
+ * `sabre.request.rawResponseHookFailed` al logger (sin el body) y la operación sigue.
223
+ */
224
+ type SabreRawResponseCallback = (raw: SabreRawResponse) => void;
225
+
198
226
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
199
227
  /**
200
228
  * Pasos 2–3 del orden de detección, aportados por cada servicio: recibe el body de una
@@ -222,6 +250,9 @@ interface RestRequest {
222
250
  classify?: ResponseClassifier;
223
251
  retry?: Partial<RetryOptions>;
224
252
  signal?: AbortSignal;
253
+ /** Método público sin `sabre.`, p. ej. `'booking.get'`. Lo recibe `onRawResponse`. */
254
+ operation?: string;
255
+ onRawResponse?: SabreRawResponseCallback;
225
256
  }
226
257
  /** Fuente del header `Authorization` de los servicios (la implementa `AuthManager`). */
227
258
  interface AuthorizationProvider {
@@ -678,6 +709,8 @@ interface BargainFinderMaxRequest {
678
709
  type BargainFinderMaxResponse = GroupedItineraryResponse;
679
710
  interface RequestOptions {
680
711
  signal?: AbortSignal;
712
+ /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */
713
+ onRawResponse?: SabreRawResponseCallback;
681
714
  /** Pisa los reintentos del cliente solo para esta request. */
682
715
  retry?: Partial<RetryOptions>;
683
716
  }
@@ -923,6 +956,8 @@ interface BookingAgency {
923
956
 
924
957
  interface CreateBookingOptions {
925
958
  signal?: AbortSignal;
959
+ /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */
960
+ onRawResponse?: SabreRawResponseCallback;
926
961
  }
927
962
  /** Elemento de `errors[]` de Create Booking. */
928
963
  type CreateBookingResponseError = BookingResponseError;
@@ -990,6 +1025,8 @@ interface GetBookingRequest {
990
1025
  }
991
1026
  interface GetBookingOptions {
992
1027
  signal?: AbortSignal;
1028
+ /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */
1029
+ onRawResponse?: SabreRawResponseCallback;
993
1030
  }
994
1031
  /**
995
1032
  * Reserva leída, con el `Booking` en el primer nivel tal cual lo define Sabre (no se normaliza
@@ -1074,6 +1111,8 @@ interface CancelBookingRequest {
1074
1111
  }
1075
1112
  interface CancelBookingOptions {
1076
1113
  signal?: AbortSignal;
1114
+ /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */
1115
+ onRawResponse?: SabreRawResponseCallback;
1077
1116
  }
1078
1117
  /** Cancelación con éxito: sin errores fatales y sin `NO_ITEMS_CANCELLED`. */
1079
1118
  interface CancelBookingResponse {
@@ -1103,6 +1142,8 @@ declare class BookingManagement {
1103
1142
  *
1104
1143
  * Nunca se reintenta automáticamente. Si la reserva se crea con avisos o errores no fatales,
1105
1144
  * no lanza: los devuelve en `warnings` y `errors`. Si no se crea, lanza `SabreBusinessError`.
1145
+ * Con `agency.ticketingPolicy: 'FUTURE_TICKETING'` y sin `agency.futureTicketingPolicy`, lanza
1146
+ * `TypeError` sin llamar a la red: Sabre lo rechaza seguro.
1106
1147
  */
1107
1148
  create(request: CreateBookingRequest, options?: CreateBookingOptions): Promise<CreateBookingResponse>;
1108
1149
  /**
@@ -1162,4 +1203,4 @@ declare function buildBookingFlightDetails(source: BookingFlightDetailsSource):
1162
1203
 
1163
1204
  declare const VERSION = "0.3.0";
1164
1205
 
1165
- 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 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 GroupedItineraryResponse, 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 OtaAirLowFareSearchRq, type PassengerInfo, type PassengerPricing, type PassengerTotalFare, type PaymentMethod, type PriceComparison, type PriceComparisonType, type PricingDetails, type PricingInformation, type PricingQualifiers, type Ref, type RefundDocumentsType, type RequestOptions, 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, type SabreLogEvent, type SabreLogLevel, type SabreLogger, SabreOrchestrationError, type SabreOrchestrationErrorOptions, type SabreProtocol, type SabreServiceErrorOptions, type SabreTokenStore, SabreWarning, type ScheduleCarrier, type ScheduleDesc, type ScheduleEndpoint, type ScheduleEquipment, type SeatAreaPreference, type SpecificFare, type StoredToken, type TaxDesc, type TaxSummaryDesc, type TicketingPolicy, type TotalFare, type TravelerPhone, type TravelerTitle, VERSION, type ValidatingCarrierDesc, buildBookingFlightDetails, buildRevalidateItineraryRequest };
1206
+ 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 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 GroupedItineraryResponse, 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 OtaAirLowFareSearchRq, type PassengerInfo, type PassengerPricing, type PassengerTotalFare, type PaymentMethod, type PriceComparison, type PriceComparisonType, type PricingDetails, type PricingInformation, type PricingQualifiers, type Ref, type RefundDocumentsType, type RequestOptions, 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, type SabreLogEvent, type SabreLogLevel, type SabreLogger, SabreOrchestrationError, type SabreOrchestrationErrorOptions, type SabreProtocol, type SabreRawResponse, type SabreRawResponseCallback, type SabreServiceErrorOptions, type SabreTokenStore, SabreWarning, type ScheduleCarrier, type ScheduleDesc, type ScheduleEndpoint, type ScheduleEquipment, type SeatAreaPreference, type SpecificFare, type StoredToken, type TaxDesc, type TaxSummaryDesc, type TicketingPolicy, type TotalFare, type TravelerPhone, type TravelerTitle, VERSION, type ValidatingCarrierDesc, buildBookingFlightDetails, buildRevalidateItineraryRequest };
package/dist/index.js CHANGED
@@ -239,7 +239,8 @@ async function bargainFinderMax(transport, request, options = {}) {
239
239
  body: request,
240
240
  classify: classifyBargainFinderMax,
241
241
  ...options.retry === void 0 ? {} : { retry: options.retry },
242
- ...options.signal === void 0 ? {} : { signal: options.signal }
242
+ ...options.signal === void 0 ? {} : { signal: options.signal },
243
+ ...options.onRawResponse === void 0 ? {} : { operation: "air.bargainFinderMax", onRawResponse: options.onRawResponse }
243
244
  });
244
245
  return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, BARGAIN_FINDER_MAX_SERVICE);
245
246
  }
@@ -310,7 +311,8 @@ async function revalidateItinerary(transport, request, options = {}) {
310
311
  body: request,
311
312
  classify: classifyRevalidateItinerary,
312
313
  ...options.retry === void 0 ? {} : { retry: options.retry },
313
- ...options.signal === void 0 ? {} : { signal: options.signal }
314
+ ...options.signal === void 0 ? {} : { signal: options.signal },
315
+ ...options.onRawResponse === void 0 ? {} : { operation: "air.revalidateItinerary", onRawResponse: options.onRawResponse }
314
316
  });
315
317
  return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, REVALIDATE_ITINERARY_SERVICE);
316
318
  }
@@ -708,7 +710,8 @@ async function cancelBooking(transport, request, options = {}) {
708
710
  idempotent: false,
709
711
  body: request,
710
712
  classify: classifyCancelBooking,
711
- ...options.signal === void 0 ? {} : { signal: options.signal }
713
+ ...options.signal === void 0 ? {} : { signal: options.signal },
714
+ ...options.onRawResponse === void 0 ? {} : { operation: "booking.cancel", onRawResponse: options.onRawResponse }
712
715
  });
713
716
  return toCancelBookingResponse(body);
714
717
  }
@@ -765,9 +768,7 @@ var CREATE_BOOKING_SERVICE = "createBooking";
765
768
  var PATH4 = "/v1/trip/orders/createBooking";
766
769
  var UNABLE_TO_RETRIEVE_BOOKING = "UNABLE_TO_RETRIEVE_BOOKING";
767
770
  async function createBooking(transport, request, options = {}) {
768
- if (typeof request !== "object" || request === null) {
769
- throw new TypeError("sabre-client: booking.create espera un objeto CreateBookingRequest");
770
- }
771
+ validateCreateBookingRequest(request);
771
772
  const body = await transport.request({
772
773
  method: "POST",
773
774
  path: PATH4,
@@ -775,10 +776,22 @@ async function createBooking(transport, request, options = {}) {
775
776
  idempotent: false,
776
777
  body: request,
777
778
  classify: classifyCreateBooking,
778
- ...options.signal === void 0 ? {} : { signal: options.signal }
779
+ ...options.signal === void 0 ? {} : { signal: options.signal },
780
+ ...options.onRawResponse === void 0 ? {} : { operation: "booking.create", onRawResponse: options.onRawResponse }
779
781
  });
780
782
  return toCreateBookingResponse(body);
781
783
  }
784
+ function validateCreateBookingRequest(request) {
785
+ if (typeof request !== "object" || request === null) {
786
+ throw new TypeError("sabre-client: booking.create espera un objeto CreateBookingRequest");
787
+ }
788
+ const agency = request.agency;
789
+ if (agency?.ticketingPolicy === "FUTURE_TICKETING" && agency.futureTicketingPolicy === void 0) {
790
+ throw new TypeError(
791
+ "sabre-client: booking.create con agency.ticketingPolicy FUTURE_TICKETING necesita agency.futureTicketingPolicy"
792
+ );
793
+ }
794
+ }
782
795
  function classifyCreateBooking(body) {
783
796
  if (!isObject2(body)) {
784
797
  return new SabreError(`${CREATE_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {
@@ -845,7 +858,8 @@ async function getBooking(transport, request, options = {}) {
845
858
  idempotent: true,
846
859
  body: request,
847
860
  classify: classifyGetBooking,
848
- ...options.signal === void 0 ? {} : { signal: options.signal }
861
+ ...options.signal === void 0 ? {} : { signal: options.signal },
862
+ ...options.onRawResponse === void 0 ? {} : { operation: "booking.get", onRawResponse: options.onRawResponse }
849
863
  });
850
864
  return toGetBookingResponse(body);
851
865
  }
@@ -895,6 +909,8 @@ var BookingManagement = class {
895
909
  *
896
910
  * Nunca se reintenta automáticamente. Si la reserva se crea con avisos o errores no fatales,
897
911
  * no lanza: los devuelve en `warnings` y `errors`. Si no se crea, lanza `SabreBusinessError`.
912
+ * Con `agency.ticketingPolicy: 'FUTURE_TICKETING'` y sin `agency.futureTicketingPolicy`, lanza
913
+ * `TypeError` sin llamar a la red: Sabre lo rechaza seguro.
898
914
  */
899
915
  create(request, options) {
900
916
  return createBooking(this.#transport, request, options);
@@ -1034,12 +1050,20 @@ var RestTransport = class {
1034
1050
  }
1035
1051
  async request(request) {
1036
1052
  if (request.retry !== void 0) validateRetryOptions(request.retry, "retry");
1053
+ const capture = request.onRawResponse === void 0 ? void 0 : { attempts: 0 };
1054
+ try {
1055
+ return await this.#attempts(request, capture);
1056
+ } finally {
1057
+ if (capture?.last !== void 0) this.#deliverRaw(request, { ...capture.last, attempts: capture.attempts });
1058
+ }
1059
+ }
1060
+ async #attempts(request, capture) {
1037
1061
  const retry = { ...this.#config.retry, ...definedOnly(request.retry ?? {}) };
1038
1062
  let reauthorized = false;
1039
1063
  for (let attempt = 0; ; attempt++) {
1040
1064
  const authorization = await this.#authorizationFor(request);
1041
1065
  try {
1042
- return await this.#send(request, attempt, authorization);
1066
+ return await this.#send(request, attempt, authorization, capture);
1043
1067
  } catch (error) {
1044
1068
  if (authorization !== void 0 && !reauthorized && isUnauthorized(error)) {
1045
1069
  reauthorized = true;
@@ -1070,11 +1094,24 @@ var RestTransport = class {
1070
1094
  }
1071
1095
  }
1072
1096
  }
1097
+ /** Un callback que lanza no rompe la operación: Create Booking no puede perder su localizador. */
1098
+ #deliverRaw(request, raw) {
1099
+ const operation = request.operation ?? request.service;
1100
+ try {
1101
+ request.onRawResponse?.({ operation, protocol: "rest", ...raw });
1102
+ } catch (error) {
1103
+ this.#log.emit("warn", "sabre.request.rawResponseHookFailed", {
1104
+ service: request.service,
1105
+ operation,
1106
+ errorName: error instanceof Error ? error.name : typeof error
1107
+ });
1108
+ }
1109
+ }
1073
1110
  async #authorizationFor(request) {
1074
1111
  if (request.auth === false || this.#authorization === void 0) return void 0;
1075
1112
  return this.#authorization.get();
1076
1113
  }
1077
- async #send(request, attempt, authorization) {
1114
+ async #send(request, attempt, authorization, capture) {
1078
1115
  const url = this.#url(request);
1079
1116
  const headers = new Headers({ Accept: "application/json", ...request.headers });
1080
1117
  const form = request.body instanceof URLSearchParams;
@@ -1086,6 +1123,7 @@ var RestTransport = class {
1086
1123
  this.#log.emit("debug", "sabre.request.start", logContext);
1087
1124
  const startedAt = Date.now();
1088
1125
  let response;
1126
+ if (capture !== void 0) capture.attempts++;
1089
1127
  try {
1090
1128
  response = await this.#config.fetch(url, {
1091
1129
  method: request.method,
@@ -1103,7 +1141,9 @@ var RestTransport = class {
1103
1141
  this.#log.emit("error", "sabre.request.end", { ...logContext, durationMs: Date.now() - startedAt, error });
1104
1142
  throw error;
1105
1143
  }
1106
- const body = await readBody(response);
1144
+ const text = await response.text();
1145
+ if (capture !== void 0) capture.last = { status: response.status, headers: response.headers, body: text };
1146
+ const body = parseBody(text);
1107
1147
  const endContext = { ...logContext, status: response.status, durationMs: Date.now() - startedAt };
1108
1148
  if (!response.ok) {
1109
1149
  const error = gatewayError(request.service, response.status, body);
@@ -1127,8 +1167,7 @@ var RestTransport = class {
1127
1167
  return url.toString();
1128
1168
  }
1129
1169
  };
1130
- async function readBody(response) {
1131
- const text = await response.text();
1170
+ function parseBody(text) {
1132
1171
  if (text === "") return void 0;
1133
1172
  try {
1134
1173
  return JSON.parse(text);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors/sabre-error.ts","../src/air/grouped-itinerary.ts","../src/air/itinerary-messages.ts","../src/air/bargain-finder-max.ts","../src/air/itinerary-flights.ts","../src/air/revalidate-itinerary.ts","../src/air/air.ts","../src/logging/redact.ts","../src/logging/logger.ts","../src/auth/token-request.ts","../src/auth/token-store.ts","../src/auth/auth-manager.ts","../src/booking/booking-errors.ts","../src/booking/cancel-booking.ts","../src/booking/create-booking.ts","../src/booking/get-booking.ts","../src/booking/booking-management.ts","../src/http/retry.ts","../src/config.ts","../src/http/rest-transport.ts","../src/sabre.ts","../src/booking/flight-details.ts","../src/index.ts"],"sourcesContent":["// Jerarquía de errores del SDK. Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md.\n\nexport interface SabreErrorOptions {\n /** Si la política de reintentos puede volver a intentar la operación. */\n retryable: boolean;\n /** Fragmento de la respuesta original sin transformar (JSON parseado o nodo XML). */\n raw?: unknown;\n cause?: unknown;\n}\n\n/**\n * Base de todos los errores del SDK.\n *\n * `raw` puede contener credenciales o datos de pasajero: no es enumerable, así que\n * no aparece en `JSON.stringify`, spreads ni serializadores de logs, pero sigue\n * accesible como `error.raw` para debugging. No lo vuelques a un logger sin sanitizar.\n */\nexport class SabreError extends Error {\n override name = 'SabreError';\n readonly retryable: boolean;\n declare readonly raw: unknown;\n\n constructor(message: string, options: SabreErrorOptions) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.retryable = options.retryable;\n Object.defineProperty(this, 'raw', {\n value: options.raw,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n }\n\n toJSON(): Record<string, unknown> {\n const fields: Record<string, unknown> = Object.fromEntries(Object.entries(this));\n return { ...fields, name: this.name, message: this.message };\n }\n}\n\nexport type SabreProtocol = 'rest' | 'soap';\n\nexport interface SabreGatewayErrorOptions extends SabreErrorOptions {\n protocol: SabreProtocol;\n /** HTTP status de la respuesta, si la hubo. */\n status?: number;\n /** Código tal cual lo devuelve el gateway (`ERR.2SG.*`, `USG_*`), si viene en el body. */\n code?: string;\n}\n\n/** Error de transporte/gateway (`ERR.2SG.*` + HTTP status en REST, `USG_*` en SOAP). */\nexport class SabreGatewayError extends SabreError {\n override name = 'SabreGatewayError';\n readonly protocol: SabreProtocol;\n readonly status: number | undefined;\n readonly code: string | undefined;\n\n constructor(message: string, options: SabreGatewayErrorOptions) {\n super(message, options);\n this.protocol = options.protocol;\n this.status = options.status;\n this.code = options.code;\n }\n}\n\nexport interface SabreOrchestrationErrorOptions extends Omit<SabreErrorOptions, 'retryable'> {\n /** `SP.PROVIDER_ERROR` o `SP.INTERNAL_ERROR`. */\n code: string;\n}\n\n/**\n * Error de servicio orquestado (`SP.*`), viaja dentro de una respuesta 200.\n * `SP.PROVIDER_ERROR` es reintentable; `SP.INTERNAL_ERROR` (y cualquier otro) no.\n */\nexport class SabreOrchestrationError extends SabreError {\n override name = 'SabreOrchestrationError';\n readonly code: string;\n\n constructor(message: string, options: SabreOrchestrationErrorOptions) {\n super(message, { ...options, retryable: options.code === 'SP.PROVIDER_ERROR' });\n this.code = options.code;\n }\n}\n\nexport interface SabreServiceErrorOptions extends Omit<SabreErrorOptions, 'retryable'> {\n /** Servicio que originó el error, p. ej. `'createBooking'`. */\n service: string;\n /** Código tal cual lo documenta Sabre, sin normalizar. */\n code: string;\n}\n\nexport interface SabreBusinessErrorOptions extends SabreServiceErrorOptions {\n /**\n * Solo para códigos que Sabre documenta como temporales en un servicio de lectura\n * (p. ej. `Transmission timeout` de Bargain Finder Max). Por defecto `false`.\n * La política de reintentos igual exige que la operación sea idempotente.\n */\n retryable?: boolean;\n /** Avisos que llegaron junto con el error (p. ej. `category: WARNING` de Create Booking). */\n warnings?: readonly SabreWarning[];\n /**\n * Otros errores que llegaron junto con este (p. ej. la causa real detrás de\n * `NO_ITEMS_CANCELLED` en Cancel Booking).\n */\n errors?: readonly SabreBusinessError[];\n}\n\n/**\n * Error del catálogo propio de un servicio. No es reintentable, salvo los códigos\n * temporales de servicios de lectura que se marcan con `retryable: true`.\n */\nexport class SabreBusinessError extends SabreError {\n override name = 'SabreBusinessError';\n readonly service: string;\n readonly code: string;\n readonly warnings: readonly SabreWarning[];\n readonly errors: readonly SabreBusinessError[];\n\n constructor(message: string, options: SabreBusinessErrorOptions) {\n super(message, { ...options, retryable: options.retryable ?? false });\n this.service = options.service;\n this.code = options.code;\n this.warnings = options.warnings ?? [];\n this.errors = options.errors ?? [];\n }\n}\n\n/**\n * Advertencia de un servicio (p. ej. `category: WARNING` de Create Booking, soft errors\n * de End Transaction): no es un fallo fatal. Nunca se reintenta automáticamente.\n */\nexport class SabreWarning extends SabreError {\n override name = 'SabreWarning';\n readonly service: string;\n readonly code: string;\n\n constructor(message: string, options: SabreServiceErrorOptions) {\n super(message, { ...options, retryable: false });\n this.service = options.service;\n this.code = options.code;\n }\n}\n","// Modelo `groupedItineraryResponse` compartido por Bargain Finder Max y Revalidate Itinerary,\n// y su desnormalizador: resuelve cada `ref` al objeto completo antes de exponerlo.\n// Ver sabre-wiki/wiki/concepts/modelo-de-itinerario.md.\n//\n// Sin schema formal: los campos salen de los ejemplos de BFM y Revalidate del wiki. Los que\n// solo aparecieron en uno de los dos van como opcionales.\nimport { SabreError } from '../errors/index.js';\n\n// ---------------------------------------------------------------------------\n// Descriptores compartidos (arrays planos indexados por `id`)\n// ---------------------------------------------------------------------------\n\nexport interface ScheduleEndpoint {\n airport: string;\n city?: string;\n /** Visto en sandbox para aeropuertos de EE. UU. */\n state?: string;\n country?: string;\n /** Hora local con offset, p. ej. `17:10:00+02:00`. */\n time: string;\n terminal?: string;\n /** Días que se suman a la fecha de salida del vuelo. Visto en sandbox (`arrival`). */\n dateAdjustment?: number;\n}\n\nexport interface ScheduleEquipment {\n code: string;\n typeForFirstLeg?: string;\n typeForLastLeg?: string;\n}\n\nexport interface ScheduleCarrier {\n marketing: string;\n marketingFlightNumber: number;\n operating?: string;\n operatingFlightNumber?: number;\n alliances?: string;\n equipment?: ScheduleEquipment;\n}\n\n/** Vuelo/segmento operado (`scheduleDescs[]`). */\nexport interface ScheduleDesc {\n id: number;\n /** Visto en sandbox, p. ej. `\"7\"`; significado sin confirmar. */\n dotRating?: string;\n frequency?: string;\n stopCount?: number;\n eTicketable?: boolean;\n totalMilesFlown?: number;\n /** Minutos. */\n elapsedTime?: number;\n departure: ScheduleEndpoint;\n arrival: ScheduleEndpoint;\n carrier: ScheduleCarrier;\n}\n\n/** Tramo lógico (`legDescs[]`): agrupa schedules por `ref`. */\nexport interface LegDesc {\n id: number;\n /** Minutos. */\n elapsedTime?: number;\n schedules: LegScheduleRef[];\n}\n\n/**\n * Schedule dentro de un tramo. `departureDateAdjustment`: días que se suman a la fecha del\n * tramo para la salida de este vuelo (conexión al día siguiente). Visto en sandbox, sin\n * documentar en los ejemplos de Sabre.\n */\nexport interface LegScheduleRef extends Ref {\n departureDateAdjustment?: number;\n}\n\n/** Impuesto individual (`taxDescs[]`). */\nexport interface TaxDesc {\n id: number;\n code: string;\n amount: number;\n currency: string;\n description?: string;\n publishedAmount?: number;\n publishedCurrency?: string;\n station?: string;\n country?: string;\n /** Visto en sandbox. */\n taxReissue?: { refundable?: boolean };\n}\n\n/** Resumen de impuestos por código (`taxSummaryDescs[]`). Misma forma que `TaxDesc`. */\nexport type TaxSummaryDesc = TaxDesc;\n\n/** Cargo adicional (`obFeeDescs[]`). Significado exacto de \"OB\" sin confirmar. */\nexport interface ObFeeDesc {\n id: number;\n amount: number;\n currency: string;\n}\n\nexport interface FareComponentDescSegment {\n segment: {\n stopover?: boolean;\n };\n}\n\n/** Componente de tarifa (`fareComponentDescs[]`). */\nexport interface FareComponentDesc {\n id: number;\n governingCarrier?: string;\n fareAmount?: number;\n fareCurrency?: string;\n fareBasisCode: string;\n farePassengerType?: string;\n publishedFareAmount?: number;\n publishedFareCurrency?: string;\n /** `FROM` / `TO`. */\n directionality?: string;\n applicablePricingCategories?: string;\n vendorCode?: string;\n fareTypeBitmap?: string;\n fareType?: string;\n fareTariff?: string;\n fareRule?: string;\n cabinCode?: string;\n segments?: FareComponentDescSegment[];\n // Vistos solo en Revalidate Itinerary.\n ticketDesignator?: string;\n mileageSurcharge?: number;\n mileage?: boolean;\n oneWayFare?: boolean;\n negotiatedFare?: boolean;\n privateFare?: boolean;\n notValidAfter?: string;\n /** Distinto de `directionality`; significado sin confirmar. */\n direction?: string;\n}\n\n/** Aerolínea validadora (`validatingCarrierDescs[]`). */\nexport interface ValidatingCarrierDesc {\n id: number;\n settlementMethod?: string;\n newVcxProcess?: boolean;\n default?: { code: string };\n}\n\n/** Franquicia de equipaje (`baggageAllowanceDescs[]`). */\nexport interface BaggageAllowanceDesc {\n id: number;\n pieceCount?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Piezas que no llevan referencias\n// ---------------------------------------------------------------------------\n\n/** Referencia a un descriptor por su `id`. */\nexport interface Ref {\n ref: number;\n}\n\nexport interface ItineraryMessage {\n severity: string;\n type: string;\n code: string;\n text: string;\n}\n\nexport interface LegDescription {\n departureDate: string;\n departureLocation: string;\n arrivalLocation: string;\n}\n\nexport interface CurrencyConversion {\n from: string;\n to: string;\n exchangeRateUsed: number;\n}\n\nexport interface PassengerTotalFare {\n totalFare: number;\n totalTaxAmount?: number;\n currency: string;\n baseFareAmount?: number;\n baseFareCurrency?: string;\n equivalentAmount?: number;\n equivalentCurrency?: string;\n constructionAmount?: number;\n constructionCurrency?: string;\n exchangeRateOne?: number;\n // Comisión de agencia: vistos solo en Revalidate Itinerary.\n commissionPercentage?: number;\n commissionAmount?: number;\n cat35CommissionPercentage?: number;\n cat35CommissionAmount?: number;\n cat35MarkupAmount?: number;\n commissionAmountInEquivalent?: number;\n commissionSource?: string;\n}\n\nexport interface TotalFare {\n totalPrice: number;\n totalTaxAmount?: number;\n currency: string;\n baseFareAmount?: number;\n baseFareCurrency?: string;\n constructionAmount?: number;\n constructionCurrency?: string;\n equivalentAmount?: number;\n equivalentCurrency?: string;\n}\n\n/** Disponibilidad del segmento dentro de un componente de tarifa. */\nexport interface FareComponentSegmentDetail {\n bookingCode?: string;\n cabinCode?: string;\n mealCode?: string;\n seatsAvailable?: number;\n availabilityBreak?: boolean;\n fareBreakPoint?: boolean;\n}\n\nexport interface FareMessage {\n type: string;\n code: string;\n /** Visto en sandbox de Revalidate. */\n carrier?: string;\n info: string;\n}\n\n// ---------------------------------------------------------------------------\n// Respuesta tal cual la manda Sabre (con `ref`). Interna: el SDK expone la desnormalizada.\n// ---------------------------------------------------------------------------\n\nexport interface RawFareComponent extends Ref {\n beginAirport?: string;\n endAirport?: string;\n segments?: Array<{ segment: FareComponentSegmentDetail }>;\n}\n\nexport interface RawBaggageInformation {\n provisionType?: string;\n airlineCode?: string;\n /** Índices de segmento, no referencias a descriptores. */\n segments?: Array<{ id: number }>;\n allowance?: Ref;\n}\n\nexport interface RawPassengerInfo {\n passengerType: string;\n passengerNumber?: number;\n nonRefundable?: boolean;\n fareComponents?: RawFareComponent[];\n taxes?: Ref[];\n taxSummaries?: Ref[];\n obFees?: Ref[];\n currencyConversion?: CurrencyConversion;\n passengerTotalFare?: PassengerTotalFare;\n baggageInformation?: RawBaggageInformation[];\n // Vistos solo en Revalidate Itinerary.\n fareMessages?: FareMessage[];\n fareCalcLine?: { info: string };\n}\n\nexport interface RawFare {\n mandatoryInd?: boolean;\n validatingCarrierCode?: string;\n vita?: boolean;\n eTicketable?: boolean;\n lastTicketDate?: string;\n lastTicketTime?: string;\n governingCarriers?: string;\n passengerInfoList: Array<{ passengerInfo: RawPassengerInfo }>;\n totalFare?: TotalFare;\n validatingCarriers?: Ref[];\n}\n\nexport interface RawPricingInformation {\n pricingSubsource?: string;\n /** P. ej. `ATPCO`. Visto en Revalidate y en sandbox de BFM. */\n distributionModel?: string;\n fare: RawFare;\n}\n\nexport interface RawItinerary {\n id: number;\n pricingSource?: string;\n /** Visto solo en Revalidate Itinerary. */\n currentItinerary?: boolean;\n /** Visto en sandbox de BFM; significado sin confirmar. */\n diversitySwapper?: { weighedPrice?: number };\n legs: Ref[];\n pricingInformation: RawPricingInformation[];\n}\n\nexport interface RawItineraryGroup {\n groupDescription: { legDescriptions: LegDescription[] };\n itineraries: RawItinerary[];\n}\n\n/** Contenido de `groupedItineraryResponse` tal cual llega de Sabre. */\nexport interface RawGroupedItineraryResponse {\n version: string;\n messages?: ItineraryMessage[];\n statistics?: { itineraryCount: number };\n scheduleDescs?: ScheduleDesc[];\n taxDescs?: TaxDesc[];\n taxSummaryDescs?: TaxSummaryDesc[];\n obFeeDescs?: ObFeeDesc[];\n fareComponentDescs?: FareComponentDesc[];\n validatingCarrierDescs?: ValidatingCarrierDesc[];\n baggageAllowanceDescs?: BaggageAllowanceDesc[];\n legDescs?: LegDesc[];\n itineraryGroups?: RawItineraryGroup[];\n}\n\n// ---------------------------------------------------------------------------\n// Respuesta desnormalizada (superficie pública)\n// ---------------------------------------------------------------------------\n\n/** Tramo con sus schedules resueltos. */\nexport interface Leg extends Omit<LegDesc, 'schedules'> {\n schedules: LegSchedule[];\n}\n\n/** Schedule resuelto, con lo que la referencia del tramo agrega. */\nexport type LegSchedule = ScheduleDesc & Omit<LegScheduleRef, 'ref'>;\n\n/** Segmento de un componente de tarifa: lo del descriptor más la disponibilidad del itinerario. */\nexport interface FareComponentSegment {\n segment: FareComponentDescSegment['segment'] & FareComponentSegmentDetail;\n}\n\n/** Componente de tarifa resuelto: descriptor + datos propios del itinerario. */\nexport interface FareComponent extends Omit<FareComponentDesc, 'segments'> {\n beginAirport?: string;\n endAirport?: string;\n segments?: FareComponentSegment[];\n}\n\nexport interface BaggageInformation extends Omit<RawBaggageInformation, 'allowance'> {\n allowance?: BaggageAllowanceDesc;\n}\n\nexport interface PassengerInfo\n extends Omit<RawPassengerInfo, 'fareComponents' | 'taxes' | 'taxSummaries' | 'obFees' | 'baggageInformation'> {\n fareComponents?: FareComponent[];\n taxes?: TaxDesc[];\n taxSummaries?: TaxSummaryDesc[];\n obFees?: ObFeeDesc[];\n baggageInformation?: BaggageInformation[];\n}\n\nexport interface Fare extends Omit<RawFare, 'passengerInfoList' | 'validatingCarriers'> {\n passengerInfoList: Array<{ passengerInfo: PassengerInfo }>;\n validatingCarriers?: ValidatingCarrierDesc[];\n}\n\nexport interface PricingInformation extends Omit<RawPricingInformation, 'fare'> {\n fare: Fare;\n}\n\nexport interface Itinerary extends Omit<RawItinerary, 'legs' | 'pricingInformation'> {\n legs: Leg[];\n pricingInformation: PricingInformation[];\n}\n\nexport interface ItineraryGroup {\n groupDescription: { legDescriptions: LegDescription[] };\n itineraries: Itinerary[];\n}\n\n/**\n * `groupedItineraryResponse` con cada `ref` resuelto al objeto completo. Los arrays de\n * descriptores (`scheduleDescs`, `legDescs`, …) ya no se exponen: su contenido vive\n * dentro de cada itinerario.\n */\nexport interface GroupedItineraryResponse {\n version: string;\n messages: ItineraryMessage[];\n statistics?: { itineraryCount: number };\n itineraryGroups: ItineraryGroup[];\n}\n\n// ---------------------------------------------------------------------------\n// Desnormalizador\n// ---------------------------------------------------------------------------\n\n/**\n * Resuelve cada `{ ref, ...resto }` a `{ ...descriptor, ...resto }` (sin `ref`; el `id` del\n * descriptor se conserva). En los componentes de tarifa, `segments` se fusiona elemento a\n * elemento: el descriptor aporta `stopover` y el itinerario la disponibilidad; si los dos\n * traen `segments` con distinto largo, la respuesta es malformada.\n *\n * Un `ref` sin descriptor con ese `id` es una respuesta malformada: lanza `SabreError`\n * no reintentable en vez de devolver un objeto a medias. No muta la entrada.\n */\nexport function denormalizeGroupedItineraryResponse(\n raw: RawGroupedItineraryResponse,\n service: string,\n): GroupedItineraryResponse {\n const resolver = new Resolver(raw, service);\n return {\n version: raw.version,\n messages: raw.messages ?? [],\n ...(raw.statistics === undefined ? {} : { statistics: raw.statistics }),\n itineraryGroups: (raw.itineraryGroups ?? []).map((group) => ({\n groupDescription: group.groupDescription,\n itineraries: group.itineraries.map((itinerary) => resolver.itinerary(itinerary)),\n })),\n };\n}\n\nclass Resolver {\n readonly #service: string;\n readonly #schedules: Map<number, ScheduleDesc>;\n readonly #legs: Map<number, LegDesc>;\n readonly #taxes: Map<number, TaxDesc>;\n readonly #taxSummaries: Map<number, TaxSummaryDesc>;\n readonly #obFees: Map<number, ObFeeDesc>;\n readonly #fareComponents: Map<number, FareComponentDesc>;\n readonly #validatingCarriers: Map<number, ValidatingCarrierDesc>;\n readonly #baggageAllowances: Map<number, BaggageAllowanceDesc>;\n\n constructor(raw: RawGroupedItineraryResponse, service: string) {\n this.#service = service;\n this.#schedules = byId(raw.scheduleDescs);\n this.#legs = byId(raw.legDescs);\n this.#taxes = byId(raw.taxDescs);\n this.#taxSummaries = byId(raw.taxSummaryDescs);\n this.#obFees = byId(raw.obFeeDescs);\n this.#fareComponents = byId(raw.fareComponentDescs);\n this.#validatingCarriers = byId(raw.validatingCarrierDescs);\n this.#baggageAllowances = byId(raw.baggageAllowanceDescs);\n }\n\n itinerary(itinerary: RawItinerary): Itinerary {\n return {\n ...itinerary,\n legs: itinerary.legs.map((ref) => this.#leg(ref)),\n pricingInformation: itinerary.pricingInformation.map((pricing) => ({\n ...pricing,\n fare: this.#fare(pricing.fare),\n })),\n };\n }\n\n #leg(ref: Ref): Leg {\n const leg = this.#merge(this.#legs, 'legDescs', ref);\n return { ...leg, schedules: leg.schedules.map((schedule) => this.#merge(this.#schedules, 'scheduleDescs', schedule)) };\n }\n\n #fare(fare: RawFare): Fare {\n const { validatingCarriers, ...rest } = fare;\n return {\n ...rest,\n passengerInfoList: fare.passengerInfoList.map(({ passengerInfo, ...entry }) => ({\n ...entry,\n passengerInfo: this.#passengerInfo(passengerInfo),\n })),\n ...(validatingCarriers === undefined\n ? {}\n : {\n validatingCarriers: validatingCarriers.map((ref) =>\n this.#merge(this.#validatingCarriers, 'validatingCarrierDescs', ref),\n ),\n }),\n };\n }\n\n #passengerInfo(info: RawPassengerInfo): PassengerInfo {\n const { fareComponents, taxes, taxSummaries, obFees, baggageInformation, ...rest } = info;\n const result: PassengerInfo = { ...rest };\n if (fareComponents !== undefined) result.fareComponents = fareComponents.map((ref) => this.#fareComponent(ref));\n if (taxes !== undefined) result.taxes = taxes.map((ref) => this.#merge(this.#taxes, 'taxDescs', ref));\n if (taxSummaries !== undefined) {\n result.taxSummaries = taxSummaries.map((ref) => this.#merge(this.#taxSummaries, 'taxSummaryDescs', ref));\n }\n if (obFees !== undefined) result.obFees = obFees.map((ref) => this.#merge(this.#obFees, 'obFeeDescs', ref));\n if (baggageInformation !== undefined) {\n result.baggageInformation = baggageInformation.map(({ allowance, ...bag }) => ({\n ...bag,\n ...(allowance === undefined\n ? {}\n : { allowance: this.#merge(this.#baggageAllowances, 'baggageAllowanceDescs', allowance) }),\n }));\n }\n return result;\n }\n\n #fareComponent(ref: RawFareComponent): FareComponent {\n const desc = this.#lookup(this.#fareComponents, 'fareComponentDescs', ref.ref);\n const { ref: _ref, segments: siteSegments, ...site } = ref;\n const { segments: descSegments, ...descRest } = desc;\n if (descSegments !== undefined && siteSegments !== undefined && descSegments.length !== siteSegments.length) {\n throw this.#malformed(\n `fareComponents con ${siteSegments.length} segmentos y fareComponentDescs ${ref.ref} con ${descSegments.length}`,\n );\n }\n const segments = mergeSegments(descSegments, siteSegments);\n return { ...descRest, ...site, ...(segments === undefined ? {} : { segments }) };\n }\n\n /** `{ ref, ...resto }` → `{ ...descriptor, ...resto }`. */\n #merge<T extends { id: number }>(index: Map<number, T>, kind: string, ref: Ref): T {\n const { ref: id, ...site } = ref;\n return { ...this.#lookup(index, kind, id), ...site };\n }\n\n #lookup<T>(index: Map<number, T>, kind: string, id: number): T {\n const desc = index.get(id);\n if (desc === undefined) throw this.#malformed(`ref ${id} sin descriptor en ${kind}`);\n return desc;\n }\n\n #malformed(detail: string): SabreError {\n return new SabreError(`${this.#service}: respuesta malformada, ${detail}`, { retryable: false });\n }\n}\n\nfunction byId<T extends { id: number }>(descs: T[] | undefined): Map<number, T> {\n return new Map((descs ?? []).map((desc) => [desc.id, desc]));\n}\n\nfunction mergeSegments(\n desc: FareComponentDescSegment[] | undefined,\n site: Array<{ segment: FareComponentSegmentDetail }> | undefined,\n): FareComponentSegment[] | undefined {\n if (desc === undefined && site === undefined) return undefined;\n // Los largos ya se validaron iguales cuando vienen los dos.\n const length = desc?.length ?? site?.length ?? 0;\n return Array.from({ length }, (_, i) => ({\n segment: { ...desc?.[i]?.segment, ...site?.[i]?.segment },\n }));\n}\n","// Clasificación de errores de negocio en `groupedItineraryResponse.messages[]`, compartida por\n// los servicios que responden con ese modelo (Bargain Finder Max, Revalidate Itinerary).\n// Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md.\nimport { SabreBusinessError, SabreError } from '../errors/index.js';\nimport type { ItineraryMessage } from './grouped-itinerary.js';\n\n/** Entrada de catálogo: se compara por substring del `text`, sin distinguir mayúsculas. */\nexport interface ItineraryMessageCatalogEntry {\n code: string;\n retryable: boolean;\n}\n\n/**\n * Paso 3 del orden de detección: un mensaje con `severity: Error` en\n * `groupedItineraryResponse.messages[]` (respuesta 200) es un `SabreBusinessError`.\n *\n * En sandbox, los mensajes `Error` son genéricos (`No complete journey can be built…`,\n * `Error during Processing`) y el texto del catálogo llega en un mensaje `Info`\n * (`NO FLIGHT SCHEDULES FOR QUALIFIERS USED`). Por eso, cuando hay algún `Error`, el\n * catálogo se busca en el `text` de todos los mensajes.\n */\nexport function classifyItineraryMessages(\n body: unknown,\n service: string,\n catalog: ReadonlyArray<ItineraryMessageCatalogEntry>,\n): SabreError | undefined {\n const response = isObject(body) ? body.groupedItineraryResponse : undefined;\n if (!isObject(response)) {\n return new SabreError(`${service}: respuesta malformada, falta groupedItineraryResponse`, {\n retryable: false,\n raw: body,\n });\n }\n const messages = Array.isArray(response.messages) ? (response.messages as Partial<ItineraryMessage>[]) : [];\n const error = messages.find((message) => message.severity?.toLowerCase() === 'error');\n if (error === undefined) return undefined;\n\n const match = findInCatalog(messages, catalog);\n const text = match?.text ?? (typeof error.text === 'string' ? error.text : '');\n const known = match?.entry;\n const code = known?.code ?? error.code ?? text;\n return new SabreBusinessError(`${service}: ${text || code}`, {\n service,\n code,\n retryable: known?.retryable ?? false,\n raw: body,\n });\n}\n\nfunction findInCatalog(\n messages: Partial<ItineraryMessage>[],\n catalog: ReadonlyArray<ItineraryMessageCatalogEntry>,\n): { entry: ItineraryMessageCatalogEntry; text: string } | undefined {\n for (const message of messages) {\n if (typeof message.text !== 'string') continue;\n const text = message.text.toLowerCase();\n const entry = catalog.find((candidate) => text.includes(candidate.code.toLowerCase()));\n if (entry !== undefined) return { entry, text: message.text };\n }\n return undefined;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","// Bargain Finder Max v5 (`POST /v5/offers/shop`).\n// Ver sabre-wiki/wiki/entities/bargain-finder-max.md.\nimport type { SabreError } from '../errors/index.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport type { RetryOptions } from '../http/retry.js';\nimport {\n denormalizeGroupedItineraryResponse,\n type GroupedItineraryResponse,\n type RawGroupedItineraryResponse,\n} from './grouped-itinerary.js';\nimport { classifyItineraryMessages, type ItineraryMessageCatalogEntry } from './itinerary-messages.js';\nimport type { OtaAirLowFareSearchRq } from './low-fare-search-request.js';\n\nexport const BARGAIN_FINDER_MAX_SERVICE = 'bargainFinderMax';\nconst PATH = '/v5/offers/shop';\n\n/** Body de Bargain Finder Max v5, tal cual lo documenta Sabre. */\nexport interface BargainFinderMaxRequest {\n OTA_AirLowFareSearchRQ: OtaAirLowFareSearchRq;\n}\n\n/** `groupedItineraryResponse` con las referencias ya resueltas. */\nexport type BargainFinderMaxResponse = GroupedItineraryResponse;\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Pisa los reintentos del cliente solo para esta request. */\n retry?: Partial<RetryOptions>;\n}\n\n/**\n * Catálogo de errores de BFM (guía oficial de errores). Se compara por substring del\n * `text` porque Sabre agrega detalle variable. Los temporales son reintentables: BFM es\n * una lectura idempotente y Sabre indica reintentar.\n */\nexport const BARGAIN_FINDER_MAX_CATALOG: ReadonlyArray<ItineraryMessageCatalogEntry> = [\n { code: 'No Availability', retryable: false },\n { code: 'NO FLIGHT SCHEDULES FOR QUALIFIERS USED', retryable: false },\n { code: 'Connection reset by peer', retryable: true },\n { code: 'Transmission timeout', retryable: true },\n { code: 'Insufficient resources', retryable: true },\n { code: 'MAX NBR COMBINATIONS EXCEEDED', retryable: true },\n];\n\nexport async function bargainFinderMax(\n transport: RestTransport,\n request: BargainFinderMaxRequest,\n options: RequestOptions = {},\n): Promise<BargainFinderMaxResponse> {\n if (typeof request !== 'object' || request === null || typeof request.OTA_AirLowFareSearchRQ !== 'object') {\n throw new TypeError('sabre-client: bargainFinderMax espera { OTA_AirLowFareSearchRQ: { ... } }');\n }\n const body = await transport.request<{ groupedItineraryResponse: RawGroupedItineraryResponse }>({\n method: 'POST',\n path: PATH,\n service: BARGAIN_FINDER_MAX_SERVICE,\n // POST, pero de solo lectura: se puede reintentar sin efectos duplicados.\n idempotent: true,\n body: request,\n classify: classifyBargainFinderMax,\n ...(options.retry === undefined ? {} : { retry: options.retry }),\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n });\n return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, BARGAIN_FINDER_MAX_SERVICE);\n}\n\n/** Ver `classifyItineraryMessages`. */\nexport function classifyBargainFinderMax(body: unknown): SabreError | undefined {\n return classifyItineraryMessages(body, BARGAIN_FINDER_MAX_SERVICE, BARGAIN_FINDER_MAX_CATALOG);\n}\n","// Reglas para fijar los vuelos de un itinerario desnormalizado, compartidas por los\n// helpers que arman requests a partir de él (Revalidate Itinerary, Create Booking).\n// Ver sabre-wiki/wiki/concepts/modelo-de-itinerario.md.\nimport type { Itinerary, ItineraryGroup, LegSchedule } from './grouped-itinerary.js';\n\n/** Un vuelo del itinerario con su fecha de salida ya resuelta y su clase de servicio. */\nexport interface ItineraryFlight {\n /** Índice del tramo (`legs[]`) al que pertenece. */\n legIndex: number;\n schedule: LegSchedule;\n /** `YYYY-MM-DD`, hora local del aeropuerto de salida. */\n departureDate: string;\n /** `YYYY-MM-DD`, hora local del aeropuerto de llegada. */\n arrivalDate: string;\n bookingCode: string;\n}\n\n/**\n * Aplana los vuelos del itinerario en orden.\n *\n * - La clase de servicio de cada vuelo sale de `fareComponents[].segments[].bookingCode` del\n * primer pasajero de la primera cotización, en el orden de los vuelos del itinerario.\n * - Las fechas salen de `legDescriptions[].departureDate` más `departureDateAdjustment` del\n * schedule (salida) y `arrival.dateAdjustment` (llegada).\n */\nexport function itineraryFlights(group: ItineraryGroup, itinerary: Itinerary): ItineraryFlight[] {\n const { legDescriptions } = group.groupDescription;\n if (legDescriptions.length !== itinerary.legs.length) {\n throw new TypeError(\n `sabre-client: el itinerario tiene ${itinerary.legs.length} tramos y el grupo ${legDescriptions.length}`,\n );\n }\n const classes = bookingCodes(itinerary);\n const flightCount = itinerary.legs.reduce((n, leg) => n + leg.schedules.length, 0);\n if (classes.length !== flightCount) {\n throw new TypeError(\n `sabre-client: el itinerario tiene ${flightCount} vuelos y ${classes.length} clases de servicio en fareComponents`,\n );\n }\n\n let next = 0;\n return itinerary.legs.flatMap((leg, legIndex) => {\n const legDate = legDescriptions[legIndex]!.departureDate;\n return leg.schedules.map((schedule) => {\n const departureDate = addDays(legDate, schedule.departureDateAdjustment ?? 0);\n return {\n legIndex,\n schedule,\n departureDate,\n arrivalDate: addDays(departureDate, schedule.arrival.dateAdjustment ?? 0),\n bookingCode: classes[next++]!,\n };\n });\n });\n}\n\nfunction bookingCodes(itinerary: Itinerary): string[] {\n const passenger = itinerary.pricingInformation[0]?.fare.passengerInfoList[0]?.passengerInfo;\n return (passenger?.fareComponents ?? []).flatMap((component) =>\n (component.segments ?? []).map(({ segment }) => {\n if (segment.bookingCode === undefined) {\n throw new TypeError('sabre-client: un segmento de fareComponents no trae bookingCode');\n }\n return segment.bookingCode;\n }),\n );\n}\n\n/** `2026-09-11` + n días, en calendario puro (sin zona horaria). */\nfunction addDays(date: string, days: number): string {\n if (days === 0) return date;\n const [year, month, day] = date.split('-').map(Number) as [number, number, number];\n return new Date(Date.UTC(year, month - 1, day + days)).toISOString().slice(0, 10);\n}\n","// Revalidate Itinerary v5 (`POST /v5/shop/flights/revalidate`).\n// Ver sabre-wiki/wiki/entities/revalidate-itinerary.md.\nimport type { SabreError } from '../errors/index.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport { BARGAIN_FINDER_MAX_CATALOG, type BargainFinderMaxRequest, type RequestOptions } from './bargain-finder-max.js';\nimport {\n denormalizeGroupedItineraryResponse,\n type GroupedItineraryResponse,\n type Itinerary,\n type ItineraryGroup,\n type RawGroupedItineraryResponse,\n} from './grouped-itinerary.js';\nimport { type ItineraryFlight, itineraryFlights } from './itinerary-flights.js';\nimport { classifyItineraryMessages, type ItineraryMessageCatalogEntry } from './itinerary-messages.js';\nimport type {\n LowFareSearchFlight,\n LowFareSearchOriginDestination,\n OtaAirLowFareSearchRq,\n} from './low-fare-search-request.js';\n\nexport const REVALIDATE_ITINERARY_SERVICE = 'revalidateItinerary';\nconst PATH = '/v5/shop/flights/revalidate';\n\n/** Body de Revalidate Itinerary v5: el mismo `OTA_AirLowFareSearchRQ` que BFM, con los vuelos fijados. */\nexport interface RevalidateItineraryRequest {\n OTA_AirLowFareSearchRQ: OtaAirLowFareSearchRq;\n}\n\n/** `groupedItineraryResponse` con las referencias ya resueltas. */\nexport type RevalidateItineraryResponse = GroupedItineraryResponse;\n\nexport async function revalidateItinerary(\n transport: RestTransport,\n request: RevalidateItineraryRequest,\n options: RequestOptions = {},\n): Promise<RevalidateItineraryResponse> {\n if (typeof request !== 'object' || request === null || typeof request.OTA_AirLowFareSearchRQ !== 'object') {\n throw new TypeError('sabre-client: revalidateItinerary espera { OTA_AirLowFareSearchRQ: { ... } }');\n }\n const body = await transport.request<{ groupedItineraryResponse: RawGroupedItineraryResponse }>({\n method: 'POST',\n path: PATH,\n service: REVALIDATE_ITINERARY_SERVICE,\n // POST, pero de solo lectura: no sostiene inventario, se puede reintentar.\n idempotent: true,\n body: request,\n classify: classifyRevalidateItinerary,\n ...(options.retry === undefined ? {} : { retry: options.retry }),\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n });\n return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, REVALIDATE_ITINERARY_SERVICE);\n}\n\n/**\n * Catálogo de errores de Revalidate (guía oficial de errores de Revalidate Itinerary, en la\n * documentación SOAP de BFM 7.2.0; ver sabre-wiki/wiki/entities/revalidate-itinerary.md).\n * Las cinco condiciones describen un dato que no existe (tarifa, horario o disponibilidad):\n * reintentar no cambia el resultado. En producción, `NO FARE FOR CLASS USED` llegó con\n * `code: 'PROCESS'`; el catálogo le da un `code` estable.\n *\n * Los temporales se heredan de BFM (mismo motor), con `retryable: true`.\n */\nexport const REVALIDATE_ITINERARY_CATALOG: ReadonlyArray<ItineraryMessageCatalogEntry> = [\n { code: 'NO COMBINABLE FARES FOR CLASS USED', retryable: false },\n { code: 'NO FARE FOR CLASS USED', retryable: false },\n { code: 'NO FLIGHT SCHEDULES FOR QUALIFIERS USED', retryable: false },\n { code: 'NO SUCH FLIGHT', retryable: false },\n { code: 'NO AVAILABILITY', retryable: false },\n ...BARGAIN_FINDER_MAX_CATALOG.filter((entry) => entry.retryable),\n];\n\n/** Ver `classifyItineraryMessages`. */\nexport function classifyRevalidateItinerary(body: unknown): SabreError | undefined {\n return classifyItineraryMessages(body, REVALIDATE_ITINERARY_SERVICE, REVALIDATE_ITINERARY_CATALOG);\n}\n\nexport interface RevalidateItineraryRequestSource {\n /** Request de BFM que produjo el itinerario: aporta `Version`, `POS`, pasajeros y `TPA_Extensions`. */\n search: BargainFinderMaxRequest;\n /** Grupo del itinerario: aporta la fecha de cada tramo. */\n group: ItineraryGroup;\n itinerary: Itinerary;\n}\n\n/**\n * Arma el request de Revalidate Itinerary para un itinerario devuelto por BFM, fijando cada\n * vuelo en `OriginDestinationInformation[].TPA_Extensions.Flight[]`.\n *\n * - Clases de servicio y fechas: ver `itineraryFlights`. Las horas salen de `time` sin el offset.\n * - `MaxStopsQuantity` es el máximo de conexiones de un tramo, para no rechazar itinerarios\n * con escala.\n * - `Fixed: false` y `VerificationItinCallLogic: \"L\"` se copian del ejemplo de Sabre; su\n * efecto no está documentado.\n */\nexport function buildRevalidateItineraryRequest(source: RevalidateItineraryRequestSource): RevalidateItineraryRequest {\n const { search, group, itinerary } = source;\n const flights = itineraryFlights(group, itinerary);\n\n const originDestinations = itinerary.legs.map((_leg, i): LowFareSearchOriginDestination => {\n const legFlights = flights.filter((f) => f.legIndex === i).map(flight);\n const first = legFlights[0]!;\n const last = legFlights.at(-1)!;\n return {\n Fixed: false,\n DepartureDateTime: first.DepartureDateTime,\n OriginLocation: { LocationCode: first.OriginLocation.LocationCode },\n DestinationLocation: { LocationCode: last.DestinationLocation.LocationCode },\n TPA_Extensions: { Flight: legFlights },\n };\n });\n\n const { Version, POS, TravelerInfoSummary, TPA_Extensions } = search.OTA_AirLowFareSearchRQ;\n return {\n OTA_AirLowFareSearchRQ: {\n Version,\n POS,\n OriginDestinationInformation: originDestinations,\n TravelPreferences: {\n MaxStopsQuantity: Math.max(...itinerary.legs.map((leg) => leg.schedules.length - 1)),\n TPA_Extensions: { VerificationItinCallLogic: { Value: 'L' } },\n },\n TravelerInfoSummary,\n ...(TPA_Extensions === undefined ? {} : { TPA_Extensions }),\n },\n };\n}\n\nfunction flight({ schedule, departureDate, arrivalDate, bookingCode }: ItineraryFlight): LowFareSearchFlight {\n const { carrier } = schedule;\n return {\n Type: 'A',\n Number: carrier.marketingFlightNumber,\n DepartureDateTime: `${departureDate}T${localTime(schedule.departure.time)}`,\n ArrivalDateTime: `${arrivalDate}T${localTime(schedule.arrival.time)}`,\n ClassOfService: bookingCode,\n OriginLocation: { LocationCode: schedule.departure.airport },\n DestinationLocation: { LocationCode: schedule.arrival.airport },\n Airline: {\n Marketing: carrier.marketing,\n ...(carrier.operating === undefined ? {} : { Operating: carrier.operating }),\n },\n };\n}\n\n/** `17:10:00+02:00` → `17:10:00`. */\nfunction localTime(time: string): string {\n return time.slice(0, 8);\n}\n","// Módulo de dominio `sabre.air`. Ver sabre-wiki/wiki/sdk/convenciones-de-nombres-y-versionado.md.\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n bargainFinderMax,\n type BargainFinderMaxRequest,\n type BargainFinderMaxResponse,\n type RequestOptions,\n} from './bargain-finder-max.js';\nimport {\n revalidateItinerary,\n type RevalidateItineraryRequest,\n type RevalidateItineraryResponse,\n} from './revalidate-itinerary.js';\n\nexport class Air {\n readonly #transport: RestTransport;\n\n /** @internal Lo construye el cliente `Sabre`. */\n constructor(transport: RestTransport) {\n this.#transport = transport;\n }\n\n /**\n * Bargain Finder Max v5: busca itinerarios de menor precio. Devuelve el\n * `groupedItineraryResponse` con las referencias ya resueltas.\n */\n bargainFinderMax(request: BargainFinderMaxRequest, options?: RequestOptions): Promise<BargainFinderMaxResponse> {\n return bargainFinderMax(this.#transport, request, options);\n }\n\n /**\n * Revalidate Itinerary v5: revalida disponibilidad y precio de un itinerario ya elegido,\n * sin sostener inventario. El request se arma con `buildRevalidateItineraryRequest`.\n */\n revalidateItinerary(\n request: RevalidateItineraryRequest,\n options?: RequestOptions,\n ): Promise<RevalidateItineraryResponse> {\n return revalidateItinerary(this.#transport, request, options);\n }\n}\n","// Redacción obligatoria antes de que cualquier dato llegue al logger.\n// Ver sabre-wiki/wiki/sdk/configuracion-logging-y-build.md.\n\nexport const REDACTED = '[REDACTED]';\n\n/**\n * Claves cuyo valor se enmascara completo, comparadas sin distinguir mayúsculas\n * ni separadores (`client_secret`, `Client-Secret` y `clientSecret` son la misma).\n */\nconst SENSITIVE_KEYS = new Set(\n [\n // Credenciales\n 'clientSecret',\n 'password',\n 'username',\n 'authorization',\n 'binarySecurityToken',\n 'accessToken',\n 'refreshToken',\n 'token',\n // Datos de pasajero\n 'travelers',\n 'passengers',\n ].map(normalizeKey),\n);\n\nfunction normalizeKey(key: string): string {\n return key.replace(/[-_\\s]/g, '').toLowerCase();\n}\n\nexport function isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEYS.has(normalizeKey(key));\n}\n\n/** Copia profunda de `value` con los campos sensibles enmascarados. No muta la entrada. */\nexport function redact(value: unknown): unknown {\n return redactValue(value, new WeakSet());\n}\n\nfunction redactValue(value: unknown, seen: WeakSet<object>): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n\n if (Array.isArray(value)) return value.map((item) => redactValue(item, seen));\n if (value instanceof Headers) return redactEntries(value.entries(), seen);\n if (value instanceof Date) return value.toISOString();\n if (value instanceof Error) {\n // Los errores del SDK definen toJSON sin `raw`; para el resto, solo nombre y mensaje.\n const json = 'toJSON' in value && typeof value.toJSON === 'function' ? value.toJSON() : undefined;\n return redactValue(json ?? { name: value.name, message: value.message }, seen);\n }\n return redactEntries(Object.entries(value), seen);\n}\n\nfunction redactEntries(entries: Iterable<[string, unknown]>, seen: WeakSet<object>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, item] of entries) {\n out[key] = isSensitiveKey(key) ? REDACTED : redactValue(item, seen);\n }\n return out;\n}\n","// Logger inyectable. Ver sabre-wiki/wiki/sdk/configuracion-logging-y-build.md.\nimport { redact } from './redact.js';\n\n/**\n * Interfaz mínima de logger, compatible con `winston` y `console`.\n * Con `pino`, que invierte el orden: `info: (m, c) => pino.info(c, m)`.\n */\nexport interface SabreLogger {\n debug(message: string, context?: Record<string, unknown>): void;\n info(message: string, context?: Record<string, unknown>): void;\n warn(message: string, context?: Record<string, unknown>): void;\n error(message: string, context?: Record<string, unknown>): void;\n}\n\nexport type SabreLogLevel = keyof SabreLogger;\n\n/** Eventos estables que emite el SDK como `message`. */\nexport type SabreLogEvent =\n | 'sabre.request.start'\n | 'sabre.request.end'\n | 'sabre.request.retry'\n | 'sabre.auth.token.refresh'\n | 'sabre.auth.token.store';\n\n/** Logger interno: redacta siempre el contexto y no hace nada si no hay logger. */\nexport class EventLogger {\n readonly #logger: SabreLogger | undefined;\n\n constructor(logger?: SabreLogger) {\n this.#logger = logger;\n }\n\n emit(level: SabreLogLevel, event: SabreLogEvent, context: Record<string, unknown> = {}): void {\n if (this.#logger === undefined) return;\n try {\n this.#logger[level](event, redact(context) as Record<string, unknown>);\n } catch {\n // Un logger que falla no debe romper la request en curso.\n }\n }\n}\n","// Armado de la request de OAuth Token Create, una estrategia por versión.\n// Ver sabre-wiki/wiki/entities/oauth-token-create.md: v2 y v3 no son intercambiables.\nimport type { SabreAuthVersion, SabreCredentials, SabreCredentialsV2 } from '../config.js';\n\nexport interface TokenRequest {\n path: string;\n /** Valor del header `Authorization` (`Basic ...`). */\n authorization: string;\n body: URLSearchParams;\n}\n\n/** v3: `Basic base64(clientId:clientSecret)` y el EPR en el body con `grant_type=password`. */\nexport function buildTokenRequestV3(credentials: SabreCredentials): TokenRequest {\n return {\n path: '/v3/auth/token',\n authorization: `Basic ${base64(`${credentials.clientId}:${credentials.clientSecret}`)}`,\n body: new URLSearchParams({\n grant_type: 'password',\n username: credentials.username,\n password: credentials.password,\n }),\n };\n}\n\n/** v2: doble Base64 sobre el EPR y su password, con `grant_type=client_credentials`. */\nexport function buildTokenRequestV2(credentials: SabreCredentialsV2): TokenRequest {\n return {\n path: '/v2/auth/token',\n authorization: `Basic ${base64(`${base64(credentials.username)}:${base64(credentials.password)}`)}`,\n body: new URLSearchParams({ grant_type: 'client_credentials' }),\n };\n}\n\nexport function buildTokenRequest(\n authVersion: SabreAuthVersion,\n credentials: SabreCredentials | SabreCredentialsV2,\n): TokenRequest {\n // `resolveConfig` ya exige clientId/clientSecret cuando la versión es v3.\n return authVersion === 'v3'\n ? buildTokenRequestV3(credentials as SabreCredentials)\n : buildTokenRequestV2(credentials);\n}\n\n/** Base64 de los bytes UTF-8 de `text`, solo con Web APIs (sin `Buffer`). */\nexport function base64(text: string): string {\n let binary = '';\n for (const byte of new TextEncoder().encode(text)) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n","// Almacén de token inyectable por el consumidor. Ver sabre-wiki/wiki/sdk/renovacion-token-oauth.md,\n// sección \"Decisiones de la Fase 4\" (decisión B).\nimport type { SabreAuthVersion, SabreCredentials, SabreCredentialsV2, SabreEnvironment } from '../config.js';\n\n/** Token ATK tal cual se guarda: tiempos absolutos, para que otro proceso sepa cuánto le queda. */\nexport interface StoredToken {\n accessToken: string;\n /** Momento de obtención, en ms desde epoch. */\n obtainedAt: number;\n /** Momento de expiración, en ms desde epoch. */\n expiresAt: number;\n}\n\n/**\n * Almacén de token del consumidor (archivo, Redis, KV…). El SDK no trae implementaciones.\n *\n * `key` identifica la configuración (entorno, versión de OAuth y credencial, sin secretos):\n * un mismo store puede servir a varios clientes sin mezclar sus tokens. El token es un\n * secreto: protegerlo dentro del store es responsabilidad del consumidor.\n *\n * Si `get` o `set` lanzan, el SDK sigue con su caché en memoria: el store nunca rompe una llamada.\n */\nexport interface SabreTokenStore {\n get(key: string): Promise<StoredToken | undefined>;\n set(key: string, token: StoredToken): Promise<void>;\n}\n\n/**\n * `sabre-client:<environment>:<authVersion>:<hash>`, donde `hash` son los primeros 16 bytes\n * en hex del SHA-256 del username EPR (y del clientId en v3). No contiene secretos.\n */\nexport async function tokenStoreKey(\n environment: SabreEnvironment,\n authVersion: SabreAuthVersion,\n credentials: Readonly<SabreCredentials | SabreCredentialsV2>,\n): Promise<string> {\n const identity = authVersion === 'v3' ? `${credentials.clientId}\\n${credentials.username}` : credentials.username;\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(identity));\n const hash = [...new Uint8Array(digest).slice(0, 16)].map((byte) => byte.toString(16).padStart(2, '0')).join('');\n return `sabre-client:${environment}:${authVersion}:${hash}`;\n}\n\n/** Un valor de `get` que no tenga la forma de `StoredToken` se ignora. */\nexport function isStoredToken(value: unknown): value is StoredToken {\n if (typeof value !== 'object' || value === null) return false;\n const { accessToken, obtainedAt, expiresAt } = value as Record<string, unknown>;\n return (\n typeof accessToken === 'string' &&\n accessToken !== '' &&\n typeof obtainedAt === 'number' &&\n typeof expiresAt === 'number' &&\n Number.isFinite(obtainedAt) &&\n expiresAt > obtainedAt\n );\n}\n","// Obtención del token ATK de OAuth Token Create.\n// Ver sabre-wiki/wiki/sdk/renovacion-token-oauth.md y wiki/entities/oauth-token-create.md.\nimport type { ResolvedConfig } from '../config.js';\nimport { SabreGatewayError } from '../errors/index.js';\nimport type { AuthorizationProvider, RestTransport } from '../http/rest-transport.js';\nimport { EventLogger } from '../logging/logger.js';\nimport { buildTokenRequest } from './token-request.js';\nimport { isStoredToken, type SabreTokenStore, type StoredToken, tokenStoreKey } from './token-store.js';\n\nexport const TOKEN_SERVICE = 'oauthTokenCreate';\n\n/** Margen de refresco proactivo: 1 h antes de expirar (o media vida si el token dura menos). */\nexport const REFRESH_THRESHOLD_S = 3600;\n\nexport type TokenRefreshReason = 'initial' | 'proactive' | 'reactive';\n\n/** Token ATK obtenido de OAuth Token Create. */\nexport interface AccessToken {\n accessToken: string;\n /** Vida del token en segundos, tal cual llega en `expires_in`. */\n expiresIn: number;\n /** Momento de obtención, en ms desde epoch. */\n obtainedAt: number;\n}\n\ninterface TokenResponse {\n access_token?: unknown;\n expires_in?: unknown;\n token_type?: unknown;\n}\n\nexport interface AuthManagerOptions {\n /** Solo para tests: reloj en ms. */\n now?: () => number;\n}\n\n/**\n * Cachea el token en memoria (y en `tokenStore`, si lo hay), lo renueva antes de que expire\n * y comparte una sola petición en vuelo entre requests concurrentes. Interno en v0.3.0.\n */\nexport class AuthManager {\n readonly #config: ResolvedConfig;\n readonly #transport: RestTransport;\n readonly #now: () => number;\n readonly #log: EventLogger;\n #token: AccessToken | undefined;\n #inFlight: Promise<AccessToken> | undefined;\n /** El último token cacheado fue rechazado con 401 (el próximo refresco es reactivo). */\n #invalidated = false;\n /** Token rechazado con 401: si el store todavía lo tiene, no se vuelve a usar. */\n #rejected: string | undefined;\n readonly #store: SabreTokenStore | undefined;\n #storeKey: Promise<string> | undefined;\n\n constructor(config: ResolvedConfig, transport: RestTransport, options: AuthManagerOptions = {}) {\n this.#config = config;\n this.#transport = transport;\n this.#now = options.now ?? Date.now;\n this.#log = new EventLogger(config.logger);\n this.#store = config.tokenStore;\n }\n\n /** Token vigente; pide uno nuevo si no hay o si cruzó el umbral de refresco. */\n async getToken(): Promise<string> {\n const token = this.#token;\n if (token !== undefined && !this.#needsRefresh(token)) return token.accessToken;\n const reason = token !== undefined ? 'proactive' : this.#invalidated ? 'reactive' : 'initial';\n return (await this.#refresh(reason)).accessToken;\n }\n\n /**\n * Descarta `accessToken` tras un 401 de un servicio. Si el caché ya tiene otro token\n * (otra request lo renovó), no hace nada: los 401 concurrentes comparten un refresco.\n */\n invalidate(accessToken: string): void {\n if (this.#token?.accessToken !== accessToken) return;\n this.#token = undefined;\n this.#invalidated = true;\n this.#rejected = accessToken;\n }\n\n /** Adaptador de salida para el transporte REST: `Authorization: Bearer <token>`. */\n bearerProvider(): AuthorizationProvider {\n return {\n get: async () => `Bearer ${await this.getToken()}`,\n invalidate: (authorization) => this.invalidate(authorization.replace(/^Bearer /, '')),\n };\n }\n\n #needsRefresh(token: AccessToken): boolean {\n const thresholdMs = Math.min(REFRESH_THRESHOLD_S, token.expiresIn / 2) * 1000;\n return this.#now() >= token.obtainedAt + token.expiresIn * 1000 - thresholdMs;\n }\n\n /** Una sola petición en vuelo: las llamadas concurrentes esperan la misma promesa. */\n #refresh(reason: TokenRefreshReason): Promise<AccessToken> {\n this.#inFlight ??= this.#obtain(reason).finally(() => {\n this.#inFlight = undefined;\n });\n return this.#inFlight;\n }\n\n /** Token del store si sigue vigente (otro proceso pudo renovarlo); si no, uno nuevo. */\n async #obtain(reason: TokenRefreshReason): Promise<AccessToken> {\n const stored = await this.#readStore();\n if (stored !== undefined && stored.accessToken !== this.#rejected && !this.#needsRefresh(stored)) {\n this.#token = stored;\n this.#invalidated = false;\n return stored;\n }\n\n const token = await this.fetchToken();\n this.#token = token;\n this.#invalidated = false;\n this.#rejected = undefined;\n this.#log.emit('info', 'sabre.auth.token.refresh', {\n authVersion: this.#config.authVersion,\n reason,\n expiresIn: token.expiresIn,\n });\n await this.#writeStore(token);\n return token;\n }\n\n async #readStore(): Promise<AccessToken | undefined> {\n if (this.#store === undefined) return undefined;\n try {\n const value = await this.#store.get(await this.#key());\n if (!isStoredToken(value)) return undefined;\n return {\n accessToken: value.accessToken,\n expiresIn: (value.expiresAt - value.obtainedAt) / 1000,\n obtainedAt: value.obtainedAt,\n };\n } catch (error) {\n this.#storeFailed('get', error);\n return undefined;\n }\n }\n\n async #writeStore(token: AccessToken): Promise<void> {\n if (this.#store === undefined) return;\n const stored: StoredToken = {\n accessToken: token.accessToken,\n obtainedAt: token.obtainedAt,\n expiresAt: token.obtainedAt + token.expiresIn * 1000,\n };\n try {\n await this.#store.set(await this.#key(), stored);\n } catch (error) {\n this.#storeFailed('set', error);\n }\n }\n\n #key(): Promise<string> {\n const { environment, authVersion, credentials } = this.#config;\n this.#storeKey ??= tokenStoreKey(environment, authVersion, credentials);\n return this.#storeKey;\n }\n\n /**\n * El store nunca rompe la llamada: se sigue con el caché en memoria. Del error solo se\n * loguea el nombre: el mensaje lo arma el store del consumidor y podría traer el token.\n */\n #storeFailed(operation: 'get' | 'set', error: unknown): void {\n this.#log.emit('warn', 'sabre.auth.token.store', {\n authVersion: this.#config.authVersion,\n operation,\n errorName: error instanceof Error ? error.name : typeof error,\n });\n }\n\n /**\n * Pide un token nuevo. Los errores del endpoint (`invalid_request`/`invalid_client` 401,\n * `unauthorized` 403) salen como `SabreGatewayError` con `retryable: false`.\n */\n async fetchToken(): Promise<AccessToken> {\n const { path, authorization, body } = buildTokenRequest(this.#config.authVersion, this.#config.credentials);\n const response = await this.#transport.request<TokenResponse | undefined>({\n method: 'POST',\n path,\n service: TOKEN_SERVICE,\n // Pedir otro token no tiene efectos duplicados: 429/5xx entran en la política genérica.\n idempotent: true,\n auth: false,\n headers: { Authorization: authorization },\n body,\n });\n return this.#parse(response);\n }\n\n #parse(response: TokenResponse | undefined): AccessToken {\n const accessToken = response?.access_token;\n const expiresIn = response?.expires_in;\n if (typeof accessToken !== 'string' || accessToken === '' || typeof expiresIn !== 'number' || !(expiresIn > 0)) {\n throw new SabreGatewayError(`${TOKEN_SERVICE}: respuesta sin access_token/expires_in válidos`, {\n protocol: 'rest',\n status: 200,\n retryable: false,\n raw: response,\n });\n }\n return { accessToken, expiresIn, obtainedAt: this.#now() };\n }\n}\n","// `errors[]` de la Booking Management API: mismo `Error` del spec en Create, Get y Cancel.\n// Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md.\nimport { SabreBusinessError, SabreWarning } from '../errors/index.js';\n\nconst WARNING = 'WARNING';\n\n/** Elemento de `errors[]` tal cual lo manda Sabre (`Error` del spec; los avisos comparten forma). */\nexport interface BookingResponseError {\n /** `BAD_REQUEST`, `APPLICATION_ERROR`, `WARNING`, … */\n category: string;\n /** P. ej. `UNABLE_TO_BOOK_FLIGHTS`. */\n type: string;\n description?: string;\n fieldPath?: string;\n fieldName?: string;\n /** Puede traer datos del request (p. ej. un email): no se copia a los errores del SDK. */\n fieldValue?: string;\n}\n\nexport function responseErrors(response: { errors?: BookingResponseError[] }): BookingResponseError[] {\n return Array.isArray(response.errors) ? response.errors.filter(isObject) as BookingResponseError[] : [];\n}\n\nexport function isWarning(item: BookingResponseError): boolean {\n return typeof item.category === 'string' && item.category.toUpperCase() === WARNING;\n}\n\nexport function toWarning(service: string, item: BookingResponseError): SabreWarning {\n return new SabreWarning(messageOf(service, item), { service, code: codeOf(item), raw: item });\n}\n\nexport interface BusinessErrorAttachments {\n warnings?: SabreWarning[];\n errors?: SabreBusinessError[];\n retryable?: boolean;\n}\n\nexport function toBusinessError(\n service: string,\n item: BookingResponseError,\n { warnings = [], errors = [], retryable = false }: BusinessErrorAttachments = {},\n): SabreBusinessError {\n return new SabreBusinessError(messageOf(service, item), {\n service,\n code: codeOf(item),\n raw: item,\n warnings,\n errors,\n retryable,\n });\n}\n\nexport function codeOf(item: BookingResponseError): string {\n return typeof item.type === 'string' && item.type !== '' ? item.type : String(item.category);\n}\n\n/** Sin `fieldValue`, que puede traer datos del pasajero; queda en `raw`. */\nfunction messageOf(service: string, item: BookingResponseError): string {\n const where = typeof item.fieldPath === 'string' && item.fieldPath !== '' ? ` en ${item.fieldPath}` : '';\n const description = typeof item.description === 'string' && item.description !== '' ? `: ${item.description}` : '';\n return `${service}: ${String(item.category)} ${codeOf(item)}${where}${description}`;\n}\n\nexport function nonEmpty(value: unknown): value is string {\n return typeof value === 'string' && value !== '';\n}\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","// Cancel Booking (`POST /v1/trip/orders/cancelBooking`).\n// Ver sabre-wiki/wiki/sdk/gestion-de-reserva.md y sabre-wiki/wiki/sources/cancel-booking.md.\nimport { SabreError, type SabreWarning } from '../errors/index.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n type BookingResponseError,\n isObject,\n isWarning,\n nonEmpty,\n responseErrors,\n toBusinessError,\n toWarning,\n} from './booking-errors.js';\nimport type { Booking } from './create-booking.js';\nimport type { BookingSource } from './get-booking.js';\n\nexport const CANCEL_BOOKING_SERVICE = 'cancelBooking';\nconst PATH = '/v1/trip/orders/cancelBooking';\n/** Llega con `category: WARNING`, pero significa que no se canceló nada (decidido en #39). */\nconst NO_ITEMS_CANCELLED = 'NO_ITEMS_CANCELLED';\nconst ITEM_LISTS = ['flights', 'hotels', 'cars', 'trains', 'cruises', 'segments'] as const;\n\n/** `HALT_ON_ERROR` (default de Sabre, con rollback) o `ALLOW_PARTIAL_CANCEL`. */\nexport type CancelBookingErrorPolicy = 'HALT_ON_ERROR' | 'ALLOW_PARTIAL_CANCEL';\n\nexport type FlightTicketOperation = 'VOID' | 'REFUND';\n\nexport type RefundDocumentsType = 'Tickets' | 'EMDs' | 'Tickets and EMDs';\n\n/** Producto a cancelar, por el `itemId` que devuelve Get Booking (p. ej. `flights[].itemId`). */\nexport interface BookingItemReference {\n itemId: string;\n}\n\n/**\n * Segmento a cancelar, por `id` o por `sequence`. Sabre desaconseja `sequence`: la posición\n * puede cambiar entre la lectura y la cancelación.\n */\nexport interface CancelSegmentReference {\n id?: string;\n sequence?: number;\n}\n\n/** `Notification` del spec: `email` o `queuePlacement`, no los dos. Se envía tal cual. */\nexport interface CancelBookingNotification {\n email?: 'DEFAULT' | 'INVOICE' | 'ETICKET' | 'ETICKET_PDF' | 'ITINERARY' | 'ITINERARY_PDF';\n queuePlacement?: Array<Record<string, unknown>>;\n}\n\n/**\n * `CancelBookingRequest` del spec v1.33. El Tier 1 usa `cancelAll` o `flights[].itemId` sobre\n * contenido ATPCO; los campos de tickets, NDC, impresoras, notificación y retención se envían\n * tal cual, sin lógica propia.\n */\nexport interface CancelBookingRequest {\n /** Localizador del PNR u Order ID (`^[A-Z0-9]{6,}$`). Único campo obligatorio. */\n confirmationId: string;\n bookingSource?: BookingSource;\n /** Cancela todos los segmentos. No se combina con las listas. */\n cancelAll?: boolean;\n flights?: BookingItemReference[];\n hotels?: BookingItemReference[];\n cars?: BookingItemReference[];\n trains?: BookingItemReference[];\n cruises?: BookingItemReference[];\n segments?: CancelSegmentReference[];\n /** Sin valor, Sabre aplica `HALT_ON_ERROR`: si algo falla, deshace lo ya cancelado. */\n errorHandlingPolicy?: CancelBookingErrorPolicy;\n /** Si es `true`, la respuesta trae el estado posterior en `booking`. */\n retrieveBooking?: boolean;\n /** Firma del cambio en el PNR. Sabre usa `LW CANCEL API` por defecto. */\n receivedFrom?: string;\n /** El contexto no se revierte al terminar. */\n targetPcc?: string;\n /** No se combina con `offerItemId`. */\n flightTicketOperation?: FlightTicketOperation;\n /** Solo NDC. No se combina con `flightTicketOperation`. */\n offerItemId?: string;\n notification?: CancelBookingNotification;\n designatePrinters?: Array<Record<string, unknown>>;\n retentionEndDate?: string;\n retentionLabel?: string;\n voidNonElectronicTickets?: boolean;\n refundDocumentsType?: RefundDocumentsType;\n}\n\nexport interface CancelBookingOptions {\n signal?: AbortSignal;\n}\n\n/** `CancelBookingResponse` tal cual llega de Sabre. */\nexport interface RawCancelBookingResponse {\n timestamp?: string;\n request?: CancelBookingRequest;\n booking?: Booking;\n tickets?: Array<Record<string, unknown>>;\n voidedTickets?: string[];\n refundedTickets?: string[];\n flightRefunds?: Array<Record<string, unknown>>;\n errors?: BookingResponseError[];\n}\n\n/** Cancelación con éxito: sin errores fatales y sin `NO_ITEMS_CANCELLED`. */\nexport interface CancelBookingResponse {\n timestamp?: string;\n /** Eco del request con los defaults de Sabre completados. */\n request?: CancelBookingRequest;\n /** Estado posterior de la reserva, anidado (solo con `retrieveBooking: true`). */\n booking?: Booking;\n tickets?: Array<Record<string, unknown>>;\n voidedTickets?: string[];\n refundedTickets?: string[];\n flightRefunds?: Array<Record<string, unknown>>;\n /**\n * Elementos de `errors[]` con `category: WARNING`. Con `END_TRANSACTION_PROBLEM` la\n * confirmación quedó pendiente: verifica el resultado con `sabre.booking.get`.\n */\n warnings: SabreWarning[];\n}\n\n/**\n * Cancel Booking: escritura sin reintento automático. Solo el reintento reactivo ante 401,\n * que el gateway rechaza antes de llegar al proveedor.\n */\nexport async function cancelBooking(\n transport: RestTransport,\n request: CancelBookingRequest,\n options: CancelBookingOptions = {},\n): Promise<CancelBookingResponse> {\n validateCancelBookingRequest(request);\n const body = await transport.request<RawCancelBookingResponse>({\n method: 'POST',\n path: PATH,\n service: CANCEL_BOOKING_SERVICE,\n idempotent: false,\n body: request,\n classify: classifyCancelBooking,\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n });\n return toCancelBookingResponse(body);\n}\n\n/** Combinaciones que Sabre rechaza seguro (`INVALID_FLAGS_COMBINATION`, `CANCEL_DATA_MISSING`). */\nfunction validateCancelBookingRequest(request: CancelBookingRequest): void {\n if (!isObject(request) || !nonEmpty(request.confirmationId)) {\n throw new TypeError('sabre-client: booking.cancel espera { confirmationId: string, ... }');\n }\n const lists = ITEM_LISTS.join(', ');\n if (request.cancelAll === true) {\n if (ITEM_LISTS.some((list) => request[list] !== undefined)) {\n throw new TypeError(`sabre-client: booking.cancel no combina cancelAll con listas (${lists})`);\n }\n } else if (!ITEM_LISTS.some((list) => Array.isArray(request[list]) && request[list].length > 0)) {\n throw new TypeError(`sabre-client: booking.cancel necesita cancelAll: true o al menos una lista (${lists})`);\n }\n if (request.offerItemId !== undefined && request.flightTicketOperation !== undefined) {\n throw new TypeError('sabre-client: booking.cancel no combina offerItemId con flightTicketOperation');\n }\n}\n\n/**\n * Paso 3 del orden de detección. Éxito = ningún error que no sea `WARNING` y ningún\n * `NO_ITEMS_CANCELLED`. Si no:\n *\n * - Con `NO_ITEMS_CANCELLED`: `SabreBusinessError` con ese código; los errores que explican\n * el fallo van en `errors` y los demás avisos en `warnings`.\n * - Sin él: `SabreBusinessError` con el primer error que no sea `WARNING`, el resto en\n * `errors` y los avisos en `warnings`.\n */\nexport function classifyCancelBooking(body: unknown): SabreError | undefined {\n if (!isObject(body)) {\n return new SabreError(`${CANCEL_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {\n retryable: false,\n raw: body,\n });\n }\n const items = responseErrors(body as RawCancelBookingResponse);\n const nothingCancelled = items.find(isNoItemsCancelled);\n const warnings = items.filter((item) => isWarning(item) && !isNoItemsCancelled(item)).map(warningOf);\n const fatal = items.filter((item) => !isWarning(item));\n\n if (nothingCancelled !== undefined) {\n return toBusinessError(CANCEL_BOOKING_SERVICE, nothingCancelled, { warnings, errors: fatal.map(errorOf) });\n }\n const [first, ...rest] = fatal;\n if (first === undefined) return undefined;\n return toBusinessError(CANCEL_BOOKING_SERVICE, first, { warnings, errors: rest.map(errorOf) });\n}\n\n/** Solo para respuestas con éxito (ver `classifyCancelBooking`): `errors[]` trae solo avisos. */\nfunction toCancelBookingResponse(body: RawCancelBookingResponse): CancelBookingResponse {\n const { errors: _errors, ...rest } = body;\n return { ...rest, warnings: responseErrors(body).map(warningOf) };\n}\n\nfunction isNoItemsCancelled(item: BookingResponseError): boolean {\n return item.type === NO_ITEMS_CANCELLED;\n}\n\nfunction warningOf(item: BookingResponseError): SabreWarning {\n return toWarning(CANCEL_BOOKING_SERVICE, item);\n}\n\nfunction errorOf(item: BookingResponseError) {\n return toBusinessError(CANCEL_BOOKING_SERVICE, item);\n}\n","// Create Booking (`POST /v1/trip/orders/createBooking`).\n// Ver sabre-wiki/wiki/entities/booking-management-api.md y\n// sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md (éxito parcial de Create Booking).\nimport { type SabreBusinessError, SabreError, type SabreWarning } from '../errors/index.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n type BookingResponseError,\n isObject,\n isWarning,\n nonEmpty,\n responseErrors,\n toBusinessError,\n toWarning,\n} from './booking-errors.js';\nimport type { CreateBookingRequest } from './create-booking-request.js';\n\nexport const CREATE_BOOKING_SERVICE = 'createBooking';\nconst PATH = '/v1/trip/orders/createBooking';\n/** Aviso cuyo `description` trae el `confirmationId` de una reserva que sí se creó. */\nconst UNABLE_TO_RETRIEVE_BOOKING = 'UNABLE_TO_RETRIEVE_BOOKING';\n\nexport interface CreateBookingOptions {\n signal?: AbortSignal;\n}\n\n/** Elemento de `errors[]` de Create Booking. */\nexport type CreateBookingResponseError = BookingResponseError;\n\n/**\n * `Booking` del spec (mismo modelo que Get Booking). Se tipa el primer nivel; el detalle de\n * `flights`, `travelers`, `fares`, etc. queda sin tipar en el Tier 1.\n */\nexport interface Booking {\n bookingId?: string;\n startDate?: string;\n endDate?: string;\n isCancelable?: boolean;\n isTicketed?: boolean;\n [field: string]: unknown;\n}\n\n/** `CreateBookingResponse` tal cual llega de Sabre. */\nexport interface RawCreateBookingResponse {\n timestamp?: string;\n confirmationId?: string;\n booking?: Booking;\n errors?: CreateBookingResponseError[];\n request?: CreateBookingRequest;\n}\n\n/**\n * Reserva creada. Si Sabre la creó con avisos o con errores no fatales (p. ej. con\n * `errorHandlingPolicy: DO_NOT_HALT_ON_*`), no se lanza: van adjuntos aquí.\n */\nexport interface CreateBookingResponse {\n /** Localizador del PNR. */\n confirmationId: string;\n timestamp?: string;\n /** Falta, p. ej., con el aviso `UNABLE_TO_RETRIEVE_BOOKING`. */\n booking?: Booking;\n /** Copia del request enviado, si Sabre la devuelve. */\n request?: CreateBookingRequest;\n /** Elementos de `errors[]` con `category: WARNING`. */\n warnings: SabreWarning[];\n /** Elementos de `errors[]` de otras categorías que no impidieron crear la reserva. */\n errors: SabreBusinessError[];\n}\n\n/**\n * Create Booking: escritura no idempotente, sin reintento automático. Solo el reintento\n * reactivo ante 401, que el gateway rechaza antes de llegar al proveedor.\n */\nexport async function createBooking(\n transport: RestTransport,\n request: CreateBookingRequest,\n options: CreateBookingOptions = {},\n): Promise<CreateBookingResponse> {\n if (typeof request !== 'object' || request === null) {\n throw new TypeError('sabre-client: booking.create espera un objeto CreateBookingRequest');\n }\n const body = await transport.request<RawCreateBookingResponse>({\n method: 'POST',\n path: PATH,\n service: CREATE_BOOKING_SERVICE,\n idempotent: false,\n body: request,\n classify: classifyCreateBooking,\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n });\n return toCreateBookingResponse(body);\n}\n\n/**\n * Paso 3 del orden de detección. Lo que decide si se lanza es si la reserva se creó, no la\n * categoría de `errors[]`:\n *\n * - Hay reserva (`confirmationId`, `booking.bookingId` o el aviso `UNABLE_TO_RETRIEVE_BOOKING`\n * con el localizador en el `description`): no hay error, `toCreateBookingResponse` adjunta\n * avisos y errores al resultado.\n * - No hay reserva: `SabreBusinessError` con el primer error que no sea `WARNING`, y los\n * avisos adjuntos.\n */\nexport function classifyCreateBooking(body: unknown): SabreError | undefined {\n if (!isObject(body)) {\n return new SabreError(`${CREATE_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {\n retryable: false,\n raw: body,\n });\n }\n const response = body as RawCreateBookingResponse;\n if (confirmationIdOf(response) !== undefined) return undefined;\n\n // La reserva existe pero no hay localizador que devolver: no es un \"no se creó\".\n if (reservationWithoutId(response)) {\n return new SabreError(\n `${CREATE_BOOKING_SERVICE}: Sabre indica que la reserva se creó, pero no devolvió su confirmationId`,\n { retryable: false, raw: body },\n );\n }\n const items = responseErrors(response);\n const fatal = items.find((item) => !isWarning(item));\n if (fatal !== undefined) return toBusinessError(CREATE_BOOKING_SERVICE, fatal, { warnings: items.filter(isWarning).map(warningOf) });\n return new SabreError(`${CREATE_BOOKING_SERVICE}: respuesta malformada, sin confirmationId ni errores fatales`, {\n retryable: false,\n raw: body,\n });\n}\n\n/** Solo para respuestas con reserva (ver `classifyCreateBooking`). */\nfunction toCreateBookingResponse(body: RawCreateBookingResponse): CreateBookingResponse {\n const items = responseErrors(body);\n return {\n confirmationId: confirmationIdOf(body)!,\n ...(body.timestamp === undefined ? {} : { timestamp: body.timestamp }),\n ...(body.booking === undefined ? {} : { booking: body.booking }),\n ...(body.request === undefined ? {} : { request: body.request }),\n warnings: items.filter(isWarning).map(warningOf),\n errors: items.filter((item) => !isWarning(item)).map((item) => toBusinessError(CREATE_BOOKING_SERVICE, item)),\n };\n}\n\nfunction confirmationIdOf(response: RawCreateBookingResponse): string | undefined {\n if (nonEmpty(response.confirmationId)) return response.confirmationId;\n if (nonEmpty(response.booking?.bookingId)) return response.booking.bookingId;\n const notRetrieved = responseErrors(response).find((item) => item.type === UNABLE_TO_RETRIEVE_BOOKING);\n return notRetrieved === undefined ? undefined : locatorIn(notRetrieved.description);\n}\n\nfunction reservationWithoutId(response: RawCreateBookingResponse): boolean {\n return response.booking !== undefined || responseErrors(response).some((item) => item.type === UNABLE_TO_RETRIEVE_BOOKING);\n}\n\n/**\n * El catálogo documenta el description como `Booking was created successfully but could not\n * be retrieved. (confirmationId)`. Se prefiere el valor entre paréntesis.\n */\nfunction locatorIn(description: string | undefined): string | undefined {\n if (description === undefined) return undefined;\n return /\\(([A-Z0-9]{6,})\\)/.exec(description)?.[1] ?? /\\b([A-Z0-9]{6,})\\b/.exec(description)?.[1];\n}\n\nfunction warningOf(item: BookingResponseError): SabreWarning {\n return toWarning(CREATE_BOOKING_SERVICE, item);\n}\n","// Get Booking (`POST /v1/trip/orders/getBooking`).\n// Ver sabre-wiki/wiki/sdk/gestion-de-reserva.md y sabre-wiki/wiki/sources/get-booking.md.\nimport { type SabreBusinessError, SabreError, type SabreWarning } from '../errors/index.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n type BookingResponseError,\n isObject,\n isWarning,\n nonEmpty,\n responseErrors,\n toBusinessError,\n toWarning,\n} from './booking-errors.js';\nimport type { Booking } from './create-booking.js';\n\nexport const GET_BOOKING_SERVICE = 'getBooking';\nconst PATH = '/v1/trip/orders/getBooking';\n/** Fallos de sistema que Sabre puede resolver al repetir la lectura (decidido en #39). */\nconst RETRYABLE_TYPES = new Set(['INTERNAL_SERVER_TIMEOUT', 'DOWNLINE_SERVICE_FAILURE']);\n\n/** Secciones de la respuesta (`ReturnOnlyEnum`). Además evitan llamadas downline de Sabre. */\nexport type GetBookingReturnOnly =\n | 'FLIGHTS'\n | 'FLIGHT_PENALTY'\n | 'BAGGAGE_POLICY'\n | 'JOURNEYS'\n | 'HOTELS'\n | 'HOTEL_ADDRESS'\n | 'CARS'\n | 'CAR_RENTAL_ADDRESS'\n | 'CAR_RENTAL_PENALTY'\n | 'TRAINS'\n | 'CRUISES'\n | 'ALL_SEGMENTS'\n | 'TRAVELERS'\n | 'TICKETS'\n | 'PAYMENTS'\n | 'PENALTIES'\n | 'REMARKS'\n | 'IS_CANCELABLE'\n | 'IS_TICKETED'\n | 'CONTACT_INFO'\n | 'OTHER_SERVICES'\n | 'SPECIAL_SERVICES'\n | 'FARES'\n | 'CREATION_DETAILS'\n | 'ANCILLARIES'\n | 'FORMS_OF_PAYMENT'\n | 'RETENTION_DATE'\n | 'ACCOUNTING_ITEMS'\n | 'NON_ELECTRONIC_TICKETS'\n | 'TRAVELERS_EMPLOYERS'\n | 'PROFILES';\n\n/** `BookingSourceEnum`. Por defecto `SABRE`. */\nexport type BookingSource = 'SABRE' | 'SABRE_ORDER';\n\n/** `ExtraFeatures` del spec (incluye `CommonExtraFeatures`). */\nexport interface GetBookingExtraFeatures {\n /** Solo NDC. Por defecto `true`. */\n returnEmptySeatObjects?: boolean;\n /** Por defecto `false`; más lento. */\n forceHotelUpdate?: boolean;\n returnFrequentRenter?: boolean;\n returnWalletFormsOfPayment?: boolean;\n returnFiscalId?: boolean;\n}\n\n/** `GetBookingRequest` del spec v1.33. */\nexport interface GetBookingRequest {\n /** Localizador del PNR u Order ID (`^[A-Z0-9]{6,}$`). Único campo obligatorio. */\n confirmationId: string;\n bookingSource?: BookingSource;\n /** Cambio de contexto (`^[A-Z0-9]{3,4}$`). */\n targetPcc?: string;\n /** Validación extra: si no coincide con el PNR, Sabre responde `UNAUTHORIZED_ACCESS`. */\n surname?: string;\n /** Según el spec, Sabre no los usa; solo `surname`. */\n givenName?: string;\n middleName?: string;\n /** Vacío o ausente: la reserva completa. */\n returnOnly?: GetBookingReturnOnly[];\n extraFeatures?: GetBookingExtraFeatures;\n /** Requiere el keyword `CCVIEW` en el EPR. */\n unmaskPaymentCardNumbers?: boolean;\n}\n\nexport interface GetBookingOptions {\n signal?: AbortSignal;\n}\n\n/** `GetBookingResponse` tal cual llega de Sabre: el `Booking` va en el primer nivel. */\nexport interface RawGetBookingResponse extends Booking {\n timestamp?: string;\n bookingSignature?: string;\n request?: GetBookingRequest;\n errors?: BookingResponseError[];\n}\n\n/**\n * Reserva leída, con el `Booking` en el primer nivel tal cual lo define Sabre (no se normaliza\n * contra Create ni Cancel, que lo anidan en `booking`). `errors[]` del original se reemplaza\n * por los errores del SDK.\n */\nexport interface GetBookingResponse extends Booking {\n bookingId: string;\n timestamp?: string;\n /** Solo viene si Sabre armó la reserva sin errores. Lo usa Modify Booking. */\n bookingSignature?: string;\n /** Copia del request enviado, si Sabre la devuelve. */\n request?: GetBookingRequest;\n /**\n * Elementos de `errors[]` con `category: WARNING`. En un PNR sin emitir es normal\n * `RESOURCE_UNAVAILABLE` por falta de fare rules.\n */\n warnings: SabreWarning[];\n /**\n * Elementos de `errors[]` de otras categorías que llegaron junto con la reserva, p. ej.\n * `UNAUTHORIZED_ACCESS` de un servicio downline: faltan secciones, pero la reserva existe.\n */\n errors: SabreBusinessError[];\n}\n\n/**\n * Get Booking: lectura idempotente. Los 429/5xx de gateway se reintentan con la política\n * genérica, y también `INTERNAL_SERVER_TIMEOUT` y `DOWNLINE_SERVICE_FAILURE`.\n */\nexport async function getBooking(\n transport: RestTransport,\n request: GetBookingRequest,\n options: GetBookingOptions = {},\n): Promise<GetBookingResponse> {\n if (!isObject(request) || !nonEmpty(request.confirmationId)) {\n throw new TypeError('sabre-client: booking.get espera { confirmationId: string, ... }');\n }\n const body = await transport.request<RawGetBookingResponse>({\n method: 'POST',\n path: PATH,\n service: GET_BOOKING_SERVICE,\n idempotent: true,\n body: request,\n classify: classifyGetBooking,\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n });\n return toGetBookingResponse(body);\n}\n\n/**\n * Paso 3 del orden de detección. Lo que decide si se lanza es si hay reserva (`bookingId`):\n *\n * - Hay reserva: no hay error; `toGetBookingResponse` adjunta avisos y errores al resultado.\n * - No hay reserva: `SabreBusinessError` con el primer error que no sea `WARNING` (p. ej.\n * `BOOKING_NOT_FOUND` o `UNAUTHORIZED_ACCESS`), y los avisos adjuntos.\n */\nexport function classifyGetBooking(body: unknown): SabreError | undefined {\n if (!isObject(body)) {\n return new SabreError(`${GET_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {\n retryable: false,\n raw: body,\n });\n }\n const response = body as RawGetBookingResponse;\n if (nonEmpty(response.bookingId)) return undefined;\n\n const items = responseErrors(response);\n const fatal = items.find((item) => !isWarning(item));\n if (fatal !== undefined) return errorOf(fatal, items.filter(isWarning).map(warningOf));\n return new SabreError(`${GET_BOOKING_SERVICE}: respuesta malformada, sin bookingId ni errores fatales`, {\n retryable: false,\n raw: body,\n });\n}\n\n/** Solo para respuestas con reserva (ver `classifyGetBooking`). */\nfunction toGetBookingResponse(body: RawGetBookingResponse): GetBookingResponse {\n const items = responseErrors(body);\n return {\n ...body,\n bookingId: body.bookingId!,\n warnings: items.filter(isWarning).map(warningOf),\n errors: items.filter((item) => !isWarning(item)).map((item) => errorOf(item, [])),\n };\n}\n\nfunction warningOf(item: BookingResponseError): SabreWarning {\n return toWarning(GET_BOOKING_SERVICE, item);\n}\n\nfunction errorOf(item: BookingResponseError, warnings: SabreWarning[]): SabreBusinessError {\n return toBusinessError(GET_BOOKING_SERVICE, item, { warnings, retryable: RETRYABLE_TYPES.has(item.type) });\n}\n","// Módulo de dominio `sabre.booking` (Booking Management API).\n// Ver sabre-wiki/wiki/sdk/convenciones-de-nombres-y-versionado.md.\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n cancelBooking,\n type CancelBookingOptions,\n type CancelBookingRequest,\n type CancelBookingResponse,\n} from './cancel-booking.js';\nimport type { CreateBookingRequest } from './create-booking-request.js';\nimport { createBooking, type CreateBookingOptions, type CreateBookingResponse } from './create-booking.js';\nimport { getBooking, type GetBookingOptions, type GetBookingRequest, type GetBookingResponse } from './get-booking.js';\n\nexport class BookingManagement {\n readonly #transport: RestTransport;\n\n /** @internal Lo construye el cliente `Sabre`. */\n constructor(transport: RestTransport) {\n this.#transport = transport;\n }\n\n /**\n * Create Booking: crea la reserva. Para un itinerario de BFM/Revalidate, `flightDetails` se\n * arma con `buildBookingFlightDetails`.\n *\n * Nunca se reintenta automáticamente. Si la reserva se crea con avisos o errores no fatales,\n * no lanza: los devuelve en `warnings` y `errors`. Si no se crea, lanza `SabreBusinessError`.\n */\n create(request: CreateBookingRequest, options?: CreateBookingOptions): Promise<CreateBookingResponse> {\n return createBooking(this.#transport, request, options);\n }\n\n /**\n * Get Booking: lee la reserva por `confirmationId`. El `Booking` va en el primer nivel de la\n * respuesta, a diferencia de `create`. Usa `returnOnly` para pedir solo las secciones que\n * hacen falta: además acelera la respuesta.\n *\n * Si la reserva existe, no lanza: los avisos y errores parciales van en `warnings` y\n * `errors`. Si no existe o no se pudo leer (p. ej. `BOOKING_NOT_FOUND`), lanza\n * `SabreBusinessError`. Es una lectura: se reintenta ante fallos transitorios.\n */\n get(request: GetBookingRequest, options?: GetBookingOptions): Promise<GetBookingResponse> {\n return getBooking(this.#transport, request, options);\n }\n\n /**\n * Cancel Booking: cancela la reserva entera (`cancelAll: true`) o por `itemId` (p. ej. los\n * `flights[].itemId` de `get`). Valida antes de enviar las combinaciones que Sabre rechaza y,\n * si encuentra una, lanza `TypeError` sin llamar a la red.\n *\n * Nunca se reintenta automáticamente. Lanza `SabreBusinessError` si algo falló o si Sabre\n * responde `NO_ITEMS_CANCELLED` (no se canceló nada), aunque llegue como aviso. Con\n * `END_TRANSACTION_PROBLEM` en `warnings`, la confirmación quedó pendiente: verifica con `get`.\n */\n cancel(request: CancelBookingRequest, options?: CancelBookingOptions): Promise<CancelBookingResponse> {\n return cancelBooking(this.#transport, request, options);\n }\n}\n","// Política de reintentos. Ver sabre-wiki/wiki/sdk/politica-de-reintentos-y-backoff.md.\nimport { SabreError } from '../errors/index.js';\n\nexport interface RetryOptions {\n /** Reintentos después de la primera llamada (3 → hasta 4 llamadas en total). */\n maxRetries: number;\n /** Delay base del backoff exponencial, en milisegundos. */\n baseDelayMs: number;\n}\n\nexport const DEFAULT_RETRY: Readonly<RetryOptions> = Object.freeze({ maxRetries: 3, baseDelayMs: 500 });\n\n/** Piso mínimo de espera que documenta Sabre para 429/5xx de gateway. */\nexport const MIN_RETRY_DELAY_MS = 500;\n\n/** Full jitter: aleatorio entre 0 y `baseDelayMs · 2^retry`, con piso de 500 ms. */\nexport function retryDelay(retry: number, baseDelayMs: number, random: () => number = Math.random): number {\n return Math.max(MIN_RETRY_DELAY_MS, Math.floor(random() * baseDelayMs * 2 ** retry));\n}\n\n/** Solo se reintenta un `SabreError` con `retryable: true` en una operación idempotente. */\nexport function shouldRetry(error: unknown, idempotent: boolean): boolean {\n return idempotent && error instanceof SabreError && error.retryable;\n}\n\nexport function validateRetryOptions(retry: Partial<RetryOptions>, where: string): void {\n if (retry.maxRetries !== undefined && !(Number.isInteger(retry.maxRetries) && retry.maxRetries >= 0)) {\n throw new TypeError(`sabre-client: ${where}.maxRetries debe ser un entero >= 0`);\n }\n if (retry.baseDelayMs !== undefined && !(Number.isFinite(retry.baseDelayMs) && retry.baseDelayMs >= 0)) {\n throw new TypeError(`sabre-client: ${where}.baseDelayMs debe ser un número >= 0`);\n }\n}\n","// Config explícita del consumidor; el SDK nunca lee variables de entorno.\n// Ver sabre-wiki/wiki/sdk/configuracion-logging-y-build.md.\nimport type { SabreTokenStore } from './auth/token-store.js';\nimport { DEFAULT_RETRY, type RetryOptions, validateRetryOptions } from './http/retry.js';\nimport type { SabreLogger } from './logging/index.js';\n\nexport type SabreEnvironment = 'sandbox' | 'production';\n\nexport type SabreAuthVersion = 'v3' | 'v2';\n\n/** Credenciales para OAuth Token Create v3: Client ID/Secret más usuario EPR. */\nexport interface SabreCredentials {\n clientId: string;\n clientSecret: string;\n /** Usuario EPR. */\n username: string;\n /** Contraseña EPR. */\n password: string;\n}\n\n/** Credenciales para OAuth Token Create v2: solo EPR; `clientId`/`clientSecret` se ignoran. */\nexport interface SabreCredentialsV2 {\n clientId?: string;\n clientSecret?: string;\n /** Usuario EPR. */\n username: string;\n /** Contraseña EPR. */\n password: string;\n}\n\ninterface SabreBaseConfig {\n environment: SabreEnvironment;\n /** Campo reservado: PCC vs iPCC sigue sin resolver. */\n pcc?: string;\n logger?: SabreLogger;\n /** Reintentos por defecto del cliente; cada request puede pisarlos. */\n retry?: Partial<RetryOptions>;\n /** `fetch` a usar en lugar del global (tests, proxies, runtimes edge). */\n fetch?: typeof fetch;\n /**\n * Almacén del token para reutilizarlo entre procesos (scripts, serverless). Sin él, el\n * token se cachea solo en memoria.\n */\n tokenStore?: SabreTokenStore;\n}\n\n/** OAuth Token Create v3 (por defecto). */\nexport interface SabreConfigV3 extends SabreBaseConfig {\n authVersion?: 'v3';\n credentials: SabreCredentials;\n}\n\n/** OAuth Token Create v2. */\nexport interface SabreConfigV2 extends SabreBaseConfig {\n authVersion: 'v2';\n credentials: SabreCredentialsV2;\n}\n\n/** Config del cliente, discriminada por `authVersion`. */\nexport type SabreConfig = SabreConfigV3 | SabreConfigV2;\n\nexport const BASE_URLS: Readonly<Record<SabreEnvironment, string>> = Object.freeze({\n sandbox: 'https://api.cert.platform.sabre.com',\n production: 'https://api.platform.sabre.com',\n});\n\n/** Config validada y con defaults aplicados. */\nexport interface ResolvedConfig {\n credentials: Readonly<SabreCredentials | SabreCredentialsV2>;\n environment: SabreEnvironment;\n baseUrl: string;\n authVersion: SabreAuthVersion;\n pcc: string | undefined;\n logger: SabreLogger | undefined;\n retry: Readonly<RetryOptions>;\n fetch: typeof fetch;\n tokenStore: SabreTokenStore | undefined;\n}\n\nconst LOGGER_METHODS = ['debug', 'info', 'warn', 'error'] as const;\n\nfunction fail(message: string): never {\n throw new TypeError(`sabre-client: ${message}`);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction requireString(value: unknown, field: string): void {\n if (typeof value !== 'string' || value.trim() === '') fail(`${field} es requerido y debe ser un string no vacío`);\n}\n\nexport function resolveConfig(config: SabreConfig): ResolvedConfig {\n if (!isObject(config)) fail('la config debe ser un objeto');\n\n const { environment } = config;\n if (environment !== 'sandbox' && environment !== 'production') {\n fail(`environment debe ser 'sandbox' o 'production' (recibido: ${JSON.stringify(environment)})`);\n }\n\n const authVersion = config.authVersion ?? 'v3';\n if (authVersion !== 'v3' && authVersion !== 'v2') {\n fail(`authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(authVersion)})`);\n }\n\n const { credentials } = config;\n if (!isObject(credentials)) fail('credentials es requerido');\n requireString(credentials.username, 'credentials.username');\n requireString(credentials.password, 'credentials.password');\n if (authVersion === 'v3') {\n requireString(credentials.clientId, 'credentials.clientId (requerido con authVersion v3)');\n requireString(credentials.clientSecret, 'credentials.clientSecret (requerido con authVersion v3)');\n }\n\n if (config.pcc !== undefined) requireString(config.pcc, 'pcc');\n\n const { logger } = config;\n if (logger !== undefined) {\n if (!isObject(logger)) fail('logger debe ser un objeto con debug/info/warn/error');\n for (const method of LOGGER_METHODS) {\n if (typeof logger[method] !== 'function') fail(`logger.${method} debe ser una función`);\n }\n }\n\n if (config.retry !== undefined) {\n if (!isObject(config.retry)) fail('retry debe ser un objeto');\n validateRetryOptions(config.retry, 'retry');\n }\n\n const { tokenStore } = config;\n if (tokenStore !== undefined) {\n if (!isObject(tokenStore) || typeof tokenStore.get !== 'function' || typeof tokenStore.set !== 'function') {\n fail('tokenStore debe ser un objeto con get(key) y set(key, token)');\n }\n }\n\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') fail('no hay fetch disponible: pasa config.fetch');\n\n return {\n credentials: Object.freeze({ ...credentials }),\n environment,\n baseUrl: BASE_URLS[environment],\n authVersion,\n pcc: config.pcc,\n logger,\n retry: Object.freeze({ ...DEFAULT_RETRY, ...definedOnly(config.retry ?? {}) }),\n // Enlazado al global para evitar \"Illegal invocation\" en algunos runtimes.\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n tokenStore,\n };\n}\n\n/** Quita claves con valor `undefined` para que no pisen los defaults. */\nexport function definedOnly<T extends object>(value: T): Partial<T> {\n return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined)) as Partial<T>;\n}\n","// Transporte REST del cliente `Sabre`: fetch JSON, detección de errores y reintentos.\n// Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md y politica-de-reintentos-y-backoff.md.\nimport { definedOnly, type ResolvedConfig } from '../config.js';\nimport { SabreError, SabreGatewayError } from '../errors/index.js';\nimport { EventLogger } from '../logging/logger.js';\nimport { type RetryOptions, retryDelay, shouldRetry, validateRetryOptions } from './retry.js';\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\n/** Status de gateway REST reintentables (ver errores-comunes-api). */\nconst RETRYABLE_STATUS = new Set([429, 500, 503, 504]);\n\n/**\n * Pasos 2–3 del orden de detección, aportados por cada servicio: recibe el body de una\n * respuesta 2xx y devuelve el error de su catálogo (orquestado, negocio o warning), o\n * `undefined` si la respuesta es data válida.\n */\nexport type ResponseClassifier = (body: unknown, response: Response) => SabreError | undefined;\n\nexport interface RestRequest {\n method: HttpMethod;\n /** Ruta relativa a la base URL, p. ej. `/v5/offers/shop`. */\n path: string;\n /** Nombre del servicio para errores y logs, p. ej. `'bargainFinderMax'`. */\n service: string;\n /**\n * Si la operación se puede repetir sin efectos duplicados. Las escrituras\n * (Create Booking, End Transaction) van en `false` y nunca se reintentan.\n */\n idempotent: boolean;\n query?: Record<string, string | number | boolean | undefined>;\n /** Se serializa como JSON, salvo `URLSearchParams`, que va como form-urlencoded. */\n body?: unknown;\n headers?: Record<string, string>;\n /** `false` para no pedir el header `Authorization` (p. ej. la propia request de token). */\n auth?: boolean;\n classify?: ResponseClassifier;\n retry?: Partial<RetryOptions>;\n signal?: AbortSignal;\n}\n\n/** Fuente del header `Authorization` de los servicios (la implementa `AuthManager`). */\nexport interface AuthorizationProvider {\n /** Valor vigente del header, p. ej. `Bearer <token>`. */\n get(): Promise<string>;\n /** El gateway rechazó `authorization` con 401: descartarlo para que `get` traiga otro. */\n invalidate(authorization: string): void;\n}\n\nexport interface RestTransportOptions {\n authorization?: AuthorizationProvider;\n /** Solo para tests: fuente de aleatoriedad del jitter. */\n random?: () => number;\n /** Solo para tests: espera entre reintentos. */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n}\n\nexport class RestTransport {\n readonly #config: ResolvedConfig;\n readonly #log: EventLogger;\n readonly #random: () => number;\n readonly #sleep: (ms: number, signal?: AbortSignal) => Promise<void>;\n #authorization: AuthorizationProvider | undefined;\n\n constructor(config: ResolvedConfig, options: RestTransportOptions = {}) {\n this.#config = config;\n this.#log = new EventLogger(config.logger);\n this.#authorization = options.authorization;\n this.#random = options.random ?? Math.random;\n this.#sleep = options.sleep ?? sleep;\n }\n\n /** Punto de enganche para `AuthManager`. */\n setAuthorizationProvider(provider: AuthorizationProvider | undefined): void {\n this.#authorization = provider;\n }\n\n async request<T>(request: RestRequest): Promise<T> {\n if (request.retry !== undefined) validateRetryOptions(request.retry, 'retry');\n const retry = { ...this.#config.retry, ...definedOnly(request.retry ?? {}) };\n\n let reauthorized = false;\n for (let attempt = 0; ; attempt++) {\n // Fuera del try: un fallo al obtener el token ya pasó por sus propios reintentos.\n const authorization = await this.#authorizationFor(request);\n try {\n return await this.#send<T>(request, attempt, authorization);\n } catch (error) {\n // Refresco reactivo: un solo reintento con token nuevo, fuera del presupuesto genérico.\n // Aplica también a escrituras: el 401 del gateway rechaza la request antes del proveedor.\n if (authorization !== undefined && !reauthorized && isUnauthorized(error)) {\n reauthorized = true;\n this.#authorization?.invalidate(authorization);\n this.#log.emit('warn', 'sabre.request.retry', {\n service: request.service,\n method: request.method,\n path: request.path,\n attempt: attempt + 1,\n reason: 'unauthorized',\n error: error as SabreError,\n });\n attempt--;\n continue;\n }\n if (attempt >= retry.maxRetries || !shouldRetry(error, request.idempotent)) throw error;\n const delayMs = retryDelay(attempt, retry.baseDelayMs, this.#random);\n this.#log.emit('warn', 'sabre.request.retry', {\n service: request.service,\n method: request.method,\n path: request.path,\n attempt: attempt + 1,\n maxRetries: retry.maxRetries,\n delayMs,\n error: error as SabreError,\n });\n await this.#sleep(delayMs, request.signal);\n }\n }\n }\n\n async #authorizationFor(request: RestRequest): Promise<string | undefined> {\n if (request.auth === false || this.#authorization === undefined) return undefined;\n return this.#authorization.get();\n }\n\n async #send<T>(request: RestRequest, attempt: number, authorization: string | undefined): Promise<T> {\n const url = this.#url(request);\n const headers = new Headers({ Accept: 'application/json', ...request.headers });\n const form = request.body instanceof URLSearchParams;\n if (request.body !== undefined && !headers.has('Content-Type')) {\n headers.set('Content-Type', form ? 'application/x-www-form-urlencoded' : 'application/json');\n }\n if (authorization !== undefined) headers.set('Authorization', authorization);\n\n const logContext = { service: request.service, method: request.method, path: request.path, attempt };\n this.#log.emit('debug', 'sabre.request.start', logContext);\n const startedAt = Date.now();\n\n let response: Response;\n try {\n response = await this.#config.fetch(url, {\n method: request.method,\n headers,\n ...(request.body === undefined ? {} : { body: form ? String(request.body) : JSON.stringify(request.body) }),\n ...(request.signal === undefined ? {} : { signal: request.signal }),\n });\n } catch (cause) {\n if (isAbort(cause, request.signal)) throw cause;\n const error = new SabreGatewayError(`${request.service}: fallo de red (${describe(cause)})`, {\n protocol: 'rest',\n retryable: true,\n cause,\n });\n this.#log.emit('error', 'sabre.request.end', { ...logContext, durationMs: Date.now() - startedAt, error });\n throw error;\n }\n\n const body = await readBody(response);\n const endContext = { ...logContext, status: response.status, durationMs: Date.now() - startedAt };\n\n // Paso 1: HTTP status de gateway.\n if (!response.ok) {\n const error = gatewayError(request.service, response.status, body);\n this.#log.emit('error', 'sabre.request.end', { ...endContext, error });\n throw error;\n }\n\n // Pasos 2–3: catálogo propio del servicio.\n const serviceError = request.classify?.(body, response);\n if (serviceError !== undefined) {\n this.#log.emit('warn', 'sabre.request.end', { ...endContext, error: serviceError });\n throw serviceError;\n }\n\n // Paso 4: data.\n this.#log.emit('info', 'sabre.request.end', endContext);\n return body as T;\n }\n\n #url(request: RestRequest): string {\n const path = request.path.startsWith('/') ? request.path : `/${request.path}`;\n const url = new URL(path, this.#config.baseUrl);\n for (const [key, value] of Object.entries(request.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n return url.toString();\n }\n}\n\n/** Body parseado como JSON; si no es JSON, el texto tal cual; vacío → `undefined`. */\nasync function readBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (text === '') return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return text;\n }\n}\n\nfunction gatewayError(service: string, status: number, body: unknown): SabreGatewayError {\n const code = extractCode(body);\n return new SabreGatewayError(`${service}: HTTP ${status}${code === undefined ? '' : ` ${code}`}`, {\n protocol: 'rest',\n status,\n retryable: RETRYABLE_STATUS.has(status),\n raw: body,\n ...(code === undefined ? {} : { code }),\n });\n}\n\n/**\n * Best-effort: el campo exacto del código `ERR.2SG.*` no está confirmado\n * (issue de fuente #21). Se prueban `errorCode` y `error`.\n */\nfunction extractCode(body: unknown): string | undefined {\n if (typeof body !== 'object' || body === null) return undefined;\n for (const key of ['errorCode', 'error'] as const) {\n const value = (body as Record<string, unknown>)[key];\n if (typeof value === 'string' && value !== '') return value;\n }\n return undefined;\n}\n\nfunction isUnauthorized(error: unknown): boolean {\n return error instanceof SabreGatewayError && error.protocol === 'rest' && error.status === 401;\n}\n\nfunction isAbort(error: unknown, signal: AbortSignal | undefined): boolean {\n return signal?.aborted === true || (error instanceof Error && error.name === 'AbortError');\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","// Cliente REST. Ver sabre-wiki/wiki/sdk/arquitectura-clientes-transporte.md.\nimport { Air } from './air/air.js';\nimport { AuthManager } from './auth/auth-manager.js';\nimport { BookingManagement } from './booking/booking-management.js';\nimport { type ResolvedConfig, resolveConfig, type SabreConfig, type SabreEnvironment } from './config.js';\nimport { RestTransport } from './http/rest-transport.js';\n\nexport class Sabre {\n readonly #config: ResolvedConfig;\n readonly #transport: RestTransport;\n /** Servicios de Air: shopping, revalidación. */\n readonly air: Air;\n /** Booking Management: creación de reservas. */\n readonly booking: BookingManagement;\n\n constructor(config: SabreConfig) {\n this.#config = resolveConfig(config);\n this.#transport = new RestTransport(this.#config);\n // Toda request lleva `Authorization: Bearer <token>`, salvo la propia de token (`auth: false`).\n const auth = new AuthManager(this.#config, this.#transport);\n this.#transport.setAuthorizationProvider(auth.bearerProvider());\n this.air = new Air(this.#transport);\n this.booking = new BookingManagement(this.#transport);\n }\n\n get environment(): SabreEnvironment {\n return this.#config.environment;\n }\n\n get baseUrl(): string {\n return this.#config.baseUrl;\n }\n}\n","// Armado de `flightDetails` de Create Booking desde un itinerario de BFM/Revalidate.\n// El mapeo está inferido, ninguna fuente lo documenta: ver la tabla \"Mapeo desde un\n// itinerario de BFM/Revalidate → flightDetails\" en sabre-wiki/wiki/entities/booking-management-api.md.\nimport type { Itinerary, ItineraryGroup } from '../air/grouped-itinerary.js';\nimport { itineraryFlights } from '../air/itinerary-flights.js';\nimport type { FlightDetails, FlightToBook, PassengerPricing, PriceComparison } from './create-booking-request.js';\n\nexport interface BookingFlightDetailsSource {\n /** Grupo del itinerario: aporta la fecha de cada tramo. */\n group: ItineraryGroup;\n /** Itinerario elegido, idealmente el devuelto por Revalidate Itinerary. */\n itinerary: Itinerary;\n /**\n * Umbral de precio. `desiredAmount` sale de `totalFare.totalPrice` del itinerario. El spec no\n * tiene campo de moneda: se supone la del pricing (la del PCC, salvo `currencyPricing`).\n */\n priceComparison?: Omit<PriceComparison, 'desiredAmount'>;\n}\n\n/**\n * Arma `flightDetails` para reservar por el camino ATPCO un itinerario ya revalidado.\n *\n * - `flights[]`: vuelo comercializador, aeropuertos, fecha y clase con las mismas reglas que\n * Revalidate (`itineraryFlights`); `departureTime` en `HH:MM` y `flightStatusCode: 'NN'`.\n * `isMarriageGroup` no se manda: no hay fuente para él.\n * - `flightPricing[0].qualifiers`: `passengersPricing` desde `passengerInfoList` y\n * `validatingAirlineCode` desde `validatingCarrierCode` de la primera cotización.\n */\nexport function buildBookingFlightDetails(source: BookingFlightDetailsSource): FlightDetails {\n const { group, itinerary, priceComparison } = source;\n const flights = itineraryFlights(group, itinerary).map(\n ({ schedule, departureDate, bookingCode }): FlightToBook => ({\n flightNumber: schedule.carrier.marketingFlightNumber,\n airlineCode: schedule.carrier.marketing,\n fromAirportCode: schedule.departure.airport,\n toAirportCode: schedule.arrival.airport,\n departureDate,\n departureTime: schedule.departure.time.slice(0, 5),\n bookingClass: bookingCode,\n flightStatusCode: 'NN',\n }),\n );\n\n const fare = itinerary.pricingInformation[0]?.fare;\n if (fare === undefined) {\n throw new TypeError('sabre-client: el itinerario no trae pricingInformation');\n }\n const passengersPricing = fare.passengerInfoList.map(\n ({ passengerInfo }): PassengerPricing => ({\n passengerCode: passengerInfo.passengerType,\n numberOfpassengers: passengerInfo.passengerNumber ?? 1,\n }),\n );\n\n let priceComparisons: PriceComparison[] | undefined;\n if (priceComparison !== undefined) {\n const total = fare.totalFare?.totalPrice;\n if (total === undefined) {\n throw new TypeError('sabre-client: el itinerario no trae totalFare.totalPrice para priceComparison');\n }\n priceComparisons = [{ desiredAmount: amount(total), ...priceComparison }];\n }\n\n return {\n flights,\n flightPricing: [\n {\n ...(priceComparisons === undefined ? {} : { priceComparisons }),\n qualifiers: {\n passengersPricing,\n ...(fare.validatingCarrierCode === undefined ? {} : { validatingAirlineCode: fare.validatingCarrierCode }),\n },\n },\n ],\n };\n}\n\n/** `1234.5` → `'1234.5'`; el spec acepta hasta 3 decimales. */\nfunction amount(value: number): string {\n return String(Math.round(value * 1000) / 1000);\n}\n","export const VERSION = '0.3.0';\n\nexport { Sabre } from './sabre.js';\nexport type { Air } from './air/air.js';\nexport type {\n BargainFinderMaxRequest,\n BargainFinderMaxResponse,\n RequestOptions,\n} from './air/bargain-finder-max.js';\nexport { buildRevalidateItineraryRequest } from './air/revalidate-itinerary.js';\nexport type {\n RevalidateItineraryRequest,\n RevalidateItineraryRequestSource,\n RevalidateItineraryResponse,\n} from './air/revalidate-itinerary.js';\nexport type {\n LowFareSearchFlight,\n LowFareSearchLocation,\n LowFareSearchOriginDestination,\n LowFareSearchPassengerTypeQuantity,\n LowFareSearchRequestorId,\n LowFareSearchSource,\n LowFareSearchTpaExtensions,\n LowFareSearchTravelerInfoSummary,\n LowFareSearchTravelPreferences,\n OtaAirLowFareSearchRq,\n} from './air/low-fare-search-request.js';\nexport type { SabreTokenStore, StoredToken } from './auth/token-store.js';\nexport type { BookingManagement } from './booking/booking-management.js';\nexport type {\n Booking,\n CreateBookingOptions,\n CreateBookingResponse,\n CreateBookingResponseError,\n} from './booking/create-booking.js';\nexport type {\n BookContactInformation,\n BookGenericSeat,\n BookingAgency,\n BookSeat,\n BookTraveler,\n BrandedFare,\n CreateBookingErrorPolicy,\n CreateBookingRequest,\n FlightDetails,\n FlightStatusCode,\n FlightToBook,\n PassengerPricing,\n PaymentMethod,\n PriceComparison,\n PriceComparisonType,\n PricingDetails,\n PricingQualifiers,\n SeatAreaPreference,\n SpecificFare,\n TicketingPolicy,\n TravelerPhone,\n TravelerTitle,\n} from './booking/create-booking-request.js';\nexport type {\n BookingSource,\n GetBookingExtraFeatures,\n GetBookingOptions,\n GetBookingRequest,\n GetBookingResponse,\n GetBookingReturnOnly,\n} from './booking/get-booking.js';\nexport type {\n BookingItemReference,\n CancelBookingErrorPolicy,\n CancelBookingNotification,\n CancelBookingOptions,\n CancelBookingRequest,\n CancelBookingResponse,\n CancelSegmentReference,\n FlightTicketOperation,\n RefundDocumentsType,\n} from './booking/cancel-booking.js';\nexport type { BookingResponseError } from './booking/booking-errors.js';\nexport { buildBookingFlightDetails } from './booking/flight-details.js';\nexport type { BookingFlightDetailsSource } from './booking/flight-details.js';\nexport type {\n SabreAuthVersion,\n SabreConfig,\n SabreConfigV2,\n SabreConfigV3,\n SabreCredentials,\n SabreCredentialsV2,\n SabreEnvironment,\n} from './config.js';\nexport type { RetryOptions } from './http/retry.js';\nexport * from './errors/index.js';\nexport * from './logging/index.js';\nexport type {\n BaggageAllowanceDesc,\n BaggageInformation,\n CurrencyConversion,\n Fare,\n FareComponent,\n FareComponentDesc,\n FareComponentDescSegment,\n FareComponentSegment,\n FareComponentSegmentDetail,\n FareMessage,\n GroupedItineraryResponse,\n Itinerary,\n ItineraryGroup,\n ItineraryMessage,\n Leg,\n LegDesc,\n LegSchedule,\n LegScheduleRef,\n LegDescription,\n ObFeeDesc,\n PassengerInfo,\n PassengerTotalFare,\n PricingInformation,\n Ref,\n ScheduleCarrier,\n ScheduleDesc,\n ScheduleEndpoint,\n ScheduleEquipment,\n TaxDesc,\n TaxSummaryDesc,\n TotalFare,\n ValidatingCarrierDesc,\n} from './air/grouped-itinerary.js';\n"],"mappings":"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","names":["PATH","isObject","PATH","isObject","PATH","isObject","warningOf","PATH","isObject","errorOf","warningOf","isObject"]}
1
+ {"version":3,"sources":["../src/errors/sabre-error.ts","../src/air/grouped-itinerary.ts","../src/air/itinerary-messages.ts","../src/air/bargain-finder-max.ts","../src/air/itinerary-flights.ts","../src/air/revalidate-itinerary.ts","../src/air/air.ts","../src/logging/redact.ts","../src/logging/logger.ts","../src/auth/token-request.ts","../src/auth/token-store.ts","../src/auth/auth-manager.ts","../src/booking/booking-errors.ts","../src/booking/cancel-booking.ts","../src/booking/create-booking.ts","../src/booking/get-booking.ts","../src/booking/booking-management.ts","../src/http/retry.ts","../src/config.ts","../src/http/rest-transport.ts","../src/sabre.ts","../src/booking/flight-details.ts","../src/index.ts"],"sourcesContent":["// Jerarquía de errores del SDK. Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md.\n\nexport interface SabreErrorOptions {\n /** Si la política de reintentos puede volver a intentar la operación. */\n retryable: boolean;\n /** Fragmento de la respuesta original sin transformar (JSON parseado o nodo XML). */\n raw?: unknown;\n cause?: unknown;\n}\n\n/**\n * Base de todos los errores del SDK.\n *\n * `raw` puede contener credenciales o datos de pasajero: no es enumerable, así que\n * no aparece en `JSON.stringify`, spreads ni serializadores de logs, pero sigue\n * accesible como `error.raw` para debugging. No lo vuelques a un logger sin sanitizar.\n */\nexport class SabreError extends Error {\n override name = 'SabreError';\n readonly retryable: boolean;\n declare readonly raw: unknown;\n\n constructor(message: string, options: SabreErrorOptions) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.retryable = options.retryable;\n Object.defineProperty(this, 'raw', {\n value: options.raw,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n }\n\n toJSON(): Record<string, unknown> {\n const fields: Record<string, unknown> = Object.fromEntries(Object.entries(this));\n return { ...fields, name: this.name, message: this.message };\n }\n}\n\nexport type SabreProtocol = 'rest' | 'soap';\n\nexport interface SabreGatewayErrorOptions extends SabreErrorOptions {\n protocol: SabreProtocol;\n /** HTTP status de la respuesta, si la hubo. */\n status?: number;\n /** Código tal cual lo devuelve el gateway (`ERR.2SG.*`, `USG_*`), si viene en el body. */\n code?: string;\n}\n\n/** Error de transporte/gateway (`ERR.2SG.*` + HTTP status en REST, `USG_*` en SOAP). */\nexport class SabreGatewayError extends SabreError {\n override name = 'SabreGatewayError';\n readonly protocol: SabreProtocol;\n readonly status: number | undefined;\n readonly code: string | undefined;\n\n constructor(message: string, options: SabreGatewayErrorOptions) {\n super(message, options);\n this.protocol = options.protocol;\n this.status = options.status;\n this.code = options.code;\n }\n}\n\nexport interface SabreOrchestrationErrorOptions extends Omit<SabreErrorOptions, 'retryable'> {\n /** `SP.PROVIDER_ERROR` o `SP.INTERNAL_ERROR`. */\n code: string;\n}\n\n/**\n * Error de servicio orquestado (`SP.*`), viaja dentro de una respuesta 200.\n * `SP.PROVIDER_ERROR` es reintentable; `SP.INTERNAL_ERROR` (y cualquier otro) no.\n */\nexport class SabreOrchestrationError extends SabreError {\n override name = 'SabreOrchestrationError';\n readonly code: string;\n\n constructor(message: string, options: SabreOrchestrationErrorOptions) {\n super(message, { ...options, retryable: options.code === 'SP.PROVIDER_ERROR' });\n this.code = options.code;\n }\n}\n\nexport interface SabreServiceErrorOptions extends Omit<SabreErrorOptions, 'retryable'> {\n /** Servicio que originó el error, p. ej. `'createBooking'`. */\n service: string;\n /** Código tal cual lo documenta Sabre, sin normalizar. */\n code: string;\n}\n\nexport interface SabreBusinessErrorOptions extends SabreServiceErrorOptions {\n /**\n * Solo para códigos que Sabre documenta como temporales en un servicio de lectura\n * (p. ej. `Transmission timeout` de Bargain Finder Max). Por defecto `false`.\n * La política de reintentos igual exige que la operación sea idempotente.\n */\n retryable?: boolean;\n /** Avisos que llegaron junto con el error (p. ej. `category: WARNING` de Create Booking). */\n warnings?: readonly SabreWarning[];\n /**\n * Otros errores que llegaron junto con este (p. ej. la causa real detrás de\n * `NO_ITEMS_CANCELLED` en Cancel Booking).\n */\n errors?: readonly SabreBusinessError[];\n}\n\n/**\n * Error del catálogo propio de un servicio. No es reintentable, salvo los códigos\n * temporales de servicios de lectura que se marcan con `retryable: true`.\n */\nexport class SabreBusinessError extends SabreError {\n override name = 'SabreBusinessError';\n readonly service: string;\n readonly code: string;\n readonly warnings: readonly SabreWarning[];\n readonly errors: readonly SabreBusinessError[];\n\n constructor(message: string, options: SabreBusinessErrorOptions) {\n super(message, { ...options, retryable: options.retryable ?? false });\n this.service = options.service;\n this.code = options.code;\n this.warnings = options.warnings ?? [];\n this.errors = options.errors ?? [];\n }\n}\n\n/**\n * Advertencia de un servicio (p. ej. `category: WARNING` de Create Booking, soft errors\n * de End Transaction): no es un fallo fatal. Nunca se reintenta automáticamente.\n */\nexport class SabreWarning extends SabreError {\n override name = 'SabreWarning';\n readonly service: string;\n readonly code: string;\n\n constructor(message: string, options: SabreServiceErrorOptions) {\n super(message, { ...options, retryable: false });\n this.service = options.service;\n this.code = options.code;\n }\n}\n","// Modelo `groupedItineraryResponse` compartido por Bargain Finder Max y Revalidate Itinerary,\n// y su desnormalizador: resuelve cada `ref` al objeto completo antes de exponerlo.\n// Ver sabre-wiki/wiki/concepts/modelo-de-itinerario.md.\n//\n// Sin schema formal: los campos salen de los ejemplos de BFM y Revalidate del wiki. Los que\n// solo aparecieron en uno de los dos van como opcionales.\nimport { SabreError } from '../errors/index.js';\n\n// ---------------------------------------------------------------------------\n// Descriptores compartidos (arrays planos indexados por `id`)\n// ---------------------------------------------------------------------------\n\nexport interface ScheduleEndpoint {\n airport: string;\n city?: string;\n /** Visto en sandbox para aeropuertos de EE. UU. */\n state?: string;\n country?: string;\n /** Hora local con offset, p. ej. `17:10:00+02:00`. */\n time: string;\n terminal?: string;\n /** Días que se suman a la fecha de salida del vuelo. Visto en sandbox (`arrival`). */\n dateAdjustment?: number;\n}\n\nexport interface ScheduleEquipment {\n code: string;\n typeForFirstLeg?: string;\n typeForLastLeg?: string;\n}\n\nexport interface ScheduleCarrier {\n marketing: string;\n marketingFlightNumber: number;\n operating?: string;\n operatingFlightNumber?: number;\n alliances?: string;\n equipment?: ScheduleEquipment;\n}\n\n/** Vuelo/segmento operado (`scheduleDescs[]`). */\nexport interface ScheduleDesc {\n id: number;\n /** Visto en sandbox, p. ej. `\"7\"`; significado sin confirmar. */\n dotRating?: string;\n frequency?: string;\n stopCount?: number;\n eTicketable?: boolean;\n totalMilesFlown?: number;\n /** Minutos. */\n elapsedTime?: number;\n departure: ScheduleEndpoint;\n arrival: ScheduleEndpoint;\n carrier: ScheduleCarrier;\n}\n\n/** Tramo lógico (`legDescs[]`): agrupa schedules por `ref`. */\nexport interface LegDesc {\n id: number;\n /** Minutos. */\n elapsedTime?: number;\n schedules: LegScheduleRef[];\n}\n\n/**\n * Schedule dentro de un tramo. `departureDateAdjustment`: días que se suman a la fecha del\n * tramo para la salida de este vuelo (conexión al día siguiente). Visto en sandbox, sin\n * documentar en los ejemplos de Sabre.\n */\nexport interface LegScheduleRef extends Ref {\n departureDateAdjustment?: number;\n}\n\n/** Impuesto individual (`taxDescs[]`). */\nexport interface TaxDesc {\n id: number;\n code: string;\n amount: number;\n currency: string;\n description?: string;\n publishedAmount?: number;\n publishedCurrency?: string;\n station?: string;\n country?: string;\n /** Visto en sandbox. */\n taxReissue?: { refundable?: boolean };\n}\n\n/** Resumen de impuestos por código (`taxSummaryDescs[]`). Misma forma que `TaxDesc`. */\nexport type TaxSummaryDesc = TaxDesc;\n\n/** Cargo adicional (`obFeeDescs[]`). Significado exacto de \"OB\" sin confirmar. */\nexport interface ObFeeDesc {\n id: number;\n amount: number;\n currency: string;\n}\n\nexport interface FareComponentDescSegment {\n segment: {\n stopover?: boolean;\n };\n}\n\n/** Componente de tarifa (`fareComponentDescs[]`). */\nexport interface FareComponentDesc {\n id: number;\n governingCarrier?: string;\n fareAmount?: number;\n fareCurrency?: string;\n fareBasisCode: string;\n farePassengerType?: string;\n publishedFareAmount?: number;\n publishedFareCurrency?: string;\n /** `FROM` / `TO`. */\n directionality?: string;\n applicablePricingCategories?: string;\n vendorCode?: string;\n fareTypeBitmap?: string;\n fareType?: string;\n fareTariff?: string;\n fareRule?: string;\n cabinCode?: string;\n segments?: FareComponentDescSegment[];\n // Vistos solo en Revalidate Itinerary.\n ticketDesignator?: string;\n mileageSurcharge?: number;\n mileage?: boolean;\n oneWayFare?: boolean;\n negotiatedFare?: boolean;\n privateFare?: boolean;\n notValidAfter?: string;\n /** Distinto de `directionality`; significado sin confirmar. */\n direction?: string;\n}\n\n/** Aerolínea validadora (`validatingCarrierDescs[]`). */\nexport interface ValidatingCarrierDesc {\n id: number;\n settlementMethod?: string;\n newVcxProcess?: boolean;\n default?: { code: string };\n}\n\n/** Franquicia de equipaje (`baggageAllowanceDescs[]`). */\nexport interface BaggageAllowanceDesc {\n id: number;\n pieceCount?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Piezas que no llevan referencias\n// ---------------------------------------------------------------------------\n\n/** Referencia a un descriptor por su `id`. */\nexport interface Ref {\n ref: number;\n}\n\nexport interface ItineraryMessage {\n severity: string;\n type: string;\n code: string;\n text: string;\n}\n\nexport interface LegDescription {\n departureDate: string;\n departureLocation: string;\n arrivalLocation: string;\n}\n\nexport interface CurrencyConversion {\n from: string;\n to: string;\n exchangeRateUsed: number;\n}\n\nexport interface PassengerTotalFare {\n totalFare: number;\n totalTaxAmount?: number;\n currency: string;\n baseFareAmount?: number;\n baseFareCurrency?: string;\n equivalentAmount?: number;\n equivalentCurrency?: string;\n constructionAmount?: number;\n constructionCurrency?: string;\n exchangeRateOne?: number;\n // Comisión de agencia: vistos solo en Revalidate Itinerary.\n commissionPercentage?: number;\n commissionAmount?: number;\n cat35CommissionPercentage?: number;\n cat35CommissionAmount?: number;\n cat35MarkupAmount?: number;\n commissionAmountInEquivalent?: number;\n commissionSource?: string;\n}\n\nexport interface TotalFare {\n totalPrice: number;\n totalTaxAmount?: number;\n currency: string;\n baseFareAmount?: number;\n baseFareCurrency?: string;\n constructionAmount?: number;\n constructionCurrency?: string;\n equivalentAmount?: number;\n equivalentCurrency?: string;\n}\n\n/** Disponibilidad del segmento dentro de un componente de tarifa. */\nexport interface FareComponentSegmentDetail {\n bookingCode?: string;\n cabinCode?: string;\n mealCode?: string;\n seatsAvailable?: number;\n availabilityBreak?: boolean;\n fareBreakPoint?: boolean;\n}\n\nexport interface FareMessage {\n type: string;\n code: string;\n /** Visto en sandbox de Revalidate. */\n carrier?: string;\n info: string;\n}\n\n// ---------------------------------------------------------------------------\n// Respuesta tal cual la manda Sabre (con `ref`). Interna: el SDK expone la desnormalizada.\n// ---------------------------------------------------------------------------\n\nexport interface RawFareComponent extends Ref {\n beginAirport?: string;\n endAirport?: string;\n segments?: Array<{ segment: FareComponentSegmentDetail }>;\n}\n\nexport interface RawBaggageInformation {\n provisionType?: string;\n airlineCode?: string;\n /** Índices de segmento, no referencias a descriptores. */\n segments?: Array<{ id: number }>;\n allowance?: Ref;\n}\n\nexport interface RawPassengerInfo {\n passengerType: string;\n passengerNumber?: number;\n nonRefundable?: boolean;\n fareComponents?: RawFareComponent[];\n taxes?: Ref[];\n taxSummaries?: Ref[];\n obFees?: Ref[];\n currencyConversion?: CurrencyConversion;\n passengerTotalFare?: PassengerTotalFare;\n baggageInformation?: RawBaggageInformation[];\n // Vistos solo en Revalidate Itinerary.\n fareMessages?: FareMessage[];\n fareCalcLine?: { info: string };\n}\n\nexport interface RawFare {\n mandatoryInd?: boolean;\n validatingCarrierCode?: string;\n vita?: boolean;\n eTicketable?: boolean;\n lastTicketDate?: string;\n lastTicketTime?: string;\n governingCarriers?: string;\n passengerInfoList: Array<{ passengerInfo: RawPassengerInfo }>;\n totalFare?: TotalFare;\n validatingCarriers?: Ref[];\n}\n\nexport interface RawPricingInformation {\n pricingSubsource?: string;\n /** P. ej. `ATPCO`. Visto en Revalidate y en sandbox de BFM. */\n distributionModel?: string;\n fare: RawFare;\n}\n\nexport interface RawItinerary {\n id: number;\n pricingSource?: string;\n /** Visto solo en Revalidate Itinerary. */\n currentItinerary?: boolean;\n /** Visto en sandbox de BFM; significado sin confirmar. */\n diversitySwapper?: { weighedPrice?: number };\n legs: Ref[];\n pricingInformation: RawPricingInformation[];\n}\n\nexport interface RawItineraryGroup {\n groupDescription: { legDescriptions: LegDescription[] };\n itineraries: RawItinerary[];\n}\n\n/** Contenido de `groupedItineraryResponse` tal cual llega de Sabre. */\nexport interface RawGroupedItineraryResponse {\n version: string;\n messages?: ItineraryMessage[];\n statistics?: { itineraryCount: number };\n scheduleDescs?: ScheduleDesc[];\n taxDescs?: TaxDesc[];\n taxSummaryDescs?: TaxSummaryDesc[];\n obFeeDescs?: ObFeeDesc[];\n fareComponentDescs?: FareComponentDesc[];\n validatingCarrierDescs?: ValidatingCarrierDesc[];\n baggageAllowanceDescs?: BaggageAllowanceDesc[];\n legDescs?: LegDesc[];\n itineraryGroups?: RawItineraryGroup[];\n}\n\n// ---------------------------------------------------------------------------\n// Respuesta desnormalizada (superficie pública)\n// ---------------------------------------------------------------------------\n\n/** Tramo con sus schedules resueltos. */\nexport interface Leg extends Omit<LegDesc, 'schedules'> {\n schedules: LegSchedule[];\n}\n\n/** Schedule resuelto, con lo que la referencia del tramo agrega. */\nexport type LegSchedule = ScheduleDesc & Omit<LegScheduleRef, 'ref'>;\n\n/** Segmento de un componente de tarifa: lo del descriptor más la disponibilidad del itinerario. */\nexport interface FareComponentSegment {\n segment: FareComponentDescSegment['segment'] & FareComponentSegmentDetail;\n}\n\n/** Componente de tarifa resuelto: descriptor + datos propios del itinerario. */\nexport interface FareComponent extends Omit<FareComponentDesc, 'segments'> {\n beginAirport?: string;\n endAirport?: string;\n segments?: FareComponentSegment[];\n}\n\nexport interface BaggageInformation extends Omit<RawBaggageInformation, 'allowance'> {\n allowance?: BaggageAllowanceDesc;\n}\n\nexport interface PassengerInfo\n extends Omit<RawPassengerInfo, 'fareComponents' | 'taxes' | 'taxSummaries' | 'obFees' | 'baggageInformation'> {\n fareComponents?: FareComponent[];\n taxes?: TaxDesc[];\n taxSummaries?: TaxSummaryDesc[];\n obFees?: ObFeeDesc[];\n baggageInformation?: BaggageInformation[];\n}\n\nexport interface Fare extends Omit<RawFare, 'passengerInfoList' | 'validatingCarriers'> {\n passengerInfoList: Array<{ passengerInfo: PassengerInfo }>;\n validatingCarriers?: ValidatingCarrierDesc[];\n}\n\nexport interface PricingInformation extends Omit<RawPricingInformation, 'fare'> {\n fare: Fare;\n}\n\nexport interface Itinerary extends Omit<RawItinerary, 'legs' | 'pricingInformation'> {\n legs: Leg[];\n pricingInformation: PricingInformation[];\n}\n\nexport interface ItineraryGroup {\n groupDescription: { legDescriptions: LegDescription[] };\n itineraries: Itinerary[];\n}\n\n/**\n * `groupedItineraryResponse` con cada `ref` resuelto al objeto completo. Los arrays de\n * descriptores (`scheduleDescs`, `legDescs`, …) ya no se exponen: su contenido vive\n * dentro de cada itinerario.\n */\nexport interface GroupedItineraryResponse {\n version: string;\n messages: ItineraryMessage[];\n statistics?: { itineraryCount: number };\n itineraryGroups: ItineraryGroup[];\n}\n\n// ---------------------------------------------------------------------------\n// Desnormalizador\n// ---------------------------------------------------------------------------\n\n/**\n * Resuelve cada `{ ref, ...resto }` a `{ ...descriptor, ...resto }` (sin `ref`; el `id` del\n * descriptor se conserva). En los componentes de tarifa, `segments` se fusiona elemento a\n * elemento: el descriptor aporta `stopover` y el itinerario la disponibilidad; si los dos\n * traen `segments` con distinto largo, la respuesta es malformada.\n *\n * Un `ref` sin descriptor con ese `id` es una respuesta malformada: lanza `SabreError`\n * no reintentable en vez de devolver un objeto a medias. No muta la entrada.\n */\nexport function denormalizeGroupedItineraryResponse(\n raw: RawGroupedItineraryResponse,\n service: string,\n): GroupedItineraryResponse {\n const resolver = new Resolver(raw, service);\n return {\n version: raw.version,\n messages: raw.messages ?? [],\n ...(raw.statistics === undefined ? {} : { statistics: raw.statistics }),\n itineraryGroups: (raw.itineraryGroups ?? []).map((group) => ({\n groupDescription: group.groupDescription,\n itineraries: group.itineraries.map((itinerary) => resolver.itinerary(itinerary)),\n })),\n };\n}\n\nclass Resolver {\n readonly #service: string;\n readonly #schedules: Map<number, ScheduleDesc>;\n readonly #legs: Map<number, LegDesc>;\n readonly #taxes: Map<number, TaxDesc>;\n readonly #taxSummaries: Map<number, TaxSummaryDesc>;\n readonly #obFees: Map<number, ObFeeDesc>;\n readonly #fareComponents: Map<number, FareComponentDesc>;\n readonly #validatingCarriers: Map<number, ValidatingCarrierDesc>;\n readonly #baggageAllowances: Map<number, BaggageAllowanceDesc>;\n\n constructor(raw: RawGroupedItineraryResponse, service: string) {\n this.#service = service;\n this.#schedules = byId(raw.scheduleDescs);\n this.#legs = byId(raw.legDescs);\n this.#taxes = byId(raw.taxDescs);\n this.#taxSummaries = byId(raw.taxSummaryDescs);\n this.#obFees = byId(raw.obFeeDescs);\n this.#fareComponents = byId(raw.fareComponentDescs);\n this.#validatingCarriers = byId(raw.validatingCarrierDescs);\n this.#baggageAllowances = byId(raw.baggageAllowanceDescs);\n }\n\n itinerary(itinerary: RawItinerary): Itinerary {\n return {\n ...itinerary,\n legs: itinerary.legs.map((ref) => this.#leg(ref)),\n pricingInformation: itinerary.pricingInformation.map((pricing) => ({\n ...pricing,\n fare: this.#fare(pricing.fare),\n })),\n };\n }\n\n #leg(ref: Ref): Leg {\n const leg = this.#merge(this.#legs, 'legDescs', ref);\n return { ...leg, schedules: leg.schedules.map((schedule) => this.#merge(this.#schedules, 'scheduleDescs', schedule)) };\n }\n\n #fare(fare: RawFare): Fare {\n const { validatingCarriers, ...rest } = fare;\n return {\n ...rest,\n passengerInfoList: fare.passengerInfoList.map(({ passengerInfo, ...entry }) => ({\n ...entry,\n passengerInfo: this.#passengerInfo(passengerInfo),\n })),\n ...(validatingCarriers === undefined\n ? {}\n : {\n validatingCarriers: validatingCarriers.map((ref) =>\n this.#merge(this.#validatingCarriers, 'validatingCarrierDescs', ref),\n ),\n }),\n };\n }\n\n #passengerInfo(info: RawPassengerInfo): PassengerInfo {\n const { fareComponents, taxes, taxSummaries, obFees, baggageInformation, ...rest } = info;\n const result: PassengerInfo = { ...rest };\n if (fareComponents !== undefined) result.fareComponents = fareComponents.map((ref) => this.#fareComponent(ref));\n if (taxes !== undefined) result.taxes = taxes.map((ref) => this.#merge(this.#taxes, 'taxDescs', ref));\n if (taxSummaries !== undefined) {\n result.taxSummaries = taxSummaries.map((ref) => this.#merge(this.#taxSummaries, 'taxSummaryDescs', ref));\n }\n if (obFees !== undefined) result.obFees = obFees.map((ref) => this.#merge(this.#obFees, 'obFeeDescs', ref));\n if (baggageInformation !== undefined) {\n result.baggageInformation = baggageInformation.map(({ allowance, ...bag }) => ({\n ...bag,\n ...(allowance === undefined\n ? {}\n : { allowance: this.#merge(this.#baggageAllowances, 'baggageAllowanceDescs', allowance) }),\n }));\n }\n return result;\n }\n\n #fareComponent(ref: RawFareComponent): FareComponent {\n const desc = this.#lookup(this.#fareComponents, 'fareComponentDescs', ref.ref);\n const { ref: _ref, segments: siteSegments, ...site } = ref;\n const { segments: descSegments, ...descRest } = desc;\n if (descSegments !== undefined && siteSegments !== undefined && descSegments.length !== siteSegments.length) {\n throw this.#malformed(\n `fareComponents con ${siteSegments.length} segmentos y fareComponentDescs ${ref.ref} con ${descSegments.length}`,\n );\n }\n const segments = mergeSegments(descSegments, siteSegments);\n return { ...descRest, ...site, ...(segments === undefined ? {} : { segments }) };\n }\n\n /** `{ ref, ...resto }` → `{ ...descriptor, ...resto }`. */\n #merge<T extends { id: number }>(index: Map<number, T>, kind: string, ref: Ref): T {\n const { ref: id, ...site } = ref;\n return { ...this.#lookup(index, kind, id), ...site };\n }\n\n #lookup<T>(index: Map<number, T>, kind: string, id: number): T {\n const desc = index.get(id);\n if (desc === undefined) throw this.#malformed(`ref ${id} sin descriptor en ${kind}`);\n return desc;\n }\n\n #malformed(detail: string): SabreError {\n return new SabreError(`${this.#service}: respuesta malformada, ${detail}`, { retryable: false });\n }\n}\n\nfunction byId<T extends { id: number }>(descs: T[] | undefined): Map<number, T> {\n return new Map((descs ?? []).map((desc) => [desc.id, desc]));\n}\n\nfunction mergeSegments(\n desc: FareComponentDescSegment[] | undefined,\n site: Array<{ segment: FareComponentSegmentDetail }> | undefined,\n): FareComponentSegment[] | undefined {\n if (desc === undefined && site === undefined) return undefined;\n // Los largos ya se validaron iguales cuando vienen los dos.\n const length = desc?.length ?? site?.length ?? 0;\n return Array.from({ length }, (_, i) => ({\n segment: { ...desc?.[i]?.segment, ...site?.[i]?.segment },\n }));\n}\n","// Clasificación de errores de negocio en `groupedItineraryResponse.messages[]`, compartida por\n// los servicios que responden con ese modelo (Bargain Finder Max, Revalidate Itinerary).\n// Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md.\nimport { SabreBusinessError, SabreError } from '../errors/index.js';\nimport type { ItineraryMessage } from './grouped-itinerary.js';\n\n/** Entrada de catálogo: se compara por substring del `text`, sin distinguir mayúsculas. */\nexport interface ItineraryMessageCatalogEntry {\n code: string;\n retryable: boolean;\n}\n\n/**\n * Paso 3 del orden de detección: un mensaje con `severity: Error` en\n * `groupedItineraryResponse.messages[]` (respuesta 200) es un `SabreBusinessError`.\n *\n * En sandbox, los mensajes `Error` son genéricos (`No complete journey can be built…`,\n * `Error during Processing`) y el texto del catálogo llega en un mensaje `Info`\n * (`NO FLIGHT SCHEDULES FOR QUALIFIERS USED`). Por eso, cuando hay algún `Error`, el\n * catálogo se busca en el `text` de todos los mensajes.\n */\nexport function classifyItineraryMessages(\n body: unknown,\n service: string,\n catalog: ReadonlyArray<ItineraryMessageCatalogEntry>,\n): SabreError | undefined {\n const response = isObject(body) ? body.groupedItineraryResponse : undefined;\n if (!isObject(response)) {\n return new SabreError(`${service}: respuesta malformada, falta groupedItineraryResponse`, {\n retryable: false,\n raw: body,\n });\n }\n const messages = Array.isArray(response.messages) ? (response.messages as Partial<ItineraryMessage>[]) : [];\n const error = messages.find((message) => message.severity?.toLowerCase() === 'error');\n if (error === undefined) return undefined;\n\n const match = findInCatalog(messages, catalog);\n const text = match?.text ?? (typeof error.text === 'string' ? error.text : '');\n const known = match?.entry;\n const code = known?.code ?? error.code ?? text;\n return new SabreBusinessError(`${service}: ${text || code}`, {\n service,\n code,\n retryable: known?.retryable ?? false,\n raw: body,\n });\n}\n\nfunction findInCatalog(\n messages: Partial<ItineraryMessage>[],\n catalog: ReadonlyArray<ItineraryMessageCatalogEntry>,\n): { entry: ItineraryMessageCatalogEntry; text: string } | undefined {\n for (const message of messages) {\n if (typeof message.text !== 'string') continue;\n const text = message.text.toLowerCase();\n const entry = catalog.find((candidate) => text.includes(candidate.code.toLowerCase()));\n if (entry !== undefined) return { entry, text: message.text };\n }\n return undefined;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","// Bargain Finder Max v5 (`POST /v5/offers/shop`).\n// Ver sabre-wiki/wiki/entities/bargain-finder-max.md.\nimport type { SabreError } from '../errors/index.js';\nimport type { SabreRawResponseCallback } from '../http/raw-response.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport type { RetryOptions } from '../http/retry.js';\nimport {\n denormalizeGroupedItineraryResponse,\n type GroupedItineraryResponse,\n type RawGroupedItineraryResponse,\n} from './grouped-itinerary.js';\nimport { classifyItineraryMessages, type ItineraryMessageCatalogEntry } from './itinerary-messages.js';\nimport type { OtaAirLowFareSearchRq } from './low-fare-search-request.js';\n\nexport const BARGAIN_FINDER_MAX_SERVICE = 'bargainFinderMax';\nconst PATH = '/v5/offers/shop';\n\n/** Body de Bargain Finder Max v5, tal cual lo documenta Sabre. */\nexport interface BargainFinderMaxRequest {\n OTA_AirLowFareSearchRQ: OtaAirLowFareSearchRq;\n}\n\n/** `groupedItineraryResponse` con las referencias ya resueltas. */\nexport type BargainFinderMaxResponse = GroupedItineraryResponse;\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */\n onRawResponse?: SabreRawResponseCallback;\n /** Pisa los reintentos del cliente solo para esta request. */\n retry?: Partial<RetryOptions>;\n}\n\n/**\n * Catálogo de errores de BFM (guía oficial de errores). Se compara por substring del\n * `text` porque Sabre agrega detalle variable. Los temporales son reintentables: BFM es\n * una lectura idempotente y Sabre indica reintentar.\n */\nexport const BARGAIN_FINDER_MAX_CATALOG: ReadonlyArray<ItineraryMessageCatalogEntry> = [\n { code: 'No Availability', retryable: false },\n { code: 'NO FLIGHT SCHEDULES FOR QUALIFIERS USED', retryable: false },\n { code: 'Connection reset by peer', retryable: true },\n { code: 'Transmission timeout', retryable: true },\n { code: 'Insufficient resources', retryable: true },\n { code: 'MAX NBR COMBINATIONS EXCEEDED', retryable: true },\n];\n\nexport async function bargainFinderMax(\n transport: RestTransport,\n request: BargainFinderMaxRequest,\n options: RequestOptions = {},\n): Promise<BargainFinderMaxResponse> {\n if (typeof request !== 'object' || request === null || typeof request.OTA_AirLowFareSearchRQ !== 'object') {\n throw new TypeError('sabre-client: bargainFinderMax espera { OTA_AirLowFareSearchRQ: { ... } }');\n }\n const body = await transport.request<{ groupedItineraryResponse: RawGroupedItineraryResponse }>({\n method: 'POST',\n path: PATH,\n service: BARGAIN_FINDER_MAX_SERVICE,\n // POST, pero de solo lectura: se puede reintentar sin efectos duplicados.\n idempotent: true,\n body: request,\n classify: classifyBargainFinderMax,\n ...(options.retry === undefined ? {} : { retry: options.retry }),\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n ...(options.onRawResponse === undefined\n ? {}\n : { operation: 'air.bargainFinderMax', onRawResponse: options.onRawResponse }),\n });\n return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, BARGAIN_FINDER_MAX_SERVICE);\n}\n\n/** Ver `classifyItineraryMessages`. */\nexport function classifyBargainFinderMax(body: unknown): SabreError | undefined {\n return classifyItineraryMessages(body, BARGAIN_FINDER_MAX_SERVICE, BARGAIN_FINDER_MAX_CATALOG);\n}\n","// Reglas para fijar los vuelos de un itinerario desnormalizado, compartidas por los\n// helpers que arman requests a partir de él (Revalidate Itinerary, Create Booking).\n// Ver sabre-wiki/wiki/concepts/modelo-de-itinerario.md.\nimport type { Itinerary, ItineraryGroup, LegSchedule } from './grouped-itinerary.js';\n\n/** Un vuelo del itinerario con su fecha de salida ya resuelta y su clase de servicio. */\nexport interface ItineraryFlight {\n /** Índice del tramo (`legs[]`) al que pertenece. */\n legIndex: number;\n schedule: LegSchedule;\n /** `YYYY-MM-DD`, hora local del aeropuerto de salida. */\n departureDate: string;\n /** `YYYY-MM-DD`, hora local del aeropuerto de llegada. */\n arrivalDate: string;\n bookingCode: string;\n}\n\n/**\n * Aplana los vuelos del itinerario en orden.\n *\n * - La clase de servicio de cada vuelo sale de `fareComponents[].segments[].bookingCode` del\n * primer pasajero de la primera cotización, en el orden de los vuelos del itinerario.\n * - Las fechas salen de `legDescriptions[].departureDate` más `departureDateAdjustment` del\n * schedule (salida) y `arrival.dateAdjustment` (llegada).\n */\nexport function itineraryFlights(group: ItineraryGroup, itinerary: Itinerary): ItineraryFlight[] {\n const { legDescriptions } = group.groupDescription;\n if (legDescriptions.length !== itinerary.legs.length) {\n throw new TypeError(\n `sabre-client: el itinerario tiene ${itinerary.legs.length} tramos y el grupo ${legDescriptions.length}`,\n );\n }\n const classes = bookingCodes(itinerary);\n const flightCount = itinerary.legs.reduce((n, leg) => n + leg.schedules.length, 0);\n if (classes.length !== flightCount) {\n throw new TypeError(\n `sabre-client: el itinerario tiene ${flightCount} vuelos y ${classes.length} clases de servicio en fareComponents`,\n );\n }\n\n let next = 0;\n return itinerary.legs.flatMap((leg, legIndex) => {\n const legDate = legDescriptions[legIndex]!.departureDate;\n return leg.schedules.map((schedule) => {\n const departureDate = addDays(legDate, schedule.departureDateAdjustment ?? 0);\n return {\n legIndex,\n schedule,\n departureDate,\n arrivalDate: addDays(departureDate, schedule.arrival.dateAdjustment ?? 0),\n bookingCode: classes[next++]!,\n };\n });\n });\n}\n\nfunction bookingCodes(itinerary: Itinerary): string[] {\n const passenger = itinerary.pricingInformation[0]?.fare.passengerInfoList[0]?.passengerInfo;\n return (passenger?.fareComponents ?? []).flatMap((component) =>\n (component.segments ?? []).map(({ segment }) => {\n if (segment.bookingCode === undefined) {\n throw new TypeError('sabre-client: un segmento de fareComponents no trae bookingCode');\n }\n return segment.bookingCode;\n }),\n );\n}\n\n/** `2026-09-11` + n días, en calendario puro (sin zona horaria). */\nfunction addDays(date: string, days: number): string {\n if (days === 0) return date;\n const [year, month, day] = date.split('-').map(Number) as [number, number, number];\n return new Date(Date.UTC(year, month - 1, day + days)).toISOString().slice(0, 10);\n}\n","// Revalidate Itinerary v5 (`POST /v5/shop/flights/revalidate`).\n// Ver sabre-wiki/wiki/entities/revalidate-itinerary.md.\nimport type { SabreError } from '../errors/index.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport { BARGAIN_FINDER_MAX_CATALOG, type BargainFinderMaxRequest, type RequestOptions } from './bargain-finder-max.js';\nimport {\n denormalizeGroupedItineraryResponse,\n type GroupedItineraryResponse,\n type Itinerary,\n type ItineraryGroup,\n type RawGroupedItineraryResponse,\n} from './grouped-itinerary.js';\nimport { type ItineraryFlight, itineraryFlights } from './itinerary-flights.js';\nimport { classifyItineraryMessages, type ItineraryMessageCatalogEntry } from './itinerary-messages.js';\nimport type {\n LowFareSearchFlight,\n LowFareSearchOriginDestination,\n OtaAirLowFareSearchRq,\n} from './low-fare-search-request.js';\n\nexport const REVALIDATE_ITINERARY_SERVICE = 'revalidateItinerary';\nconst PATH = '/v5/shop/flights/revalidate';\n\n/** Body de Revalidate Itinerary v5: el mismo `OTA_AirLowFareSearchRQ` que BFM, con los vuelos fijados. */\nexport interface RevalidateItineraryRequest {\n OTA_AirLowFareSearchRQ: OtaAirLowFareSearchRq;\n}\n\n/** `groupedItineraryResponse` con las referencias ya resueltas. */\nexport type RevalidateItineraryResponse = GroupedItineraryResponse;\n\nexport async function revalidateItinerary(\n transport: RestTransport,\n request: RevalidateItineraryRequest,\n options: RequestOptions = {},\n): Promise<RevalidateItineraryResponse> {\n if (typeof request !== 'object' || request === null || typeof request.OTA_AirLowFareSearchRQ !== 'object') {\n throw new TypeError('sabre-client: revalidateItinerary espera { OTA_AirLowFareSearchRQ: { ... } }');\n }\n const body = await transport.request<{ groupedItineraryResponse: RawGroupedItineraryResponse }>({\n method: 'POST',\n path: PATH,\n service: REVALIDATE_ITINERARY_SERVICE,\n // POST, pero de solo lectura: no sostiene inventario, se puede reintentar.\n idempotent: true,\n body: request,\n classify: classifyRevalidateItinerary,\n ...(options.retry === undefined ? {} : { retry: options.retry }),\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n ...(options.onRawResponse === undefined\n ? {}\n : { operation: 'air.revalidateItinerary', onRawResponse: options.onRawResponse }),\n });\n return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, REVALIDATE_ITINERARY_SERVICE);\n}\n\n/**\n * Catálogo de errores de Revalidate (guía oficial de errores de Revalidate Itinerary, en la\n * documentación SOAP de BFM 7.2.0; ver sabre-wiki/wiki/entities/revalidate-itinerary.md).\n * Las cinco condiciones describen un dato que no existe (tarifa, horario o disponibilidad):\n * reintentar no cambia el resultado. En producción, `NO FARE FOR CLASS USED` llegó con\n * `code: 'PROCESS'`; el catálogo le da un `code` estable.\n *\n * Los temporales se heredan de BFM (mismo motor), con `retryable: true`.\n */\nexport const REVALIDATE_ITINERARY_CATALOG: ReadonlyArray<ItineraryMessageCatalogEntry> = [\n { code: 'NO COMBINABLE FARES FOR CLASS USED', retryable: false },\n { code: 'NO FARE FOR CLASS USED', retryable: false },\n { code: 'NO FLIGHT SCHEDULES FOR QUALIFIERS USED', retryable: false },\n { code: 'NO SUCH FLIGHT', retryable: false },\n { code: 'NO AVAILABILITY', retryable: false },\n ...BARGAIN_FINDER_MAX_CATALOG.filter((entry) => entry.retryable),\n];\n\n/** Ver `classifyItineraryMessages`. */\nexport function classifyRevalidateItinerary(body: unknown): SabreError | undefined {\n return classifyItineraryMessages(body, REVALIDATE_ITINERARY_SERVICE, REVALIDATE_ITINERARY_CATALOG);\n}\n\nexport interface RevalidateItineraryRequestSource {\n /** Request de BFM que produjo el itinerario: aporta `Version`, `POS`, pasajeros y `TPA_Extensions`. */\n search: BargainFinderMaxRequest;\n /** Grupo del itinerario: aporta la fecha de cada tramo. */\n group: ItineraryGroup;\n itinerary: Itinerary;\n}\n\n/**\n * Arma el request de Revalidate Itinerary para un itinerario devuelto por BFM, fijando cada\n * vuelo en `OriginDestinationInformation[].TPA_Extensions.Flight[]`.\n *\n * - Clases de servicio y fechas: ver `itineraryFlights`. Las horas salen de `time` sin el offset.\n * - `MaxStopsQuantity` es el máximo de conexiones de un tramo, para no rechazar itinerarios\n * con escala.\n * - `Fixed: false` y `VerificationItinCallLogic: \"L\"` se copian del ejemplo de Sabre; su\n * efecto no está documentado.\n */\nexport function buildRevalidateItineraryRequest(source: RevalidateItineraryRequestSource): RevalidateItineraryRequest {\n const { search, group, itinerary } = source;\n const flights = itineraryFlights(group, itinerary);\n\n const originDestinations = itinerary.legs.map((_leg, i): LowFareSearchOriginDestination => {\n const legFlights = flights.filter((f) => f.legIndex === i).map(flight);\n const first = legFlights[0]!;\n const last = legFlights.at(-1)!;\n return {\n Fixed: false,\n DepartureDateTime: first.DepartureDateTime,\n OriginLocation: { LocationCode: first.OriginLocation.LocationCode },\n DestinationLocation: { LocationCode: last.DestinationLocation.LocationCode },\n TPA_Extensions: { Flight: legFlights },\n };\n });\n\n const { Version, POS, TravelerInfoSummary, TPA_Extensions } = search.OTA_AirLowFareSearchRQ;\n return {\n OTA_AirLowFareSearchRQ: {\n Version,\n POS,\n OriginDestinationInformation: originDestinations,\n TravelPreferences: {\n MaxStopsQuantity: Math.max(...itinerary.legs.map((leg) => leg.schedules.length - 1)),\n TPA_Extensions: { VerificationItinCallLogic: { Value: 'L' } },\n },\n TravelerInfoSummary,\n ...(TPA_Extensions === undefined ? {} : { TPA_Extensions }),\n },\n };\n}\n\nfunction flight({ schedule, departureDate, arrivalDate, bookingCode }: ItineraryFlight): LowFareSearchFlight {\n const { carrier } = schedule;\n return {\n Type: 'A',\n Number: carrier.marketingFlightNumber,\n DepartureDateTime: `${departureDate}T${localTime(schedule.departure.time)}`,\n ArrivalDateTime: `${arrivalDate}T${localTime(schedule.arrival.time)}`,\n ClassOfService: bookingCode,\n OriginLocation: { LocationCode: schedule.departure.airport },\n DestinationLocation: { LocationCode: schedule.arrival.airport },\n Airline: {\n Marketing: carrier.marketing,\n ...(carrier.operating === undefined ? {} : { Operating: carrier.operating }),\n },\n };\n}\n\n/** `17:10:00+02:00` → `17:10:00`. */\nfunction localTime(time: string): string {\n return time.slice(0, 8);\n}\n","// Módulo de dominio `sabre.air`. Ver sabre-wiki/wiki/sdk/convenciones-de-nombres-y-versionado.md.\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n bargainFinderMax,\n type BargainFinderMaxRequest,\n type BargainFinderMaxResponse,\n type RequestOptions,\n} from './bargain-finder-max.js';\nimport {\n revalidateItinerary,\n type RevalidateItineraryRequest,\n type RevalidateItineraryResponse,\n} from './revalidate-itinerary.js';\n\nexport class Air {\n readonly #transport: RestTransport;\n\n /** @internal Lo construye el cliente `Sabre`. */\n constructor(transport: RestTransport) {\n this.#transport = transport;\n }\n\n /**\n * Bargain Finder Max v5: busca itinerarios de menor precio. Devuelve el\n * `groupedItineraryResponse` con las referencias ya resueltas.\n */\n bargainFinderMax(request: BargainFinderMaxRequest, options?: RequestOptions): Promise<BargainFinderMaxResponse> {\n return bargainFinderMax(this.#transport, request, options);\n }\n\n /**\n * Revalidate Itinerary v5: revalida disponibilidad y precio de un itinerario ya elegido,\n * sin sostener inventario. El request se arma con `buildRevalidateItineraryRequest`.\n */\n revalidateItinerary(\n request: RevalidateItineraryRequest,\n options?: RequestOptions,\n ): Promise<RevalidateItineraryResponse> {\n return revalidateItinerary(this.#transport, request, options);\n }\n}\n","// Redacción obligatoria antes de que cualquier dato llegue al logger.\n// Ver sabre-wiki/wiki/sdk/configuracion-logging-y-build.md.\n\nexport const REDACTED = '[REDACTED]';\n\n/**\n * Claves cuyo valor se enmascara completo, comparadas sin distinguir mayúsculas\n * ni separadores (`client_secret`, `Client-Secret` y `clientSecret` son la misma).\n */\nconst SENSITIVE_KEYS = new Set(\n [\n // Credenciales\n 'clientSecret',\n 'password',\n 'username',\n 'authorization',\n 'binarySecurityToken',\n 'accessToken',\n 'refreshToken',\n 'token',\n // Datos de pasajero\n 'travelers',\n 'passengers',\n ].map(normalizeKey),\n);\n\nfunction normalizeKey(key: string): string {\n return key.replace(/[-_\\s]/g, '').toLowerCase();\n}\n\nexport function isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEYS.has(normalizeKey(key));\n}\n\n/** Copia profunda de `value` con los campos sensibles enmascarados. No muta la entrada. */\nexport function redact(value: unknown): unknown {\n return redactValue(value, new WeakSet());\n}\n\nfunction redactValue(value: unknown, seen: WeakSet<object>): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n\n if (Array.isArray(value)) return value.map((item) => redactValue(item, seen));\n if (value instanceof Headers) return redactEntries(value.entries(), seen);\n if (value instanceof Date) return value.toISOString();\n if (value instanceof Error) {\n // Los errores del SDK definen toJSON sin `raw`; para el resto, solo nombre y mensaje.\n const json = 'toJSON' in value && typeof value.toJSON === 'function' ? value.toJSON() : undefined;\n return redactValue(json ?? { name: value.name, message: value.message }, seen);\n }\n return redactEntries(Object.entries(value), seen);\n}\n\nfunction redactEntries(entries: Iterable<[string, unknown]>, seen: WeakSet<object>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, item] of entries) {\n out[key] = isSensitiveKey(key) ? REDACTED : redactValue(item, seen);\n }\n return out;\n}\n","// Logger inyectable. Ver sabre-wiki/wiki/sdk/configuracion-logging-y-build.md.\nimport { redact } from './redact.js';\n\n/**\n * Interfaz mínima de logger, compatible con `winston` y `console`.\n * Con `pino`, que invierte el orden: `info: (m, c) => pino.info(c, m)`.\n */\nexport interface SabreLogger {\n debug(message: string, context?: Record<string, unknown>): void;\n info(message: string, context?: Record<string, unknown>): void;\n warn(message: string, context?: Record<string, unknown>): void;\n error(message: string, context?: Record<string, unknown>): void;\n}\n\nexport type SabreLogLevel = keyof SabreLogger;\n\n/** Eventos estables que emite el SDK como `message`. */\nexport type SabreLogEvent =\n | 'sabre.request.start'\n | 'sabre.request.end'\n | 'sabre.request.retry'\n | 'sabre.request.rawResponseHookFailed'\n | 'sabre.auth.token.refresh'\n | 'sabre.auth.token.store';\n\n/** Logger interno: redacta siempre el contexto y no hace nada si no hay logger. */\nexport class EventLogger {\n readonly #logger: SabreLogger | undefined;\n\n constructor(logger?: SabreLogger) {\n this.#logger = logger;\n }\n\n emit(level: SabreLogLevel, event: SabreLogEvent, context: Record<string, unknown> = {}): void {\n if (this.#logger === undefined) return;\n try {\n this.#logger[level](event, redact(context) as Record<string, unknown>);\n } catch {\n // Un logger que falla no debe romper la request en curso.\n }\n }\n}\n","// Armado de la request de OAuth Token Create, una estrategia por versión.\n// Ver sabre-wiki/wiki/entities/oauth-token-create.md: v2 y v3 no son intercambiables.\nimport type { SabreAuthVersion, SabreCredentials, SabreCredentialsV2 } from '../config.js';\n\nexport interface TokenRequest {\n path: string;\n /** Valor del header `Authorization` (`Basic ...`). */\n authorization: string;\n body: URLSearchParams;\n}\n\n/** v3: `Basic base64(clientId:clientSecret)` y el EPR en el body con `grant_type=password`. */\nexport function buildTokenRequestV3(credentials: SabreCredentials): TokenRequest {\n return {\n path: '/v3/auth/token',\n authorization: `Basic ${base64(`${credentials.clientId}:${credentials.clientSecret}`)}`,\n body: new URLSearchParams({\n grant_type: 'password',\n username: credentials.username,\n password: credentials.password,\n }),\n };\n}\n\n/** v2: doble Base64 sobre el EPR y su password, con `grant_type=client_credentials`. */\nexport function buildTokenRequestV2(credentials: SabreCredentialsV2): TokenRequest {\n return {\n path: '/v2/auth/token',\n authorization: `Basic ${base64(`${base64(credentials.username)}:${base64(credentials.password)}`)}`,\n body: new URLSearchParams({ grant_type: 'client_credentials' }),\n };\n}\n\nexport function buildTokenRequest(\n authVersion: SabreAuthVersion,\n credentials: SabreCredentials | SabreCredentialsV2,\n): TokenRequest {\n // `resolveConfig` ya exige clientId/clientSecret cuando la versión es v3.\n return authVersion === 'v3'\n ? buildTokenRequestV3(credentials as SabreCredentials)\n : buildTokenRequestV2(credentials);\n}\n\n/** Base64 de los bytes UTF-8 de `text`, solo con Web APIs (sin `Buffer`). */\nexport function base64(text: string): string {\n let binary = '';\n for (const byte of new TextEncoder().encode(text)) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n","// Almacén de token inyectable por el consumidor. Ver sabre-wiki/wiki/sdk/renovacion-token-oauth.md,\n// sección \"Decisiones de la Fase 4\" (decisión B).\nimport type { SabreAuthVersion, SabreCredentials, SabreCredentialsV2, SabreEnvironment } from '../config.js';\n\n/** Token ATK tal cual se guarda: tiempos absolutos, para que otro proceso sepa cuánto le queda. */\nexport interface StoredToken {\n accessToken: string;\n /** Momento de obtención, en ms desde epoch. */\n obtainedAt: number;\n /** Momento de expiración, en ms desde epoch. */\n expiresAt: number;\n}\n\n/**\n * Almacén de token del consumidor (archivo, Redis, KV…). El SDK no trae implementaciones.\n *\n * `key` identifica la configuración (entorno, versión de OAuth y credencial, sin secretos):\n * un mismo store puede servir a varios clientes sin mezclar sus tokens. El token es un\n * secreto: protegerlo dentro del store es responsabilidad del consumidor.\n *\n * Si `get` o `set` lanzan, el SDK sigue con su caché en memoria: el store nunca rompe una llamada.\n */\nexport interface SabreTokenStore {\n get(key: string): Promise<StoredToken | undefined>;\n set(key: string, token: StoredToken): Promise<void>;\n}\n\n/**\n * `sabre-client:<environment>:<authVersion>:<hash>`, donde `hash` son los primeros 16 bytes\n * en hex del SHA-256 del username EPR (y del clientId en v3). No contiene secretos.\n */\nexport async function tokenStoreKey(\n environment: SabreEnvironment,\n authVersion: SabreAuthVersion,\n credentials: Readonly<SabreCredentials | SabreCredentialsV2>,\n): Promise<string> {\n const identity = authVersion === 'v3' ? `${credentials.clientId}\\n${credentials.username}` : credentials.username;\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(identity));\n const hash = [...new Uint8Array(digest).slice(0, 16)].map((byte) => byte.toString(16).padStart(2, '0')).join('');\n return `sabre-client:${environment}:${authVersion}:${hash}`;\n}\n\n/** Un valor de `get` que no tenga la forma de `StoredToken` se ignora. */\nexport function isStoredToken(value: unknown): value is StoredToken {\n if (typeof value !== 'object' || value === null) return false;\n const { accessToken, obtainedAt, expiresAt } = value as Record<string, unknown>;\n return (\n typeof accessToken === 'string' &&\n accessToken !== '' &&\n typeof obtainedAt === 'number' &&\n typeof expiresAt === 'number' &&\n Number.isFinite(obtainedAt) &&\n expiresAt > obtainedAt\n );\n}\n","// Obtención del token ATK de OAuth Token Create.\n// Ver sabre-wiki/wiki/sdk/renovacion-token-oauth.md y wiki/entities/oauth-token-create.md.\nimport type { ResolvedConfig } from '../config.js';\nimport { SabreGatewayError } from '../errors/index.js';\nimport type { AuthorizationProvider, RestTransport } from '../http/rest-transport.js';\nimport { EventLogger } from '../logging/logger.js';\nimport { buildTokenRequest } from './token-request.js';\nimport { isStoredToken, type SabreTokenStore, type StoredToken, tokenStoreKey } from './token-store.js';\n\nexport const TOKEN_SERVICE = 'oauthTokenCreate';\n\n/** Margen de refresco proactivo: 1 h antes de expirar (o media vida si el token dura menos). */\nexport const REFRESH_THRESHOLD_S = 3600;\n\nexport type TokenRefreshReason = 'initial' | 'proactive' | 'reactive';\n\n/** Token ATK obtenido de OAuth Token Create. */\nexport interface AccessToken {\n accessToken: string;\n /** Vida del token en segundos, tal cual llega en `expires_in`. */\n expiresIn: number;\n /** Momento de obtención, en ms desde epoch. */\n obtainedAt: number;\n}\n\ninterface TokenResponse {\n access_token?: unknown;\n expires_in?: unknown;\n token_type?: unknown;\n}\n\nexport interface AuthManagerOptions {\n /** Solo para tests: reloj en ms. */\n now?: () => number;\n}\n\n/**\n * Cachea el token en memoria (y en `tokenStore`, si lo hay), lo renueva antes de que expire\n * y comparte una sola petición en vuelo entre requests concurrentes. Interno en v0.3.0.\n */\nexport class AuthManager {\n readonly #config: ResolvedConfig;\n readonly #transport: RestTransport;\n readonly #now: () => number;\n readonly #log: EventLogger;\n #token: AccessToken | undefined;\n #inFlight: Promise<AccessToken> | undefined;\n /** El último token cacheado fue rechazado con 401 (el próximo refresco es reactivo). */\n #invalidated = false;\n /** Token rechazado con 401: si el store todavía lo tiene, no se vuelve a usar. */\n #rejected: string | undefined;\n readonly #store: SabreTokenStore | undefined;\n #storeKey: Promise<string> | undefined;\n\n constructor(config: ResolvedConfig, transport: RestTransport, options: AuthManagerOptions = {}) {\n this.#config = config;\n this.#transport = transport;\n this.#now = options.now ?? Date.now;\n this.#log = new EventLogger(config.logger);\n this.#store = config.tokenStore;\n }\n\n /** Token vigente; pide uno nuevo si no hay o si cruzó el umbral de refresco. */\n async getToken(): Promise<string> {\n const token = this.#token;\n if (token !== undefined && !this.#needsRefresh(token)) return token.accessToken;\n const reason = token !== undefined ? 'proactive' : this.#invalidated ? 'reactive' : 'initial';\n return (await this.#refresh(reason)).accessToken;\n }\n\n /**\n * Descarta `accessToken` tras un 401 de un servicio. Si el caché ya tiene otro token\n * (otra request lo renovó), no hace nada: los 401 concurrentes comparten un refresco.\n */\n invalidate(accessToken: string): void {\n if (this.#token?.accessToken !== accessToken) return;\n this.#token = undefined;\n this.#invalidated = true;\n this.#rejected = accessToken;\n }\n\n /** Adaptador de salida para el transporte REST: `Authorization: Bearer <token>`. */\n bearerProvider(): AuthorizationProvider {\n return {\n get: async () => `Bearer ${await this.getToken()}`,\n invalidate: (authorization) => this.invalidate(authorization.replace(/^Bearer /, '')),\n };\n }\n\n #needsRefresh(token: AccessToken): boolean {\n const thresholdMs = Math.min(REFRESH_THRESHOLD_S, token.expiresIn / 2) * 1000;\n return this.#now() >= token.obtainedAt + token.expiresIn * 1000 - thresholdMs;\n }\n\n /** Una sola petición en vuelo: las llamadas concurrentes esperan la misma promesa. */\n #refresh(reason: TokenRefreshReason): Promise<AccessToken> {\n this.#inFlight ??= this.#obtain(reason).finally(() => {\n this.#inFlight = undefined;\n });\n return this.#inFlight;\n }\n\n /** Token del store si sigue vigente (otro proceso pudo renovarlo); si no, uno nuevo. */\n async #obtain(reason: TokenRefreshReason): Promise<AccessToken> {\n const stored = await this.#readStore();\n if (stored !== undefined && stored.accessToken !== this.#rejected && !this.#needsRefresh(stored)) {\n this.#token = stored;\n this.#invalidated = false;\n return stored;\n }\n\n const token = await this.fetchToken();\n this.#token = token;\n this.#invalidated = false;\n this.#rejected = undefined;\n this.#log.emit('info', 'sabre.auth.token.refresh', {\n authVersion: this.#config.authVersion,\n reason,\n expiresIn: token.expiresIn,\n });\n await this.#writeStore(token);\n return token;\n }\n\n async #readStore(): Promise<AccessToken | undefined> {\n if (this.#store === undefined) return undefined;\n try {\n const value = await this.#store.get(await this.#key());\n if (!isStoredToken(value)) return undefined;\n return {\n accessToken: value.accessToken,\n expiresIn: (value.expiresAt - value.obtainedAt) / 1000,\n obtainedAt: value.obtainedAt,\n };\n } catch (error) {\n this.#storeFailed('get', error);\n return undefined;\n }\n }\n\n async #writeStore(token: AccessToken): Promise<void> {\n if (this.#store === undefined) return;\n const stored: StoredToken = {\n accessToken: token.accessToken,\n obtainedAt: token.obtainedAt,\n expiresAt: token.obtainedAt + token.expiresIn * 1000,\n };\n try {\n await this.#store.set(await this.#key(), stored);\n } catch (error) {\n this.#storeFailed('set', error);\n }\n }\n\n #key(): Promise<string> {\n const { environment, authVersion, credentials } = this.#config;\n this.#storeKey ??= tokenStoreKey(environment, authVersion, credentials);\n return this.#storeKey;\n }\n\n /**\n * El store nunca rompe la llamada: se sigue con el caché en memoria. Del error solo se\n * loguea el nombre: el mensaje lo arma el store del consumidor y podría traer el token.\n */\n #storeFailed(operation: 'get' | 'set', error: unknown): void {\n this.#log.emit('warn', 'sabre.auth.token.store', {\n authVersion: this.#config.authVersion,\n operation,\n errorName: error instanceof Error ? error.name : typeof error,\n });\n }\n\n /**\n * Pide un token nuevo. Los errores del endpoint (`invalid_request`/`invalid_client` 401,\n * `unauthorized` 403) salen como `SabreGatewayError` con `retryable: false`.\n */\n async fetchToken(): Promise<AccessToken> {\n const { path, authorization, body } = buildTokenRequest(this.#config.authVersion, this.#config.credentials);\n const response = await this.#transport.request<TokenResponse | undefined>({\n method: 'POST',\n path,\n service: TOKEN_SERVICE,\n // Pedir otro token no tiene efectos duplicados: 429/5xx entran en la política genérica.\n idempotent: true,\n auth: false,\n headers: { Authorization: authorization },\n body,\n });\n return this.#parse(response);\n }\n\n #parse(response: TokenResponse | undefined): AccessToken {\n const accessToken = response?.access_token;\n const expiresIn = response?.expires_in;\n if (typeof accessToken !== 'string' || accessToken === '' || typeof expiresIn !== 'number' || !(expiresIn > 0)) {\n throw new SabreGatewayError(`${TOKEN_SERVICE}: respuesta sin access_token/expires_in válidos`, {\n protocol: 'rest',\n status: 200,\n retryable: false,\n raw: response,\n });\n }\n return { accessToken, expiresIn, obtainedAt: this.#now() };\n }\n}\n","// `errors[]` de la Booking Management API: mismo `Error` del spec en Create, Get y Cancel.\n// Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md.\nimport { SabreBusinessError, SabreWarning } from '../errors/index.js';\n\nconst WARNING = 'WARNING';\n\n/** Elemento de `errors[]` tal cual lo manda Sabre (`Error` del spec; los avisos comparten forma). */\nexport interface BookingResponseError {\n /** `BAD_REQUEST`, `APPLICATION_ERROR`, `WARNING`, … */\n category: string;\n /** P. ej. `UNABLE_TO_BOOK_FLIGHTS`. */\n type: string;\n description?: string;\n fieldPath?: string;\n fieldName?: string;\n /** Puede traer datos del request (p. ej. un email): no se copia a los errores del SDK. */\n fieldValue?: string;\n}\n\nexport function responseErrors(response: { errors?: BookingResponseError[] }): BookingResponseError[] {\n return Array.isArray(response.errors) ? response.errors.filter(isObject) as BookingResponseError[] : [];\n}\n\nexport function isWarning(item: BookingResponseError): boolean {\n return typeof item.category === 'string' && item.category.toUpperCase() === WARNING;\n}\n\nexport function toWarning(service: string, item: BookingResponseError): SabreWarning {\n return new SabreWarning(messageOf(service, item), { service, code: codeOf(item), raw: item });\n}\n\nexport interface BusinessErrorAttachments {\n warnings?: SabreWarning[];\n errors?: SabreBusinessError[];\n retryable?: boolean;\n}\n\nexport function toBusinessError(\n service: string,\n item: BookingResponseError,\n { warnings = [], errors = [], retryable = false }: BusinessErrorAttachments = {},\n): SabreBusinessError {\n return new SabreBusinessError(messageOf(service, item), {\n service,\n code: codeOf(item),\n raw: item,\n warnings,\n errors,\n retryable,\n });\n}\n\nexport function codeOf(item: BookingResponseError): string {\n return typeof item.type === 'string' && item.type !== '' ? item.type : String(item.category);\n}\n\n/** Sin `fieldValue`, que puede traer datos del pasajero; queda en `raw`. */\nfunction messageOf(service: string, item: BookingResponseError): string {\n const where = typeof item.fieldPath === 'string' && item.fieldPath !== '' ? ` en ${item.fieldPath}` : '';\n const description = typeof item.description === 'string' && item.description !== '' ? `: ${item.description}` : '';\n return `${service}: ${String(item.category)} ${codeOf(item)}${where}${description}`;\n}\n\nexport function nonEmpty(value: unknown): value is string {\n return typeof value === 'string' && value !== '';\n}\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","// Cancel Booking (`POST /v1/trip/orders/cancelBooking`).\n// Ver sabre-wiki/wiki/sdk/gestion-de-reserva.md y sabre-wiki/wiki/sources/cancel-booking.md.\nimport { SabreError, type SabreWarning } from '../errors/index.js';\nimport type { SabreRawResponseCallback } from '../http/raw-response.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n type BookingResponseError,\n isObject,\n isWarning,\n nonEmpty,\n responseErrors,\n toBusinessError,\n toWarning,\n} from './booking-errors.js';\nimport type { Booking } from './create-booking.js';\nimport type { BookingSource } from './get-booking.js';\n\nexport const CANCEL_BOOKING_SERVICE = 'cancelBooking';\nconst PATH = '/v1/trip/orders/cancelBooking';\n/** Llega con `category: WARNING`, pero significa que no se canceló nada (decidido en #39). */\nconst NO_ITEMS_CANCELLED = 'NO_ITEMS_CANCELLED';\nconst ITEM_LISTS = ['flights', 'hotels', 'cars', 'trains', 'cruises', 'segments'] as const;\n\n/** `HALT_ON_ERROR` (default de Sabre, con rollback) o `ALLOW_PARTIAL_CANCEL`. */\nexport type CancelBookingErrorPolicy = 'HALT_ON_ERROR' | 'ALLOW_PARTIAL_CANCEL';\n\nexport type FlightTicketOperation = 'VOID' | 'REFUND';\n\nexport type RefundDocumentsType = 'Tickets' | 'EMDs' | 'Tickets and EMDs';\n\n/** Producto a cancelar, por el `itemId` que devuelve Get Booking (p. ej. `flights[].itemId`). */\nexport interface BookingItemReference {\n itemId: string;\n}\n\n/**\n * Segmento a cancelar, por `id` o por `sequence`. Sabre desaconseja `sequence`: la posición\n * puede cambiar entre la lectura y la cancelación.\n */\nexport interface CancelSegmentReference {\n id?: string;\n sequence?: number;\n}\n\n/** `Notification` del spec: `email` o `queuePlacement`, no los dos. Se envía tal cual. */\nexport interface CancelBookingNotification {\n email?: 'DEFAULT' | 'INVOICE' | 'ETICKET' | 'ETICKET_PDF' | 'ITINERARY' | 'ITINERARY_PDF';\n queuePlacement?: Array<Record<string, unknown>>;\n}\n\n/**\n * `CancelBookingRequest` del spec v1.33. El Tier 1 usa `cancelAll` o `flights[].itemId` sobre\n * contenido ATPCO; los campos de tickets, NDC, impresoras, notificación y retención se envían\n * tal cual, sin lógica propia.\n */\nexport interface CancelBookingRequest {\n /** Localizador del PNR u Order ID (`^[A-Z0-9]{6,}$`). Único campo obligatorio. */\n confirmationId: string;\n bookingSource?: BookingSource;\n /** Cancela todos los segmentos. No se combina con las listas. */\n cancelAll?: boolean;\n flights?: BookingItemReference[];\n hotels?: BookingItemReference[];\n cars?: BookingItemReference[];\n trains?: BookingItemReference[];\n cruises?: BookingItemReference[];\n segments?: CancelSegmentReference[];\n /** Sin valor, Sabre aplica `HALT_ON_ERROR`: si algo falla, deshace lo ya cancelado. */\n errorHandlingPolicy?: CancelBookingErrorPolicy;\n /** Si es `true`, la respuesta trae el estado posterior en `booking`. */\n retrieveBooking?: boolean;\n /** Firma del cambio en el PNR. Sabre usa `LW CANCEL API` por defecto. */\n receivedFrom?: string;\n /** El contexto no se revierte al terminar. */\n targetPcc?: string;\n /** No se combina con `offerItemId`. */\n flightTicketOperation?: FlightTicketOperation;\n /** Solo NDC. No se combina con `flightTicketOperation`. */\n offerItemId?: string;\n notification?: CancelBookingNotification;\n designatePrinters?: Array<Record<string, unknown>>;\n retentionEndDate?: string;\n retentionLabel?: string;\n voidNonElectronicTickets?: boolean;\n refundDocumentsType?: RefundDocumentsType;\n}\n\nexport interface CancelBookingOptions {\n signal?: AbortSignal;\n /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */\n onRawResponse?: SabreRawResponseCallback;\n}\n\n/** `CancelBookingResponse` tal cual llega de Sabre. */\nexport interface RawCancelBookingResponse {\n timestamp?: string;\n request?: CancelBookingRequest;\n booking?: Booking;\n tickets?: Array<Record<string, unknown>>;\n voidedTickets?: string[];\n refundedTickets?: string[];\n flightRefunds?: Array<Record<string, unknown>>;\n errors?: BookingResponseError[];\n}\n\n/** Cancelación con éxito: sin errores fatales y sin `NO_ITEMS_CANCELLED`. */\nexport interface CancelBookingResponse {\n timestamp?: string;\n /** Eco del request con los defaults de Sabre completados. */\n request?: CancelBookingRequest;\n /** Estado posterior de la reserva, anidado (solo con `retrieveBooking: true`). */\n booking?: Booking;\n tickets?: Array<Record<string, unknown>>;\n voidedTickets?: string[];\n refundedTickets?: string[];\n flightRefunds?: Array<Record<string, unknown>>;\n /**\n * Elementos de `errors[]` con `category: WARNING`. Con `END_TRANSACTION_PROBLEM` la\n * confirmación quedó pendiente: verifica el resultado con `sabre.booking.get`.\n */\n warnings: SabreWarning[];\n}\n\n/**\n * Cancel Booking: escritura sin reintento automático. Solo el reintento reactivo ante 401,\n * que el gateway rechaza antes de llegar al proveedor.\n */\nexport async function cancelBooking(\n transport: RestTransport,\n request: CancelBookingRequest,\n options: CancelBookingOptions = {},\n): Promise<CancelBookingResponse> {\n validateCancelBookingRequest(request);\n const body = await transport.request<RawCancelBookingResponse>({\n method: 'POST',\n path: PATH,\n service: CANCEL_BOOKING_SERVICE,\n idempotent: false,\n body: request,\n classify: classifyCancelBooking,\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n ...(options.onRawResponse === undefined\n ? {}\n : { operation: 'booking.cancel', onRawResponse: options.onRawResponse }),\n });\n return toCancelBookingResponse(body);\n}\n\n/** Combinaciones que Sabre rechaza seguro (`INVALID_FLAGS_COMBINATION`, `CANCEL_DATA_MISSING`). */\nfunction validateCancelBookingRequest(request: CancelBookingRequest): void {\n if (!isObject(request) || !nonEmpty(request.confirmationId)) {\n throw new TypeError('sabre-client: booking.cancel espera { confirmationId: string, ... }');\n }\n const lists = ITEM_LISTS.join(', ');\n if (request.cancelAll === true) {\n if (ITEM_LISTS.some((list) => request[list] !== undefined)) {\n throw new TypeError(`sabre-client: booking.cancel no combina cancelAll con listas (${lists})`);\n }\n } else if (!ITEM_LISTS.some((list) => Array.isArray(request[list]) && request[list].length > 0)) {\n throw new TypeError(`sabre-client: booking.cancel necesita cancelAll: true o al menos una lista (${lists})`);\n }\n if (request.offerItemId !== undefined && request.flightTicketOperation !== undefined) {\n throw new TypeError('sabre-client: booking.cancel no combina offerItemId con flightTicketOperation');\n }\n}\n\n/**\n * Paso 3 del orden de detección. Éxito = ningún error que no sea `WARNING` y ningún\n * `NO_ITEMS_CANCELLED`. Si no:\n *\n * - Con `NO_ITEMS_CANCELLED`: `SabreBusinessError` con ese código; los errores que explican\n * el fallo van en `errors` y los demás avisos en `warnings`.\n * - Sin él: `SabreBusinessError` con el primer error que no sea `WARNING`, el resto en\n * `errors` y los avisos en `warnings`.\n */\nexport function classifyCancelBooking(body: unknown): SabreError | undefined {\n if (!isObject(body)) {\n return new SabreError(`${CANCEL_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {\n retryable: false,\n raw: body,\n });\n }\n const items = responseErrors(body as RawCancelBookingResponse);\n const nothingCancelled = items.find(isNoItemsCancelled);\n const warnings = items.filter((item) => isWarning(item) && !isNoItemsCancelled(item)).map(warningOf);\n const fatal = items.filter((item) => !isWarning(item));\n\n if (nothingCancelled !== undefined) {\n return toBusinessError(CANCEL_BOOKING_SERVICE, nothingCancelled, { warnings, errors: fatal.map(errorOf) });\n }\n const [first, ...rest] = fatal;\n if (first === undefined) return undefined;\n return toBusinessError(CANCEL_BOOKING_SERVICE, first, { warnings, errors: rest.map(errorOf) });\n}\n\n/** Solo para respuestas con éxito (ver `classifyCancelBooking`): `errors[]` trae solo avisos. */\nfunction toCancelBookingResponse(body: RawCancelBookingResponse): CancelBookingResponse {\n const { errors: _errors, ...rest } = body;\n return { ...rest, warnings: responseErrors(body).map(warningOf) };\n}\n\nfunction isNoItemsCancelled(item: BookingResponseError): boolean {\n return item.type === NO_ITEMS_CANCELLED;\n}\n\nfunction warningOf(item: BookingResponseError): SabreWarning {\n return toWarning(CANCEL_BOOKING_SERVICE, item);\n}\n\nfunction errorOf(item: BookingResponseError) {\n return toBusinessError(CANCEL_BOOKING_SERVICE, item);\n}\n","// Create Booking (`POST /v1/trip/orders/createBooking`).\n// Ver sabre-wiki/wiki/entities/booking-management-api.md y\n// sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md (éxito parcial de Create Booking).\nimport { type SabreBusinessError, SabreError, type SabreWarning } from '../errors/index.js';\nimport type { SabreRawResponseCallback } from '../http/raw-response.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n type BookingResponseError,\n isObject,\n isWarning,\n nonEmpty,\n responseErrors,\n toBusinessError,\n toWarning,\n} from './booking-errors.js';\nimport type { CreateBookingRequest } from './create-booking-request.js';\n\nexport const CREATE_BOOKING_SERVICE = 'createBooking';\nconst PATH = '/v1/trip/orders/createBooking';\n/** Aviso cuyo `description` trae el `confirmationId` de una reserva que sí se creó. */\nconst UNABLE_TO_RETRIEVE_BOOKING = 'UNABLE_TO_RETRIEVE_BOOKING';\n\nexport interface CreateBookingOptions {\n signal?: AbortSignal;\n /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */\n onRawResponse?: SabreRawResponseCallback;\n}\n\n/** Elemento de `errors[]` de Create Booking. */\nexport type CreateBookingResponseError = BookingResponseError;\n\n/**\n * `Booking` del spec (mismo modelo que Get Booking). Se tipa el primer nivel; el detalle de\n * `flights`, `travelers`, `fares`, etc. queda sin tipar en el Tier 1.\n */\nexport interface Booking {\n bookingId?: string;\n startDate?: string;\n endDate?: string;\n isCancelable?: boolean;\n isTicketed?: boolean;\n [field: string]: unknown;\n}\n\n/** `CreateBookingResponse` tal cual llega de Sabre. */\nexport interface RawCreateBookingResponse {\n timestamp?: string;\n confirmationId?: string;\n booking?: Booking;\n errors?: CreateBookingResponseError[];\n request?: CreateBookingRequest;\n}\n\n/**\n * Reserva creada. Si Sabre la creó con avisos o con errores no fatales (p. ej. con\n * `errorHandlingPolicy: DO_NOT_HALT_ON_*`), no se lanza: van adjuntos aquí.\n */\nexport interface CreateBookingResponse {\n /** Localizador del PNR. */\n confirmationId: string;\n timestamp?: string;\n /** Falta, p. ej., con el aviso `UNABLE_TO_RETRIEVE_BOOKING`. */\n booking?: Booking;\n /** Copia del request enviado, si Sabre la devuelve. */\n request?: CreateBookingRequest;\n /** Elementos de `errors[]` con `category: WARNING`. */\n warnings: SabreWarning[];\n /** Elementos de `errors[]` de otras categorías que no impidieron crear la reserva. */\n errors: SabreBusinessError[];\n}\n\n/**\n * Create Booking: escritura no idempotente, sin reintento automático. Solo el reintento\n * reactivo ante 401, que el gateway rechaza antes de llegar al proveedor.\n */\nexport async function createBooking(\n transport: RestTransport,\n request: CreateBookingRequest,\n options: CreateBookingOptions = {},\n): Promise<CreateBookingResponse> {\n validateCreateBookingRequest(request);\n const body = await transport.request<RawCreateBookingResponse>({\n method: 'POST',\n path: PATH,\n service: CREATE_BOOKING_SERVICE,\n idempotent: false,\n body: request,\n classify: classifyCreateBooking,\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n ...(options.onRawResponse === undefined\n ? {}\n : { operation: 'booking.create', onRawResponse: options.onRawResponse }),\n });\n return toCreateBookingResponse(body);\n}\n\n/**\n * Reglas de la API que Sabre rechaza seguro, iguales para todas las agencias:\n * `FUTURE_TICKETING` sin `futureTicketingPolicy` vuelve como `MANDATORY_DATA_MISSING`. Solo se\n * revisa que la policy esté, no su contenido; los valores de la agencia van tal cual.\n */\nfunction validateCreateBookingRequest(request: CreateBookingRequest): void {\n if (typeof request !== 'object' || request === null) {\n throw new TypeError('sabre-client: booking.create espera un objeto CreateBookingRequest');\n }\n const agency = request.agency;\n if (agency?.ticketingPolicy === 'FUTURE_TICKETING' && agency.futureTicketingPolicy === undefined) {\n throw new TypeError(\n 'sabre-client: booking.create con agency.ticketingPolicy FUTURE_TICKETING necesita agency.futureTicketingPolicy',\n );\n }\n}\n\n/**\n * Paso 3 del orden de detección. Lo que decide si se lanza es si la reserva se creó, no la\n * categoría de `errors[]`:\n *\n * - Hay reserva (`confirmationId`, `booking.bookingId` o el aviso `UNABLE_TO_RETRIEVE_BOOKING`\n * con el localizador en el `description`): no hay error, `toCreateBookingResponse` adjunta\n * avisos y errores al resultado.\n * - No hay reserva: `SabreBusinessError` con el primer error que no sea `WARNING`, y los\n * avisos adjuntos.\n */\nexport function classifyCreateBooking(body: unknown): SabreError | undefined {\n if (!isObject(body)) {\n return new SabreError(`${CREATE_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {\n retryable: false,\n raw: body,\n });\n }\n const response = body as RawCreateBookingResponse;\n if (confirmationIdOf(response) !== undefined) return undefined;\n\n // La reserva existe pero no hay localizador que devolver: no es un \"no se creó\".\n if (reservationWithoutId(response)) {\n return new SabreError(\n `${CREATE_BOOKING_SERVICE}: Sabre indica que la reserva se creó, pero no devolvió su confirmationId`,\n { retryable: false, raw: body },\n );\n }\n const items = responseErrors(response);\n const fatal = items.find((item) => !isWarning(item));\n if (fatal !== undefined) return toBusinessError(CREATE_BOOKING_SERVICE, fatal, { warnings: items.filter(isWarning).map(warningOf) });\n return new SabreError(`${CREATE_BOOKING_SERVICE}: respuesta malformada, sin confirmationId ni errores fatales`, {\n retryable: false,\n raw: body,\n });\n}\n\n/** Solo para respuestas con reserva (ver `classifyCreateBooking`). */\nfunction toCreateBookingResponse(body: RawCreateBookingResponse): CreateBookingResponse {\n const items = responseErrors(body);\n return {\n confirmationId: confirmationIdOf(body)!,\n ...(body.timestamp === undefined ? {} : { timestamp: body.timestamp }),\n ...(body.booking === undefined ? {} : { booking: body.booking }),\n ...(body.request === undefined ? {} : { request: body.request }),\n warnings: items.filter(isWarning).map(warningOf),\n errors: items.filter((item) => !isWarning(item)).map((item) => toBusinessError(CREATE_BOOKING_SERVICE, item)),\n };\n}\n\nfunction confirmationIdOf(response: RawCreateBookingResponse): string | undefined {\n if (nonEmpty(response.confirmationId)) return response.confirmationId;\n if (nonEmpty(response.booking?.bookingId)) return response.booking.bookingId;\n const notRetrieved = responseErrors(response).find((item) => item.type === UNABLE_TO_RETRIEVE_BOOKING);\n return notRetrieved === undefined ? undefined : locatorIn(notRetrieved.description);\n}\n\nfunction reservationWithoutId(response: RawCreateBookingResponse): boolean {\n return response.booking !== undefined || responseErrors(response).some((item) => item.type === UNABLE_TO_RETRIEVE_BOOKING);\n}\n\n/**\n * El catálogo documenta el description como `Booking was created successfully but could not\n * be retrieved. (confirmationId)`. Se prefiere el valor entre paréntesis.\n */\nfunction locatorIn(description: string | undefined): string | undefined {\n if (description === undefined) return undefined;\n return /\\(([A-Z0-9]{6,})\\)/.exec(description)?.[1] ?? /\\b([A-Z0-9]{6,})\\b/.exec(description)?.[1];\n}\n\nfunction warningOf(item: BookingResponseError): SabreWarning {\n return toWarning(CREATE_BOOKING_SERVICE, item);\n}\n","// Get Booking (`POST /v1/trip/orders/getBooking`).\n// Ver sabre-wiki/wiki/sdk/gestion-de-reserva.md y sabre-wiki/wiki/sources/get-booking.md.\nimport { type SabreBusinessError, SabreError, type SabreWarning } from '../errors/index.js';\nimport type { SabreRawResponseCallback } from '../http/raw-response.js';\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n type BookingResponseError,\n isObject,\n isWarning,\n nonEmpty,\n responseErrors,\n toBusinessError,\n toWarning,\n} from './booking-errors.js';\nimport type { Booking } from './create-booking.js';\n\nexport const GET_BOOKING_SERVICE = 'getBooking';\nconst PATH = '/v1/trip/orders/getBooking';\n/** Fallos de sistema que Sabre puede resolver al repetir la lectura (decidido en #39). */\nconst RETRYABLE_TYPES = new Set(['INTERNAL_SERVER_TIMEOUT', 'DOWNLINE_SERVICE_FAILURE']);\n\n/** Secciones de la respuesta (`ReturnOnlyEnum`). Además evitan llamadas downline de Sabre. */\nexport type GetBookingReturnOnly =\n | 'FLIGHTS'\n | 'FLIGHT_PENALTY'\n | 'BAGGAGE_POLICY'\n | 'JOURNEYS'\n | 'HOTELS'\n | 'HOTEL_ADDRESS'\n | 'CARS'\n | 'CAR_RENTAL_ADDRESS'\n | 'CAR_RENTAL_PENALTY'\n | 'TRAINS'\n | 'CRUISES'\n | 'ALL_SEGMENTS'\n | 'TRAVELERS'\n | 'TICKETS'\n | 'PAYMENTS'\n | 'PENALTIES'\n | 'REMARKS'\n | 'IS_CANCELABLE'\n | 'IS_TICKETED'\n | 'CONTACT_INFO'\n | 'OTHER_SERVICES'\n | 'SPECIAL_SERVICES'\n | 'FARES'\n | 'CREATION_DETAILS'\n | 'ANCILLARIES'\n | 'FORMS_OF_PAYMENT'\n | 'RETENTION_DATE'\n | 'ACCOUNTING_ITEMS'\n | 'NON_ELECTRONIC_TICKETS'\n | 'TRAVELERS_EMPLOYERS'\n | 'PROFILES';\n\n/** `BookingSourceEnum`. Por defecto `SABRE`. */\nexport type BookingSource = 'SABRE' | 'SABRE_ORDER';\n\n/** `ExtraFeatures` del spec (incluye `CommonExtraFeatures`). */\nexport interface GetBookingExtraFeatures {\n /** Solo NDC. Por defecto `true`. */\n returnEmptySeatObjects?: boolean;\n /** Por defecto `false`; más lento. */\n forceHotelUpdate?: boolean;\n returnFrequentRenter?: boolean;\n returnWalletFormsOfPayment?: boolean;\n returnFiscalId?: boolean;\n}\n\n/** `GetBookingRequest` del spec v1.33. */\nexport interface GetBookingRequest {\n /** Localizador del PNR u Order ID (`^[A-Z0-9]{6,}$`). Único campo obligatorio. */\n confirmationId: string;\n bookingSource?: BookingSource;\n /** Cambio de contexto (`^[A-Z0-9]{3,4}$`). */\n targetPcc?: string;\n /** Validación extra: si no coincide con el PNR, Sabre responde `UNAUTHORIZED_ACCESS`. */\n surname?: string;\n /** Según el spec, Sabre no los usa; solo `surname`. */\n givenName?: string;\n middleName?: string;\n /** Vacío o ausente: la reserva completa. */\n returnOnly?: GetBookingReturnOnly[];\n extraFeatures?: GetBookingExtraFeatures;\n /** Requiere el keyword `CCVIEW` en el EPR. */\n unmaskPaymentCardNumbers?: boolean;\n}\n\nexport interface GetBookingOptions {\n signal?: AbortSignal;\n /** Respuesta cruda del último intento HTTP. El body trae PII: ver `SabreRawResponse`. */\n onRawResponse?: SabreRawResponseCallback;\n}\n\n/** `GetBookingResponse` tal cual llega de Sabre: el `Booking` va en el primer nivel. */\nexport interface RawGetBookingResponse extends Booking {\n timestamp?: string;\n bookingSignature?: string;\n request?: GetBookingRequest;\n errors?: BookingResponseError[];\n}\n\n/**\n * Reserva leída, con el `Booking` en el primer nivel tal cual lo define Sabre (no se normaliza\n * contra Create ni Cancel, que lo anidan en `booking`). `errors[]` del original se reemplaza\n * por los errores del SDK.\n */\nexport interface GetBookingResponse extends Booking {\n bookingId: string;\n timestamp?: string;\n /** Solo viene si Sabre armó la reserva sin errores. Lo usa Modify Booking. */\n bookingSignature?: string;\n /** Copia del request enviado, si Sabre la devuelve. */\n request?: GetBookingRequest;\n /**\n * Elementos de `errors[]` con `category: WARNING`. En un PNR sin emitir es normal\n * `RESOURCE_UNAVAILABLE` por falta de fare rules.\n */\n warnings: SabreWarning[];\n /**\n * Elementos de `errors[]` de otras categorías que llegaron junto con la reserva, p. ej.\n * `UNAUTHORIZED_ACCESS` de un servicio downline: faltan secciones, pero la reserva existe.\n */\n errors: SabreBusinessError[];\n}\n\n/**\n * Get Booking: lectura idempotente. Los 429/5xx de gateway se reintentan con la política\n * genérica, y también `INTERNAL_SERVER_TIMEOUT` y `DOWNLINE_SERVICE_FAILURE`.\n */\nexport async function getBooking(\n transport: RestTransport,\n request: GetBookingRequest,\n options: GetBookingOptions = {},\n): Promise<GetBookingResponse> {\n if (!isObject(request) || !nonEmpty(request.confirmationId)) {\n throw new TypeError('sabre-client: booking.get espera { confirmationId: string, ... }');\n }\n const body = await transport.request<RawGetBookingResponse>({\n method: 'POST',\n path: PATH,\n service: GET_BOOKING_SERVICE,\n idempotent: true,\n body: request,\n classify: classifyGetBooking,\n ...(options.signal === undefined ? {} : { signal: options.signal }),\n ...(options.onRawResponse === undefined\n ? {}\n : { operation: 'booking.get', onRawResponse: options.onRawResponse }),\n });\n return toGetBookingResponse(body);\n}\n\n/**\n * Paso 3 del orden de detección. Lo que decide si se lanza es si hay reserva (`bookingId`):\n *\n * - Hay reserva: no hay error; `toGetBookingResponse` adjunta avisos y errores al resultado.\n * - No hay reserva: `SabreBusinessError` con el primer error que no sea `WARNING` (p. ej.\n * `BOOKING_NOT_FOUND` o `UNAUTHORIZED_ACCESS`), y los avisos adjuntos.\n */\nexport function classifyGetBooking(body: unknown): SabreError | undefined {\n if (!isObject(body)) {\n return new SabreError(`${GET_BOOKING_SERVICE}: respuesta malformada, se esperaba un objeto`, {\n retryable: false,\n raw: body,\n });\n }\n const response = body as RawGetBookingResponse;\n if (nonEmpty(response.bookingId)) return undefined;\n\n const items = responseErrors(response);\n const fatal = items.find((item) => !isWarning(item));\n if (fatal !== undefined) return errorOf(fatal, items.filter(isWarning).map(warningOf));\n return new SabreError(`${GET_BOOKING_SERVICE}: respuesta malformada, sin bookingId ni errores fatales`, {\n retryable: false,\n raw: body,\n });\n}\n\n/** Solo para respuestas con reserva (ver `classifyGetBooking`). */\nfunction toGetBookingResponse(body: RawGetBookingResponse): GetBookingResponse {\n const items = responseErrors(body);\n return {\n ...body,\n bookingId: body.bookingId!,\n warnings: items.filter(isWarning).map(warningOf),\n errors: items.filter((item) => !isWarning(item)).map((item) => errorOf(item, [])),\n };\n}\n\nfunction warningOf(item: BookingResponseError): SabreWarning {\n return toWarning(GET_BOOKING_SERVICE, item);\n}\n\nfunction errorOf(item: BookingResponseError, warnings: SabreWarning[]): SabreBusinessError {\n return toBusinessError(GET_BOOKING_SERVICE, item, { warnings, retryable: RETRYABLE_TYPES.has(item.type) });\n}\n","// Módulo de dominio `sabre.booking` (Booking Management API).\n// Ver sabre-wiki/wiki/sdk/convenciones-de-nombres-y-versionado.md.\nimport type { RestTransport } from '../http/rest-transport.js';\nimport {\n cancelBooking,\n type CancelBookingOptions,\n type CancelBookingRequest,\n type CancelBookingResponse,\n} from './cancel-booking.js';\nimport type { CreateBookingRequest } from './create-booking-request.js';\nimport { createBooking, type CreateBookingOptions, type CreateBookingResponse } from './create-booking.js';\nimport { getBooking, type GetBookingOptions, type GetBookingRequest, type GetBookingResponse } from './get-booking.js';\n\nexport class BookingManagement {\n readonly #transport: RestTransport;\n\n /** @internal Lo construye el cliente `Sabre`. */\n constructor(transport: RestTransport) {\n this.#transport = transport;\n }\n\n /**\n * Create Booking: crea la reserva. Para un itinerario de BFM/Revalidate, `flightDetails` se\n * arma con `buildBookingFlightDetails`.\n *\n * Nunca se reintenta automáticamente. Si la reserva se crea con avisos o errores no fatales,\n * no lanza: los devuelve en `warnings` y `errors`. Si no se crea, lanza `SabreBusinessError`.\n * Con `agency.ticketingPolicy: 'FUTURE_TICKETING'` y sin `agency.futureTicketingPolicy`, lanza\n * `TypeError` sin llamar a la red: Sabre lo rechaza seguro.\n */\n create(request: CreateBookingRequest, options?: CreateBookingOptions): Promise<CreateBookingResponse> {\n return createBooking(this.#transport, request, options);\n }\n\n /**\n * Get Booking: lee la reserva por `confirmationId`. El `Booking` va en el primer nivel de la\n * respuesta, a diferencia de `create`. Usa `returnOnly` para pedir solo las secciones que\n * hacen falta: además acelera la respuesta.\n *\n * Si la reserva existe, no lanza: los avisos y errores parciales van en `warnings` y\n * `errors`. Si no existe o no se pudo leer (p. ej. `BOOKING_NOT_FOUND`), lanza\n * `SabreBusinessError`. Es una lectura: se reintenta ante fallos transitorios.\n */\n get(request: GetBookingRequest, options?: GetBookingOptions): Promise<GetBookingResponse> {\n return getBooking(this.#transport, request, options);\n }\n\n /**\n * Cancel Booking: cancela la reserva entera (`cancelAll: true`) o por `itemId` (p. ej. los\n * `flights[].itemId` de `get`). Valida antes de enviar las combinaciones que Sabre rechaza y,\n * si encuentra una, lanza `TypeError` sin llamar a la red.\n *\n * Nunca se reintenta automáticamente. Lanza `SabreBusinessError` si algo falló o si Sabre\n * responde `NO_ITEMS_CANCELLED` (no se canceló nada), aunque llegue como aviso. Con\n * `END_TRANSACTION_PROBLEM` en `warnings`, la confirmación quedó pendiente: verifica con `get`.\n */\n cancel(request: CancelBookingRequest, options?: CancelBookingOptions): Promise<CancelBookingResponse> {\n return cancelBooking(this.#transport, request, options);\n }\n}\n","// Política de reintentos. Ver sabre-wiki/wiki/sdk/politica-de-reintentos-y-backoff.md.\nimport { SabreError } from '../errors/index.js';\n\nexport interface RetryOptions {\n /** Reintentos después de la primera llamada (3 → hasta 4 llamadas en total). */\n maxRetries: number;\n /** Delay base del backoff exponencial, en milisegundos. */\n baseDelayMs: number;\n}\n\nexport const DEFAULT_RETRY: Readonly<RetryOptions> = Object.freeze({ maxRetries: 3, baseDelayMs: 500 });\n\n/** Piso mínimo de espera que documenta Sabre para 429/5xx de gateway. */\nexport const MIN_RETRY_DELAY_MS = 500;\n\n/** Full jitter: aleatorio entre 0 y `baseDelayMs · 2^retry`, con piso de 500 ms. */\nexport function retryDelay(retry: number, baseDelayMs: number, random: () => number = Math.random): number {\n return Math.max(MIN_RETRY_DELAY_MS, Math.floor(random() * baseDelayMs * 2 ** retry));\n}\n\n/** Solo se reintenta un `SabreError` con `retryable: true` en una operación idempotente. */\nexport function shouldRetry(error: unknown, idempotent: boolean): boolean {\n return idempotent && error instanceof SabreError && error.retryable;\n}\n\nexport function validateRetryOptions(retry: Partial<RetryOptions>, where: string): void {\n if (retry.maxRetries !== undefined && !(Number.isInteger(retry.maxRetries) && retry.maxRetries >= 0)) {\n throw new TypeError(`sabre-client: ${where}.maxRetries debe ser un entero >= 0`);\n }\n if (retry.baseDelayMs !== undefined && !(Number.isFinite(retry.baseDelayMs) && retry.baseDelayMs >= 0)) {\n throw new TypeError(`sabre-client: ${where}.baseDelayMs debe ser un número >= 0`);\n }\n}\n","// Config explícita del consumidor; el SDK nunca lee variables de entorno.\n// Ver sabre-wiki/wiki/sdk/configuracion-logging-y-build.md.\nimport type { SabreTokenStore } from './auth/token-store.js';\nimport { DEFAULT_RETRY, type RetryOptions, validateRetryOptions } from './http/retry.js';\nimport type { SabreLogger } from './logging/index.js';\n\nexport type SabreEnvironment = 'sandbox' | 'production';\n\nexport type SabreAuthVersion = 'v3' | 'v2';\n\n/** Credenciales para OAuth Token Create v3: Client ID/Secret más usuario EPR. */\nexport interface SabreCredentials {\n clientId: string;\n clientSecret: string;\n /** Usuario EPR. */\n username: string;\n /** Contraseña EPR. */\n password: string;\n}\n\n/** Credenciales para OAuth Token Create v2: solo EPR; `clientId`/`clientSecret` se ignoran. */\nexport interface SabreCredentialsV2 {\n clientId?: string;\n clientSecret?: string;\n /** Usuario EPR. */\n username: string;\n /** Contraseña EPR. */\n password: string;\n}\n\ninterface SabreBaseConfig {\n environment: SabreEnvironment;\n /** Campo reservado: PCC vs iPCC sigue sin resolver. */\n pcc?: string;\n logger?: SabreLogger;\n /** Reintentos por defecto del cliente; cada request puede pisarlos. */\n retry?: Partial<RetryOptions>;\n /** `fetch` a usar en lugar del global (tests, proxies, runtimes edge). */\n fetch?: typeof fetch;\n /**\n * Almacén del token para reutilizarlo entre procesos (scripts, serverless). Sin él, el\n * token se cachea solo en memoria.\n */\n tokenStore?: SabreTokenStore;\n}\n\n/** OAuth Token Create v3 (por defecto). */\nexport interface SabreConfigV3 extends SabreBaseConfig {\n authVersion?: 'v3';\n credentials: SabreCredentials;\n}\n\n/** OAuth Token Create v2. */\nexport interface SabreConfigV2 extends SabreBaseConfig {\n authVersion: 'v2';\n credentials: SabreCredentialsV2;\n}\n\n/** Config del cliente, discriminada por `authVersion`. */\nexport type SabreConfig = SabreConfigV3 | SabreConfigV2;\n\nexport const BASE_URLS: Readonly<Record<SabreEnvironment, string>> = Object.freeze({\n sandbox: 'https://api.cert.platform.sabre.com',\n production: 'https://api.platform.sabre.com',\n});\n\n/** Config validada y con defaults aplicados. */\nexport interface ResolvedConfig {\n credentials: Readonly<SabreCredentials | SabreCredentialsV2>;\n environment: SabreEnvironment;\n baseUrl: string;\n authVersion: SabreAuthVersion;\n pcc: string | undefined;\n logger: SabreLogger | undefined;\n retry: Readonly<RetryOptions>;\n fetch: typeof fetch;\n tokenStore: SabreTokenStore | undefined;\n}\n\nconst LOGGER_METHODS = ['debug', 'info', 'warn', 'error'] as const;\n\nfunction fail(message: string): never {\n throw new TypeError(`sabre-client: ${message}`);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction requireString(value: unknown, field: string): void {\n if (typeof value !== 'string' || value.trim() === '') fail(`${field} es requerido y debe ser un string no vacío`);\n}\n\nexport function resolveConfig(config: SabreConfig): ResolvedConfig {\n if (!isObject(config)) fail('la config debe ser un objeto');\n\n const { environment } = config;\n if (environment !== 'sandbox' && environment !== 'production') {\n fail(`environment debe ser 'sandbox' o 'production' (recibido: ${JSON.stringify(environment)})`);\n }\n\n const authVersion = config.authVersion ?? 'v3';\n if (authVersion !== 'v3' && authVersion !== 'v2') {\n fail(`authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(authVersion)})`);\n }\n\n const { credentials } = config;\n if (!isObject(credentials)) fail('credentials es requerido');\n requireString(credentials.username, 'credentials.username');\n requireString(credentials.password, 'credentials.password');\n if (authVersion === 'v3') {\n requireString(credentials.clientId, 'credentials.clientId (requerido con authVersion v3)');\n requireString(credentials.clientSecret, 'credentials.clientSecret (requerido con authVersion v3)');\n }\n\n if (config.pcc !== undefined) requireString(config.pcc, 'pcc');\n\n const { logger } = config;\n if (logger !== undefined) {\n if (!isObject(logger)) fail('logger debe ser un objeto con debug/info/warn/error');\n for (const method of LOGGER_METHODS) {\n if (typeof logger[method] !== 'function') fail(`logger.${method} debe ser una función`);\n }\n }\n\n if (config.retry !== undefined) {\n if (!isObject(config.retry)) fail('retry debe ser un objeto');\n validateRetryOptions(config.retry, 'retry');\n }\n\n const { tokenStore } = config;\n if (tokenStore !== undefined) {\n if (!isObject(tokenStore) || typeof tokenStore.get !== 'function' || typeof tokenStore.set !== 'function') {\n fail('tokenStore debe ser un objeto con get(key) y set(key, token)');\n }\n }\n\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') fail('no hay fetch disponible: pasa config.fetch');\n\n return {\n credentials: Object.freeze({ ...credentials }),\n environment,\n baseUrl: BASE_URLS[environment],\n authVersion,\n pcc: config.pcc,\n logger,\n retry: Object.freeze({ ...DEFAULT_RETRY, ...definedOnly(config.retry ?? {}) }),\n // Enlazado al global para evitar \"Illegal invocation\" en algunos runtimes.\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n tokenStore,\n };\n}\n\n/** Quita claves con valor `undefined` para que no pisen los defaults. */\nexport function definedOnly<T extends object>(value: T): Partial<T> {\n return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined)) as Partial<T>;\n}\n","// Transporte REST del cliente `Sabre`: fetch JSON, detección de errores y reintentos.\n// Ver sabre-wiki/wiki/sdk/manejo-y-mapeo-de-errores.md y politica-de-reintentos-y-backoff.md.\nimport { definedOnly, type ResolvedConfig } from '../config.js';\nimport { SabreError, SabreGatewayError } from '../errors/index.js';\nimport { EventLogger } from '../logging/logger.js';\nimport type { SabreRawResponse, SabreRawResponseCallback } from './raw-response.js';\nimport { type RetryOptions, retryDelay, shouldRetry, validateRetryOptions } from './retry.js';\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\n/** Status de gateway REST reintentables (ver errores-comunes-api). */\nconst RETRYABLE_STATUS = new Set([429, 500, 503, 504]);\n\n/**\n * Pasos 2–3 del orden de detección, aportados por cada servicio: recibe el body de una\n * respuesta 2xx y devuelve el error de su catálogo (orquestado, negocio o warning), o\n * `undefined` si la respuesta es data válida.\n */\nexport type ResponseClassifier = (body: unknown, response: Response) => SabreError | undefined;\n\nexport interface RestRequest {\n method: HttpMethod;\n /** Ruta relativa a la base URL, p. ej. `/v5/offers/shop`. */\n path: string;\n /** Nombre del servicio para errores y logs, p. ej. `'bargainFinderMax'`. */\n service: string;\n /**\n * Si la operación se puede repetir sin efectos duplicados. Las escrituras\n * (Create Booking, End Transaction) van en `false` y nunca se reintentan.\n */\n idempotent: boolean;\n query?: Record<string, string | number | boolean | undefined>;\n /** Se serializa como JSON, salvo `URLSearchParams`, que va como form-urlencoded. */\n body?: unknown;\n headers?: Record<string, string>;\n /** `false` para no pedir el header `Authorization` (p. ej. la propia request de token). */\n auth?: boolean;\n classify?: ResponseClassifier;\n retry?: Partial<RetryOptions>;\n signal?: AbortSignal;\n /** Método público sin `sabre.`, p. ej. `'booking.get'`. Lo recibe `onRawResponse`. */\n operation?: string;\n onRawResponse?: SabreRawResponseCallback;\n}\n\n/** Último intento con respuesta HTTP. Solo se lleva si hay `onRawResponse`. */\ninterface RawCapture {\n attempts: number;\n last?: { status: number; headers: Headers; body: string };\n}\n\n/** Fuente del header `Authorization` de los servicios (la implementa `AuthManager`). */\nexport interface AuthorizationProvider {\n /** Valor vigente del header, p. ej. `Bearer <token>`. */\n get(): Promise<string>;\n /** El gateway rechazó `authorization` con 401: descartarlo para que `get` traiga otro. */\n invalidate(authorization: string): void;\n}\n\nexport interface RestTransportOptions {\n authorization?: AuthorizationProvider;\n /** Solo para tests: fuente de aleatoriedad del jitter. */\n random?: () => number;\n /** Solo para tests: espera entre reintentos. */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n}\n\nexport class RestTransport {\n readonly #config: ResolvedConfig;\n readonly #log: EventLogger;\n readonly #random: () => number;\n readonly #sleep: (ms: number, signal?: AbortSignal) => Promise<void>;\n #authorization: AuthorizationProvider | undefined;\n\n constructor(config: ResolvedConfig, options: RestTransportOptions = {}) {\n this.#config = config;\n this.#log = new EventLogger(config.logger);\n this.#authorization = options.authorization;\n this.#random = options.random ?? Math.random;\n this.#sleep = options.sleep ?? sleep;\n }\n\n /** Punto de enganche para `AuthManager`. */\n setAuthorizationProvider(provider: AuthorizationProvider | undefined): void {\n this.#authorization = provider;\n }\n\n async request<T>(request: RestRequest): Promise<T> {\n if (request.retry !== undefined) validateRetryOptions(request.retry, 'retry');\n const capture: RawCapture | undefined = request.onRawResponse === undefined ? undefined : { attempts: 0 };\n try {\n return await this.#attempts<T>(request, capture);\n } finally {\n // Antes de devolver o de lanzar, con el último intento que tuvo respuesta HTTP.\n if (capture?.last !== undefined) this.#deliverRaw(request, { ...capture.last, attempts: capture.attempts });\n }\n }\n\n async #attempts<T>(request: RestRequest, capture: RawCapture | undefined): Promise<T> {\n const retry = { ...this.#config.retry, ...definedOnly(request.retry ?? {}) };\n\n let reauthorized = false;\n for (let attempt = 0; ; attempt++) {\n // Fuera del try: un fallo al obtener el token ya pasó por sus propios reintentos.\n const authorization = await this.#authorizationFor(request);\n try {\n return await this.#send<T>(request, attempt, authorization, capture);\n } catch (error) {\n // Refresco reactivo: un solo reintento con token nuevo, fuera del presupuesto genérico.\n // Aplica también a escrituras: el 401 del gateway rechaza la request antes del proveedor.\n if (authorization !== undefined && !reauthorized && isUnauthorized(error)) {\n reauthorized = true;\n this.#authorization?.invalidate(authorization);\n this.#log.emit('warn', 'sabre.request.retry', {\n service: request.service,\n method: request.method,\n path: request.path,\n attempt: attempt + 1,\n reason: 'unauthorized',\n error: error as SabreError,\n });\n attempt--;\n continue;\n }\n if (attempt >= retry.maxRetries || !shouldRetry(error, request.idempotent)) throw error;\n const delayMs = retryDelay(attempt, retry.baseDelayMs, this.#random);\n this.#log.emit('warn', 'sabre.request.retry', {\n service: request.service,\n method: request.method,\n path: request.path,\n attempt: attempt + 1,\n maxRetries: retry.maxRetries,\n delayMs,\n error: error as SabreError,\n });\n await this.#sleep(delayMs, request.signal);\n }\n }\n }\n\n /** Un callback que lanza no rompe la operación: Create Booking no puede perder su localizador. */\n #deliverRaw(request: RestRequest, raw: Omit<SabreRawResponse, 'operation' | 'protocol'>): void {\n const operation = request.operation ?? request.service;\n try {\n request.onRawResponse?.({ operation, protocol: 'rest', ...raw });\n } catch (error) {\n this.#log.emit('warn', 'sabre.request.rawResponseHookFailed', {\n service: request.service,\n operation,\n errorName: error instanceof Error ? error.name : typeof error,\n });\n }\n }\n\n async #authorizationFor(request: RestRequest): Promise<string | undefined> {\n if (request.auth === false || this.#authorization === undefined) return undefined;\n return this.#authorization.get();\n }\n\n async #send<T>(\n request: RestRequest,\n attempt: number,\n authorization: string | undefined,\n capture: RawCapture | undefined,\n ): Promise<T> {\n const url = this.#url(request);\n const headers = new Headers({ Accept: 'application/json', ...request.headers });\n const form = request.body instanceof URLSearchParams;\n if (request.body !== undefined && !headers.has('Content-Type')) {\n headers.set('Content-Type', form ? 'application/x-www-form-urlencoded' : 'application/json');\n }\n if (authorization !== undefined) headers.set('Authorization', authorization);\n\n const logContext = { service: request.service, method: request.method, path: request.path, attempt };\n this.#log.emit('debug', 'sabre.request.start', logContext);\n const startedAt = Date.now();\n\n let response: Response;\n if (capture !== undefined) capture.attempts++;\n try {\n response = await this.#config.fetch(url, {\n method: request.method,\n headers,\n ...(request.body === undefined ? {} : { body: form ? String(request.body) : JSON.stringify(request.body) }),\n ...(request.signal === undefined ? {} : { signal: request.signal }),\n });\n } catch (cause) {\n if (isAbort(cause, request.signal)) throw cause;\n const error = new SabreGatewayError(`${request.service}: fallo de red (${describe(cause)})`, {\n protocol: 'rest',\n retryable: true,\n cause,\n });\n this.#log.emit('error', 'sabre.request.end', { ...logContext, durationMs: Date.now() - startedAt, error });\n throw error;\n }\n\n const text = await response.text();\n if (capture !== undefined) capture.last = { status: response.status, headers: response.headers, body: text };\n const body = parseBody(text);\n const endContext = { ...logContext, status: response.status, durationMs: Date.now() - startedAt };\n\n // Paso 1: HTTP status de gateway.\n if (!response.ok) {\n const error = gatewayError(request.service, response.status, body);\n this.#log.emit('error', 'sabre.request.end', { ...endContext, error });\n throw error;\n }\n\n // Pasos 2–3: catálogo propio del servicio.\n const serviceError = request.classify?.(body, response);\n if (serviceError !== undefined) {\n this.#log.emit('warn', 'sabre.request.end', { ...endContext, error: serviceError });\n throw serviceError;\n }\n\n // Paso 4: data.\n this.#log.emit('info', 'sabre.request.end', endContext);\n return body as T;\n }\n\n #url(request: RestRequest): string {\n const path = request.path.startsWith('/') ? request.path : `/${request.path}`;\n const url = new URL(path, this.#config.baseUrl);\n for (const [key, value] of Object.entries(request.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n return url.toString();\n }\n}\n\n/** Body parseado como JSON; si no es JSON, el texto tal cual; vacío → `undefined`. */\nfunction parseBody(text: string): unknown {\n if (text === '') return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return text;\n }\n}\n\nfunction gatewayError(service: string, status: number, body: unknown): SabreGatewayError {\n const code = extractCode(body);\n return new SabreGatewayError(`${service}: HTTP ${status}${code === undefined ? '' : ` ${code}`}`, {\n protocol: 'rest',\n status,\n retryable: RETRYABLE_STATUS.has(status),\n raw: body,\n ...(code === undefined ? {} : { code }),\n });\n}\n\n/**\n * Best-effort: el campo exacto del código `ERR.2SG.*` no está confirmado\n * (issue de fuente #21). Se prueban `errorCode` y `error`.\n */\nfunction extractCode(body: unknown): string | undefined {\n if (typeof body !== 'object' || body === null) return undefined;\n for (const key of ['errorCode', 'error'] as const) {\n const value = (body as Record<string, unknown>)[key];\n if (typeof value === 'string' && value !== '') return value;\n }\n return undefined;\n}\n\nfunction isUnauthorized(error: unknown): boolean {\n return error instanceof SabreGatewayError && error.protocol === 'rest' && error.status === 401;\n}\n\nfunction isAbort(error: unknown, signal: AbortSignal | undefined): boolean {\n return signal?.aborted === true || (error instanceof Error && error.name === 'AbortError');\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","// Cliente REST. Ver sabre-wiki/wiki/sdk/arquitectura-clientes-transporte.md.\nimport { Air } from './air/air.js';\nimport { AuthManager } from './auth/auth-manager.js';\nimport { BookingManagement } from './booking/booking-management.js';\nimport { type ResolvedConfig, resolveConfig, type SabreConfig, type SabreEnvironment } from './config.js';\nimport { RestTransport } from './http/rest-transport.js';\n\nexport class Sabre {\n readonly #config: ResolvedConfig;\n readonly #transport: RestTransport;\n /** Servicios de Air: shopping, revalidación. */\n readonly air: Air;\n /** Booking Management: creación de reservas. */\n readonly booking: BookingManagement;\n\n constructor(config: SabreConfig) {\n this.#config = resolveConfig(config);\n this.#transport = new RestTransport(this.#config);\n // Toda request lleva `Authorization: Bearer <token>`, salvo la propia de token (`auth: false`).\n const auth = new AuthManager(this.#config, this.#transport);\n this.#transport.setAuthorizationProvider(auth.bearerProvider());\n this.air = new Air(this.#transport);\n this.booking = new BookingManagement(this.#transport);\n }\n\n get environment(): SabreEnvironment {\n return this.#config.environment;\n }\n\n get baseUrl(): string {\n return this.#config.baseUrl;\n }\n}\n","// Armado de `flightDetails` de Create Booking desde un itinerario de BFM/Revalidate.\n// El mapeo está inferido, ninguna fuente lo documenta: ver la tabla \"Mapeo desde un\n// itinerario de BFM/Revalidate → flightDetails\" en sabre-wiki/wiki/entities/booking-management-api.md.\nimport type { Itinerary, ItineraryGroup } from '../air/grouped-itinerary.js';\nimport { itineraryFlights } from '../air/itinerary-flights.js';\nimport type { FlightDetails, FlightToBook, PassengerPricing, PriceComparison } from './create-booking-request.js';\n\nexport interface BookingFlightDetailsSource {\n /** Grupo del itinerario: aporta la fecha de cada tramo. */\n group: ItineraryGroup;\n /** Itinerario elegido, idealmente el devuelto por Revalidate Itinerary. */\n itinerary: Itinerary;\n /**\n * Umbral de precio. `desiredAmount` sale de `totalFare.totalPrice` del itinerario. El spec no\n * tiene campo de moneda: se supone la del pricing (la del PCC, salvo `currencyPricing`).\n */\n priceComparison?: Omit<PriceComparison, 'desiredAmount'>;\n}\n\n/**\n * Arma `flightDetails` para reservar por el camino ATPCO un itinerario ya revalidado.\n *\n * - `flights[]`: vuelo comercializador, aeropuertos, fecha y clase con las mismas reglas que\n * Revalidate (`itineraryFlights`); `departureTime` en `HH:MM` y `flightStatusCode: 'NN'`.\n * `isMarriageGroup` no se manda: no hay fuente para él.\n * - `flightPricing[0].qualifiers`: `passengersPricing` desde `passengerInfoList` y\n * `validatingAirlineCode` desde `validatingCarrierCode` de la primera cotización.\n */\nexport function buildBookingFlightDetails(source: BookingFlightDetailsSource): FlightDetails {\n const { group, itinerary, priceComparison } = source;\n const flights = itineraryFlights(group, itinerary).map(\n ({ schedule, departureDate, bookingCode }): FlightToBook => ({\n flightNumber: schedule.carrier.marketingFlightNumber,\n airlineCode: schedule.carrier.marketing,\n fromAirportCode: schedule.departure.airport,\n toAirportCode: schedule.arrival.airport,\n departureDate,\n departureTime: schedule.departure.time.slice(0, 5),\n bookingClass: bookingCode,\n flightStatusCode: 'NN',\n }),\n );\n\n const fare = itinerary.pricingInformation[0]?.fare;\n if (fare === undefined) {\n throw new TypeError('sabre-client: el itinerario no trae pricingInformation');\n }\n const passengersPricing = fare.passengerInfoList.map(\n ({ passengerInfo }): PassengerPricing => ({\n passengerCode: passengerInfo.passengerType,\n numberOfpassengers: passengerInfo.passengerNumber ?? 1,\n }),\n );\n\n let priceComparisons: PriceComparison[] | undefined;\n if (priceComparison !== undefined) {\n const total = fare.totalFare?.totalPrice;\n if (total === undefined) {\n throw new TypeError('sabre-client: el itinerario no trae totalFare.totalPrice para priceComparison');\n }\n priceComparisons = [{ desiredAmount: amount(total), ...priceComparison }];\n }\n\n return {\n flights,\n flightPricing: [\n {\n ...(priceComparisons === undefined ? {} : { priceComparisons }),\n qualifiers: {\n passengersPricing,\n ...(fare.validatingCarrierCode === undefined ? {} : { validatingAirlineCode: fare.validatingCarrierCode }),\n },\n },\n ],\n };\n}\n\n/** `1234.5` → `'1234.5'`; el spec acepta hasta 3 decimales. */\nfunction amount(value: number): string {\n return String(Math.round(value * 1000) / 1000);\n}\n","export const VERSION = '0.3.0';\n\nexport { Sabre } from './sabre.js';\nexport type { Air } from './air/air.js';\nexport type {\n BargainFinderMaxRequest,\n BargainFinderMaxResponse,\n RequestOptions,\n} from './air/bargain-finder-max.js';\nexport { buildRevalidateItineraryRequest } from './air/revalidate-itinerary.js';\nexport type {\n RevalidateItineraryRequest,\n RevalidateItineraryRequestSource,\n RevalidateItineraryResponse,\n} from './air/revalidate-itinerary.js';\nexport type {\n LowFareSearchFlight,\n LowFareSearchLocation,\n LowFareSearchOriginDestination,\n LowFareSearchPassengerTypeQuantity,\n LowFareSearchRequestorId,\n LowFareSearchSource,\n LowFareSearchTpaExtensions,\n LowFareSearchTravelerInfoSummary,\n LowFareSearchTravelPreferences,\n OtaAirLowFareSearchRq,\n} from './air/low-fare-search-request.js';\nexport type { SabreTokenStore, StoredToken } from './auth/token-store.js';\nexport type { BookingManagement } from './booking/booking-management.js';\nexport type {\n Booking,\n CreateBookingOptions,\n CreateBookingResponse,\n CreateBookingResponseError,\n} from './booking/create-booking.js';\nexport type {\n BookContactInformation,\n BookGenericSeat,\n BookingAgency,\n BookSeat,\n BookTraveler,\n BrandedFare,\n CreateBookingErrorPolicy,\n CreateBookingRequest,\n FlightDetails,\n FlightStatusCode,\n FlightToBook,\n PassengerPricing,\n PaymentMethod,\n PriceComparison,\n PriceComparisonType,\n PricingDetails,\n PricingQualifiers,\n SeatAreaPreference,\n SpecificFare,\n TicketingPolicy,\n TravelerPhone,\n TravelerTitle,\n} from './booking/create-booking-request.js';\nexport type {\n BookingSource,\n GetBookingExtraFeatures,\n GetBookingOptions,\n GetBookingRequest,\n GetBookingResponse,\n GetBookingReturnOnly,\n} from './booking/get-booking.js';\nexport type {\n BookingItemReference,\n CancelBookingErrorPolicy,\n CancelBookingNotification,\n CancelBookingOptions,\n CancelBookingRequest,\n CancelBookingResponse,\n CancelSegmentReference,\n FlightTicketOperation,\n RefundDocumentsType,\n} from './booking/cancel-booking.js';\nexport type { BookingResponseError } from './booking/booking-errors.js';\nexport { buildBookingFlightDetails } from './booking/flight-details.js';\nexport type { BookingFlightDetailsSource } from './booking/flight-details.js';\nexport type {\n SabreAuthVersion,\n SabreConfig,\n SabreConfigV2,\n SabreConfigV3,\n SabreCredentials,\n SabreCredentialsV2,\n SabreEnvironment,\n} from './config.js';\nexport type { RetryOptions } from './http/retry.js';\nexport type { SabreRawResponse, SabreRawResponseCallback } from './http/raw-response.js';\nexport * from './errors/index.js';\nexport * from './logging/index.js';\nexport type {\n BaggageAllowanceDesc,\n BaggageInformation,\n CurrencyConversion,\n Fare,\n FareComponent,\n FareComponentDesc,\n FareComponentDescSegment,\n FareComponentSegment,\n FareComponentSegmentDetail,\n FareMessage,\n GroupedItineraryResponse,\n Itinerary,\n ItineraryGroup,\n ItineraryMessage,\n Leg,\n LegDesc,\n LegSchedule,\n LegScheduleRef,\n LegDescription,\n ObFeeDesc,\n PassengerInfo,\n PassengerTotalFare,\n PricingInformation,\n Ref,\n ScheduleCarrier,\n ScheduleDesc,\n ScheduleEndpoint,\n ScheduleEquipment,\n TaxDesc,\n TaxSummaryDesc,\n TotalFare,\n ValidatingCarrierDesc,\n} from './air/grouped-itinerary.js';\n"],"mappings":";AAiBO,IAAM,aAAN,cAAyB,MAAM;AAAA,EAC3B,OAAO;AAAA,EACP;AAAA,EAGT,YAAY,SAAiB,SAA4B;AACvD,UAAM,SAAS,QAAQ,UAAU,SAAY,SAAY,EAAE,OAAO,QAAQ,MAAM,CAAC;AACjF,SAAK,YAAY,QAAQ;AACzB,WAAO,eAAe,MAAM,OAAO;AAAA,MACjC,OAAO,QAAQ;AAAA,MACf,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,SAAkC;AAChC,UAAM,SAAkC,OAAO,YAAY,OAAO,QAAQ,IAAI,CAAC;AAC/E,WAAO,EAAE,GAAG,QAAQ,MAAM,KAAK,MAAM,SAAS,KAAK,QAAQ;AAAA,EAC7D;AACF;AAaO,IAAM,oBAAN,cAAgC,WAAW;AAAA,EACvC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,SAAmC;AAC9D,UAAM,SAAS,OAAO;AACtB,SAAK,WAAW,QAAQ;AACxB,SAAK,SAAS,QAAQ;AACtB,SAAK,OAAO,QAAQ;AAAA,EACtB;AACF;AAWO,IAAM,0BAAN,cAAsC,WAAW;AAAA,EAC7C,OAAO;AAAA,EACP;AAAA,EAET,YAAY,SAAiB,SAAyC;AACpE,UAAM,SAAS,EAAE,GAAG,SAAS,WAAW,QAAQ,SAAS,oBAAoB,CAAC;AAC9E,SAAK,OAAO,QAAQ;AAAA,EACtB;AACF;AA6BO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EACxC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,SAAoC;AAC/D,UAAM,SAAS,EAAE,GAAG,SAAS,WAAW,QAAQ,aAAa,MAAM,CAAC;AACpE,SAAK,UAAU,QAAQ;AACvB,SAAK,OAAO,QAAQ;AACpB,SAAK,WAAW,QAAQ,YAAY,CAAC;AACrC,SAAK,SAAS,QAAQ,UAAU,CAAC;AAAA,EACnC;AACF;AAMO,IAAM,eAAN,cAA2B,WAAW;AAAA,EAClC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,SAAmC;AAC9D,UAAM,SAAS,EAAE,GAAG,SAAS,WAAW,MAAM,CAAC;AAC/C,SAAK,UAAU,QAAQ;AACvB,SAAK,OAAO,QAAQ;AAAA,EACtB;AACF;;;ACgQO,SAAS,oCACd,KACA,SAC0B;AAC1B,QAAM,WAAW,IAAI,SAAS,KAAK,OAAO;AAC1C,SAAO;AAAA,IACL,SAAS,IAAI;AAAA,IACb,UAAU,IAAI,YAAY,CAAC;AAAA,IAC3B,GAAI,IAAI,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,IAAI,WAAW;AAAA,IACrE,kBAAkB,IAAI,mBAAmB,CAAC,GAAG,IAAI,CAAC,WAAW;AAAA,MAC3D,kBAAkB,MAAM;AAAA,MACxB,aAAa,MAAM,YAAY,IAAI,CAAC,cAAc,SAAS,UAAU,SAAS,CAAC;AAAA,IACjF,EAAE;AAAA,EACJ;AACF;AAEA,IAAM,WAAN,MAAe;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,KAAkC,SAAiB;AAC7D,SAAK,WAAW;AAChB,SAAK,aAAa,KAAK,IAAI,aAAa;AACxC,SAAK,QAAQ,KAAK,IAAI,QAAQ;AAC9B,SAAK,SAAS,KAAK,IAAI,QAAQ;AAC/B,SAAK,gBAAgB,KAAK,IAAI,eAAe;AAC7C,SAAK,UAAU,KAAK,IAAI,UAAU;AAClC,SAAK,kBAAkB,KAAK,IAAI,kBAAkB;AAClD,SAAK,sBAAsB,KAAK,IAAI,sBAAsB;AAC1D,SAAK,qBAAqB,KAAK,IAAI,qBAAqB;AAAA,EAC1D;AAAA,EAEA,UAAU,WAAoC;AAC5C,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,UAAU,KAAK,IAAI,CAAC,QAAQ,KAAK,KAAK,GAAG,CAAC;AAAA,MAChD,oBAAoB,UAAU,mBAAmB,IAAI,CAAC,aAAa;AAAA,QACjE,GAAG;AAAA,QACH,MAAM,KAAK,MAAM,QAAQ,IAAI;AAAA,MAC/B,EAAE;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,KAAK,KAAe;AAClB,UAAM,MAAM,KAAK,OAAO,KAAK,OAAO,YAAY,GAAG;AACnD,WAAO,EAAE,GAAG,KAAK,WAAW,IAAI,UAAU,IAAI,CAAC,aAAa,KAAK,OAAO,KAAK,YAAY,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACvH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,oBAAoB,GAAG,KAAK,IAAI;AACxC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,mBAAmB,KAAK,kBAAkB,IAAI,CAAC,EAAE,eAAe,GAAG,MAAM,OAAO;AAAA,QAC9E,GAAG;AAAA,QACH,eAAe,KAAK,eAAe,aAAa;AAAA,MAClD,EAAE;AAAA,MACF,GAAI,uBAAuB,SACvB,CAAC,IACD;AAAA,QACE,oBAAoB,mBAAmB;AAAA,UAAI,CAAC,QAC1C,KAAK,OAAO,KAAK,qBAAqB,0BAA0B,GAAG;AAAA,QACrE;AAAA,MACF;AAAA,IACN;AAAA,EACF;AAAA,EAEA,eAAe,MAAuC;AACpD,UAAM,EAAE,gBAAgB,OAAO,cAAc,QAAQ,oBAAoB,GAAG,KAAK,IAAI;AACrF,UAAM,SAAwB,EAAE,GAAG,KAAK;AACxC,QAAI,mBAAmB,OAAW,QAAO,iBAAiB,eAAe,IAAI,CAAC,QAAQ,KAAK,eAAe,GAAG,CAAC;AAC9G,QAAI,UAAU,OAAW,QAAO,QAAQ,MAAM,IAAI,CAAC,QAAQ,KAAK,OAAO,KAAK,QAAQ,YAAY,GAAG,CAAC;AACpG,QAAI,iBAAiB,QAAW;AAC9B,aAAO,eAAe,aAAa,IAAI,CAAC,QAAQ,KAAK,OAAO,KAAK,eAAe,mBAAmB,GAAG,CAAC;AAAA,IACzG;AACA,QAAI,WAAW,OAAW,QAAO,SAAS,OAAO,IAAI,CAAC,QAAQ,KAAK,OAAO,KAAK,SAAS,cAAc,GAAG,CAAC;AAC1G,QAAI,uBAAuB,QAAW;AACpC,aAAO,qBAAqB,mBAAmB,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,OAAO;AAAA,QAC7E,GAAG;AAAA,QACH,GAAI,cAAc,SACd,CAAC,IACD,EAAE,WAAW,KAAK,OAAO,KAAK,oBAAoB,yBAAyB,SAAS,EAAE;AAAA,MAC5F,EAAE;AAAA,IACJ;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,KAAsC;AACnD,UAAM,OAAO,KAAK,QAAQ,KAAK,iBAAiB,sBAAsB,IAAI,GAAG;AAC7E,UAAM,EAAE,KAAK,MAAM,UAAU,cAAc,GAAG,KAAK,IAAI;AACvD,UAAM,EAAE,UAAU,cAAc,GAAG,SAAS,IAAI;AAChD,QAAI,iBAAiB,UAAa,iBAAiB,UAAa,aAAa,WAAW,aAAa,QAAQ;AAC3G,YAAM,KAAK;AAAA,QACT,sBAAsB,aAAa,MAAM,mCAAmC,IAAI,GAAG,QAAQ,aAAa,MAAM;AAAA,MAChH;AAAA,IACF;AACA,UAAM,WAAW,cAAc,cAAc,YAAY;AACzD,WAAO,EAAE,GAAG,UAAU,GAAG,MAAM,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS,EAAG;AAAA,EACjF;AAAA;AAAA,EAGA,OAAiC,OAAuB,MAAc,KAAa;AACjF,UAAM,EAAE,KAAK,IAAI,GAAG,KAAK,IAAI;AAC7B,WAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,MAAM,EAAE,GAAG,GAAG,KAAK;AAAA,EACrD;AAAA,EAEA,QAAW,OAAuB,MAAc,IAAe;AAC7D,UAAM,OAAO,MAAM,IAAI,EAAE;AACzB,QAAI,SAAS,OAAW,OAAM,KAAK,WAAW,OAAO,EAAE,sBAAsB,IAAI,EAAE;AACnF,WAAO;AAAA,EACT;AAAA,EAEA,WAAW,QAA4B;AACrC,WAAO,IAAI,WAAW,GAAG,KAAK,QAAQ,2BAA2B,MAAM,IAAI,EAAE,WAAW,MAAM,CAAC;AAAA,EACjG;AACF;AAEA,SAAS,KAA+B,OAAwC;AAC9E,SAAO,IAAI,KAAK,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAC7D;AAEA,SAAS,cACP,MACA,MACoC;AACpC,MAAI,SAAS,UAAa,SAAS,OAAW,QAAO;AAErD,QAAM,SAAS,MAAM,UAAU,MAAM,UAAU;AAC/C,SAAO,MAAM,KAAK,EAAE,OAAO,GAAG,CAAC,GAAG,OAAO;AAAA,IACvC,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,QAAQ;AAAA,EAC1D,EAAE;AACJ;;;AChgBO,SAAS,0BACd,MACA,SACA,SACwB;AACxB,QAAM,WAAW,SAAS,IAAI,IAAI,KAAK,2BAA2B;AAClE,MAAI,CAAC,SAAS,QAAQ,GAAG;AACvB,WAAO,IAAI,WAAW,GAAG,OAAO,0DAA0D;AAAA,MACxF,WAAW;AAAA,MACX,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACA,QAAM,WAAW,MAAM,QAAQ,SAAS,QAAQ,IAAK,SAAS,WAA2C,CAAC;AAC1G,QAAM,QAAQ,SAAS,KAAK,CAAC,YAAY,QAAQ,UAAU,YAAY,MAAM,OAAO;AACpF,MAAI,UAAU,OAAW,QAAO;AAEhC,QAAM,QAAQ,cAAc,UAAU,OAAO;AAC7C,QAAM,OAAO,OAAO,SAAS,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAC3E,QAAM,QAAQ,OAAO;AACrB,QAAM,OAAO,OAAO,QAAQ,MAAM,QAAQ;AAC1C,SAAO,IAAI,mBAAmB,GAAG,OAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,IAC3D;AAAA,IACA;AAAA,IACA,WAAW,OAAO,aAAa;AAAA,IAC/B,KAAK;AAAA,EACP,CAAC;AACH;AAEA,SAAS,cACP,UACA,SACmE;AACnE,aAAW,WAAW,UAAU;AAC9B,QAAI,OAAO,QAAQ,SAAS,SAAU;AACtC,UAAM,OAAO,QAAQ,KAAK,YAAY;AACtC,UAAM,QAAQ,QAAQ,KAAK,CAAC,cAAc,KAAK,SAAS,UAAU,KAAK,YAAY,CAAC,CAAC;AACrF,QAAI,UAAU,OAAW,QAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA,EAC9D;AACA,SAAO;AACT;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;;AClDO,IAAM,6BAA6B;AAC1C,IAAM,OAAO;AAuBN,IAAM,6BAA0E;AAAA,EACrF,EAAE,MAAM,mBAAmB,WAAW,MAAM;AAAA,EAC5C,EAAE,MAAM,2CAA2C,WAAW,MAAM;AAAA,EACpE,EAAE,MAAM,4BAA4B,WAAW,KAAK;AAAA,EACpD,EAAE,MAAM,wBAAwB,WAAW,KAAK;AAAA,EAChD,EAAE,MAAM,0BAA0B,WAAW,KAAK;AAAA,EAClD,EAAE,MAAM,iCAAiC,WAAW,KAAK;AAC3D;AAEA,eAAsB,iBACpB,WACA,SACA,UAA0B,CAAC,GACQ;AACnC,MAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,OAAO,QAAQ,2BAA2B,UAAU;AACzG,UAAM,IAAI,UAAU,2EAA2E;AAAA,EACjG;AACA,QAAM,OAAO,MAAM,UAAU,QAAmE;AAAA,IAC9F,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA;AAAA,IAET,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,GAAI,QAAQ,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,QAAQ,MAAM;AAAA,IAC9D,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,IACjE,GAAI,QAAQ,kBAAkB,SAC1B,CAAC,IACD,EAAE,WAAW,wBAAwB,eAAe,QAAQ,cAAc;AAAA,EAChF,CAAC;AACD,SAAO,oCAAoC,KAAK,0BAA0B,0BAA0B;AACtG;AAGO,SAAS,yBAAyB,MAAuC;AAC9E,SAAO,0BAA0B,MAAM,4BAA4B,0BAA0B;AAC/F;;;AClDO,SAAS,iBAAiB,OAAuB,WAAyC;AAC/F,QAAM,EAAE,gBAAgB,IAAI,MAAM;AAClC,MAAI,gBAAgB,WAAW,UAAU,KAAK,QAAQ;AACpD,UAAM,IAAI;AAAA,MACR,qCAAqC,UAAU,KAAK,MAAM,sBAAsB,gBAAgB,MAAM;AAAA,IACxG;AAAA,EACF;AACA,QAAM,UAAU,aAAa,SAAS;AACtC,QAAM,cAAc,UAAU,KAAK,OAAO,CAAC,GAAG,QAAQ,IAAI,IAAI,UAAU,QAAQ,CAAC;AACjF,MAAI,QAAQ,WAAW,aAAa;AAClC,UAAM,IAAI;AAAA,MACR,qCAAqC,WAAW,aAAa,QAAQ,MAAM;AAAA,IAC7E;AAAA,EACF;AAEA,MAAI,OAAO;AACX,SAAO,UAAU,KAAK,QAAQ,CAAC,KAAK,aAAa;AAC/C,UAAM,UAAU,gBAAgB,QAAQ,EAAG;AAC3C,WAAO,IAAI,UAAU,IAAI,CAAC,aAAa;AACrC,YAAM,gBAAgB,QAAQ,SAAS,SAAS,2BAA2B,CAAC;AAC5E,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,QAAQ,eAAe,SAAS,QAAQ,kBAAkB,CAAC;AAAA,QACxE,aAAa,QAAQ,MAAM;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,aAAa,WAAgC;AACpD,QAAM,YAAY,UAAU,mBAAmB,CAAC,GAAG,KAAK,kBAAkB,CAAC,GAAG;AAC9E,UAAQ,WAAW,kBAAkB,CAAC,GAAG;AAAA,IAAQ,CAAC,eAC/C,UAAU,YAAY,CAAC,GAAG,IAAI,CAAC,EAAE,QAAQ,MAAM;AAC9C,UAAI,QAAQ,gBAAgB,QAAW;AACrC,cAAM,IAAI,UAAU,iEAAiE;AAAA,MACvF;AACA,aAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AACF;AAGA,SAAS,QAAQ,MAAc,MAAsB;AACnD,MAAI,SAAS,EAAG,QAAO;AACvB,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AACrD,SAAO,IAAI,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAClF;;;ACrDO,IAAM,+BAA+B;AAC5C,IAAMA,QAAO;AAUb,eAAsB,oBACpB,WACA,SACA,UAA0B,CAAC,GACW;AACtC,MAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,OAAO,QAAQ,2BAA2B,UAAU;AACzG,UAAM,IAAI,UAAU,8EAA8E;AAAA,EACpG;AACA,QAAM,OAAO,MAAM,UAAU,QAAmE;AAAA,IAC9F,QAAQ;AAAA,IACR,MAAMA;AAAA,IACN,SAAS;AAAA;AAAA,IAET,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,GAAI,QAAQ,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,QAAQ,MAAM;AAAA,IAC9D,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,IACjE,GAAI,QAAQ,kBAAkB,SAC1B,CAAC,IACD,EAAE,WAAW,2BAA2B,eAAe,QAAQ,cAAc;AAAA,EACnF,CAAC;AACD,SAAO,oCAAoC,KAAK,0BAA0B,4BAA4B;AACxG;AAWO,IAAM,+BAA4E;AAAA,EACvF,EAAE,MAAM,sCAAsC,WAAW,MAAM;AAAA,EAC/D,EAAE,MAAM,0BAA0B,WAAW,MAAM;AAAA,EACnD,EAAE,MAAM,2CAA2C,WAAW,MAAM;AAAA,EACpE,EAAE,MAAM,kBAAkB,WAAW,MAAM;AAAA,EAC3C,EAAE,MAAM,mBAAmB,WAAW,MAAM;AAAA,EAC5C,GAAG,2BAA2B,OAAO,CAAC,UAAU,MAAM,SAAS;AACjE;AAGO,SAAS,4BAA4B,MAAuC;AACjF,SAAO,0BAA0B,MAAM,8BAA8B,4BAA4B;AACnG;AAoBO,SAAS,gCAAgC,QAAsE;AACpH,QAAM,EAAE,QAAQ,OAAO,UAAU,IAAI;AACrC,QAAM,UAAU,iBAAiB,OAAO,SAAS;AAEjD,QAAM,qBAAqB,UAAU,KAAK,IAAI,CAAC,MAAM,MAAsC;AACzF,UAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,IAAI,MAAM;AACrE,UAAM,QAAQ,WAAW,CAAC;AAC1B,UAAM,OAAO,WAAW,GAAG,EAAE;AAC7B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,mBAAmB,MAAM;AAAA,MACzB,gBAAgB,EAAE,cAAc,MAAM,eAAe,aAAa;AAAA,MAClE,qBAAqB,EAAE,cAAc,KAAK,oBAAoB,aAAa;AAAA,MAC3E,gBAAgB,EAAE,QAAQ,WAAW;AAAA,IACvC;AAAA,EACF,CAAC;AAED,QAAM,EAAE,SAAS,KAAK,qBAAqB,eAAe,IAAI,OAAO;AACrE,SAAO;AAAA,IACL,wBAAwB;AAAA,MACtB;AAAA,MACA;AAAA,MACA,8BAA8B;AAAA,MAC9B,mBAAmB;AAAA,QACjB,kBAAkB,KAAK,IAAI,GAAG,UAAU,KAAK,IAAI,CAAC,QAAQ,IAAI,UAAU,SAAS,CAAC,CAAC;AAAA,QACnF,gBAAgB,EAAE,2BAA2B,EAAE,OAAO,IAAI,EAAE;AAAA,MAC9D;AAAA,MACA;AAAA,MACA,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,SAAS,OAAO,EAAE,UAAU,eAAe,aAAa,YAAY,GAAyC;AAC3G,QAAM,EAAE,QAAQ,IAAI;AACpB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,QAAQ;AAAA,IAChB,mBAAmB,GAAG,aAAa,IAAI,UAAU,SAAS,UAAU,IAAI,CAAC;AAAA,IACzE,iBAAiB,GAAG,WAAW,IAAI,UAAU,SAAS,QAAQ,IAAI,CAAC;AAAA,IACnE,gBAAgB;AAAA,IAChB,gBAAgB,EAAE,cAAc,SAAS,UAAU,QAAQ;AAAA,IAC3D,qBAAqB,EAAE,cAAc,SAAS,QAAQ,QAAQ;AAAA,IAC9D,SAAS;AAAA,MACP,WAAW,QAAQ;AAAA,MACnB,GAAI,QAAQ,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;AAAA,IAC5E;AAAA,EACF;AACF;AAGA,SAAS,UAAU,MAAsB;AACvC,SAAO,KAAK,MAAM,GAAG,CAAC;AACxB;;;ACxIO,IAAM,MAAN,MAAU;AAAA,EACN;AAAA;AAAA,EAGT,YAAY,WAA0B;AACpC,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,SAAkC,SAA6D;AAC9G,WAAO,iBAAiB,KAAK,YAAY,SAAS,OAAO;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBACE,SACA,SACsC;AACtC,WAAO,oBAAoB,KAAK,YAAY,SAAS,OAAO;AAAA,EAC9D;AACF;;;ACrCO,IAAM,WAAW;AAMxB,IAAM,iBAAiB,IAAI;AAAA,EACzB;AAAA;AAAA,IAEE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,EACF,EAAE,IAAI,YAAY;AACpB;AAEA,SAAS,aAAa,KAAqB;AACzC,SAAO,IAAI,QAAQ,WAAW,EAAE,EAAE,YAAY;AAChD;AAEO,SAAS,eAAe,KAAsB;AACnD,SAAO,eAAe,IAAI,aAAa,GAAG,CAAC;AAC7C;AAGO,SAAS,OAAO,OAAyB;AAC9C,SAAO,YAAY,OAAO,oBAAI,QAAQ,CAAC;AACzC;AAEA,SAAS,YAAY,OAAgB,MAAgC;AACnE,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,MAAI,KAAK,IAAI,KAAK,EAAG,QAAO;AAC5B,OAAK,IAAI,KAAK;AAEd,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,CAAC,SAAS,YAAY,MAAM,IAAI,CAAC;AAC5E,MAAI,iBAAiB,QAAS,QAAO,cAAc,MAAM,QAAQ,GAAG,IAAI;AACxE,MAAI,iBAAiB,KAAM,QAAO,MAAM,YAAY;AACpD,MAAI,iBAAiB,OAAO;AAE1B,UAAM,OAAO,YAAY,SAAS,OAAO,MAAM,WAAW,aAAa,MAAM,OAAO,IAAI;AACxF,WAAO,YAAY,QAAQ,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/E;AACA,SAAO,cAAc,OAAO,QAAQ,KAAK,GAAG,IAAI;AAClD;AAEA,SAAS,cAAc,SAAsC,MAAgD;AAC3G,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,IAAI,KAAK,SAAS;AACjC,QAAI,GAAG,IAAI,eAAe,GAAG,IAAI,WAAW,YAAY,MAAM,IAAI;AAAA,EACpE;AACA,SAAO;AACT;;;ACnCO,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EAET,YAAY,QAAsB;AAChC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,KAAK,OAAsB,OAAsB,UAAmC,CAAC,GAAS;AAC5F,QAAI,KAAK,YAAY,OAAW;AAChC,QAAI;AACF,WAAK,QAAQ,KAAK,EAAE,OAAO,OAAO,OAAO,CAA4B;AAAA,IACvE,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AC7BO,SAAS,oBAAoB,aAA6C;AAC/E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,SAAS,OAAO,GAAG,YAAY,QAAQ,IAAI,YAAY,YAAY,EAAE,CAAC;AAAA,IACrF,MAAM,IAAI,gBAAgB;AAAA,MACxB,YAAY;AAAA,MACZ,UAAU,YAAY;AAAA,MACtB,UAAU,YAAY;AAAA,IACxB,CAAC;AAAA,EACH;AACF;AAGO,SAAS,oBAAoB,aAA+C;AACjF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,SAAS,OAAO,GAAG,OAAO,YAAY,QAAQ,CAAC,IAAI,OAAO,YAAY,QAAQ,CAAC,EAAE,CAAC;AAAA,IACjG,MAAM,IAAI,gBAAgB,EAAE,YAAY,qBAAqB,CAAC;AAAA,EAChE;AACF;AAEO,SAAS,kBACd,aACA,aACc;AAEd,SAAO,gBAAgB,OACnB,oBAAoB,WAA+B,IACnD,oBAAoB,WAAW;AACrC;AAGO,SAAS,OAAO,MAAsB;AAC3C,MAAI,SAAS;AACb,aAAW,QAAQ,IAAI,YAAY,EAAE,OAAO,IAAI,EAAG,WAAU,OAAO,aAAa,IAAI;AACrF,SAAO,KAAK,MAAM;AACpB;;;ACjBA,eAAsB,cACpB,aACA,aACA,aACiB;AACjB,QAAM,WAAW,gBAAgB,OAAO,GAAG,YAAY,QAAQ;AAAA,EAAK,YAAY,QAAQ,KAAK,YAAY;AACzG,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,EAAE,OAAO,QAAQ,CAAC;AACvF,QAAM,OAAO,CAAC,GAAG,IAAI,WAAW,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC/G,SAAO,gBAAgB,WAAW,IAAI,WAAW,IAAI,IAAI;AAC3D;AAGO,SAAS,cAAc,OAAsC;AAClE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,EAAE,aAAa,YAAY,UAAU,IAAI;AAC/C,SACE,OAAO,gBAAgB,YACvB,gBAAgB,MAChB,OAAO,eAAe,YACtB,OAAO,cAAc,YACrB,OAAO,SAAS,UAAU,KAC1B,YAAY;AAEhB;;;AC7CO,IAAM,gBAAgB;AAGtB,IAAM,sBAAsB;AA4B5B,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EACA;AAAA;AAAA,EAEA,eAAe;AAAA;AAAA,EAEf;AAAA,EACS;AAAA,EACT;AAAA,EAEA,YAAY,QAAwB,WAA0B,UAA8B,CAAC,GAAG;AAC9F,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,OAAO,QAAQ,OAAO,KAAK;AAChC,SAAK,OAAO,IAAI,YAAY,OAAO,MAAM;AACzC,SAAK,SAAS,OAAO;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,WAA4B;AAChC,UAAM,QAAQ,KAAK;AACnB,QAAI,UAAU,UAAa,CAAC,KAAK,cAAc,KAAK,EAAG,QAAO,MAAM;AACpE,UAAM,SAAS,UAAU,SAAY,cAAc,KAAK,eAAe,aAAa;AACpF,YAAQ,MAAM,KAAK,SAAS,MAAM,GAAG;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,aAA2B;AACpC,QAAI,KAAK,QAAQ,gBAAgB,YAAa;AAC9C,SAAK,SAAS;AACd,SAAK,eAAe;AACpB,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA,EAGA,iBAAwC;AACtC,WAAO;AAAA,MACL,KAAK,YAAY,UAAU,MAAM,KAAK,SAAS,CAAC;AAAA,MAChD,YAAY,CAAC,kBAAkB,KAAK,WAAW,cAAc,QAAQ,YAAY,EAAE,CAAC;AAAA,IACtF;AAAA,EACF;AAAA,EAEA,cAAc,OAA6B;AACzC,UAAM,cAAc,KAAK,IAAI,qBAAqB,MAAM,YAAY,CAAC,IAAI;AACzE,WAAO,KAAK,KAAK,KAAK,MAAM,aAAa,MAAM,YAAY,MAAO;AAAA,EACpE;AAAA;AAAA,EAGA,SAAS,QAAkD;AACzD,SAAK,cAAc,KAAK,QAAQ,MAAM,EAAE,QAAQ,MAAM;AACpD,WAAK,YAAY;AAAA,IACnB,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,QAAQ,QAAkD;AAC9D,UAAM,SAAS,MAAM,KAAK,WAAW;AACrC,QAAI,WAAW,UAAa,OAAO,gBAAgB,KAAK,aAAa,CAAC,KAAK,cAAc,MAAM,GAAG;AAChG,WAAK,SAAS;AACd,WAAK,eAAe;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,MAAM,KAAK,WAAW;AACpC,SAAK,SAAS;AACd,SAAK,eAAe;AACpB,SAAK,YAAY;AACjB,SAAK,KAAK,KAAK,QAAQ,4BAA4B;AAAA,MACjD,aAAa,KAAK,QAAQ;AAAA,MAC1B;AAAA,MACA,WAAW,MAAM;AAAA,IACnB,CAAC;AACD,UAAM,KAAK,YAAY,KAAK;AAC5B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAA+C;AACnD,QAAI,KAAK,WAAW,OAAW,QAAO;AACtC,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,CAAC;AACrD,UAAI,CAAC,cAAc,KAAK,EAAG,QAAO;AAClC,aAAO;AAAA,QACL,aAAa,MAAM;AAAA,QACnB,YAAY,MAAM,YAAY,MAAM,cAAc;AAAA,QAClD,YAAY,MAAM;AAAA,MACpB;AAAA,IACF,SAAS,OAAO;AACd,WAAK,aAAa,OAAO,KAAK;AAC9B,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAmC;AACnD,QAAI,KAAK,WAAW,OAAW;AAC/B,UAAM,SAAsB;AAAA,MAC1B,aAAa,MAAM;AAAA,MACnB,YAAY,MAAM;AAAA,MAClB,WAAW,MAAM,aAAa,MAAM,YAAY;AAAA,IAClD;AACA,QAAI;AACF,YAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,GAAG,MAAM;AAAA,IACjD,SAAS,OAAO;AACd,WAAK,aAAa,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,OAAwB;AACtB,UAAM,EAAE,aAAa,aAAa,YAAY,IAAI,KAAK;AACvD,SAAK,cAAc,cAAc,aAAa,aAAa,WAAW;AACtE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,WAA0B,OAAsB;AAC3D,SAAK,KAAK,KAAK,QAAQ,0BAA0B;AAAA,MAC/C,aAAa,KAAK,QAAQ;AAAA,MAC1B;AAAA,MACA,WAAW,iBAAiB,QAAQ,MAAM,OAAO,OAAO;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAmC;AACvC,UAAM,EAAE,MAAM,eAAe,KAAK,IAAI,kBAAkB,KAAK,QAAQ,aAAa,KAAK,QAAQ,WAAW;AAC1G,UAAM,WAAW,MAAM,KAAK,WAAW,QAAmC;AAAA,MACxE,QAAQ;AAAA,MACR;AAAA,MACA,SAAS;AAAA;AAAA,MAET,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,SAAS,EAAE,eAAe,cAAc;AAAA,MACxC;AAAA,IACF,CAAC;AACD,WAAO,KAAK,OAAO,QAAQ;AAAA,EAC7B;AAAA,EAEA,OAAO,UAAkD;AACvD,UAAM,cAAc,UAAU;AAC9B,UAAM,YAAY,UAAU;AAC5B,QAAI,OAAO,gBAAgB,YAAY,gBAAgB,MAAM,OAAO,cAAc,YAAY,EAAE,YAAY,IAAI;AAC9G,YAAM,IAAI,kBAAkB,GAAG,aAAa,sDAAmD;AAAA,QAC7F,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AACA,WAAO,EAAE,aAAa,WAAW,YAAY,KAAK,KAAK,EAAE;AAAA,EAC3D;AACF;;;ACxMA,IAAM,UAAU;AAeT,SAAS,eAAe,UAAuE;AACpG,SAAO,MAAM,QAAQ,SAAS,MAAM,IAAI,SAAS,OAAO,OAAOC,SAAQ,IAA8B,CAAC;AACxG;AAEO,SAAS,UAAU,MAAqC;AAC7D,SAAO,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,YAAY,MAAM;AAC9E;AAEO,SAAS,UAAU,SAAiB,MAA0C;AACnF,SAAO,IAAI,aAAa,UAAU,SAAS,IAAI,GAAG,EAAE,SAAS,MAAM,OAAO,IAAI,GAAG,KAAK,KAAK,CAAC;AAC9F;AAQO,SAAS,gBACd,SACA,MACA,EAAE,WAAW,CAAC,GAAG,SAAS,CAAC,GAAG,YAAY,MAAM,IAA8B,CAAC,GAC3D;AACpB,SAAO,IAAI,mBAAmB,UAAU,SAAS,IAAI,GAAG;AAAA,IACtD;AAAA,IACA,MAAM,OAAO,IAAI;AAAA,IACjB,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEO,SAAS,OAAO,MAAoC;AACzD,SAAO,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,KAAK,KAAK,OAAO,OAAO,KAAK,QAAQ;AAC7F;AAGA,SAAS,UAAU,SAAiB,MAAoC;AACtE,QAAM,QAAQ,OAAO,KAAK,cAAc,YAAY,KAAK,cAAc,KAAK,OAAO,KAAK,SAAS,KAAK;AACtG,QAAM,cAAc,OAAO,KAAK,gBAAgB,YAAY,KAAK,gBAAgB,KAAK,KAAK,KAAK,WAAW,KAAK;AAChH,SAAO,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,GAAG,WAAW;AACnF;AAEO,SAAS,SAAS,OAAiC;AACxD,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,SAASA,UAAS,OAAkD;AACzE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;;ACpDO,IAAM,yBAAyB;AACtC,IAAMC,QAAO;AAEb,IAAM,qBAAqB;AAC3B,IAAM,aAAa,CAAC,WAAW,UAAU,QAAQ,UAAU,WAAW,UAAU;AA0GhF,eAAsB,cACpB,WACA,SACA,UAAgC,CAAC,GACD;AAChC,+BAA6B,OAAO;AACpC,QAAM,OAAO,MAAM,UAAU,QAAkC;AAAA,IAC7D,QAAQ;AAAA,IACR,MAAMA;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,IACjE,GAAI,QAAQ,kBAAkB,SAC1B,CAAC,IACD,EAAE,WAAW,kBAAkB,eAAe,QAAQ,cAAc;AAAA,EAC1E,CAAC;AACD,SAAO,wBAAwB,IAAI;AACrC;AAGA,SAAS,6BAA6B,SAAqC;AACzE,MAAI,CAACC,UAAS,OAAO,KAAK,CAAC,SAAS,QAAQ,cAAc,GAAG;AAC3D,UAAM,IAAI,UAAU,qEAAqE;AAAA,EAC3F;AACA,QAAM,QAAQ,WAAW,KAAK,IAAI;AAClC,MAAI,QAAQ,cAAc,MAAM;AAC9B,QAAI,WAAW,KAAK,CAAC,SAAS,QAAQ,IAAI,MAAM,MAAS,GAAG;AAC1D,YAAM,IAAI,UAAU,iEAAiE,KAAK,GAAG;AAAA,IAC/F;AAAA,EACF,WAAW,CAAC,WAAW,KAAK,CAAC,SAAS,MAAM,QAAQ,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI,EAAE,SAAS,CAAC,GAAG;AAC/F,UAAM,IAAI,UAAU,+EAA+E,KAAK,GAAG;AAAA,EAC7G;AACA,MAAI,QAAQ,gBAAgB,UAAa,QAAQ,0BAA0B,QAAW;AACpF,UAAM,IAAI,UAAU,+EAA+E;AAAA,EACrG;AACF;AAWO,SAAS,sBAAsB,MAAuC;AAC3E,MAAI,CAACA,UAAS,IAAI,GAAG;AACnB,WAAO,IAAI,WAAW,GAAG,sBAAsB,iDAAiD;AAAA,MAC9F,WAAW;AAAA,MACX,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACA,QAAM,QAAQ,eAAe,IAAgC;AAC7D,QAAM,mBAAmB,MAAM,KAAK,kBAAkB;AACtD,QAAM,WAAW,MAAM,OAAO,CAAC,SAAS,UAAU,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,EAAE,IAAI,SAAS;AACnG,QAAM,QAAQ,MAAM,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC;AAErD,MAAI,qBAAqB,QAAW;AAClC,WAAO,gBAAgB,wBAAwB,kBAAkB,EAAE,UAAU,QAAQ,MAAM,IAAI,OAAO,EAAE,CAAC;AAAA,EAC3G;AACA,QAAM,CAAC,OAAO,GAAG,IAAI,IAAI;AACzB,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,gBAAgB,wBAAwB,OAAO,EAAE,UAAU,QAAQ,KAAK,IAAI,OAAO,EAAE,CAAC;AAC/F;AAGA,SAAS,wBAAwB,MAAuD;AACtF,QAAM,EAAE,QAAQ,SAAS,GAAG,KAAK,IAAI;AACrC,SAAO,EAAE,GAAG,MAAM,UAAU,eAAe,IAAI,EAAE,IAAI,SAAS,EAAE;AAClE;AAEA,SAAS,mBAAmB,MAAqC;AAC/D,SAAO,KAAK,SAAS;AACvB;AAEA,SAAS,UAAU,MAA0C;AAC3D,SAAO,UAAU,wBAAwB,IAAI;AAC/C;AAEA,SAAS,QAAQ,MAA4B;AAC3C,SAAO,gBAAgB,wBAAwB,IAAI;AACrD;;;AClMO,IAAM,yBAAyB;AACtC,IAAMC,QAAO;AAEb,IAAM,6BAA6B;AAuDnC,eAAsB,cACpB,WACA,SACA,UAAgC,CAAC,GACD;AAChC,+BAA6B,OAAO;AACpC,QAAM,OAAO,MAAM,UAAU,QAAkC;AAAA,IAC7D,QAAQ;AAAA,IACR,MAAMA;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,IACjE,GAAI,QAAQ,kBAAkB,SAC1B,CAAC,IACD,EAAE,WAAW,kBAAkB,eAAe,QAAQ,cAAc;AAAA,EAC1E,CAAC;AACD,SAAO,wBAAwB,IAAI;AACrC;AAOA,SAAS,6BAA6B,SAAqC;AACzE,MAAI,OAAO,YAAY,YAAY,YAAY,MAAM;AACnD,UAAM,IAAI,UAAU,oEAAoE;AAAA,EAC1F;AACA,QAAM,SAAS,QAAQ;AACvB,MAAI,QAAQ,oBAAoB,sBAAsB,OAAO,0BAA0B,QAAW;AAChG,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAYO,SAAS,sBAAsB,MAAuC;AAC3E,MAAI,CAACC,UAAS,IAAI,GAAG;AACnB,WAAO,IAAI,WAAW,GAAG,sBAAsB,iDAAiD;AAAA,MAC9F,WAAW;AAAA,MACX,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACA,QAAM,WAAW;AACjB,MAAI,iBAAiB,QAAQ,MAAM,OAAW,QAAO;AAGrD,MAAI,qBAAqB,QAAQ,GAAG;AAClC,WAAO,IAAI;AAAA,MACT,GAAG,sBAAsB;AAAA,MACzB,EAAE,WAAW,OAAO,KAAK,KAAK;AAAA,IAChC;AAAA,EACF;AACA,QAAM,QAAQ,eAAe,QAAQ;AACrC,QAAM,QAAQ,MAAM,KAAK,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC;AACnD,MAAI,UAAU,OAAW,QAAO,gBAAgB,wBAAwB,OAAO,EAAE,UAAU,MAAM,OAAO,SAAS,EAAE,IAAIC,UAAS,EAAE,CAAC;AACnI,SAAO,IAAI,WAAW,GAAG,sBAAsB,iEAAiE;AAAA,IAC9G,WAAW;AAAA,IACX,KAAK;AAAA,EACP,CAAC;AACH;AAGA,SAAS,wBAAwB,MAAuD;AACtF,QAAM,QAAQ,eAAe,IAAI;AACjC,SAAO;AAAA,IACL,gBAAgB,iBAAiB,IAAI;AAAA,IACrC,GAAI,KAAK,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU;AAAA,IACpE,GAAI,KAAK,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ;AAAA,IAC9D,GAAI,KAAK,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ;AAAA,IAC9D,UAAU,MAAM,OAAO,SAAS,EAAE,IAAIA,UAAS;AAAA,IAC/C,QAAQ,MAAM,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,gBAAgB,wBAAwB,IAAI,CAAC;AAAA,EAC9G;AACF;AAEA,SAAS,iBAAiB,UAAwD;AAChF,MAAI,SAAS,SAAS,cAAc,EAAG,QAAO,SAAS;AACvD,MAAI,SAAS,SAAS,SAAS,SAAS,EAAG,QAAO,SAAS,QAAQ;AACnE,QAAM,eAAe,eAAe,QAAQ,EAAE,KAAK,CAAC,SAAS,KAAK,SAAS,0BAA0B;AACrG,SAAO,iBAAiB,SAAY,SAAY,UAAU,aAAa,WAAW;AACpF;AAEA,SAAS,qBAAqB,UAA6C;AACzE,SAAO,SAAS,YAAY,UAAa,eAAe,QAAQ,EAAE,KAAK,CAAC,SAAS,KAAK,SAAS,0BAA0B;AAC3H;AAMA,SAAS,UAAU,aAAqD;AACtE,MAAI,gBAAgB,OAAW,QAAO;AACtC,SAAO,qBAAqB,KAAK,WAAW,IAAI,CAAC,KAAK,qBAAqB,KAAK,WAAW,IAAI,CAAC;AAClG;AAEA,SAASA,WAAU,MAA0C;AAC3D,SAAO,UAAU,wBAAwB,IAAI;AAC/C;;;ACxKO,IAAM,sBAAsB;AACnC,IAAMC,QAAO;AAEb,IAAM,kBAAkB,oBAAI,IAAI,CAAC,2BAA2B,0BAA0B,CAAC;AA+GvF,eAAsB,WACpB,WACA,SACA,UAA6B,CAAC,GACD;AAC7B,MAAI,CAACC,UAAS,OAAO,KAAK,CAAC,SAAS,QAAQ,cAAc,GAAG;AAC3D,UAAM,IAAI,UAAU,kEAAkE;AAAA,EACxF;AACA,QAAM,OAAO,MAAM,UAAU,QAA+B;AAAA,IAC1D,QAAQ;AAAA,IACR,MAAMD;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,IACjE,GAAI,QAAQ,kBAAkB,SAC1B,CAAC,IACD,EAAE,WAAW,eAAe,eAAe,QAAQ,cAAc;AAAA,EACvE,CAAC;AACD,SAAO,qBAAqB,IAAI;AAClC;AASO,SAAS,mBAAmB,MAAuC;AACxE,MAAI,CAACC,UAAS,IAAI,GAAG;AACnB,WAAO,IAAI,WAAW,GAAG,mBAAmB,iDAAiD;AAAA,MAC3F,WAAW;AAAA,MACX,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AACA,QAAM,WAAW;AACjB,MAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AAEzC,QAAM,QAAQ,eAAe,QAAQ;AACrC,QAAM,QAAQ,MAAM,KAAK,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC;AACnD,MAAI,UAAU,OAAW,QAAOC,SAAQ,OAAO,MAAM,OAAO,SAAS,EAAE,IAAIC,UAAS,CAAC;AACrF,SAAO,IAAI,WAAW,GAAG,mBAAmB,4DAA4D;AAAA,IACtG,WAAW;AAAA,IACX,KAAK;AAAA,EACP,CAAC;AACH;AAGA,SAAS,qBAAqB,MAAiD;AAC7E,QAAM,QAAQ,eAAe,IAAI;AACjC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW,KAAK;AAAA,IAChB,UAAU,MAAM,OAAO,SAAS,EAAE,IAAIA,UAAS;AAAA,IAC/C,QAAQ,MAAM,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC,EAAE,IAAI,CAAC,SAASD,SAAQ,MAAM,CAAC,CAAC,CAAC;AAAA,EAClF;AACF;AAEA,SAASC,WAAU,MAA0C;AAC3D,SAAO,UAAU,qBAAqB,IAAI;AAC5C;AAEA,SAASD,SAAQ,MAA4B,UAA8C;AACzF,SAAO,gBAAgB,qBAAqB,MAAM,EAAE,UAAU,WAAW,gBAAgB,IAAI,KAAK,IAAI,EAAE,CAAC;AAC3G;;;ACvLO,IAAM,oBAAN,MAAwB;AAAA,EACpB;AAAA;AAAA,EAGT,YAAY,WAA0B;AACpC,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,SAA+B,SAAgE;AACpG,WAAO,cAAc,KAAK,YAAY,SAAS,OAAO;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI,SAA4B,SAA0D;AACxF,WAAO,WAAW,KAAK,YAAY,SAAS,OAAO;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,SAA+B,SAAgE;AACpG,WAAO,cAAc,KAAK,YAAY,SAAS,OAAO;AAAA,EACxD;AACF;;;ACjDO,IAAM,gBAAwC,OAAO,OAAO,EAAE,YAAY,GAAG,aAAa,IAAI,CAAC;AAG/F,IAAM,qBAAqB;AAG3B,SAAS,WAAW,OAAe,aAAqB,SAAuB,KAAK,QAAgB;AACzG,SAAO,KAAK,IAAI,oBAAoB,KAAK,MAAM,OAAO,IAAI,cAAc,KAAK,KAAK,CAAC;AACrF;AAGO,SAAS,YAAY,OAAgB,YAA8B;AACxE,SAAO,cAAc,iBAAiB,cAAc,MAAM;AAC5D;AAEO,SAAS,qBAAqB,OAA8B,OAAqB;AACtF,MAAI,MAAM,eAAe,UAAa,EAAE,OAAO,UAAU,MAAM,UAAU,KAAK,MAAM,cAAc,IAAI;AACpG,UAAM,IAAI,UAAU,iBAAiB,KAAK,qCAAqC;AAAA,EACjF;AACA,MAAI,MAAM,gBAAgB,UAAa,EAAE,OAAO,SAAS,MAAM,WAAW,KAAK,MAAM,eAAe,IAAI;AACtG,UAAM,IAAI,UAAU,iBAAiB,KAAK,yCAAsC;AAAA,EAClF;AACF;;;AC6BO,IAAM,YAAwD,OAAO,OAAO;AAAA,EACjF,SAAS;AAAA,EACT,YAAY;AACd,CAAC;AAeD,IAAM,iBAAiB,CAAC,SAAS,QAAQ,QAAQ,OAAO;AAExD,SAAS,KAAK,SAAwB;AACpC,QAAM,IAAI,UAAU,iBAAiB,OAAO,EAAE;AAChD;AAEA,SAASE,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,cAAc,OAAgB,OAAqB;AAC1D,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,GAAI,MAAK,GAAG,KAAK,gDAA6C;AAClH;AAEO,SAAS,cAAc,QAAqC;AACjE,MAAI,CAACA,UAAS,MAAM,EAAG,MAAK,8BAA8B;AAE1D,QAAM,EAAE,YAAY,IAAI;AACxB,MAAI,gBAAgB,aAAa,gBAAgB,cAAc;AAC7D,SAAK,4DAA4D,KAAK,UAAU,WAAW,CAAC,GAAG;AAAA,EACjG;AAEA,QAAM,cAAc,OAAO,eAAe;AAC1C,MAAI,gBAAgB,QAAQ,gBAAgB,MAAM;AAChD,SAAK,+CAA+C,KAAK,UAAU,WAAW,CAAC,GAAG;AAAA,EACpF;AAEA,QAAM,EAAE,YAAY,IAAI;AACxB,MAAI,CAACA,UAAS,WAAW,EAAG,MAAK,0BAA0B;AAC3D,gBAAc,YAAY,UAAU,sBAAsB;AAC1D,gBAAc,YAAY,UAAU,sBAAsB;AAC1D,MAAI,gBAAgB,MAAM;AACxB,kBAAc,YAAY,UAAU,qDAAqD;AACzF,kBAAc,YAAY,cAAc,yDAAyD;AAAA,EACnG;AAEA,MAAI,OAAO,QAAQ,OAAW,eAAc,OAAO,KAAK,KAAK;AAE7D,QAAM,EAAE,OAAO,IAAI;AACnB,MAAI,WAAW,QAAW;AACxB,QAAI,CAACA,UAAS,MAAM,EAAG,MAAK,qDAAqD;AACjF,eAAW,UAAU,gBAAgB;AACnC,UAAI,OAAO,OAAO,MAAM,MAAM,WAAY,MAAK,UAAU,MAAM,0BAAuB;AAAA,IACxF;AAAA,EACF;AAEA,MAAI,OAAO,UAAU,QAAW;AAC9B,QAAI,CAACA,UAAS,OAAO,KAAK,EAAG,MAAK,0BAA0B;AAC5D,yBAAqB,OAAO,OAAO,OAAO;AAAA,EAC5C;AAEA,QAAM,EAAE,WAAW,IAAI;AACvB,MAAI,eAAe,QAAW;AAC5B,QAAI,CAACA,UAAS,UAAU,KAAK,OAAO,WAAW,QAAQ,cAAc,OAAO,WAAW,QAAQ,YAAY;AACzG,WAAK,8DAA8D;AAAA,IACrE;AAAA,EACF;AAEA,QAAM,YAAY,OAAO,SAAS,WAAW;AAC7C,MAAI,OAAO,cAAc,WAAY,MAAK,4CAA4C;AAEtF,SAAO;AAAA,IACL,aAAa,OAAO,OAAO,EAAE,GAAG,YAAY,CAAC;AAAA,IAC7C;AAAA,IACA,SAAS,UAAU,WAAW;AAAA,IAC9B;AAAA,IACA,KAAK,OAAO;AAAA,IACZ;AAAA,IACA,OAAO,OAAO,OAAO,EAAE,GAAG,eAAe,GAAG,YAAY,OAAO,SAAS,CAAC,CAAC,EAAE,CAAC;AAAA;AAAA,IAE7E,OAAO,OAAO,SAAS,WAAW,MAAM,KAAK,UAAU;AAAA,IACvD;AAAA,EACF;AACF;AAGO,SAAS,YAA8B,OAAsB;AAClE,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,CAAC;AACpF;;;AClJA,IAAM,mBAAmB,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAK,GAAG,CAAC;AAwD9C,IAAM,gBAAN,MAAoB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EAEA,YAAY,QAAwB,UAAgC,CAAC,GAAG;AACtE,SAAK,UAAU;AACf,SAAK,OAAO,IAAI,YAAY,OAAO,MAAM;AACzC,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,UAAU,QAAQ,UAAU,KAAK;AACtC,SAAK,SAAS,QAAQ,SAAS;AAAA,EACjC;AAAA;AAAA,EAGA,yBAAyB,UAAmD;AAC1E,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,MAAM,QAAW,SAAkC;AACjD,QAAI,QAAQ,UAAU,OAAW,sBAAqB,QAAQ,OAAO,OAAO;AAC5E,UAAM,UAAkC,QAAQ,kBAAkB,SAAY,SAAY,EAAE,UAAU,EAAE;AACxG,QAAI;AACF,aAAO,MAAM,KAAK,UAAa,SAAS,OAAO;AAAA,IACjD,UAAE;AAEA,UAAI,SAAS,SAAS,OAAW,MAAK,YAAY,SAAS,EAAE,GAAG,QAAQ,MAAM,UAAU,QAAQ,SAAS,CAAC;AAAA,IAC5G;AAAA,EACF;AAAA,EAEA,MAAM,UAAa,SAAsB,SAA6C;AACpF,UAAM,QAAQ,EAAE,GAAG,KAAK,QAAQ,OAAO,GAAG,YAAY,QAAQ,SAAS,CAAC,CAAC,EAAE;AAE3E,QAAI,eAAe;AACnB,aAAS,UAAU,KAAK,WAAW;AAEjC,YAAM,gBAAgB,MAAM,KAAK,kBAAkB,OAAO;AAC1D,UAAI;AACF,eAAO,MAAM,KAAK,MAAS,SAAS,SAAS,eAAe,OAAO;AAAA,MACrE,SAAS,OAAO;AAGd,YAAI,kBAAkB,UAAa,CAAC,gBAAgB,eAAe,KAAK,GAAG;AACzE,yBAAe;AACf,eAAK,gBAAgB,WAAW,aAAa;AAC7C,eAAK,KAAK,KAAK,QAAQ,uBAAuB;AAAA,YAC5C,SAAS,QAAQ;AAAA,YACjB,QAAQ,QAAQ;AAAA,YAChB,MAAM,QAAQ;AAAA,YACd,SAAS,UAAU;AAAA,YACnB,QAAQ;AAAA,YACR;AAAA,UACF,CAAC;AACD;AACA;AAAA,QACF;AACA,YAAI,WAAW,MAAM,cAAc,CAAC,YAAY,OAAO,QAAQ,UAAU,EAAG,OAAM;AAClF,cAAM,UAAU,WAAW,SAAS,MAAM,aAAa,KAAK,OAAO;AACnE,aAAK,KAAK,KAAK,QAAQ,uBAAuB;AAAA,UAC5C,SAAS,QAAQ;AAAA,UACjB,QAAQ,QAAQ;AAAA,UAChB,MAAM,QAAQ;AAAA,UACd,SAAS,UAAU;AAAA,UACnB,YAAY,MAAM;AAAA,UAClB;AAAA,UACA;AAAA,QACF,CAAC;AACD,cAAM,KAAK,OAAO,SAAS,QAAQ,MAAM;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,YAAY,SAAsB,KAA6D;AAC7F,UAAM,YAAY,QAAQ,aAAa,QAAQ;AAC/C,QAAI;AACF,cAAQ,gBAAgB,EAAE,WAAW,UAAU,QAAQ,GAAG,IAAI,CAAC;AAAA,IACjE,SAAS,OAAO;AACd,WAAK,KAAK,KAAK,QAAQ,uCAAuC;AAAA,QAC5D,SAAS,QAAQ;AAAA,QACjB;AAAA,QACA,WAAW,iBAAiB,QAAQ,MAAM,OAAO,OAAO;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,SAAmD;AACzE,QAAI,QAAQ,SAAS,SAAS,KAAK,mBAAmB,OAAW,QAAO;AACxE,WAAO,KAAK,eAAe,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,MACJ,SACA,SACA,eACA,SACY;AACZ,UAAM,MAAM,KAAK,KAAK,OAAO;AAC7B,UAAM,UAAU,IAAI,QAAQ,EAAE,QAAQ,oBAAoB,GAAG,QAAQ,QAAQ,CAAC;AAC9E,UAAM,OAAO,QAAQ,gBAAgB;AACrC,QAAI,QAAQ,SAAS,UAAa,CAAC,QAAQ,IAAI,cAAc,GAAG;AAC9D,cAAQ,IAAI,gBAAgB,OAAO,sCAAsC,kBAAkB;AAAA,IAC7F;AACA,QAAI,kBAAkB,OAAW,SAAQ,IAAI,iBAAiB,aAAa;AAE3E,UAAM,aAAa,EAAE,SAAS,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,MAAM,QAAQ,MAAM,QAAQ;AACnG,SAAK,KAAK,KAAK,SAAS,uBAAuB,UAAU;AACzD,UAAM,YAAY,KAAK,IAAI;AAE3B,QAAI;AACJ,QAAI,YAAY,OAAW,SAAQ;AACnC,QAAI;AACF,iBAAW,MAAM,KAAK,QAAQ,MAAM,KAAK;AAAA,QACvC,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA,GAAI,QAAQ,SAAS,SAAY,CAAC,IAAI,EAAE,MAAM,OAAO,OAAO,QAAQ,IAAI,IAAI,KAAK,UAAU,QAAQ,IAAI,EAAE;AAAA,QACzG,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,MACnE,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,QAAQ,OAAO,QAAQ,MAAM,EAAG,OAAM;AAC1C,YAAM,QAAQ,IAAI,kBAAkB,GAAG,QAAQ,OAAO,mBAAmB,SAAS,KAAK,CAAC,KAAK;AAAA,QAC3F,UAAU;AAAA,QACV,WAAW;AAAA,QACX;AAAA,MACF,CAAC;AACD,WAAK,KAAK,KAAK,SAAS,qBAAqB,EAAE,GAAG,YAAY,YAAY,KAAK,IAAI,IAAI,WAAW,MAAM,CAAC;AACzG,YAAM;AAAA,IACR;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,YAAY,OAAW,SAAQ,OAAO,EAAE,QAAQ,SAAS,QAAQ,SAAS,SAAS,SAAS,MAAM,KAAK;AAC3G,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,aAAa,EAAE,GAAG,YAAY,QAAQ,SAAS,QAAQ,YAAY,KAAK,IAAI,IAAI,UAAU;AAGhG,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,aAAa,QAAQ,SAAS,SAAS,QAAQ,IAAI;AACjE,WAAK,KAAK,KAAK,SAAS,qBAAqB,EAAE,GAAG,YAAY,MAAM,CAAC;AACrE,YAAM;AAAA,IACR;AAGA,UAAM,eAAe,QAAQ,WAAW,MAAM,QAAQ;AACtD,QAAI,iBAAiB,QAAW;AAC9B,WAAK,KAAK,KAAK,QAAQ,qBAAqB,EAAE,GAAG,YAAY,OAAO,aAAa,CAAC;AAClF,YAAM;AAAA,IACR;AAGA,SAAK,KAAK,KAAK,QAAQ,qBAAqB,UAAU;AACtD,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,SAA8B;AACjC,UAAM,OAAO,QAAQ,KAAK,WAAW,GAAG,IAAI,QAAQ,OAAO,IAAI,QAAQ,IAAI;AAC3E,UAAM,MAAM,IAAI,IAAI,MAAM,KAAK,QAAQ,OAAO;AAC9C,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,GAAG;AAC9D,UAAI,UAAU,OAAW,KAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IAClE;AACA,WAAO,IAAI,SAAS;AAAA,EACtB;AACF;AAGA,SAAS,UAAU,MAAuB;AACxC,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,aAAa,SAAiB,QAAgB,MAAkC;AACvF,QAAM,OAAO,YAAY,IAAI;AAC7B,SAAO,IAAI,kBAAkB,GAAG,OAAO,UAAU,MAAM,GAAG,SAAS,SAAY,KAAK,IAAI,IAAI,EAAE,IAAI;AAAA,IAChG,UAAU;AAAA,IACV;AAAA,IACA,WAAW,iBAAiB,IAAI,MAAM;AAAA,IACtC,KAAK;AAAA,IACL,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,KAAK;AAAA,EACvC,CAAC;AACH;AAMA,SAAS,YAAY,MAAmC;AACtD,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,aAAW,OAAO,CAAC,aAAa,OAAO,GAAY;AACjD,UAAM,QAAS,KAAiC,GAAG;AACnD,QAAI,OAAO,UAAU,YAAY,UAAU,GAAI,QAAO;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAAyB;AAC/C,SAAO,iBAAiB,qBAAqB,MAAM,aAAa,UAAU,MAAM,WAAW;AAC7F;AAEA,SAAS,QAAQ,OAAgB,QAA0C;AACzE,SAAO,QAAQ,YAAY,QAAS,iBAAiB,SAAS,MAAM,SAAS;AAC/E;AAEA,SAAS,SAAS,OAAwB;AACxC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,SAAS,MAAM,IAAY,QAAqC;AAC9D,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,QAAQ,QAAS,QAAO,OAAO,OAAO,MAAM;AAChD,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ,oBAAoB,SAAS,OAAO;AAC5C,cAAQ;AAAA,IACV,GAAG,EAAE;AACL,UAAM,UAAU,MAAM;AACpB,mBAAa,KAAK;AAClB,aAAO,QAAQ,MAAM;AAAA,IACvB;AACA,YAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D,CAAC;AACH;;;AC3RO,IAAM,QAAN,MAAY;AAAA,EACR;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,QAAqB;AAC/B,SAAK,UAAU,cAAc,MAAM;AACnC,SAAK,aAAa,IAAI,cAAc,KAAK,OAAO;AAEhD,UAAM,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,UAAU;AAC1D,SAAK,WAAW,yBAAyB,KAAK,eAAe,CAAC;AAC9D,SAAK,MAAM,IAAI,IAAI,KAAK,UAAU;AAClC,SAAK,UAAU,IAAI,kBAAkB,KAAK,UAAU;AAAA,EACtD;AAAA,EAEA,IAAI,cAAgC;AAClC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,IAAI,UAAkB;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AACF;;;ACJO,SAAS,0BAA0B,QAAmD;AAC3F,QAAM,EAAE,OAAO,WAAW,gBAAgB,IAAI;AAC9C,QAAM,UAAU,iBAAiB,OAAO,SAAS,EAAE;AAAA,IACjD,CAAC,EAAE,UAAU,eAAe,YAAY,OAAqB;AAAA,MAC3D,cAAc,SAAS,QAAQ;AAAA,MAC/B,aAAa,SAAS,QAAQ;AAAA,MAC9B,iBAAiB,SAAS,UAAU;AAAA,MACpC,eAAe,SAAS,QAAQ;AAAA,MAChC;AAAA,MACA,eAAe,SAAS,UAAU,KAAK,MAAM,GAAG,CAAC;AAAA,MACjD,cAAc;AAAA,MACd,kBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,OAAO,UAAU,mBAAmB,CAAC,GAAG;AAC9C,MAAI,SAAS,QAAW;AACtB,UAAM,IAAI,UAAU,wDAAwD;AAAA,EAC9E;AACA,QAAM,oBAAoB,KAAK,kBAAkB;AAAA,IAC/C,CAAC,EAAE,cAAc,OAAyB;AAAA,MACxC,eAAe,cAAc;AAAA,MAC7B,oBAAoB,cAAc,mBAAmB;AAAA,IACvD;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,oBAAoB,QAAW;AACjC,UAAM,QAAQ,KAAK,WAAW;AAC9B,QAAI,UAAU,QAAW;AACvB,YAAM,IAAI,UAAU,+EAA+E;AAAA,IACrG;AACA,uBAAmB,CAAC,EAAE,eAAe,OAAO,KAAK,GAAG,GAAG,gBAAgB,CAAC;AAAA,EAC1E;AAEA,SAAO;AAAA,IACL;AAAA,IACA,eAAe;AAAA,MACb;AAAA,QACE,GAAI,qBAAqB,SAAY,CAAC,IAAI,EAAE,iBAAiB;AAAA,QAC7D,YAAY;AAAA,UACV;AAAA,UACA,GAAI,KAAK,0BAA0B,SAAY,CAAC,IAAI,EAAE,uBAAuB,KAAK,sBAAsB;AAAA,QAC1G;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAGA,SAAS,OAAO,OAAuB;AACrC,SAAO,OAAO,KAAK,MAAM,QAAQ,GAAI,IAAI,GAAI;AAC/C;;;AChFO,IAAM,UAAU;","names":["PATH","isObject","PATH","isObject","PATH","isObject","warningOf","PATH","isObject","errorOf","warningOf","isObject"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sabre-client",
3
- "version": "0.3.0-next.0",
3
+ "version": "0.3.0-next.1",
4
4
  "description": "TypeScript SDK for the Sabre GDS APIs: managed OAuth, air shopping, itinerary revalidation and booking over REST, built on Web Standard APIs to run on any server runtime.",
5
5
  "license": "MIT",
6
6
  "repository": {