@algolia/client-common 5.52.1 → 5.54.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.cts CHANGED
@@ -59,6 +59,67 @@ type FallbackableCacheOptions = {
59
59
  caches: Cache[];
60
60
  };
61
61
 
62
+ /**
63
+ * Shared configuration for chunked helpers that poll for task completion.
64
+ */
65
+ type ChunkedHelperOptions = {
66
+ /**
67
+ * The maximum number of retries when polling for task completion. 100 by default.
68
+ */
69
+ maxRetries?: number | undefined;
70
+ };
71
+
72
+ /**
73
+ * WHATWG-compliant Server-Sent Events parser.
74
+ *
75
+ * Three-layer architecture:
76
+ * 1. iterLines() — byte chunking → line decoding
77
+ * 2. SSEDecoder — line → SSE event decoding
78
+ * 3. iterSSEEvents — top-level composer (exported)
79
+ *
80
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
81
+ */
82
+ type ServerSentEvent = {
83
+ /** Concatenated data: field values, joined by '\n'. */
84
+ data: string;
85
+ /** Event type from the event: field. Defaults to "" (empty string). */
86
+ event: string;
87
+ /** Last event ID. Persists across dispatches until changed. */
88
+ id: string | null;
89
+ /** Reconnection time in ms. Persists across dispatches until changed. */
90
+ retry: number | null;
91
+ };
92
+ /**
93
+ * Wrapper for a parsed SSE event, yielded by the typed `*Stream` methods.
94
+ *
95
+ * - `data` is the JSON-parsed payload when parsing succeeds, `null` otherwise.
96
+ * - `raw` is the original {@link ServerSentEvent} (always present).
97
+ * - `error` is set when JSON parsing of `event.data` failed.
98
+ */
99
+ type StreamEvent<T = Record<string, unknown>> = {
100
+ /** Parsed data from the event, or `null` if parsing failed. */
101
+ data: T | null;
102
+ /** The original, unparsed SSE event. */
103
+ raw: ServerSentEvent;
104
+ /** The error that occurred while parsing `event.data`, if any. */
105
+ error?: Error;
106
+ };
107
+ /**
108
+ * Parses a byte stream as WHATWG Server-Sent Events.
109
+ *
110
+ * Accepts both ReadableStream<Uint8Array> (browser fetch) and
111
+ * AsyncIterable<Uint8Array> (Node.js streams / Buffer chunks).
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * const response = await fetch(url);
116
+ * for await (const event of iterSSEEvents(response.body!)) {
117
+ * console.log(event.event, event.data);
118
+ * }
119
+ * ```
120
+ */
121
+ declare function iterSSEEvents(stream: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>): AsyncGenerator<ServerSentEvent>;
122
+
62
123
  type Host = {
63
124
  /**
64
125
  * The host URL.
@@ -173,6 +234,10 @@ type Requester = {
173
234
  * Sends the given `request` to the server.
174
235
  */
175
236
  send: (request: EndRequest) => Promise<Response>;
237
+ /**
238
+ * Sends the given `request` and returns a raw byte stream for streaming responses (e.g. SSE).
239
+ */
240
+ sendStream?: (request: EndRequest) => Promise<ReadableStream<Uint8Array>>;
176
241
  };
177
242
 
