sabre-client 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -223,6 +223,22 @@ function isObject(value) {
223
223
  return typeof value === "object" && value !== null;
224
224
  }
225
225
 
226
+ // src/http/raw-request.ts
227
+ function rawRequestHeaders(headers) {
228
+ const copy = new Headers(headers);
229
+ copy.delete("Authorization");
230
+ return copy;
231
+ }
232
+ function rawHooks(options, operation) {
233
+ const { onRawResponse, onRawRequest } = options;
234
+ if (onRawResponse === void 0 && onRawRequest === void 0) return {};
235
+ return {
236
+ operation,
237
+ ...onRawResponse === void 0 ? {} : { onRawResponse },
238
+ ...onRawRequest === void 0 ? {} : { onRawRequest }
239
+ };
240
+ }
241
+
226
242
  // src/air/bargain-finder-max.ts
227
243
  var BARGAIN_FINDER_MAX_SERVICE = "bargainFinderMax";
228
244
  var PATH = "/v5/offers/shop";
@@ -248,7 +264,7 @@ async function bargainFinderMax(transport, request, options = {}) {
248
264
  classify: classifyBargainFinderMax,
249
265
  ...options.retry === void 0 ? {} : { retry: options.retry },
250
266
  ...options.signal === void 0 ? {} : { signal: options.signal },
251
- ...options.onRawResponse === void 0 ? {} : { operation: "air.bargainFinderMax", onRawResponse: options.onRawResponse }
267
+ ...rawHooks(options, "air.bargainFinderMax")
252
268
  });
253
269
  return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, BARGAIN_FINDER_MAX_SERVICE);
254
270
  }
@@ -327,7 +343,7 @@ async function send(transport, path, service, request, options) {
327
343
  classify: (raw) => classifyGetSeats(raw, service),
328
344
  ...options.retry === void 0 ? {} : { retry: options.retry },
329
345
  ...options.signal === void 0 ? {} : { signal: options.signal },
330
- ...options.onRawResponse === void 0 ? {} : { operation: `air.${service}`, onRawResponse: options.onRawResponse }
346
+ ...rawHooks(options, `air.${service}`)
331
347
  });
332
348
  return {
333
349
  response: body.response,
@@ -418,7 +434,7 @@ async function revalidateItinerary(transport, request, options = {}) {
418
434
  classify: classifyRevalidateItinerary,
419
435
  ...options.retry === void 0 ? {} : { retry: options.retry },
420
436
  ...options.signal === void 0 ? {} : { signal: options.signal },
421
- ...options.onRawResponse === void 0 ? {} : { operation: "air.revalidateItinerary", onRawResponse: options.onRawResponse }
437
+ ...rawHooks(options, "air.revalidateItinerary")
422
438
  });
423
439
  return denormalizeGroupedItineraryResponse(body.groupedItineraryResponse, REVALIDATE_ITINERARY_SERVICE);
424
440
  }
@@ -797,7 +813,7 @@ async function cancelBooking(transport, request, options = {}) {
797
813
  body: request,
798
814
  classify: classifyCancelBooking,
799
815
  ...options.signal === void 0 ? {} : { signal: options.signal },
800
- ...options.onRawResponse === void 0 ? {} : { operation: "booking.cancel", onRawResponse: options.onRawResponse }
816
+ ...rawHooks(options, "booking.cancel")
801
817
  });
802
818
  return toCancelBookingResponse(body);
803
819
  }
@@ -974,7 +990,7 @@ async function createBooking(transport, request, options = {}) {
974
990
  body: request,
975
991
  classify: classifyCreateBooking,
976
992
  ...options.signal === void 0 ? {} : { signal: options.signal },
977
- ...options.onRawResponse === void 0 ? {} : { operation: "booking.create", onRawResponse: options.onRawResponse }
993
+ ...rawHooks(options, "booking.create")
978
994
  });
979
995
  return toCreateBookingResponse(body);
980
996
  }
@@ -1066,7 +1082,7 @@ async function getBooking(transport, request, options = {}) {
1066
1082
  body: request,
1067
1083
  classify: classifyGetBooking,
1068
1084
  ...options.signal === void 0 ? {} : { signal: options.signal },
1069
- ...options.onRawResponse === void 0 ? {} : { operation: "booking.get", onRawResponse: options.onRawResponse }
1085
+ ...rawHooks(options, "booking.get")
1070
1086
  });
1071
1087
  return toGetBookingResponse(body);
1072
1088
  }
@@ -1207,19 +1223,26 @@ function resolveConfig(config) {
1207
1223
  if (environment !== "sandbox" && environment !== "production") {
1208
1224
  fail(`environment debe ser 'sandbox' o 'production' (recibido: ${JSON.stringify(environment)})`);
1209
1225
  }
1210
- const authVersion = config.authVersion ?? "v3";
1211
- if (authVersion !== "v3" && authVersion !== "v2") {
1212
- fail(`authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(authVersion)})`);
1226
+ const configVersion = config.authVersion ?? void 0;
1227
+ if (configVersion !== void 0 && configVersion !== "v3" && configVersion !== "v2") {
1228
+ fail(`authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(configVersion)})`);
1213
1229
  }
1214
1230
  const { credentials } = config;
1215
1231
  if (!isObject3(credentials)) fail("credentials es requerido");
1232
+ const credentialsVersion = credentials.authVersion ?? void 0;
1233
+ if (credentialsVersion !== void 0 && credentialsVersion !== "v3" && credentialsVersion !== "v2") {
1234
+ fail(`credentials.authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(credentialsVersion)})`);
1235
+ }
1236
+ if (configVersion !== void 0 && credentialsVersion !== void 0 && configVersion !== credentialsVersion) {
1237
+ fail(`authVersion '${configVersion}' no coincide con credentials.authVersion '${credentialsVersion}'`);
1238
+ }
1239
+ const authVersion = configVersion ?? credentialsVersion ?? "v3";
1216
1240
  requireString(credentials.username, "credentials.username");
1217
1241
  requireString(credentials.password, "credentials.password");
1218
1242
  if (authVersion === "v3") {
1219
1243
  requireString(credentials.clientId, "credentials.clientId (requerido con authVersion v3)");
1220
1244
  requireString(credentials.clientSecret, "credentials.clientSecret (requerido con authVersion v3)");
1221
1245
  }
1222
- if (config.pcc !== void 0) requireString(config.pcc, "pcc");
1223
1246
  const { logger } = config;
1224
1247
  if (logger !== void 0) {
1225
1248
  if (!isObject3(logger)) fail("logger debe ser un objeto con debug/info/warn/error");
@@ -1240,12 +1263,12 @@ function resolveConfig(config) {
1240
1263
  const fetchImpl = config.fetch ?? globalThis.fetch;
1241
1264
  if (typeof fetchImpl !== "function") fail("no hay fetch disponible: pasa config.fetch");
1242
1265
  return {
1266
+ // Ya validado arriba: con v3 trae clientId/clientSecret; la marca de versión ya se resolvió.
1243
1267
  credentials: Object.freeze({ ...credentials }),
1244
1268
  environment,
1245
1269
  baseUrl: BASE_URLS[environment],
1246
1270
  soapBaseUrl: SOAP_BASE_URLS[environment],
1247
1271
  authVersion,
1248
- pcc: config.pcc,
1249
1272
  logger,
1250
1273
  retry: Object.freeze({ ...DEFAULT_RETRY, ...definedOnly(config.retry ?? {}) }),
1251
1274
  // Enlazado al global para evitar "Illegal invocation" en algunos runtimes.
@@ -1282,10 +1305,12 @@ var RestTransport = class {
1282
1305
  }
1283
1306
  async request(request) {
1284
1307
  if (request.retry !== void 0) validateRetryOptions(request.retry, "retry");
1285
- const capture = request.onRawResponse === void 0 ? void 0 : { attempts: 0 };
1308
+ const wantsRequest = request.onRawRequest !== void 0 && request.auth !== false;
1309
+ const capture = request.onRawResponse === void 0 && !wantsRequest ? void 0 : { attempts: 0 };
1286
1310
  try {
1287
1311
  return await this.#attempts(request, capture);
1288
1312
  } finally {
1313
+ if (wantsRequest && capture?.request !== void 0) this.#deliverRawRequest(request, capture.request, capture.attempts);
1289
1314
  if (capture?.last !== void 0) this.#deliverRaw(request, { ...capture.last, attempts: capture.attempts });
1290
1315
  }
1291
1316
  }
@@ -1339,6 +1364,19 @@ var RestTransport = class {
1339
1364
  });
1340
1365
  }
1341
1366
  }
1367
+ /** Igual que `#deliverRaw`: un callback que lanza no rompe la operación. */
1368
+ #deliverRawRequest(request, raw, attempts) {
1369
+ const operation = request.operation ?? request.service;
1370
+ try {
1371
+ request.onRawRequest?.({ operation, protocol: "rest", ...raw, attempts });
1372
+ } catch (error) {
1373
+ this.#log.emit("warn", "sabre.request.rawRequestHookFailed", {
1374
+ service: request.service,
1375
+ operation,
1376
+ errorName: error instanceof Error ? error.name : typeof error
1377
+ });
1378
+ }
1379
+ }
1342
1380
  async #authorizationFor(request) {
