@algolia/client-common 5.56.0 → 5.59.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/common.d.ts CHANGED
@@ -261,6 +261,10 @@ type Logger = {
261
261
  * Logs info messages.
262
262
  */
263
263
  info: (message: string, args?: any | undefined) => Promise<void>;
264
+ /**
265
+ * Logs warning messages. When not implemented, warnings fall back to `console.warn` so they stay visible with the default no-op logger.
266
+ */
267
+ warn?: (message: string, args?: any | undefined) => Promise<void>;
264
268
  /**
265
269
  * Logs error messages.
266
270
  */
@@ -373,6 +377,12 @@ type TransporterOptions = {
373
377
  * retry strategy.
374
378
  */
375
379
  timeouts: Timeouts;
380
+ /**
381
+ * How many times to wait and retry on the same host after HTTP 429.
382
+ * Default is 3. `0` fails on the first 429 (no wait).
383
+ * Wait time is `Retry-After` in whole seconds, or 1 second if the header is missing or invalid.
384
+ */
385
+ maxRateLimitRetries?: number | undefined;
376
386
  /**
377
387
  * The hosts used by the requester.
378
388
  */
@@ -401,6 +411,12 @@ type TransporterOptions = {
401
411
  */
402
412
  compress?: (data: string) => Promise<Uint8Array>;
403
413
  compression?: 'gzip';
414
+ /**
415
+ * Where the generated Request-ID is sent: as the `Request-ID` header, or as the
416
+ * `x-algolia-request-id` query parameter. When undefined, no Request-ID is sent.
417
+ * A caller-supplied Request-ID is never overwritten.
418
+ */
419
+ requestIdChannel?: 'headers' | 'queryParameters' | undefined;
404
420
  };
405
421
  type Transporter = TransporterOptions & {
406
422
  /**
@@ -513,11 +529,16 @@ declare function getAlgoliaAgent({ algoliaAgents, client, version }: GetAlgoliaA
513
529
 
514
530
  declare function createNullLogger(): Logger;
515
531
 
532
+ /**
533
+ * Prefers the logger's optional `warn` method and falls back to `console.warn`, so warnings stay visible with the default no-op logger.
534
+ */
535
+ declare function logWarning(logger: Logger, message: string): void;
536
+
516
537
  declare const COMPRESSION_THRESHOLD = 750;
517
538
 
518
539
  declare function createStatefulHost(host: Host, status?: StatefulHost['status']): StatefulHost;
519
540
 
520
- declare function createTransporter({ hosts, hostsCache, baseHeaders, logger, baseQueryParameters, algoliaAgent, timeouts, requester, requestsCache, responsesCache, compress, compression, }: TransporterOptions): TransporterWithHttpInfo;
541
+ declare function createTransporter({ hosts, hostsCache, baseHeaders, logger, baseQueryParameters, algoliaAgent, timeouts, requester, requestsCache, responsesCache, compress, compression, requestIdChannel, maxRateLimitRetries, }: TransporterOptions): TransporterWithHttpInfo;
521
542
 
522
543
  declare class AlgoliaError extends Error {
523
544
  name: string;
@@ -534,18 +555,29 @@ declare class IndexAlreadyExistsError extends AlgoliaError {
534
555
  }
535
556
  declare class ErrorWithStackTrace extends AlgoliaError {
536
557
  stackTrace: StackFrame[];
537
- constructor(message: string, stackTrace: StackFrame[], name: string);
558
+ correlationId?: string | undefined;
559
+ constructor(message: string, stackTrace: StackFrame[], name: string, correlationId?: string | undefined);
538
560
  }
539
561
  declare class RetryError extends ErrorWithStackTrace {
540
- constructor(stackTrace: StackFrame[]);
562
+ constructor(stackTrace: StackFrame[], correlationId?: string | undefined);
541
563
  }
542
564
  declare class ApiError extends ErrorWithStackTrace {
543
565
  status: number;
544
- constructor(message: string, status: number, stackTrace: StackFrame[], name?: string);
566
+ constructor(message: string, status: number, stackTrace: StackFrame[], name?: string, correlationId?: string | undefined);
567
+ }
568
+ /**
569
+ * Thrown by `sendStream` when the HTTP status is not 2xx, so `requestStream` can
570
+ * wait and retry on 429 using `Retry-After` without parsing the error message.
571
+ */
572
+ declare class StreamRequestError extends AlgoliaError {
573
+ status: number;
574
+ headers?: Headers | undefined;
575
+ constructor(status: number, body: string, headers?: Headers | undefined);
545
576
  }
546
577
  declare class DeserializationError extends AlgoliaError {
547
578
  response: Response;
548
- constructor(message: string, response: Response);
579
+ correlationId?: string | undefined;
580
+ constructor(message: string, response: Response, correlationId?: string | undefined);
549
581
  }
550
582
  type DetailedErrorWithMessage = {
551
583
  message: string;
@@ -562,7 +594,7 @@ type DetailedError = {
562
594
  };
563
595
  declare class DetailedApiError extends ApiError {
564
596
  error: DetailedError;
565
- constructor(message: string, status: number, error: DetailedError, stackTrace: StackFrame[]);
597
+ constructor(message: string, status: number, error: DetailedError, stackTrace: StackFrame[], correlationId?: string | undefined);
566
598
  }
567
599
 
568
600
  declare function shuffle<TData>(array: TData[]): TData[];
@@ -572,15 +604,37 @@ declare function serializeData(request: Request, requestOptions: RequestOptions)
572
604
  declare function serializeHeaders(baseHeaders: Headers, requestHeaders: Headers, requestOptionsHeaders?: Headers | undefined): Headers;
573
605
  declare function deserializeSuccess<TObject>(response: Response): TObject;
574
606
  declare function deserializeSuccessWithHttpInfo<TData>(response: Response): AlgoliaHttpResponse<TData>;
575
- declare function deserializeFailure({ content, status }: Response, stackFrame: StackFrame[]): Error;
607
+ declare function getCorrelationId(headers: Headers | undefined): string | undefined;
608
+ declare function getLastCorrelationId(stackTrace: StackFrame[]): string | undefined;
609
+ declare function deserializeFailure(response: Response, stackFrame: StackFrame[]): Error;
610
+
611
+ declare function generateRequestId(): string;
612
+ /**
613
+ * Returns request options carrying a Request-ID on the transporter's channel, so that every
614
+ * request a multi-request helper performs shares the same ID. Returns the options unchanged
615
+ * when the channel is off or when a Request-ID is already supplied. Never apply ahead of a
616
+ * cacheable operation: the ID enters the cache key and defeats caching and deduplication.
617
+ */
618
+ declare function withRequestId(transporter: Pick<Transporter, 'requestIdChannel' | 'baseHeaders' | 'baseQueryParameters'>, requestOptions?: RequestOptions | undefined): RequestOptions | undefined;
576
619
 
577
620
  declare function isNetworkError({ isTimedOut, status }: Omit<Response, 'content'>): boolean;
578
621
  declare function isRetryable({ isTimedOut, status }: Omit<Response, 'content'>): boolean;
579
622
  declare function isSuccess({ status }: Pick<Response, 'status'>): boolean;
623
+ declare function isRateLimited({ status }: Pick<Response, 'status'>): boolean;
624
+ /**
625
+ * 429 from `sendStream`: a status-bearing error, or the `HTTP 429:` string requesters used to throw.
626
+ */
627
+ declare function isRateLimitedError(error: unknown): boolean;
628
+ declare function headersFromError(error: unknown): Headers | undefined;
629
+ /**
630
+ * `Retry-After` as a wait in milliseconds.
631
+ * Only a positive whole-number-of-seconds string is honored; anything else (missing, `0`, HTTP-date, junk) waits 1s.
632
+ */
633
+ declare function parseRetryAfterMs(headers: Headers | undefined): number;
580
634
 
581
635
  declare function stackTraceWithoutCredentials(stackTrace: StackFrame[]): StackFrame[];
582
636
  declare function stackFrameWithoutCredentials(stackFrame: StackFrame): StackFrame;
583
637
 
584
638
  declare function validateRequired(field: string, method: string, value: unknown): void;
585
639
 
586
- export { type AlgoliaAgent, type AlgoliaAgentOptions, AlgoliaError, type AlgoliaHttpResponse, ApiError, type AuthMode, type BrowserLocalStorageCacheItem, type BrowserLocalStorageOptions, COMPRESSION_THRESHOLD, type Cache, type CacheEvents, type ChunkedHelperOptions, type ClientOptions, type CreateClientOptions, type CreateIterablePromise, DEFAULT_CONNECT_TIMEOUT_BROWSER, DEFAULT_CONNECT_TIMEOUT_NODE, DEFAULT_READ_TIMEOUT_BROWSER, DEFAULT_READ_TIMEOUT_NODE, DEFAULT_REPLACE_ALL_OBJECTS_MAX_RETRIES, DEFAULT_WRITE_TIMEOUT_BROWSER, DEFAULT_WRITE_TIMEOUT_NODE, DeserializationError, DetailedApiError, type DetailedError, type DetailedErrorWithMessage, type DetailedErrorWithTypeID, type EndRequest, ErrorWithStackTrace, type FallbackableCacheOptions, type GetAlgoliaAgent, type Headers, type Host, IndexAlreadyExistsError, IndexNotFoundError, IndicesInSameAppError, type IterableOptions, LogLevelEnum, type LogLevelType, type Logger, type MemoryCacheOptions, type Method, type QueryParameters, type Request, type RequestOptions, type Requester, type Response, RetryError, type ServerSentEvent, type StackFrame, type StatefulHost, type StreamEvent, type Timeouts, type Transporter, type TransporterOptions, type TransporterWithHttpInfo, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, deserializeSuccessWithHttpInfo, getAlgoliaAgent, isNetworkError, isRetryable, isSuccess, iterSSEEvents, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials, validateRequired };
640
+ export { type AlgoliaAgent, type AlgoliaAgentOptions, AlgoliaError, type AlgoliaHttpResponse, ApiError, type AuthMode, type BrowserLocalStorageCacheItem, type BrowserLocalStorageOptions, COMPRESSION_THRESHOLD, type Cache, type CacheEvents, type ChunkedHelperOptions, type ClientOptions, type CreateClientOptions, type CreateIterablePromise, DEFAULT_CONNECT_TIMEOUT_BROWSER, DEFAULT_CONNECT_TIMEOUT_NODE, DEFAULT_READ_TIMEOUT_BROWSER, DEFAULT_READ_TIMEOUT_NODE, DEFAULT_REPLACE_ALL_OBJECTS_MAX_RETRIES, DEFAULT_WRITE_TIMEOUT_BROWSER, DEFAULT_WRITE_TIMEOUT_NODE, DeserializationError, DetailedApiError, type DetailedError, type DetailedErrorWithMessage, type DetailedErrorWithTypeID, type EndRequest, ErrorWithStackTrace, type FallbackableCacheOptions, type GetAlgoliaAgent, type Headers, type Host, IndexAlreadyExistsError, IndexNotFoundError, IndicesInSameAppError, type IterableOptions, LogLevelEnum, type LogLevelType, type Logger, type MemoryCacheOptions, type Method, type QueryParameters, type Request, type RequestOptions, type Requester, type Response, RetryError, type ServerSentEvent, type StackFrame, type StatefulHost, type StreamEvent, StreamRequestError, type Timeouts, type Transporter, type TransporterOptions, type TransporterWithHttpInfo, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, deserializeSuccessWithHttpInfo, generateRequestId, getAlgoliaAgent, getCorrelationId, getLastCorrelationId, headersFromError, isNetworkError, isRateLimited, isRateLimitedError, isRetryable, isSuccess, iterSSEEvents, logWarning, parseRetryAfterMs, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials, validateRequired, withRequestId };
package/dist/common.js CHANGED
@@ -264,6 +264,16 @@ function createNullLogger() {
264
264
  };
265
265
  }
266
266
 
267
+ // src/logger/logWarning.ts
268
+ function logWarning(logger, message) {
269
+ if (logger.warn) {
270
+ void Promise.resolve(logger.warn(message)).catch(() => {
271
+ });
272
+ } else {
273
+ console.warn(message);
274
+ }
275
+ }
276
+
267
277
  // src/sse.ts
268
278
  var MAX_LINE_BUFFER_SIZE = 10 * 1024 * 1024;
269
279
  async function* readableStreamToAsyncIterable(stream) {
@@ -466,38 +476,52 @@ var IndexAlreadyExistsError = class extends AlgoliaError {
466
476
  };
467
477
  var ErrorWithStackTrace = class extends AlgoliaError {
468
478
  stackTrace;
469
- constructor(message, stackTrace, name) {
470
- super(message, name);
479
+ correlationId;
480
+ constructor(message, stackTrace, name, correlationId) {
481
+ super(correlationId ? `${message} (Correlation-ID: ${correlationId})` : message, name);
471
482
  this.stackTrace = stackTrace;
483
+ this.correlationId = correlationId;
472
484
  }
473
485
  };
474
486
  var RetryError = class extends ErrorWithStackTrace {
475
- constructor(stackTrace) {
487
+ constructor(stackTrace, correlationId) {
476
488
  super(
477
489
  "Unreachable hosts - your application id may be incorrect. If the error persists, please visit our help center https://alg.li/support-unreachable-hosts or reach out to the Algolia Support team: https://alg.li/support",
478
490
  stackTrace,
479
- "RetryError"
491
+ "RetryError",
492
+ correlationId
480
493
  );
481
494
  }
482
495
  };
483
496
  var ApiError = class extends ErrorWithStackTrace {
484
497
  status;
485
- constructor(message, status, stackTrace, name = "ApiError") {
486
- super(message, stackTrace, name);
498
+ constructor(message, status, stackTrace, name = "ApiError", correlationId) {
499
+ super(message, stackTrace, name, correlationId);
500
+ this.status = status;
501
+ }
502
+ };
503
+ var StreamRequestError = class extends AlgoliaError {
504
+ status;
505
+ headers;
506
+ constructor(status, body, headers) {
507
+ super(`HTTP ${status}: ${body}`, "StreamRequestError");
487
508
  this.status = status;
509
+ this.headers = headers;
488
510
  }
489
511
  };
490
512
  var DeserializationError = class extends AlgoliaError {
491
513
  response;
492
- constructor(message, response) {
493
- super(message, "DeserializationError");
514
+ correlationId;
515
+ constructor(message, response, correlationId) {
516
+ super(correlationId ? `${message} (Correlation-ID: ${correlationId})` : message, "DeserializationError");
494
517
  this.response = response;
518
+ this.correlationId = correlationId;
495
519
  }
496
520
  };
497
521
  var DetailedApiError = class extends ApiError {
498
522
  error;
499
- constructor(message, status, error, stackTrace) {
500
- super(message, status, stackTrace, "DetailedApiError");
523
+ constructor(message, status, error, stackTrace, correlationId) {
524
+ super(message, status, stackTrace, "DetailedApiError", correlationId);
501
525
  this.error = error;
502
526
  }
503
527
  };
@@ -556,7 +580,7 @@ function deserializeSuccess(response) {
556
580
  try {
557
581
  return JSON.parse(response.content);
558
582
  } catch (e) {
559
- throw new DeserializationError(e.message, response);
583
+ throw new DeserializationError(e.message, response, getCorrelationId(response.headers));
560
584
  }
561
585
  }
562
586
  function deserializeSuccessWithHttpInfo(response) {
@@ -567,19 +591,76 @@ function deserializeSuccessWithHttpInfo(response) {
567
591
  data: deserializeSuccess(response)
568
592
  };
569
593
  }
570
- function deserializeFailure({ content, status }, stackFrame) {
594
+ function getCorrelationId(headers) {
595
+ if (!headers) {
596
+ return void 0;
597
+ }
598
+ if (headers["correlation-id"] !== void 0) {
599
+ return headers["correlation-id"];
600
+ }
601
+ const header = Object.keys(headers).find((key) => key.toLowerCase() === "correlation-id");
602
+ return header === void 0 ? void 0 : headers[header];
603
+ }
604
+ function getLastCorrelationId(stackTrace) {
605
+ for (let i = stackTrace.length - 1; i >= 0; i--) {
606
+ const correlationId = getCorrelationId(stackTrace[i].response.headers);
607
+ if (correlationId !== void 0) {
608
+ return correlationId;
609
+ }
610
+ }
611
+ return void 0;
612
+ }
613
+ function deserializeFailure(response, stackFrame) {
614
+ const { content, status } = response;
615
+ const correlationId = getCorrelationId(response.headers);
571
616
  try {
572
617
  const parsed = JSON.parse(content);
573
618
  if ("error" in parsed) {
574
- return new DetailedApiError(parsed.message, status, parsed.error, stackFrame);
619
+ return new DetailedApiError(parsed.message, status, parsed.error, stackFrame, correlationId);
575
620
  }
576
- return new ApiError(parsed.message, status, stackFrame);
621
+ return new ApiError(parsed.message, status, stackFrame, "ApiError", correlationId);
577
622
  } catch {
578
623
  }
579
- return new ApiError(content, status, stackFrame);
624
+ return new ApiError(content, status, stackFrame, "ApiError", correlationId);
625
+ }
626
+
627
+ // src/transporter/requestId.ts
628
+ var BASE62_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
629
+ var REQUEST_ID_LENGTH = 11;
630
+ function generateRequestId() {
631
+ var _a;
632
+ let requestId = "";
633
+ if (typeof ((_a = globalThis.crypto) == null ? void 0 : _a.getRandomValues) === "function") {
634
+ const bytes = new Uint8Array(REQUEST_ID_LENGTH);
635
+ globalThis.crypto.getRandomValues(bytes);
636
+ for (const byte of bytes) {
637
+ requestId += BASE62_CHARS[byte % BASE62_CHARS.length];
638
+ }
639
+ return requestId;
640
+ }
641
+ for (let i = 0; i < REQUEST_ID_LENGTH; i++) {
642
+ requestId += BASE62_CHARS[Math.floor(Math.random() * BASE62_CHARS.length)];
643
+ }
644
+ return requestId;
645
+ }
646
+ function hasRequestId(headers, queryParameters) {
647
+ return headers !== void 0 && Object.keys(headers).some((header) => header.toLowerCase() === "request-id") || queryParameters !== void 0 && Object.keys(queryParameters).some((parameter) => parameter.toLowerCase() === "x-algolia-request-id");
648
+ }
649
+ function withRequestId(transporter, requestOptions) {
650
+ if (transporter.requestIdChannel === void 0 || hasRequestId(transporter.baseHeaders, transporter.baseQueryParameters) || hasRequestId(requestOptions == null ? void 0 : requestOptions.headers, requestOptions == null ? void 0 : requestOptions.queryParameters)) {
651
+ return requestOptions;
652
+ }
653
+ if (transporter.requestIdChannel === "headers") {
654
+ return { ...requestOptions, headers: { ...requestOptions == null ? void 0 : requestOptions.headers, "request-id": generateRequestId() } };
655
+ }
656
+ return {
657
+ ...requestOptions,
658
+ queryParameters: { ...requestOptions == null ? void 0 : requestOptions.queryParameters, "x-algolia-request-id": generateRequestId() }
659
+ };
580
660
  }
581
661
 
582
662
  // src/transporter/responses.ts
663
+ var DEFAULT_RATE_LIMIT_WAIT_MS = 1e3;
583
664
  function isNetworkError({ isTimedOut, status }) {
584
665
  return !isTimedOut && ~~status === 0;
585
666
  }
@@ -589,6 +670,37 @@ function isRetryable({ isTimedOut, status }) {
589
670
  function isSuccess({ status }) {
590
671
  return ~~(status / 100) === 2;
591
672
  }
673
+ function isRateLimited({ status }) {
674
+ return ~~status === 429;
675
+ }
676
+ var HTTP_429_MESSAGE = /^HTTP 429(?:\D|$)/;
677
+ function isRateLimitedError(error) {
678
+ if (typeof error === "object" && error !== null && "status" in error) {
679
+ return isRateLimited(error);
680
+ }
681
+ return error instanceof Error && HTTP_429_MESSAGE.test(error.message);
682
+ }
683
+ function headersFromError(error) {
684
+ if (typeof error === "object" && error !== null && "headers" in error) {
685
+ return error.headers;
686
+ }
687
+ return void 0;
688
+ }
689
+ function parseRetryAfterMs(headers) {
690
+ var _a;
691
+ const raw = (_a = headers == null ? void 0 : headers["retry-after"]) == null ? void 0 : _a.trim();
692
+ if (raw === void 0 || raw.length === 0) {
693
+ return DEFAULT_RATE_LIMIT_WAIT_MS;
694
+ }
695
+ if (!/^\d+$/.test(raw)) {
696
+ return DEFAULT_RATE_LIMIT_WAIT_MS;
697
+ }
698
+ const seconds = Number.parseInt(raw, 10);
699
+ if (seconds <= 0) {
700
+ return DEFAULT_RATE_LIMIT_WAIT_MS;
701
+ }
702
+ return seconds * 1e3;
703
+ }
592
704
 
593
705
  // src/transporter/stackTrace.ts
594
706
  function stackTraceWithoutCredentials(stackTrace) {
@@ -621,8 +733,23 @@ function createTransporter({
621
733
  requestsCache,
622
734
  responsesCache,
623
735
  compress,
624
- compression
736
+ compression,
737
+ requestIdChannel,
738
+ maxRateLimitRetries = 3
625
739
  }) {
740
+ function injectRequestId(headers, queryParameters) {
741
+ if (requestIdChannel === void 0 || headers["request-id"] !== void 0 || Object.keys(queryParameters).some((parameter) => parameter.toLowerCase() === "x-algolia-request-id")) {
742
+ return;
743
+ }
744
+ if (requestIdChannel === "headers") {
745
+ headers["request-id"] = generateRequestId();
746
+ } else {
747
+ queryParameters["x-algolia-request-id"] = generateRequestId();
748
+ }
749
+ }
750
+ const wait = (ms) => new Promise((resolve) => {
751
+ setTimeout(resolve, ms);
752
+ });
626
753
  async function createRetryableOptions(compatibleHosts) {
627
754
  const statefulHosts = await Promise.all(
628
755
  compatibleHosts.map((compatibleHost) => {
@@ -677,11 +804,13 @@ function createTransporter({
677
804
  }
678
805
  }
679
806
  }
807
+ injectRequestId(headers, queryParameters);
680
808
  let timeoutsCount = 0;
809
+ let rateLimitRetriesLeft = maxRateLimitRetries;
681
810
  const retry = async (retryableHosts, getTimeout) => {
682
811
  const host = retryableHosts.pop();
683
812
  if (host === void 0) {
684
- throw new RetryError(stackTraceWithoutCredentials(stackTrace));
813
+ throw new RetryError(stackTraceWithoutCredentials(stackTrace), getLastCorrelationId(stackTrace));
685
814
  }
686
815
  const timeout = { ...timeouts, ...requestOptions.timeouts };
687
816
  const payload = {
@@ -703,6 +832,19 @@ function createTransporter({
703
832
  return stackFrame;
704
833
  };
705
834
  const response = await requester.send(payload);
835
+ if (isRateLimited(response) && rateLimitRetriesLeft > 0) {
836
+ rateLimitRetriesLeft--;
837
+ retryableHosts.push(host);
838
+ const stackFrame = pushToStackTrace(response);
839
+ const waitMs = parseRetryAfterMs(response.headers);
840
+ logger.info("Retryable failure", {
841
+ ...stackFrameWithoutCredentials(stackFrame),
842
+ wait: waitMs,
843
+ rateLimitRetriesLeft
844
+ });
845
+ await wait(waitMs);
846
+ return retry(retryableHosts, getTimeout);
847
+ }
706
848
  if (isRetryable(response)) {
707
849
  const stackFrame = pushToStackTrace(response);
708
850
  if (response.isTimedOut) {
@@ -805,6 +947,7 @@ function createTransporter({
805
947
  }
806
948
  }
807
949
  }
950
+ injectRequestId(headers, queryParameters);
808
951
  const isRead = request.useReadTransporter || request.method === "GET";
809
952
  const compatibleHosts = hosts.filter(
810
953
  (host2) => host2.accept === "readWrite" || (isRead ? host2.accept === "read" : host2.accept === "write")
@@ -823,8 +966,28 @@ function createTransporter({
823
966
  connectTimeout: timeout.connect,
824
967
  responseTimeout: isRead ? timeout.read : timeout.write
825
968
  };
826
- const stream = await requester.sendStream(payload);
827
- yield* iterSSEEvents(stream);
969
+ let rateLimitRetriesLeft = maxRateLimitRetries;
970
+ while (true) {
971
+ let stream;
972
+ try {
973
+ stream = await requester.sendStream(payload);
974
+ } catch (error) {
975
+ if (isRateLimitedError(error) && rateLimitRetriesLeft > 0) {
976
+ rateLimitRetriesLeft--;
977
+ const waitMs = parseRetryAfterMs(headersFromError(error));
978
+ logger.info("Retryable failure", {
979
+ wait: waitMs,
980
+ rateLimitRetriesLeft,
981
+ host
982
+ });
983
+ await wait(waitMs);
984
+ continue;
985
+ }
986
+ throw error;
987
+ }
988
+ yield* iterSSEEvents(stream);
989
+ return;
990
+ }
828
991
  }
829
992
  return {
830
993
  hostsCache,
@@ -834,7 +997,9 @@ function createTransporter({
834
997
  algoliaAgent,
835
998
  baseHeaders,
836
999
  baseQueryParameters,
1000
+ requestIdChannel,
837
1001
  hosts,
1002
+ maxRateLimitRetries,
838
1003
  request: createRequest,
839
1004
  requestWithHttpInfo: createRequestWithHttpInfo,
840
1005
  requestStream,
@@ -875,6 +1040,7 @@ export {
875
1040
  IndicesInSameAppError,
876
1041
  LogLevelEnum,
877
1042
  RetryError,
1043
+ StreamRequestError,
878
1044
  createAlgoliaAgent,
879
1045
  createAuth,
880
1046
  createBrowserLocalStorageCache,
@@ -888,11 +1054,19 @@ export {
888
1054
  deserializeFailure,
889
1055
  deserializeSuccess,
890
1056
  deserializeSuccessWithHttpInfo,
1057
+ generateRequestId,
891
1058
  getAlgoliaAgent,
1059
+ getCorrelationId,
1060
+ getLastCorrelationId,
1061
+ headersFromError,
892
1062
  isNetworkError,
1063
+ isRateLimited,
1064
+ isRateLimitedError,
893
1065
  isRetryable,
894
1066
  isSuccess,
895
1067
  iterSSEEvents,
1068
+ logWarning,
1069
+ parseRetryAfterMs,
896
1070
  serializeData,
897
1071
  serializeHeaders,
898
1072
  serializeQueryParameters,
@@ -900,6 +1074,7 @@ export {
900
1074
  shuffle,
901
1075
  stackFrameWithoutCredentials,
902
1076
  stackTraceWithoutCredentials,
903
- validateRequired
1077
+ validateRequired,
1078
+ withRequestId
904
1079
  };
905
1080
  //# sourceMappingURL=common.js.map