178
243
  type RequestOptions = Pick<Request, 'cacheable'> & {
@@ -316,6 +381,7 @@ type Transporter = TransporterOptions & {
316
381
  * The `baseRequest` and `baseRequestOptions` will be merged accordingly.
317
382
  */
318
383
  request: <TResponse>(baseRequest: Request, baseRequestOptions?: RequestOptions) => Promise<TResponse>;
384
+ requestStream: (baseRequest: Request, baseRequestOptions?: RequestOptions) => AsyncGenerator<ServerSentEvent>;
319
385
  };
320
386
 
321
387
  type AuthMode = 'WithinHeaders' | 'WithinQueryParameters';
@@ -474,4 +540,6 @@ declare function isSuccess({ status }: Pick<Response, 'status'>): boolean;
474
540
  declare function stackTraceWithoutCredentials(stackTrace: StackFrame[]): StackFrame[];
475
541
  declare function stackFrameWithoutCredentials(stackFrame: StackFrame): StackFrame;
476
542
 
477
- export { type AlgoliaAgent, type AlgoliaAgentOptions, AlgoliaError, ApiError, type AuthMode, type BrowserLocalStorageCacheItem, type BrowserLocalStorageOptions, COMPRESSION_THRESHOLD, type Cache, type CacheEvents, type ClientOptions, type CreateClientOptions, type CreateIterablePromise, DEFAULT_CONNECT_TIMEOUT_BROWSER, DEFAULT_CONNECT_TIMEOUT_NODE, DEFAULT_READ_TIMEOUT_BROWSER, DEFAULT_READ_TIMEOUT_NODE, 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 StackFrame, type StatefulHost, type Timeouts, type Transporter, type TransporterOptions, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, getAlgoliaAgent, isNetworkError, isRetryable, isSuccess, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials };
543
+ declare function validateRequired(field: string, method: string, value: unknown): void;
544
+
545
+ export { type AlgoliaAgent, type AlgoliaAgentOptions, AlgoliaError, 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_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, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, getAlgoliaAgent, isNetworkError, isRetryable, isSuccess, iterSSEEvents, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials, validateRequired };
package/dist/common.d.ts CHANGED
@@ -59,6 +59,67 @@ type FallbackableCacheOptions = {
59
59
  caches: Cache[];
60
60
  };
61
61
 
62
+ /**
63
+ * Shared configuration for chunked helpers that poll for task completion.
64
+ */
65
+ type ChunkedHelperOptions = {
66
+ /**
67
+ * The maximum number of retries when polling for task completion. 100 by default.
68
+ */
69
+ maxRetries?: number | undefined;
70
+ };
71
+
72
+ /**
73
+ * WHATWG-compliant Server-Sent Events parser.
74
+ *
75
+ * Three-layer architecture:
76
+ * 1. iterLines() — byte chunking → line decoding
77
+ * 2. SSEDecoder — line → SSE event decoding
78
+ * 3. iterSSEEvents — top-level composer (exported)
79
+ *
80
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
81
+ */
82
+ type ServerSentEvent = {
83
+ /** Concatenated data: field values, joined by '\n'. */
84
+ data: string;
85
+ /** Event type from the event: field. Defaults to "" (empty string). */
86
+ event: string;
87
+ /** Last event ID. Persists across dispatches until changed. */
88
+ id: string | null;
89
+ /** Reconnection time in ms. Persists across dispatches until changed. */
90
+ retry: number | null;
91
+ };
92
+ /**
93
+ * Wrapper for a parsed SSE event, yielded by the typed `*Stream` methods.
94
+ *
95
+ * - `data` is the JSON-parsed payload when parsing succeeds, `null` otherwise.
96
+ * - `raw` is the original {@link ServerSentEvent} (always present).
97
+ * - `error` is set when JSON parsing of `event.data` failed.
98
+ */
99
+ type StreamEvent<T = Record<string, unknown>> = {
100
+ /** Parsed data from the event, or `null` if parsing failed. */
101
+ data: T | null;
102
+ /** The original, unparsed SSE event. */
103
+ raw: ServerSentEvent;
104
+ /** The error that occurred while parsing `event.data`, if any. */
105
+ error?: Error;
106
+ };
107
+ /**
108
+ * Parses a byte stream as WHATWG Server-Sent Events.
109
+ *
110
+ * Accepts both ReadableStream<Uint8Array> (browser fetch) and
111
+ * AsyncIterable<Uint8Array> (Node.js streams / Buffer chunks).
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * const response = await fetch(url);
116
+ * for await (const event of iterSSEEvents(response.body!)) {
117
+ * console.log(event.event, event.data);
118
+ * }
119
+ * ```
120
+ */
121
+ declare function iterSSEEvents(stream: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>): AsyncGenerator<ServerSentEvent>;
122
+
62
123
  type Host = {
63
124
  /**
64
125
  * The host URL.
@@ -173,6 +234,10 @@ type Requester = {
173
234
  * Sends the given `request` to the server.
174
235
  */
175
236
  send: (request: EndRequest) => Promise<Response>;
237
+ /**
238
+ * Sends the given `request` and returns a raw byte stream for streaming responses (e.g. SSE).
239
+ */
240
+ sendStream?: (request: EndRequest) => Promise<ReadableStream<Uint8Array>>;
176
241
  };
177
242
 
178
243
  type RequestOptions = Pick<Request, 'cacheable'> & {
@@ -316,6 +381,7 @@ type Transporter = TransporterOptions & {
316
381
  * The `baseRequest` and `baseRequestOptions` will be merged accordingly.
317
382
  */
318
383
  request: <TResponse>(baseRequest: Request, baseRequestOptions?: RequestOptions) => Promise<TResponse>;
384
+ requestStream: (baseRequest: Request, baseRequestOptions?: RequestOptions) => AsyncGenerator<ServerSentEvent>;
319
385
  };
320
386
 
321
387
  type AuthMode = 'WithinHeaders' | 'WithinQueryParameters';
@@ -474,4 +540,6 @@ declare function isSuccess({ status }: Pick<Response, 'status'>): boolean;
474
540
  declare function stackTraceWithoutCredentials(stackTrace: StackFrame[]): StackFrame[];
475
541
  declare function stackFrameWithoutCredentials(stackFrame: StackFrame): StackFrame;
476
542
 
477
- export { type AlgoliaAgent, type AlgoliaAgentOptions, AlgoliaError, ApiError, type AuthMode, type BrowserLocalStorageCacheItem, type BrowserLocalStorageOptions, COMPRESSION_THRESHOLD, type Cache, type CacheEvents, type ClientOptions, type CreateClientOptions, type CreateIterablePromise, DEFAULT_CONNECT_TIMEOUT_BROWSER, DEFAULT_CONNECT_TIMEOUT_NODE, DEFAULT_READ_TIMEOUT_BROWSER, DEFAULT_READ_TIMEOUT_NODE, 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 StackFrame, type StatefulHost, type Timeouts, type Transporter, type TransporterOptions, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, getAlgoliaAgent, isNetworkError, isRetryable, isSuccess, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials };
543
+ declare function validateRequired(field: string, method: string, value: unknown): void;
544
+
545
+ export { type AlgoliaAgent, type AlgoliaAgentOptions, AlgoliaError, 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_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, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, getAlgoliaAgent, isNetworkError, isRetryable, isSuccess, iterSSEEvents, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials, validateRequired };
package/dist/common.js CHANGED
@@ -14,42 +14,50 @@ function createBrowserLocalStorageCache(options) {
14
14
  function setNamespace(namespace) {
15
15
  getStorage().setItem(namespaceKey, JSON.stringify(namespace));
16
16
  }
17
- function removeOutdatedCacheItems() {
17
+ function yieldToMain() {
18
+ return new Promise((resolve) => setTimeout(resolve, 0));
19
+ }
20
+ function getFilteredNamespace() {
18
21
  const timeToLive = options.timeToLive ? options.timeToLive * 1e3 : null;
19
22
  const namespace = getNamespace();
20
- const filteredNamespaceWithoutOldFormattedCacheItems = Object.fromEntries(
23
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
24
+ let changed = false;
25
+ const filtered = Object.fromEntries(
21
26
  Object.entries(namespace).filter(([, cacheItem]) => {
22
- return cacheItem.timestamp !== void 0;
23
- })
24
- );
25
- setNamespace(filteredNamespaceWithoutOldFormattedCacheItems);
26
- if (!timeToLive) {
27
- return;
28
- }
29
- const filteredNamespaceWithoutExpiredItems = Object.fromEntries(
30
- Object.entries(filteredNamespaceWithoutOldFormattedCacheItems).filter(([, cacheItem]) => {
31
- const currentTimestamp = (/* @__PURE__ */ new Date()).getTime();
32
- const isExpired = cacheItem.timestamp + timeToLive < currentTimestamp;
33
- return !isExpired;
27
+ if (!cacheItem || cacheItem.timestamp === void 0) {
28
+ changed = true;
29
+ return false;
30
+ }
31
+ if (!timeToLive) {
32
+ return true;
33
+ }
34
+ if (cacheItem.timestamp + timeToLive < currentTime) {
35
+ changed = true;
36
+ return false;
37
+ }
38
+ return true;
34
39
  })
35
40
  );
36
- setNamespace(filteredNamespaceWithoutExpiredItems);
41
+ return { namespace: filtered, changed };
37
42
  }
38
43
  return {
39
44
  get(key, defaultValue, events = {
40
45
  miss: () => Promise.resolve()
41
46
  }) {
42
- return Promise.resolve().then(() => {
43
- removeOutdatedCacheItems();
44
- return getNamespace()[JSON.stringify(key)];
45
- }).then((value) => {
46
- return Promise.all([value ? value.value : defaultValue(), value !== void 0]);
47
- }).then(([value, exists]) => {
48
- return Promise.all([value, exists || events.miss(value)]);
49
- }).then(([value]) => value);
47
+ return yieldToMain().then(() => {
48
+ const { namespace, changed } = getFilteredNamespace();
49
+ const cachedItem = namespace[JSON.stringify(key)];
50
+ if (changed) {
51
+ setNamespace(namespace);
52
+ }
53
+ if (cachedItem) {
54
+ return cachedItem.value;
55
+ }
56
+ return defaultValue().then((value) => events.miss(value).then(() => value));
57
+ });
50
58
  },
51
59
  set(key, value) {
52
- return Promise.resolve().then(() => {
60
+ return yieldToMain().then(() => {
53
61
  const namespace = getNamespace();
54
62
  namespace[JSON.stringify(key)] = {
55
63
  timestamp: (/* @__PURE__ */ new Date()).getTime(),
@@ -60,7 +68,7 @@ function createBrowserLocalStorageCache(options) {
60
68
  });
61
69
  },
62
70
  delete(key) {
63
- return Promise.resolve().then(() => {
71
+ return yieldToMain().then(() => {
64
72
  const namespace = getNamespace();
65
73
  delete namespace[JSON.stringify(key)];
66
74
  getStorage().setItem(namespaceKey, JSON.stringify(namespace));
@@ -255,6 +263,165 @@ function createNullLogger() {
255
263
  };
256
264
  }
257
265
 
266
+ // src/sse.ts
267
+ var MAX_LINE_BUFFER_SIZE = 10 * 1024 * 1024;
268
+ async function* readableStreamToAsyncIterable(stream) {
269
+ const reader = stream.getReader();
270
+ try {
271
+ while (true) {
272
+ const { done, value } = await reader.read();
273
+ if (done) return;
274
+ yield value;
275
+ }
276
+ } finally {
277
+ reader.releaseLock();
278
+ }
279
+ }
280
+ function toAsyncIterable(stream) {
281
+ if (Symbol.asyncIterator in stream) {
282
+ return stream;
283
+ }
284
+ return readableStreamToAsyncIterable(stream);
285
+ }
286
+ async function* iterLines(stream) {
287
+ const decoder = new TextDecoder("utf-8");
288
+ const buffer = [];
289
+ let bufferSize = 0;
290
+ let trailingCR = false;
291
+ let isFirstLine = true;
292
+ for await (const chunk of toAsyncIterable(stream)) {
293
+ const text = decoder.decode(chunk, { stream: true });
294
+ let offset = 0;
295
+ if (trailingCR) {
296
+ trailingCR = false;
297
+ if (text.length > 0 && text[0] === "\n") {
298
+ offset = 1;
299
+ }
300
+ }
301
+ while (offset < text.length) {
302
+ const crIdx = text.indexOf("\r", offset);
303
+ const lfIdx = text.indexOf("\n", offset);
304
+ if (crIdx === -1 && lfIdx === -1) {
305
+ const remaining2 = text.slice(offset);
306
+ buffer.push(remaining2);
307
+ bufferSize += remaining2.length;
308
+ if (bufferSize > MAX_LINE_BUFFER_SIZE) {
309
+ throw new Error("SSE line buffer exceeded 10MB");
310
+ }
311
+ break;
312
+ }
313
+ let endIdx;
314
+ let skipLen;
315
+ if (crIdx !== -1 && (lfIdx === -1 || crIdx < lfIdx)) {
316
+ endIdx = crIdx;
317
+ if (crIdx + 1 < text.length) {
318
+ skipLen = text[crIdx + 1] === "\n" ? 2 : 1;
319
+ } else {
320
+ trailingCR = true;
321
+ skipLen = 1;
322
+ }
323
+ } else {
324
+ endIdx = lfIdx;
325
+ skipLen = 1;
326
+ }
327
+ const segment = text.slice(offset, endIdx);
328
+ buffer.push(segment);
329
+ let line = buffer.length === 1 ? buffer[0] : buffer.join("");
330
+ buffer.length = 0;
331
+ bufferSize = 0;
332
+ if (isFirstLine) {
333
+ if (line.startsWith("\uFEFF")) {
334
+ line = line.slice(1);
335
+ }
336
+ isFirstLine = false;
337
+ }
338
+ yield line;
339
+ offset = endIdx + skipLen;
340
+ }
341
+ }
342
+ const remaining = decoder.decode();
343
+ if (remaining) {
344
+ buffer.push(remaining);
345
+ }
346
+ if (buffer.length > 0) {
347
+ let line = buffer.join("");
348
+ if (isFirstLine && line.startsWith("\uFEFF")) {
349
+ line = line.slice(1);
350
+ }
351
+ yield line;
352
+ }
353
+ }
354
+ var SSEDecoder = class {
355
+ data = [];
356
+ eventType = "";
357
+ lastEventId = null;
358
+ retry = null;
359
+ decode(line) {
360
+ if (line === "") {
361
+ return this.dispatch();
362
+ }
363
+ if (line[0] === ":") {
364
+ return null;
365
+ }
366
+ const colonIdx = line.indexOf(":");
367
+ let field;
368
+ let value;
369
+ if (colonIdx === -1) {
370
+ field = line;
371
+ value = "";
372
+ } else {
373
+ field = line.slice(0, colonIdx);
374
+ value = line.slice(colonIdx + 1);
375
+ if (value[0] === " ") {
376
+ value = value.slice(1);
377
+ }
378
+ }
379
+ switch (field) {
380
+ case "data":
381
+ this.data.push(value);
382
+ break;
383
+ case "event":
384
+ this.eventType = value;
385
+ break;
386
+ case "id":
387
+ if (!value.includes("\0")) {
388
+ this.lastEventId = value;
389
+ }
390
+ break;
391
+ case "retry":
392
+ if (/^[0-9]+$/.test(value)) {
393
+ this.retry = parseInt(value, 10);
394
+ }
395
+ break;
396
+ }
397
+ return null;
398
+ }
399
+ dispatch() {
400
+ const currentEventType = this.eventType;
401
+ this.eventType = "";
402
+ if (this.data.length === 0) {
403
+ return null;
404
+ }
405
+ const event = {
406
+ data: this.data.join("\n"),
407
+ event: currentEventType,
408
+ id: this.lastEventId,
409
+ retry: this.retry
410
+ };
411
+ this.data = [];
412
+ return event;
413
+ }
414
+ };
415
+ async function* iterSSEEvents(stream) {
416
+ const decoder = new SSEDecoder();
417
+ for await (const line of iterLines(stream)) {
418
+ const event = decoder.decode(line);
419
+ if (event !== null) {
420
+ yield event;
421
+ }
422
+ }
423
+ }
424
+
258
425
  // src/transporter/compress.ts
259
426
  var COMPRESSION_THRESHOLD = 750;
260
427
 
@@ -382,6 +549,9 @@ function serializeHeaders(baseHeaders, requestHeaders, requestOptionsHeaders) {
382
549
  return serializedHeaders;
383
550
  }
384
551
  function deserializeSuccess(response) {
552
+ if (response.status === 204 || response.content.length === 0) {
553
+ return void 0;
554
+ }
385
555
  try {
386
556
  return JSON.parse(response.content);
387
557
  } catch (e) {
@@ -590,6 +760,55 @@ function createTransporter({
590
760
  }
591
761
  );
592
762
  }
763
+ async function* requestStream(request, requestOptions = {}) {
764
+ if (!requester.sendStream) {
765
+ throw new Error("This requester does not support streaming");
766
+ }
767
+ const data = serializeData(request, requestOptions);
768
+ const headers = serializeHeaders(baseHeaders, request.headers, requestOptions.headers);
769
+ headers["accept"] = "text/event-stream";
770
+ const dataQueryParameters = request.method === "GET" ? {
771
+ ...request.data,
772
+ ...requestOptions.data
773
+ } : {};
774
+ const queryParameters = {
775
+ ...baseQueryParameters,
776
+ ...request.queryParameters,
777
+ ...dataQueryParameters
778
+ };
779
+ if (algoliaAgent.value) {
780
+ queryParameters["x-algolia-agent"] = algoliaAgent.value;
781
+ }
782
+ if (requestOptions && requestOptions.queryParameters) {
783
+ for (const key of Object.keys(requestOptions.queryParameters)) {
784
+ if (!requestOptions.queryParameters[key] || Object.prototype.toString.call(requestOptions.queryParameters[key]) === "[object Object]") {
785
+ queryParameters[key] = requestOptions.queryParameters[key];
786
+ } else {
787
+ queryParameters[key] = requestOptions.queryParameters[key].toString();
788
+ }
789
+ }
790
+ }
791
+ const isRead = request.useReadTransporter || request.method === "GET";
792
+ const compatibleHosts = hosts.filter(
793
+ (host2) => host2.accept === "readWrite" || (isRead ? host2.accept === "read" : host2.accept === "write")
794
+ );
795
+ const options = await createRetryableOptions(compatibleHosts);
796
+ const host = options.hosts[0];
797
+ if (!host) {
798
+ throw new RetryError([]);
799
+ }
800
+ const timeout = { ...timeouts, ...requestOptions.timeouts };
801
+ const payload = {
802
+ data,
803
+ headers,
804
+ method: request.method,
805
+ url: serializeUrl(host, request.path, queryParameters),
806
+ connectTimeout: timeout.connect,
807
+ responseTimeout: isRead ? timeout.read : timeout.write
808
+ };
809
+ const stream = await requester.sendStream(payload);
810
+ yield* iterSSEEvents(stream);
811
+ }
593
812
  return {
594
813
  hostsCache,
595
814
  requester,
@@ -600,6 +819,7 @@ function createTransporter({
600
819
  baseQueryParameters,
601
820
  hosts,
602
821
  request: createRequest,
822
+ requestStream,
603
823
  requestsCache,
604
824
  responsesCache
605
825
  };
@@ -611,6 +831,13 @@ var LogLevelEnum = {
611
831
  Info: 2,
612
832
  Error: 3
613
833
  };
834
+
835
+ // src/validateParam.ts
836
+ function validateRequired(field, method, value) {
837
+ if (value === null || value === void 0 || typeof value === "string" && value.length === 0) {
838
+ throw new Error(`Parameter \`${field}\` is required when calling \`${method}\`.`);
839
+ }
840
+ }
614
841
  export {
615
842
  AlgoliaError,
616
843
  ApiError,
@@ -645,12 +872,14 @@ export {
645
872
  isNetworkError,
646
873
  isRetryable,
647
874
  isSuccess,
875
+ iterSSEEvents,
648
876
  serializeData,
649
877
  serializeHeaders,
650
878
  serializeQueryParameters,
651
879
  serializeUrl,
652
880
  shuffle,
653
881
  stackFrameWithoutCredentials,
654
- stackTraceWithoutCredentials
882
+ stackTraceWithoutCredentials,
883
+ validateRequired
655
884
  };
656
885
  //# sourceMappingURL=common.js.map