1343
1381
  if (request.auth === false || this.#authorization === void 0) return void 0;
1344
1382
  return this.#authorization.get();
@@ -1355,12 +1393,18 @@ var RestTransport = class {
1355
1393
  this.#log.emit("debug", "sabre.request.start", logContext);
1356
1394
  const startedAt = Date.now();
1357
1395
  let response;
1358
- if (capture !== void 0) capture.attempts++;
1396
+ const body = request.body === void 0 ? void 0 : form ? String(request.body) : JSON.stringify(request.body);
1397
+ if (capture !== void 0) {
1398
+ capture.attempts++;
1399
+ if (request.onRawRequest !== void 0 && request.auth !== false) {
1400
+ capture.request = { method: request.method, url, headers: rawRequestHeaders(headers), body };
1401
+ }
1402
+ }
1359
1403
  try {
1360
1404
  response = await this.#config.fetch(url, {
1361
1405
  method: request.method,
1362
1406
  headers,
1363
- ...request.body === void 0 ? {} : { body: form ? String(request.body) : JSON.stringify(request.body) },
1407
+ ...body === void 0 ? {} : { body },
1364
1408
  ...request.signal === void 0 ? {} : { signal: request.signal }
1365
1409
  });
1366
1410
  } catch (cause) {
@@ -1375,20 +1419,20 @@ var RestTransport = class {
1375
1419
  }
1376
1420
  const text = await response.text();
1377
1421
  if (capture !== void 0) capture.last = { status: response.status, headers: response.headers, body: text };
1378
- const body = parseBody(text);
1422
+ const parsed = parseBody(text);
1379
1423
  const endContext = { ...logContext, status: response.status, durationMs: Date.now() - startedAt };
1380
1424
  if (!response.ok) {
1381
- const error = gatewayError(request.service, response.status, body);
1425
+ const error = gatewayError(request.service, response.status, parsed);
1382
1426
  this.#log.emit("error", "sabre.request.end", { ...endContext, error });
1383
1427
  throw error;
1384
1428
  }
1385
- const serviceError = request.classify?.(body, response);
1429
+ const serviceError = request.classify?.(parsed, response);
1386
1430
  if (serviceError !== void 0) {
1387
1431
  this.#log.emit("warn", "sabre.request.end", { ...endContext, error: serviceError });
1388
1432
  throw serviceError;
1389
1433
  }
1390
1434
  this.#log.emit("info", "sabre.request.end", endContext);
1391
- return body;
1435
+ return parsed;
1392
1436
  }
1393
1437
  #url(request) {
1394
1438
  const path = request.path.startsWith("/") ? request.path : `/${request.path}`;
