@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.cjs +206 -21
- package/dist/common.cjs.map +1 -1
- package/dist/common.d.cts +62 -8
- package/dist/common.d.ts +62 -8
- package/dist/common.js +195 -20
- package/dist/common.js.map +1 -1
- package/package.json +5 -5
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
470
|
-
|
|
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
|
-
|
|
493
|
-
|
|
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
|
|
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
|
-
|
|
827
|
-
|
|
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
|