@@ -1491,6 +1535,7 @@ var TRANSIENT_CODES = /* @__PURE__ */ new Set([
1491
1535
  var PREVIOUS_ENTRY_ACTIVE_RETRIES = 3;
1492
1536
  var PREVIOUS_ENTRY_ACTIVE_DELAY_MS = 1e3;
1493
1537
  var PREVIOUS_ENTRY_ACTIVE = /PREVIOUS ENTRY ACTIVE/i;
1538
+ var SOAP_HEADERS = { "Content-Type": "text/xml; charset=utf-8", Accept: "text/xml" };
1494
1539
  var PARSER_OPTIONS = {
1495
1540
  ignoreAttributes: false,
1496
1541
  attributeNamePrefix: "@",
@@ -1526,6 +1571,7 @@ var SoapTransport = class {
1526
1571
  try {
1527
1572
  return await this.#attempts(request, capture);
1528
1573
  } finally {
1574
+ if (capture.request !== void 0) this.#deliverRawRequest(request, capture.request, capture.attempts);
1529
1575
  if (capture.last !== void 0) this.#deliverRaw(request, { ...capture.last, attempts: capture.attempts });
1530
1576
  }
1531
1577
  }
@@ -1572,10 +1618,18 @@ var SoapTransport = class {
1572
1618
  const startedAt = Date.now();
1573
1619
  let response;
1574
1620
  capture.attempts++;
1621
+ if (wantsRawRequest(request)) {
1622
+ capture.request = {
1623
+ method: "POST",
1624
+ url: this.#config.soapBaseUrl,
1625
+ headers: rawRequestHeaders(SOAP_HEADERS),
1626
+ body: redactSoapEnvelope(scrubToken(envelope, request.security))
1627
+ };
1628
+ }
1575
1629
  try {
1576
1630
  response = await this.#config.fetch(this.#config.soapBaseUrl, {
1577
1631
  method: "POST",
1578
- headers: { "Content-Type": "text/xml; charset=utf-8", Accept: "text/xml" },
1632
+ headers: SOAP_HEADERS,
1579
1633
  body: envelope,
1580
1634
  ...request.signal === void 0 ? {} : { signal: request.signal }
1581
1635
  });
@@ -1606,6 +1660,7 @@ var SoapTransport = class {
1606
1660
  return {
1607
1661
  ...result,
1608
1662
  messageId,
1663
+ respondedAt: respondedAtOf(text),
1609
1664
  raw: text,
1610
1665
  securityToken: request.readSecurityToken === true ? readSecurityToken(original) : void 0,
1611
1666
  status: response.status
@@ -1648,12 +1703,12 @@ var SoapTransport = class {
1648
1703
  });
1649
1704
  }
1650
1705
  const results = asNode(payload.ApplicationResults);
1651
- const warnings = asArray(results?.Warning).map((node2) => {
1652
- const entry = resultEntry(node2);
1706
+ const warnings = asArray(results?.Warning).map((node3) => {
1707
+ const entry = resultEntry(node3);
1653
1708
  return new SabreWarning(`${service}: ${entry.description}`, { service, code: entry.code, raw: text });
1654
1709
  });
1655
- const errors = asArray(results?.Error).map((node2) => {
1656
- const entry = resultEntry(node2);
1710
+ const errors = asArray(results?.Error).map((node3) => {
1711
+ const entry = resultEntry(node3);
1657
1712
  return new SabreBusinessError(`${service}: ${entry.description}`, {
1658
1713
  service,
1659
1714
  code: entry.code,
@@ -1699,6 +1754,19 @@ var SoapTransport = class {
1699
1754
  ].join("");
1700
1755
  }
1701
1756
  /** Un callback que lanza no rompe la operación (mismo criterio que REST). */
1757
+ #deliverRawRequest(request, raw, attempts) {
1758
+ const operation = request.operation ?? request.service;
1759
+ try {
1760
+ request.onRawRequest?.({ operation, protocol: "soap", ...raw, attempts });
1761
+ } catch (error) {
1762
+ this.#log.emit("warn", "sabre.request.rawRequestHookFailed", {
1763
+ service: request.service,
1764
+ operation,
1765
+ errorName: error instanceof Error ? error.name : typeof error
1766
+ });
1767
+ }
1768
+ }
1769
+ /** Un callback que lanza no rompe la operación (mismo criterio que REST). */
1702
1770
  #deliverRaw(request, raw) {
1703
1771
  if (request.onRawResponse === void 0) return;
1704
1772
  const operation = request.operation ?? request.service;
@@ -1713,6 +1781,18 @@ var SoapTransport = class {
1713
1781
  }
1714
1782
  }
1715
1783
  };
1784
+ function respondedAtOf(raw) {
1785
+ if (typeof raw !== "string") return void 0;
1786
+ const header = /<(?:[\w-]+:)?Header\b[\s\S]*?<\/(?:[\w-]+:)?Header>/.exec(raw)?.[0];
1787
+ const value = header === void 0 ? void 0 : /<(?:[\w-]+:)?Timestamp>\s*([^<\s]+)\s*</.exec(header)?.[1];
1788
+ const match = value === void 0 ? null : /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?)(Z|[+-]\d{2}:\d{2})?$/.exec(value);
1789
+ if (match === null) return void 0;
1790
+ return `${match[1]}${match[2] ?? "Z"}`;
1791
+ }
1792
+ function respondedAtField(raw) {
1793
+ const respondedAt = respondedAtOf(raw);
1794
+ return respondedAt === void 0 ? {} : { respondedAt };
1795
+ }
1716
1796
  function xmlEscape(value) {
1717
1797
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1718
1798
  }
@@ -1735,6 +1815,9 @@ function securityHeader(security) {
1735
1815
  "</wsse:Security>"
1736
1816
  ].join("");
1737
1817
  }
1818
+ function wantsRawRequest(request) {
1819
+ return request.onRawRequest !== void 0 && "binarySecurityToken" in request.security;
1820
+ }
1738
1821
  function scrubToken(text, security) {
1739
1822
  if (!("binarySecurityToken" in security) || security.binarySecurityToken === "") return text;
1740
1823
  const token = security.binarySecurityToken;
@@ -1774,8 +1857,8 @@ function faultError(service, status, fault, text) {
1774
1857
  ...code === void 0 || code === "" ? {} : { code }
1775
1858
  });
1776
1859
  }
1777
- function resultEntry(node2) {
1778
- const entry = asNode(node2) ?? {};
1860
+ function resultEntry(node3) {
1861
+ const entry = asNode(node3) ?? {};
1779
1862
  const messages = [];
1780
1863
  const shortTexts = [];
1781
1864
  let code;
@@ -1813,8 +1896,8 @@ function untrimmedPayload(raw) {
1813
1896
  const document = parseEnvelope(raw, untrimmedParser);
1814
1897
  return document === void 0 ? void 0 : asNode(firstElement(document.Body)[1]);
1815
1898
  }
1816
- function firstElement(node2) {
1817
- for (const [key, value] of Object.entries(node2)) {
1899
+ function firstElement(node3) {
1900
+ for (const [key, value] of Object.entries(node3)) {
1818
1901
  if (!key.startsWith("@") && key !== "#text") return [key, Array.isArray(value) ? value[0] : value];
1819
1902
  }
1820
1903
  return [void 0, void 0];
@@ -1829,14 +1912,14 @@ function asArray(value) {
1829
1912
  }
1830
1913
  function textOf(value) {
1831
1914
  if (typeof value === "string") return value;
1832
- const node2 = asNode(value);
1833
- const text = node2?.["#text"];
1834
- return typeof text === "string" ? text : node2 === void 0 ? void 0 : "";
1915
+ const node3 = asNode(value);
1916
+ const text = node3?.["#text"];
1917
+ return typeof text === "string" ? text : node3 === void 0 ? void 0 : "";
1835
1918
  }
1836
1919
  function stringAt(root2, ...path) {
1837
- let node2 = root2;
1838
- for (const key of path) node2 = asNode(node2)?.[key];
1839
- return nonEmpty2(textOf(node2));
1920
+ let node3 = root2;
1921
+ for (const key of path) node3 = asNode(node3)?.[key];
1922
+ return nonEmpty2(textOf(node3));
1840
1923
  }
1841
1924
  function nonEmpty2(value) {
1842
1925
  return typeof value === "string" && value !== "" ? value : void 0;
@@ -1893,27 +1976,41 @@ import { XMLParser as XMLParser2 } from "fast-xml-parser";
1893
1976
  // src/queue/queue-ref.ts
1894
1977
  var MIN_QUEUE_NUMBER = 0;
1895
1978
  var MAX_QUEUE_NUMBER = 511;
1979
+ var MESSAGE_QUEUE = "S";
1980
+ var ALPHA_QUEUE = /^[A-Z]{1,2}$/;
1981
+ function fail3(message) {
1982
+ throw new TypeError(`sabre-client: ${message}`);
1983
+ }
1896
1984
  function validateQueueRef(value, label) {
1897
1985
  if (typeof value === "number") {
1898
1986
  if (Number.isInteger(value) && value >= MIN_QUEUE_NUMBER && value <= MAX_QUEUE_NUMBER) return;
1899
- throw new TypeError(
1900
- `sabre-client: ${label} debe ser un n\xFAmero de cola entero de ${MIN_QUEUE_NUMBER} a ${MAX_QUEUE_NUMBER}, o { name }`
1901
- );
1987
+ fail3(`${label} debe ser un n\xFAmero de cola entero de ${MIN_QUEUE_NUMBER} a ${MAX_QUEUE_NUMBER}, una cola alfab\xE9tica ('S') o { name }`);
1988
+ }
1989
+ if (typeof value === "string") {
1990
+ if (ALPHA_QUEUE.test(value)) return;
1991
+ if (/^\d+$/.test(value.trim())) fail3(`${label}: una cola num\xE9rica va como n\xFAmero (${Number(value)}), no como string`);
1992
+ fail3(`${label} debe ser una cola alfab\xE9tica de una o dos letras may\xFAsculas (p. ej. 'S')`);
1902
1993
  }
1903
1994
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1904
1995
  const { name } = value;
1905
- if (typeof name === "string" && name.trim() !== "") return;
1906
- throw new TypeError(`sabre-client: ${label}.name debe ser un string no vac\xEDo`);
1996
+ if (typeof name !== "string" || name.trim() === "") fail3(`${label}.name debe ser un string no vac\xEDo`);
1997
+ if (ALPHA_QUEUE.test(name)) fail3(`${label}: '${name}' es una cola alfab\xE9tica: pasa '${name}', no { name: '${name}' }`);
1998
+ return;
1907
1999
  }
1908
- throw new TypeError(`sabre-client: ${label} debe ser un n\xFAmero de cola (0\u2013511) o { name }`);
2000
+ fail3(`${label} debe ser un n\xFAmero de cola (0\u2013511), una cola alfab\xE9tica ('S') o { name }`);
1909
2001
  }
1910
2002
  function queueRefAttribute(queue) {
1911
- return typeof queue === "number" ? `Number="${queue}"` : `Name="${xmlEscape(queue.name)}"`;
2003
+ if (typeof queue === "number") return `Number="${queue}"`;
2004
+ if (typeof queue === "string") return `Number="${xmlEscape(queue)}"`;
2005
+ return `Name="${xmlEscape(queue.name)}"`;
2006
+ }
2007
+ function isMessageQueue(queue) {
2008
+ return queue === MESSAGE_QUEUE;
1912
2009
  }
1913
2010
  function toQueueRef(value) {
1914
2011
  const text = value?.trim();
1915
2012
  if (text === void 0 || text === "") return void 0;
1916
- return /^\d+$/.test(text) ? Number(text) : { name: text };
2013
+ return /^\d+$/.test(text) ? Number(text) : text;
1917
2014
  }
1918
2015
 
1919
2016
  // src/queue/queue-access.ts
@@ -1931,9 +2028,11 @@ function root(body) {
1931
2028
  function identifier(queue, pcc) {
1932
2029
  return `<QueueIdentifier ${queueRefAttribute(queue)} PseudoCityCode="${xmlEscape(pcc)}"/>`;
1933
2030
  }
2031
+ function selectionXml(selection) {
2032
+ return selection.map((filter) => `<Selection Function="${xmlEscape(filter.function)}" Criteria="${xmlEscape(filter.criteria)}"/>`).join("");
2033
+ }
1934
2034
  function queueAccessPayload(queue, pcc, selection = []) {
1935
- const filters = selection.map((filter) => `<Selection Function="${xmlEscape(filter.function)}" Criteria="${xmlEscape(filter.criteria)}"/>`).join("");
1936
- return root(`${identifier(queue, pcc)}${filters}`);
2035
+ return root(`${identifier(queue, pcc)}${selectionXml(selection)}`);
1937
2036
  }
1938
2037
  function queueNavigationPayload(action, from = []) {
1939
2038
  return root(`<Navigation Action="${action}"/>${from.map((target) => identifier(target.queue, target.pcc)).join("")}`);
@@ -1999,17 +2098,21 @@ function queueEndError(error, service) {
1999
2098
  function isOffQueueError(error) {
2000
2099
  return error instanceof SabreBusinessError && [error, ...error.errors].some((result) => resultHasText(result, OFF_QUEUE));
2001
2100
  }
2002
- function endStep(warnings, reason = "end-of-display") {
2003
- return { done: true, reason, message: reason === "empty" ? QUEUE_EMPTY : END_OF_DISPLAY, warnings };
2101
+ function endStep(warnings, reason = "end-of-display", raw) {
2102
+ return { done: true, reason, message: reason === "empty" ? QUEUE_EMPTY : END_OF_DISPLAY, warnings, ...respondedAtField(raw) };
2004
2103
  }
2005
- function parseQueueStep(response) {
2104
+ function parseQueueStep(response, { messages = false } = {}) {
2006
2105
  const { warnings } = response;
2007
2106
  const paragraph = paragraphLines(response.raw);
2008
2107
  const firstLine = paragraph.find((line) => line.trim() !== "");
2009
- if (isEndOfDisplay(firstLine) || warnings.some(isEndOfDisplayResult)) return endStep(warnings);
2010
- const fields = lineFields(response.payload.Line);
2108
+ if (isEndOfDisplay(firstLine) || warnings.some(isEndOfDisplayResult)) return endStep(warnings, "end-of-display", response.raw);
2109
+ if (messages && response.payload.Line === void 0 && firstLine !== void 0) {
2110
+ return { done: false, kind: "message", message: { text: paragraph }, warnings, ...respondedAtField(response.raw) };
2111
+ }
2112
+ const fields = messages ? void 0 : lineFields(response.payload.Line);
2011
2113
  if (fields === void 0) {
2012
- throw new SabreGatewayError(`${QUEUE_ACCESS_SERVICE}: respuesta no reconocida (sin Line/UniqueID ni fin de cola)`, {
2114
+ const expected = messages ? "sin Paragraph de mensaje ni fin de cola en la cola S" : "sin Line/UniqueID ni fin de cola";
2115
+ throw new SabreGatewayError(`${QUEUE_ACCESS_SERVICE}: respuesta no reconocida (${expected})`, {
2013
2116
  protocol: "soap",
2014
2117
  status: response.status,
2015
2118
  retryable: false,
@@ -2017,7 +2120,7 @@ function parseQueueStep(response) {
2017
2120
  });
2018
2121
  }
2019
2122
  const item = { ...fields, paragraph };
2020
- return { done: false, item, warnings };
2123
+ return { done: false, kind: "pnr", item, warnings, ...respondedAtField(response.raw) };
2021
2124
  }
2022
2125
  function lineFields(value) {
2023
2126
  const line = node(value);
@@ -2064,8 +2167,8 @@ function parseHostCount(value) {
2064
2167
  const match = /^[.\s]*(\d+)\s*$/.exec(value ?? "");
2065
2168
  return match === null ? void 0 : Number(match[1]);
2066
2169
  }
2067
- function attribute2(node2, name) {
2068
- const value = node2?.[`@${name}`];
2170
+ function attribute2(node3, name) {
2171
+ const value = node3?.[`@${name}`];
2069
2172
  return typeof value === "string" ? value : void 0;
2070
2173
  }
2071
2174
  function parseQueueCountResponse(response) {
@@ -2075,7 +2178,8 @@ function parseQueueCountResponse(response) {
2075
2178
  countedAt ??= nonEmpty3(attribute2(info, "DateTime"));
2076
2179
  for (const identifier2 of asArray(info.QueueIdentifier)) {
2077
2180
  const number = attribute2(identifier2, "Number");
2078
- const queue = toQueueRef(number);
2181
+ const name = nonEmpty3(attribute2(identifier2, "Name"));
2182
+ const queue = number === void 0 && name !== void 0 ? { name } : toQueueRef(number);
2079
2183
  const count = parseHostCount(attribute2(identifier2, "Count"));
2080
2184
  if (queue === void 0 || count === void 0) {
2081
2185
  throw malformed(`QueueIdentifier con Number="${number ?? ""}" y Count="${attribute2(identifier2, "Count") ?? ""}"`, response);
@@ -2091,7 +2195,13 @@ function parseQueueCountResponse(response) {
2091
2195
  if (count === void 0) throw malformed(`Totals ${key} con Count="${attribute2(total, "Count") ?? ""}"`, response);
2092
2196
  totals[key] = count;
2093
2197
  }
2094
- return { queues, totals, ...countedAt === void 0 ? {} : { countedAt }, warnings: response.warnings };
2198
+ return {
2199
+ queues,
2200
+ totals,
2201
+ ...countedAt === void 0 ? {} : { countedAt },
2202
+ warnings: response.warnings,
2203
+ ...respondedAtField(response.raw)
2204
+ };
2095
2205
  }
2096
2206
  function malformed(detail, response) {
2097
2207
  return new SabreGatewayError(`${QUEUE_COUNT_SERVICE}: respuesta no reconocida (${detail})`, {
@@ -2108,9 +2218,10 @@ function nonEmpty3(value) {
2108
2218
 
2109
2219
  // src/queue/queue-list.ts
2110
2220
  var NAMESPACE3 = "http://webservices.sabre.com/sabreXML/2011/10";
2111
- function queueListPayload(queue, pcc, primaryPassenger) {
2221
+ var LIST_SELECTION_FUNCTIONS = ["QD", "AK"];
2222
+ function queueListPayload(queue, pcc, primaryPassenger, selection = []) {
2112
2223
  const list = primaryPassenger ? '<List Ind="true" PrimaryPassenger="true"/>' : '<List Ind="true"/>';
2113
- return `<QueueAccessRQ Version="2.1.1" xmlns="${NAMESPACE3}"><QueueIdentifier ${queueRefAttribute(queue)} PseudoCityCode="${xmlEscape(pcc)}">${list}</QueueIdentifier></QueueAccessRQ>`;
2224
+ return `<QueueAccessRQ Version="2.1.1" xmlns="${NAMESPACE3}"><QueueIdentifier ${queueRefAttribute(queue)} PseudoCityCode="${xmlEscape(pcc)}">${list}</QueueIdentifier>${selectionXml(selection)}</QueueAccessRQ>`;
2114
2225
  }
2115
2226
  function queueListRequest(payload, options) {
2116
2227
  return {
@@ -2122,14 +2233,14 @@ function queueListRequest(payload, options) {
2122
2233
  ...options
2123
2234
  };
2124
2235
  }
2125
- function emptyList(warnings, paragraph = []) {
2126
- return { locators: [], entries: [], paragraph, warnings };
2236
+ function emptyList(warnings, paragraph = [], raw) {
2237
+ return { locators: [], entries: [], paragraph, warnings, ...respondedAtField(raw) };
2127
2238
  }
2128
2239
  function parseQueueList(response) {
2129
2240
  const { warnings } = response;
2130
2241
  const paragraph = paragraphLines(response.raw);
2131
2242
  const firstLine = paragraph.find((line) => line.trim() !== "");
2132
- if (isEndOfDisplay(firstLine) || warnings.some(isEndOfDisplayResult)) return emptyList(warnings, paragraph);
2243
+ if (isEndOfDisplay(firstLine) || warnings.some(isEndOfDisplayResult)) return emptyList(warnings, paragraph, response.raw);
2133
2244
  const entries = asArray(response.payload.Line).map((line) => {
2134
2245
  const fields = lineFields(line);
2135
2246
  if (fields === void 0) {
@@ -2144,12 +2255,88 @@ function parseQueueList(response) {
2144
2255
  const position = number !== void 0 && /^\d+$/.test(number) ? Number(number) : void 0;
2145
2256
  return { ...position === void 0 ? {} : { position }, ...fields };
2146
2257
  });
2147
- return { locators: entries.map((entry) => entry.locator), entries, paragraph, warnings };
2258
+ return { locators: entries.map((entry) => entry.locator), entries, paragraph, warnings, ...respondedAtField(response.raw) };
2259
+ }
2260
+
2261
+ // src/queue/queue-activity.ts
2262
+ var QUEUE_ACTIVITY_SERVICE = "queueAnalysis";
2263
+ var NAMESPACE4 = "http://webservices.sabre.com/sabreXML/2011/10";
2264
+ var COUNTERS = [
2265
+ ["NumMessages", "numMessages"],
2266
+ ["Ended", "ended"],
2267
+ ["Ignored", "ignored"],
2268
+ ["Moved", "moved"],
2269
+ ["Removed", "removed"],
2270
+ ["Transferred", "transferred"],
2271
+ ["LeftMessageToContact", "leftMessageToContact"],
2272
+ ["UnableToReach", "unableToReach"]
2273
+ ];
2274
+ function queueActivityPayload(pcc) {
2275
+ return `<QueueAnalysisRQ Version="2.0.0" xmlns="${NAMESPACE4}"><QueueInfo><QueueIdentifier PseudoCityCode="${xmlEscape(pcc)}"/></QueueInfo></QueueAnalysisRQ>`;
2276
+ }
2277
+ function queueActivityRequest(pcc, options) {
2278
+ return {
2279
+ service: QUEUE_ACTIVITY_SERVICE,
2280
+ action: "QueueAnalysisLLSRQ",
2281
+ payload: queueActivityPayload(pcc),
2282
+ idempotent: true,
2283
+ operation: "queue.activity",
2284
+ ...options
2285
+ };
2286
+ }
2287
+ function attribute3(node3, name) {
2288
+ const value = (Array.isArray(node3) ? node3[0] : node3)?.[`@${name}`];
2289
+ return typeof value === "string" ? value : void 0;
2290
+ }
2291
+ function nonEmpty4(value) {
2292
+ const text = value?.trim();
2293
+ return text === void 0 || text === "" ? void 0 : text;
2294
+ }
2295
+ function parseQueueActivityResponse(response) {
2296
+ const queues = [];
2297
+ let analyzedAt;
2298
+ for (const info of asArray(response.payload.QueueInfo)) {
2299
+ analyzedAt ??= nonEmpty4(attribute3(info, "DateTime"));
2300
+ for (const identifier2 of asArray(info.QueueIdentifier)) {
2301
+ const number = attribute3(identifier2, "Number");
2302
+ const name = nonEmpty4(attribute3(identifier2, "Name"));
2303
+ const queue = number === void 0 && name !== void 0 ? { name } : toQueueRef(number);
2304
+ if (queue === void 0) throw malformed2(`QueueIdentifier con Number="${number ?? ""}"`, response);
2305
+ queues.push({ queue, ...counters(identifier2, `la cola ${number ?? name}`, response) });
2306
+ }
2307
+ }
2308
+ const totalsNode = asArray(response.payload.Totals)[0];
2309
+ const totals = totalsNode === void 0 ? void 0 : counters(totalsNode, "Totals", response);
2310
+ return {
2311
+ queues,
2312
+ ...totals === void 0 ? {} : { totals },
2313
+ ...analyzedAt === void 0 ? {} : { analyzedAt },
2314
+ warnings: response.warnings,
2315
+ ...respondedAtField(response.raw)
2316
+ };
2317
+ }
2318
+ function counters(node3, label, response) {
2319
+ const result = {};
2320
+ for (const [element2, key] of COUNTERS) {
2321
+ const raw = attribute3(node3[element2], "Count");
2322
+ const count = parseHostCount(raw);
2323
+ if (count === void 0) throw malformed2(`${label} con ${element2} Count="${raw ?? ""}"`, response);
2324
+ result[key] = count;
2325
+ }
2326
+ return result;
2327
+ }
2328
+ function malformed2(detail, response) {
2329
+ return new SabreGatewayError(`${QUEUE_ACTIVITY_SERVICE}: respuesta no reconocida (${detail})`, {
2330
+ protocol: "soap",
2331
+ status: response.status,
2332
+ retryable: false,
2333
+ raw: response.raw
2334
+ });
2148
2335
  }
2149
2336
 
2150
2337
  // src/queue/queue-place.ts
2151
2338
  var QUEUE_PLACE_SERVICE = "queuePlace";
2152
- var NAMESPACE4 = "http://webservices.sabre.com/sabreXML/2011/10";
2339
+ var NAMESPACE5 = "http://webservices.sabre.com/sabreXML/2011/10";
2153
2340
  var MAX_PLACE_TO = 10;
2154
2341
  var MAX_PLACE_LOCATORS = 6;
2155
2342
  var INSTRUCTION_CODE_RANGES = [
@@ -2165,7 +2352,7 @@ function queuePlacePayload(to, locators = []) {
2165
2352
  return `<QueueIdentifier ${queueRefAttribute(target.queue)}${pic} PseudoCityCode="${xmlEscape(target.pcc)}"/>`;
2166
2353
  }).join("");
2167
2354
  const ids = locators.map((locator) => `<UniqueID ID="${xmlEscape(locator)}"/>`).join("");
2168
- return `<QueuePlaceRQ Version="2.0.4" xmlns="${NAMESPACE4}"><QueueInfo>${identifiers}${ids}</QueueInfo></QueuePlaceRQ>`;
2355
+ return `<QueuePlaceRQ Version="2.0.4" xmlns="${NAMESPACE5}"><QueueInfo>${identifiers}${ids}</QueueInfo></QueuePlaceRQ>`;
2169
2356
  }
2170
2357
  function queuePlaceRequest(payload, options) {
2171
2358
  return {
@@ -2190,7 +2377,7 @@ function isEnd(response, text) {
2190
2377
  }
2191
2378
  function parsePlaceStep(response) {
2192
2379
  const text = textLines(response.raw, "QueuePlaceRS");
2193
- if (isEnd(response, text)) return endStep(response.warnings);
2380
+ if (isEnd(response, text)) return endStep(response.warnings, "end-of-display", response.raw);
2194
2381
  const locator = signatureLocator(text);
2195
2382
  if (locator === void 0) {
2196
2383
  throw new SabreGatewayError(`${QUEUE_PLACE_SERVICE}: respuesta no reconocida (sin l\xEDnea de firma del PNR ni fin de cola)`, {
@@ -2200,7 +2387,7 @@ function parsePlaceStep(response) {
2200
2387
  raw: response.raw
2201
2388
  });
2202
2389
  }
2203
- return { done: false, item: { locator, paragraph: text }, warnings: response.warnings };
2390
+ return { done: false, kind: "pnr", item: { locator, paragraph: text }, warnings: response.warnings, ...respondedAtField(response.raw) };
2204
2391
  }
2205
2392
  function parsePlaceUnknown(response) {
2206
2393
  const text = textLines(response.raw, "QueuePlaceRS");
@@ -2223,11 +2410,16 @@ function parsePlaceResult(response) {
2223
2410
  ...placedAt === void 0 ? {} : { placedAt }
2224
2411
  };
2225
2412
  });
2226
- return { placements, text: textLines(response.raw, "QueuePlaceRS"), warnings: response.warnings };
2413
+ return {
2414
+ placements,
2415
+ text: textLines(response.raw, "QueuePlaceRS"),
2416
+ warnings: response.warnings,
2417
+ ...respondedAtField(response.raw)
2418
+ };
2227
2419
  }
2228
2420
 
2229
2421
  // src/queue/queue-management.ts
2230
- function fail3(message) {
2422
+ function fail4(message) {
2231
2423
  throw new TypeError(`sabre-client: ${message}`);
2232
2424
  }
2233
2425
  function rejectedBySabre(error) {
@@ -2236,6 +2428,8 @@ function rejectedBySabre(error) {
2236
2428
  var QueueManagement = class {
2237
2429
  #context;
2238
2430
  #state = "outside";
2431
+ /** Si la última cola a la que se entró es la `S`: ahí cada paso es un mensaje, no un PNR. */
2432
+ #messages = false;
2239
2433
  /** @internal Lo construye `SabreSession`. */
2240
2434
  constructor(context) {
2241
2435
  this.#context = context;
@@ -2261,31 +2455,61 @@ var QueueManagement = class {
2261
2455
  const response = await this.#context.send(queueCountRequest(pcc, options));
2262
2456
  return parseQueueCountResponse(response);
2263
2457
  }
2458
+ /**
2459
+ * Get Queue Activity (`QueueAnalysisLLSRQ` 2.0.0, el `QA` del host): por cada cola del PCC, los
2460
+ * ocho contadores de actividad (`numMessages`, `ended`, `ignored`, `moved`, `removed`,
2461
+ * `transferred`, `leftMessageToContact` y `unableToReach`), más los totales. Cada `queue` se puede
2462
+ * pasar tal cual a las demás operaciones de cola. Ninguna fuente dice desde cuándo cuentan
2463
+ * (Q-097): el SDK los devuelve sin interpretar.
2464
+ *
2465
+ * Se puede llamar dentro o fuera de una cola, y no cambia `state`. Es una lectura: se reintenta
2466
+ * ante fallos transitorios. No pide duty code 9 (CERT y producción, Q-098). Un PCC que no tiene 3
2467
+ * o 4 caracteres alfanuméricos lanza `TypeError` sin red.
2468
+ */
2469
+ async activity(request = {}, options = {}) {
2470
+ if (typeof request !== "object" || request === null) fail4("queue.activity recibe { pcc? }");
2471
+ const pcc = this.#pcc(request.pcc, "pcc");
2472
+ const response = await this.#context.send(queueActivityRequest(pcc, options));
2473
+ return parseQueueActivityResponse(response);
2474
+ }
2264
2475
  /**
2265
2476
  * La lista de localizadores de una cola (`QueueAccessLLSRQ` con `List`), sin recorrerla. Con
2266
2477
  * `primaryPassenger: true`, cada entrada trae también el pasajero principal. Una cola vacía da
2267
2478
  * una lista vacía.
2268
2479
  *
2480
+ * No pagina: Sabre devuelve la cola entera en una respuesta, también con más de 1000 PNR. Con
2481
+ * `selection`, solo los PNR que cumplen el filtro; Sabre acepta solo `QD` o `AK` en la lista.
2482
+ *
2269
2483
  * No cambia `state`. Es una lectura: se reintenta ante fallos transitorios. Lanza `TypeError`
2270
- * sin red si `queue` o `pcc` no son válidos, o si `primaryPassenger` no es un boolean.
2484
+ * sin red si `queue` o `pcc` no son válidos, si `primaryPassenger` no es un boolean, o si
2485
+ * `selection` no es válida o trae un código que no es `QD` ni `AK`.
2271
2486
  */
2272
2487
  async list(request, options = {}) {
2273
- if (typeof request !== "object" || request === null) fail3("queue.list recibe { queue, pcc?, primaryPassenger? }");
2488
+ if (typeof request !== "object" || request === null) fail4("queue.list recibe { queue, pcc?, primaryPassenger?, selection? }");
2274
2489
  validateQueueRef(request.queue, "queue");
2490
+ if (isMessageQueue(request.queue)) fail4("la cola 'S' es la de mensajes del PCC: no tiene PNR y Sabre no la lista");
2275
2491
  const pcc = this.#pcc(request.pcc, "pcc");
2276
2492
  const { primaryPassenger = false } = request;
2277
- if (typeof primaryPassenger !== "boolean") fail3("primaryPassenger debe ser un boolean");
2278
- const send2 = queueListRequest(queueListPayload(request.queue, pcc, primaryPassenger), options);
2493
+ if (typeof primaryPassenger !== "boolean") fail4("primaryPassenger debe ser un boolean");
2494
+ const selection = validateSelection(request.selection);
2495
+ selection.forEach((filter, index) => {
2496
+ if (!LIST_SELECTION_FUNCTIONS.includes(filter.function)) {
2497
+ fail4(`selection[${index}].function en list solo puede ser ${LIST_SELECTION_FUNCTIONS.join(" o ")}: Sabre no acepta otro c\xF3digo en la lista`);
2498
+ }
2499
+ });
2500
+ const send2 = queueListRequest(queueListPayload(request.queue, pcc, primaryPassenger, selection), options);
2279
2501
  try {
2280
2502
  return parseQueueList(await this.#context.send(send2));
2281
2503
  } catch (error) {
2282
2504
  const end = queueEndError(error, send2.service);
2283
- if (end !== void 0) return emptyList([...end.error.warnings]);
2505
+ if (end !== void 0) return emptyList([...end.error.warnings], [], end.error.raw);
2284
2506
  throw error;
2285
2507
  }
2286
2508
  }
2287
2509
  /**
2288
- * Access Queue (`QueueAccessLLSRQ` 2.1.1): entra a una cola y devuelve su primer PNR. Una cola
2510
+ * Access Queue (`QueueAccessLLSRQ` 2.1.1): entra a una cola y devuelve su primer PNR
2511
+ * (`kind: 'pnr'`). En la cola `S`, la de mensajes, devuelve el primer mensaje
2512
+ * (`kind: 'message'`), y `ignore` pasa al siguiente sin borrarlo (CERT, 2026-11-06). Una cola
2289
2513
  * vacía, o sin PNR que cumplan `selection`, devuelve `{ done: true }` y la sesión sigue afuera.
2290
2514
  *
2291
2515
  * Lanza `TypeError` sin red si la sesión ya está dentro de una cola (o en `'unknown'`: hay que
@@ -2294,12 +2518,13 @@ var QueueManagement = class {
2294
2518
  * `'unknown'`.
2295
2519
  */
2296
2520
  async access(request, options = {}) {
2297
- if (this.#state === "inside") fail3("la sesi\xF3n ya est\xE1 dentro de una cola: sal con queue.exit() antes de entrar a otra");
2298
- if (this.#state === "unknown") fail3("no se sabe si la sesi\xF3n sigue dentro de una cola: llama a queue.exit() antes de entrar");
2299
- if (typeof request !== "object" || request === null) fail3("queue.access recibe { queue, pcc?, selection? }");
2521
+ if (this.#state === "inside") fail4("la sesi\xF3n ya est\xE1 dentro de una cola: sal con queue.exit() antes de entrar a otra");
2522
+ if (this.#state === "unknown") fail4("no se sabe si la sesi\xF3n sigue dentro de una cola: llama a queue.exit() antes de entrar");
2523
+ if (typeof request !== "object" || request === null) fail4("queue.access recibe { queue, pcc?, selection? }");
2300
2524
  validateQueueRef(request.queue, "queue");
2301
2525
  const pcc = this.#pcc(request.pcc, "pcc");
2302
2526
  const selection = validateSelection(request.selection);
2527
+ this.#messages = isMessageQueue(request.queue);
2303
2528
  return this.#step(queueAccessRequest(queueAccessPayload(request.queue, pcc, selection), "queue.access", options));
2304
2529
  }
2305
2530
  /**
@@ -2312,7 +2537,8 @@ var QueueManagement = class {
2312
2537
  }
2313
2538
  /**
2314
2539
  * Saca el PNR actual de la cola y pasa al siguiente (`QR`). Con `from` (de 1 a 3 colas), lo saca
2315
- * de esas colas a la vez. Fuera de una cola lanza `TypeError` sin red.
2540
+ * de esas colas a la vez. Fuera de una cola lanza `TypeError` sin red. En la cola `S` manda `QR`
2541
+ * igual, pero no hay evidencia de qué hace Sabre con el mensaje.
2316
2542
  */
2317
2543
  async remove(request = {}, options = {}) {
2318
2544
  this.#requireQueue("remove");
@@ -2359,10 +2585,11 @@ var QueueManagement = class {
2359
2585
  * `options` se aplica a cada llamada a Sabre del recorrido.
2360
2586
  */
2361
2587
  async process(request, callback, options = {}) {
2362
- if (typeof request !== "object" || request === null) fail3("queue.process recibe { queue, pcc?, selection?, limit? }");
2363
- if (typeof callback !== "function") fail3("queue.process necesita un callback");
2588
+ if (typeof request !== "object" || request === null) fail4("queue.process recibe { queue, pcc?, selection?, limit? }");
2589
+ if (typeof callback !== "function") fail4("queue.process necesita un callback");
2364
2590
  const { limit, ...access } = request;
2365
- if (limit !== void 0 && !(Number.isInteger(limit) && limit >= 1)) fail3("limit debe ser un entero mayor o igual a 1");
2591
+ if (isMessageQueue(access.queue)) fail4("queue.process no recorre la cola 'S', la de mensajes: usa queue.access() e queue.ignore()");
2592
+ if (limit !== void 0 && !(Number.isInteger(limit) && limit >= 1)) fail4("limit debe ser un entero mayor o igual a 1");
2366
2593
  const startedOutside = this.#state === "outside";
2367
2594
  let visited = 0;
2368
2595
  try {
@@ -2372,6 +2599,7 @@ var QueueManagement = class {
2372
2599
  await this.exit(options);
2373
2600
  return { visited, ended: "limit" };
2374
2601
  }
2602
+ if (step.kind !== "pnr") throw new TypeError("sabre-client: queue.process recibi\xF3 un mensaje en vez de un PNR");
2375
2603
  const action = await callback(step.item);
2376
2604
  visited++;
2377
2605
  step = await this.#processAction(action, options);
@@ -2403,17 +2631,20 @@ var QueueManagement = class {
2403
2631
  }
2404
2632
  }
2405
2633
  async place(request, options = {}) {
2406
- if (typeof request !== "object" || request === null) fail3("queue.place recibe { to, locators? }");
2634
+ if (typeof request !== "object" || request === null) fail4("queue.place recibe { to, locators? }");
2407
2635
  const to = this.#placeTo(request.to);
2408
2636
  const locators = validateLocators(request.locators);
2637
+ if (this.#messages && this.#state !== "outside") {
2638
+ fail4("queue.place no se puede dentro de la cola 'S': lo que hay en pantalla es un mensaje, no un PNR");
2639
+ }
2409
2640
  if (locators.length > 0 && this.#state === "inside") {
2410
- fail3("queue.place con locators no se puede dentro de una cola, donde coloca el PNR actual: sal con queue.exit() antes");
2641
+ fail4("queue.place con locators no se puede dentro de una cola, donde coloca el PNR actual: sal con queue.exit() antes");
2411
2642
  }
2412
2643
  if (locators.length > 0 && this.#state === "unknown") {
2413
- fail3("no se sabe si la sesi\xF3n sigue dentro de una cola: llama a queue.exit() antes de colocar por localizador");
2644
+ fail4("no se sabe si la sesi\xF3n sigue dentro de una cola: llama a queue.exit() antes de colocar por localizador");
2414
2645
  }
2415
2646
  if (to.some((target) => target.instructionCode === void 0)) {
2416
- fail3("queue.place necesita instructionCode en cada destino: Sabre lo exige, dentro y fuera de una cola");
2647
+ fail4("queue.place necesita instructionCode en cada destino: Sabre lo exige, dentro y fuera de una cola");
2417
2648
  }
2418
2649
  const send2 = queuePlaceRequest(queuePlacePayload(to, locators), options);
2419
2650
  if (this.#state === "outside") return parsePlaceResult(await this.#context.send(send2));
@@ -2421,7 +2652,8 @@ var QueueManagement = class {
2421
2652
  }
2422
2653
  /** Manda una operación que avanza y actualiza `state` con el resultado. */
2423
2654
  #step(request) {
2424
- return this.#advance(request, parseQueueStep);
2655
+ const messages = this.#messages;
2656
+ return this.#advance(request, (response) => parseQueueStep(response, { messages }));
2425
2657
  }
2426
2658
  /**
2427
2659
  * Manda una operación que puede mover el cursor. Un `QueueStep` fija el estado: `'outside'` con
@@ -2435,7 +2667,7 @@ var QueueManagement = class {
2435
2667
  const end = queueEndError(error, request.service);
2436
2668
  if (end !== void 0) {
2437
2669
  this.#state = "outside";
2438
- return endStep([...end.error.warnings], end.reason);
2670
+ return endStep([...end.error.warnings], end.reason, end.error.raw);
2439
2671
  }
2440
2672
  this.#onError(error);
2441
2673
  throw error;
@@ -2456,14 +2688,14 @@ var QueueManagement = class {
2456
2688
  }
2457
2689
  #placeTo(to) {
2458
2690
  if (!Array.isArray(to) || to.length === 0 || to.length > MAX_PLACE_TO) {
2459
- fail3(`to debe ser una lista de 1 a ${MAX_PLACE_TO} colas`);
2691
+ fail4(`to debe ser una lista de 1 a ${MAX_PLACE_TO} colas`);
2460
2692
  }
2461
2693
  return to.map((target, index) => {
2462
- if (typeof target !== "object" || target === null) fail3(`to[${index}] debe ser { queue, pcc?, instructionCode }`);
2694
+ if (typeof target !== "object" || target === null) fail4(`to[${index}] debe ser { queue, pcc?, instructionCode }`);
2463
2695
  const { queue, pcc, instructionCode } = target;
2464
2696
  validateQueueRef(queue, `to[${index}].queue`);
2465
2697
  if (instructionCode !== void 0 && !isInstructionCode(instructionCode)) {
2466
- fail3(`to[${index}].instructionCode debe ser un entero de 0 a 191 o de 200 a 254`);
2698
+ fail4(`to[${index}].instructionCode debe ser un entero de 0 a 191 o de 200 a 254`);
2467
2699
  }
2468
2700
  return {
2469
2701
  queue,
@@ -2473,20 +2705,20 @@ var QueueManagement = class {
2473
2705
  });
2474
2706
  }
2475
2707
  #requireQueue(operation) {
2476
- if (this.#state === "outside") fail3(`queue.${operation} necesita estar dentro de una cola: entra con queue.access()`);
2708
+ if (this.#state === "outside") fail4(`queue.${operation} necesita estar dentro de una cola: entra con queue.access()`);
2477
2709
  }
2478
2710
  #pcc(value, label) {
2479
2711
  if (value === void 0) return this.#context.pcc;
2480
- if (!isPseudoCityCode(value)) fail3(`${label} debe tener 3 o 4 caracteres alfanum\xE9ricos`);
2712
+ if (!isPseudoCityCode(value)) fail4(`${label} debe tener 3 o 4 caracteres alfanum\xE9ricos`);
2481
2713
  return value;
2482
2714
  }
2483
2715
  #removeFrom(from) {
2484
2716
  if (from === void 0) return [];
2485
2717
  if (!Array.isArray(from) || from.length === 0 || from.length > MAX_REMOVE_FROM) {
2486
- fail3(`from debe ser una lista de 1 a ${MAX_REMOVE_FROM} colas`);
2718
+ fail4(`from debe ser una lista de 1 a ${MAX_REMOVE_FROM} colas`);
2487
2719
  }
2488
2720
  return from.map((target, index) => {
2489
- if (typeof target !== "object" || target === null) fail3(`from[${index}] debe ser { queue, pcc? }`);
2721
+ if (typeof target !== "object" || target === null) fail4(`from[${index}] debe ser { queue, pcc? }`);
2490
2722
  const { queue, pcc } = target;
2491
2723
  validateQueueRef(queue, `from[${index}].queue`);
2492
2724
  return { queue, pcc: this.#pcc(pcc, `from[${index}].pcc`) };
@@ -2496,37 +2728,171 @@ var QueueManagement = class {
2496
2728
  function validateLocators(locators) {
2497
2729
  if (locators === void 0) return [];
2498
2730
  if (!Array.isArray(locators) || locators.length === 0 || locators.length > MAX_PLACE_LOCATORS) {
2499
- fail3(`locators debe ser una lista de 1 a ${MAX_PLACE_LOCATORS} localizadores`);
2731
+ fail4(`locators debe ser una lista de 1 a ${MAX_PLACE_LOCATORS} localizadores`);
2500
2732
  }
2501
2733
  return locators.map((locator, index) => {
2502
- if (typeof locator !== "string" || locator.trim() === "") fail3(`locators[${index}] debe ser un string no vac\xEDo`);
2734
+ if (typeof locator !== "string" || locator.trim() === "") fail4(`locators[${index}] debe ser un string no vac\xEDo`);
2503
2735
  return locator;
2504
2736
  });
2505
2737
  }
2506
2738
  function validateSelection(selection) {
2507
2739
  if (selection === void 0) return [];
2508
- if (!Array.isArray(selection)) fail3("selection debe ser una lista de { function, criteria }");
2509
- if (selection.length > MAX_SELECTIONS) fail3(`selection admite hasta ${MAX_SELECTIONS} filtros`);
2740
+ if (!Array.isArray(selection)) fail4("selection debe ser una lista de { function, criteria }");
2741
+ if (selection.length > MAX_SELECTIONS) fail4(`selection admite hasta ${MAX_SELECTIONS} filtros`);
2510
2742
  return selection.map((filter, index) => {
2511
2743
  const { function: fn, criteria } = typeof filter === "object" && filter !== null ? filter : {};
2512
- if (typeof fn !== "string" || fn.trim() === "") fail3(`selection[${index}].function debe ser un string no vac\xEDo`);
2744
+ if (typeof fn !== "string" || fn.trim() === "") fail4(`selection[${index}].function debe ser un string no vac\xEDo`);
2513
2745
  if (typeof criteria !== "string" || criteria.trim() === "") {
2514
- fail3(`selection[${index}].criteria debe ser un string no vac\xEDo`);
2746
+ fail4(`selection[${index}].criteria debe ser un string no vac\xEDo`);
2515
2747
  }
2516
2748
  return { function: fn, criteria };
2517
2749
  });
2518
2750
  }
2519
2751
 
2752
+ // src/reservation/reservation-history.ts
2753
+ var RESERVATION_HISTORY_SERVICE = "itineraryHistory";
2754
+ var NAMESPACE6 = "http://webservices.sabre.com/sabreXML/2011/10";
2755
+ var LOCATOR = /^[A-Z0-9]{6}$/;
2756
+ function isRecordLocator(value) {
2757
+ return typeof value === "string" && LOCATOR.test(value);
2758
+ }
2759
+ function reservationHistoryPayload(locator) {
2760
+ return `<TravelItineraryHistoryRQ Version="2.4.0" xmlns="${NAMESPACE6}"><UniqueID ID="${xmlEscape(locator)}"/></TravelItineraryHistoryRQ>`;
2761
+ }
2762
+ function reservationHistoryRequest(locator, options) {
2763
+ return {
2764
+ service: RESERVATION_HISTORY_SERVICE,
2765
+ action: "TravelItineraryHistoryLLSRQ",
2766
+ payload: reservationHistoryPayload(locator),
2767
+ idempotent: true,
2768
+ operation: "reservation.history",
2769
+ ...options
2770
+ };
2771
+ }
2772
+ function node2(value) {
2773
+ const first = Array.isArray(value) ? value[0] : value;
2774
+ return typeof first === "object" && first !== null ? first : void 0;
2775
+ }
2776
+ function attribute4(value, name) {
2777
+ const text = node2(value)?.[`@${name}`];
2778
+ if (typeof text !== "string") return void 0;
2779
+ const trimmed = text.trim();
2780
+ return trimmed === "" ? void 0 : trimmed;
2781
+ }
2782
+ function defined(fields) {
2783
+ return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== void 0));
2784
+ }
2785
+ function integer(value) {
2786
+ return value !== void 0 && /^\d+$/.test(value) ? Number(value) : void 0;
2787
+ }
2788
+ function parseReservationHistoryResponse(response) {
2789
+ const transactions = asArray(response.payload.HistoricalInfo).map((info) => transaction(node2(info) ?? {}, response));
2790
+ return { transactions, warnings: response.warnings, ...respondedAtField(response.raw) };
2791
+ }
2792
+ function transaction(info, response) {
2793
+ const source = node2(node2(info.ItineraryRef)?.Source);
2794
+ const flightSegments = asArray(node2(node2(info.ItineraryInfo)?.ReservationItems)?.Item).flatMap(
2795
+ (item) => asArray(node2(item)?.FlightSegment).map((segment) => flightSegment(node2(segment) ?? {}, response))
2796
+ );
2797
+ return {
2798
+ ...defined({
2799
+ rph: integer(attribute4(info, "RPH")),
2800
+ createdAt: attribute4(source, "CreateDateTime"),
2801
+ agent: attribute4(source, "CreationAgent"),
2802
+ agentDutyCode: attribute4(source, "CreationAgentDutyCode"),
2803
+ agentFunctionCode: attribute4(source, "CreationAgentFunctionCode"),
2804
+ pcc: attribute4(source, "PseudoCityCode"),
2805
+ aaaPcc: attribute4(source, "AAA_PseudoCityCode") ?? attribute4(source, "AAAPseudoCityCode"),
2806
+ receivedFrom: attribute4(source, "ReceivedFrom")
2807
+ }),
2808
+ flightSegments,
2809
+ generalInfo: asArray(info.GeneralInfo).map((entry) => textEntry(entry, "GeneralInfo", response)),
2810
+ remarks: asArray(node2(info.RemarkInfo)?.Remark).map((entry) => textEntry(entry, "Remark", response)),
2811
+ accounting: asArray(info.AccountingInfo).map(
2812
+ (entry) => defined({ action: attribute4(entry, "Action"), type: attribute4(entry, "Type"), linkCode: attribute4(entry, "LinkCode") })
2813
+ )
2814
+ };
2815
+ }
2816
+ function textEntry(entry, label, response) {
2817
+ const action = attribute4(entry, "Action");
2818
+ if (action === void 0) throw malformed3(`${label} sin Action`, response);
2819
+ const texts = asArray(node2(entry)?.Text).map((text) => textOf(text) ?? "");
2820
+ return { action, text: texts.join("\n") };
2821
+ }
2822
+ function flightSegment(segment, response) {
2823
+ const action = attribute4(segment, "Action");
2824
+ if (action === void 0) throw malformed3("FlightSegment sin Action", response);
2825
+ return {
2826
+ action,
2827
+ ...defined({
2828
+ status: attribute4(segment, "Status"),
2829
+ marketingAirline: attribute4(segment.MarketingAirline, "Code"),
2830
+ flightNumber: attribute4(segment, "FlightNumber") ?? attribute4(segment.MarketingAirline, "FlightNumber"),
2831
+ bookingClass: attribute4(segment, "ResBookDesigCode"),
2832
+ origin: attribute4(segment.OriginLocation, "LocationCode"),
2833
+ destination: attribute4(segment.DestinationLocation, "LocationCode"),
2834
+ departureDateTime: attribute4(segment, "DepartureDateTime"),
2835
+ arrivalDateTime: attribute4(segment, "ArrivalDateTime"),
2836
+ numberInParty: integer(attribute4(segment, "NumberInParty")),
2837
+ supplierRef: attribute4(segment.SupplierRef, "ID")
2838
+ })
2839
+ };
2840
+ }
2841
+ function malformed3(detail, response) {
2842
+ return new SabreGatewayError(`${RESERVATION_HISTORY_SERVICE}: respuesta no reconocida (${detail})`, {
2843
+ protocol: "soap",
2844
+ status: response.status,
2845
+ retryable: false,
2846
+ raw: response.raw
2847
+ });
2848
+ }
2849
+
2850
+ // src/reservation/session-reservation.ts
2851
+ var SessionReservation = class {
2852
+ #context;
2853
+ /** @internal Lo construye `SabreSession`. */
2854
+ constructor(context) {
2855
+ this.#context = context;
2856
+ }
2857
+ /**
2858
+ * Get Itinerary History (`TravelItineraryHistoryLLSRQ` 2.4.0, el `*H` del host): el historial
2859
+ * del PNR, una entrada por transacción. Cada una trae quién la firmó, cuándo y desde qué PCC, y
2860
+ * los elementos que cambió con su `action`: los segmentos de vuelo con su estado en ese momento,
2861
+ * y SSR, ticketing, teléfonos, nombres y emails como texto en `generalInfo`. Lo que no se tipa
2862
+ * queda en la respuesta cruda (`onRawResponse`). **Trae datos del pasajero.**
2863
+ *
2864
+ * El historial no registra las colocaciones en cola, ni las del sistema ni un `place` manual
2865
+ * (CERT, 2026-11-06, Q-097): para eso están `queue.list`/`access` o los remarks `QUEUE_PLACE` de
2866
+ * Get Booking.
2867
+ *
2868
+ * **Dentro de una cola, Sabre lo rechaza** para otro PNR (CERT, 2026-11-06, Q-102): lanza
2869
+ * `SabreBusinessError` con `NAK6 -NOT ALLOWED- FINISH OR IGNORE OTHER ACTIVITY`. El PNR del AAA
2870
+ * no cambia, `queue.state` sigue en `'inside'` y el recorrido sigue con `ignore`. Conviene
2871
+ * llamarlo fuera de una cola.
2872
+ *
2873
+ * Es una lectura: se reintenta ante fallos transitorios. Un `locator` que no es de 6 caracteres
2874
+ * alfanuméricos en mayúscula lanza `TypeError` sin red. Un PNR que no existe sale como
2875
+ * `SabreBusinessError` (`service: 'itineraryHistory'`).
2876
+ */
2877
+ async history(locator, options = {}) {
2878
+ if (!isRecordLocator(locator)) {
2879
+ throw new TypeError("sabre-client: reservation.history necesita un localizador de 6 caracteres alfanum\xE9ricos en may\xFAscula");
2880
+ }
2881
+ const response = await this.#context.send(reservationHistoryRequest(locator, options));
2882
+ return parseReservationHistoryResponse(response);
2883
+ }
2884
+ };
2885
+
2520
2886
  // src/session/command.ts
2521
2887
  var SABRE_COMMAND_SERVICE = "sabreCommand";
2522
- var NAMESPACE5 = "http://webservices.sabre.com/sabreXML/2011/10";
2888
+ var NAMESPACE7 = "http://webservices.sabre.com/sabreXML/2011/10";
2523
2889
  var MAX_COMMAND_LENGTH = 1023;
2524
2890
  var DOUBLE_WIDTH = /* @__PURE__ */ new Set(["!", "%", "$", "&", "\xA5", "\xA7"]);
2525
- function fail4(message) {
2891
+ function fail5(message) {
2526
2892
  throw new TypeError(`sabre-client: ${message}`);
2527
2893
  }
2528
2894
  function sabreCommandPayload(command) {
2529
- return `<SabreCommandLLSRQ xmlns="${NAMESPACE5}" Version="2.0.0" ReturnHostCommand="true"><Request Output="SCREEN"><HostCommand>${xmlEscape(command)}</HostCommand></Request></SabreCommandLLSRQ>`;
2895
+ return `<SabreCommandLLSRQ xmlns="${NAMESPACE7}" Version="2.0.0" ReturnHostCommand="true"><Request Output="SCREEN"><HostCommand>${xmlEscape(command)}</HostCommand></Request></SabreCommandLLSRQ>`;
2530
2896
  }
2531
2897
  function commandToken(command) {
2532
2898
  return (command.trim().split(/[¥‡\s]/u)[0] ?? "").slice(0, 4);
@@ -2537,13 +2903,13 @@ function sabreCommandLength(command) {
2537
2903
  return length;
2538
2904
  }
2539
2905
  function sabreCommandRequest(command, options) {
2540
- if (typeof command !== "string" || command.trim() === "") fail4("command es requerido y debe ser un string no vac\xEDo");
2906
+ if (typeof command !== "string" || command.trim() === "") fail5("command es requerido y debe ser un string no vac\xEDo");
2541
2907
  const length = sabreCommandLength(command);
2542
2908
  if (length > MAX_COMMAND_LENGTH) {
2543
- fail4(`command mide ${length} y el m\xE1ximo es ${MAX_COMMAND_LENGTH} (!, %, $, &, \xA5 y \xA7 cuentan 2); Sabre responder\xEDa REQUEST EXCEEDED MAXIMUM LENGTH`);
2909
+ fail5(`command mide ${length} y el m\xE1ximo es ${MAX_COMMAND_LENGTH} (!, %, $, &, \xA5 y \xA7 cuentan 2); Sabre responder\xEDa REQUEST EXCEEDED MAXIMUM LENGTH`);
2544
2910
  }
2545
2911
  const { idempotent = false, ...requestOptions } = options;
2546
- if (typeof idempotent !== "boolean") fail4("idempotent debe ser un boolean");
2912
+ if (typeof idempotent !== "boolean") fail5("idempotent debe ser un boolean");
2547
2913
  return {
2548
2914
  service: SABRE_COMMAND_SERVICE,
2549
2915
  action: "SabreCommandLLSRQ",
@@ -2565,7 +2931,8 @@ function parseSabreCommandResponse(response) {
2565
2931
  return {
2566
2932
  text: textOf((untrimmedPayload(response.raw) ?? response.payload).Response) ?? "",
2567
2933
  warnings: response.warnings,
2568
- messageId: response.messageId
2934
+ messageId: response.messageId,
2935
+ ...respondedAtField(response.raw)
2569
2936
  };
2570
2937
  }
2571
2938
 
@@ -2573,7 +2940,7 @@ function parseSabreCommandResponse(response) {
2573
2940
  var OTA_NAMESPACE = "http://www.opentravel.org/OTA/2002/11";
2574
2941
  var SWS_NAMESPACE = "http://webservices.sabre.com";
2575
2942
  var sessionSend = /* @__PURE__ */ Symbol("sabre-client.session.send");
2576
- function fail5(message) {
2943
+ function fail6(message) {
2577
2944
  throw new TypeError(`sabre-client: ${message}`);
2578
2945
  }
2579
2946
  var SESSION_ERROR_KINDS = /* @__PURE__ */ new Map([
@@ -2602,6 +2969,8 @@ var KEEP_ALIVE_IDLE_MS = 13 * 6e4;
2602
2969
  var SabreSession = class {
2603
2970
  /** Queue Management: contar, recorrer y colocar en colas, dentro de esta sesión. */
2604
2971
  queue;
2972
+ /** La reserva: el historial de un PNR, dentro de esta sesión. */
2973
+ reservation;
2605
2974
  #transport;
2606
2975
  #pcc;
2607
2976
  #conversationId;
@@ -2629,6 +2998,7 @@ var SabreSession = class {
2629
2998
  pcc: internal.pcc,
2630
2999
  log: internal.transport.log
2631
3000
  });
3001
+ this.reservation = new SessionReservation({ send: (request) => this[sessionSend](request) });
2632
3002
  if (internal.keepAlive) this.#scheduleKeepAlive(KEEP_ALIVE_IDLE_MS);
2633
3003
  }
2634
3004
  /**
@@ -2684,11 +3054,11 @@ var SabreSession = class {
2684
3054
  return this.#send(request);
2685
3055
  }
2686
3056
  async #send(request) {
2687
- if (this.#closing !== void 0) fail5("session closed");
3057
+ if (this.#closing !== void 0) fail6("session closed");
2688
3058
  if (this.#unusable !== void 0) {
2689
3059
  throw new TypeError(`sabre-client: session unusable (${this.#unusable.kind})`, { cause: this.#unusable });
2690
3060
  }
2691
- if (this.#busy) fail5("session busy");
3061
+ if (this.#busy) fail6("session busy");
2692
3062
  this.#busy = true;
2693
3063
  try {
2694
3064
  const response = await this.#transport.request({ ...request, ...this.#envelopeFields() });
@@ -2703,6 +3073,7 @@ var SabreSession = class {
2703
3073
  }
2704
3074
  async #sendClose(options) {
2705
3075
  if (this.#unusable !== void 0) return;
3076
+ const { onRawRequest: _skipped, ...closeOptions } = options;
2706
3077
  this.#busy = true;
2707
3078
  try {
2708
3079
  await this.#transport.request({
@@ -2713,7 +3084,7 @@ var SabreSession = class {
2713
3084
  // Solo se reintenta ante `USG_*_BUSY`: tras un fallo de red no se sabe si ya se cerró.
2714
3085
  idempotent: false,
2715
3086
  operation: "close",
2716
- ...options
3087
+ ...closeOptions
2717
3088
  });
2718
3089
  } catch (error) {
2719
3090
  throw this.#markUnusable(error);
@@ -2843,7 +3214,7 @@ function usernameToken(credentials) {
2843
3214
  }
2844
3215
  async function openSession(transport, credentials, options = {}) {
2845
3216
  const { keepAlive = false, ...requestOptions } = options;
2846
- if (typeof keepAlive !== "boolean") fail5("keepAlive debe ser un boolean");
3217
+ if (typeof keepAlive !== "boolean") fail6("keepAlive debe ser un boolean");
2847
3218
  const conversationId = globalThis.crypto.randomUUID();
2848
3219
  const request = {
2849
3220
  service: "sessionCreate",
@@ -2948,34 +3319,35 @@ var SabreLegacy = class {
2948
3319
 
2949
3320
  // src/auth/credentials.ts
2950
3321
  var DEFAULT_DOMAIN = "AA";
2951
- function fail6(message) {
3322
+ function fail7(message) {
2952
3323
  throw new TypeError(`sabre-client: ${message}`);
2953
3324
  }
2954
3325
  function requireString2(value, field) {
2955
- if (typeof value !== "string" || value.trim() === "") fail6(`${field} es requerido y debe ser un string no vac\xEDo`);
3326
+ if (typeof value !== "string" || value.trim() === "") fail7(`${field} es requerido y debe ser un string no vac\xEDo`);
2956
3327
  }
2957
3328
  function buildCredentials(options) {
2958
- if (typeof options !== "object" || options === null) fail6("buildCredentials recibe un objeto");
3329
+ if (typeof options !== "object" || options === null) fail7("buildCredentials recibe un objeto");
2959
3330
  const authVersion = options.authVersion ?? "v3";
2960
3331
  if (authVersion !== "v3" && authVersion !== "v2") {
2961
- fail6(`authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(authVersion)})`);
3332
+ fail7(`authVersion debe ser 'v3' o 'v2' (recibido: ${JSON.stringify(authVersion)})`);
2962
3333
  }
2963
3334
  const { user, pcc, password, clientId, clientSecret } = options;
2964
3335
  const domain = options.domain ?? DEFAULT_DOMAIN;
2965
3336
  requireString2(user, "user");
2966
3337
  requireString2(password, "password");
2967
- if (!isPseudoCityCode(pcc)) fail6("pcc debe tener 3 o 4 caracteres alfanum\xE9ricos");
3338
+ if (!isPseudoCityCode(pcc)) fail7("pcc debe tener 3 o 4 caracteres alfanum\xE9ricos");
2968
3339
  requireString2(domain, "domain");
2969
- if (/[-:]/.test(domain)) fail6("domain no puede contener '-' ni ':'");
3340
+ if (/[-:]/.test(domain)) fail7("domain no puede contener '-' ni ':'");
2970
3341
  if (clientId === void 0 !== (clientSecret === void 0)) {
2971
- fail6("clientId y clientSecret van juntos: pasa los dos o ninguno");
3342
+ fail7("clientId y clientSecret van juntos: pasa los dos o ninguno");
2972
3343
  }
2973
3344
  if (authVersion === "v3" || clientId !== void 0) {
2974
3345
  requireString2(clientId, authVersion === "v3" ? "clientId (requerido con authVersion v3)" : "clientId");
2975
3346
  requireString2(clientSecret, authVersion === "v3" ? "clientSecret (requerido con authVersion v3)" : "clientSecret");
2976
3347
  }
2977
3348
  const username = authVersion === "v3" ? `${user}-${pcc}-${domain}` : `V1:${user}:${pcc}:${domain}`;
2978
- return clientId === void 0 ? { username, password } : { clientId, clientSecret, username, password };
3349
+ if (authVersion === "v3") return { authVersion, clientId, clientSecret, username, password };
3350
+ return clientId === void 0 ? { authVersion, username, password } : { authVersion, clientId, clientSecret, username, password };
2979
3351
  }
2980
3352
 
2981
3353
  // src/queue/host-date.ts
@@ -3276,6 +3648,22 @@ function hostTime(text) {
3276
3648
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
3277
3649
  }
3278
3650
 
3651
+ // src/queue/queue-place-remark.ts
3652
+ var MONTHS2 = /* @__PURE__ */ new Set(["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]);
3653
+ var REMARK = /^([A-Z0-9]{3,4})(\d{2})([A-Z]{3})(\d{1,3})\/(\d{1,3})$/;
3654
+ function parseQueuePlaceRemark(text) {
3655
+ if (typeof text !== "string") return null;
3656
+ const match = REMARK.exec(text.trim());
3657
+ if (match === null) return null;
3658
+ const [, pcc, day, month, queueText, picText] = match;
3659
+ const dayNumber2 = Number(day);
3660
+ if (dayNumber2 < 1 || dayNumber2 > 31 || !MONTHS2.has(month)) return null;
3661
+ const queue = Number(queueText);
3662
+ const pic = Number(picText);
3663
+ if (queue > MAX_QUEUE_NUMBER || !isInstructionCode(pic)) return null;
3664
+ return { pcc, date: `${day}${month}`, queue, pic };
3665
+ }
3666
+
3279
3667
  // src/air/seat-availability-request.ts
3280
3668
  function buildSeatAvailabilityRequest(source) {
3281
3669
  const { group, itinerary, segments: only, currencyCode } = source;
@@ -3360,7 +3748,7 @@ function fareComponent(fareComponentId, component) {
3360
3748
  }
3361
3749
 
3362
3750
  // src/index.ts
3363
- var VERSION = "0.4.0";
3751
+ var VERSION = "0.5.0";
3364
3752
  export {
3365
3753
  Sabre,
3366
3754
  SabreBusinessError,
@@ -3376,6 +3764,7 @@ export {
3376
3764
  buildRevalidateItineraryRequest,
3377
3765
  buildSeatAvailabilityRequest,
3378
3766
  parseQueueParagraph,
3767
+ parseQueuePlaceRemark,
3379
3768
  resolveHostDate
3380
3769
  };
3381
3770
  //# sourceMappingURL=index.js.map