react-instantsearch 7.38.0 → 7.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /*! React InstantSearch 7.38.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
1
+ /*! React InstantSearch 7.39.1 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
4
4
  typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
@@ -24,7 +24,7 @@
24
24
 
25
25
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
26
 
27
- var version$2 = '7.38.0';
27
+ var version$2 = '7.39.1';
28
28
 
29
29
  function _define_property(obj, key, value) {
30
30
  if (key in obj) {
@@ -571,10 +571,10 @@
571
571
  return objectHasKeys_1;
572
572
  }
573
573
 
574
- var omit;
574
+ var omit$1;
575
575
  var hasRequiredOmit;
576
576
  function requireOmit() {
577
- if (hasRequiredOmit) return omit;
577
+ if (hasRequiredOmit) return omit$1;
578
578
  hasRequiredOmit = 1;
579
579
  // https://github.com/babel/babel/blob/3aaafae053fa75febb3aa45d45b6f00646e30ba4/packages/babel-helpers/src/helpers.js#L604-L620
580
580
  function _objectWithoutPropertiesLoose(source, excluded) {
@@ -591,8 +591,8 @@
591
591
  }
592
592
  return target;
593
593
  }
594
- omit = _objectWithoutPropertiesLoose;
595
- return omit;
594
+ omit$1 = _objectWithoutPropertiesLoose;
595
+ return omit$1;
596
596
  }
597
597
 
598
598
  var RecommendParameters_1;
@@ -3919,7 +3919,7 @@
3919
3919
  function requireVersion() {
3920
3920
  if (hasRequiredVersion) return version$1;
3921
3921
  hasRequiredVersion = 1;
3922
- version$1 = '3.29.1';
3922
+ version$1 = '3.29.2';
3923
3923
  return version$1;
3924
3924
  }
3925
3925
 
@@ -7259,19 +7259,23 @@
7259
7259
  * This is used to log issues in development environment only.
7260
7260
  */ var warn = noop;
7261
7261
 
7262
- function range(param) {
7263
- var _param_start = param.start, start = _param_start === void 0 ? 0 : _param_start, end = param.end, _param_step = param.step, step = _param_step === void 0 ? 1 : _param_step;
7264
- // We can't divide by 0 so we re-assign the step to 1 if it happens.
7265
- var limitStep = step === 0 ? 1 : step;
7266
- // In some cases the array to create has a decimal length.
7267
- // We therefore need to round the value.
7268
- // Example:
7269
- // { start: 1, end: 5000, step: 500 }
7270
- // => Array length = (5000 - 1) / 500 = 9.998
7271
- var arrayLength = Math.round((end - start) / limitStep);
7272
- return _to_consumable_array(Array(arrayLength)).map(function(_, current) {
7273
- return start + current * limitStep;
7274
- });
7262
+ /**
7263
+ * Creates a new object with the same keys as the original object, but without the excluded keys.
7264
+ * @param source original object
7265
+ * @param excluded keys to remove from the original object
7266
+ * @returns the new object
7267
+ */ function omit(source, excluded) {
7268
+ if (source === null || source === undefined) {
7269
+ return source;
7270
+ }
7271
+ return Object.keys(source).reduce(function(target, key) {
7272
+ if (excluded.indexOf(key) >= 0) {
7273
+ return target;
7274
+ }
7275
+ var validKey = key;
7276
+ target[validKey] = source[validKey];
7277
+ return target;
7278
+ }, {});
7275
7279
  }
7276
7280
 
7277
7281
  function createInitArgs(instantSearchInstance, parent, uiState) {
@@ -7319,6 +7323,132 @@
7319
7323
  instantSearchInstance.renderState = _object_spread_props(_object_spread({}, instantSearchInstance.renderState), _define_property({}, parentIndexName, _object_spread({}, instantSearchInstance.renderState[parentIndexName], renderState)));
7320
7324
  }
7321
7325
 
7326
+ function serializeParamValue(value) {
7327
+ if (value === undefined || value === null) {
7328
+ return null;
7329
+ }
7330
+ var t = typeof value === "undefined" ? "undefined" : _type_of(value);
7331
+ if (t === 'string' || t === 'number' || t === 'boolean') {
7332
+ return {
7333
+ value: String(value),
7334
+ type: t
7335
+ };
7336
+ }
7337
+ if (Array.isArray(value) || t === 'object') {
7338
+ var type = Array.isArray(value) ? 'array' : 'object';
7339
+ try {
7340
+ return {
7341
+ value: JSON.stringify(value),
7342
+ type: type
7343
+ };
7344
+ } catch (unused) {
7345
+ return {
7346
+ type: type
7347
+ };
7348
+ }
7349
+ }
7350
+ if (t === 'function') {
7351
+ return {
7352
+ value: value.name,
7353
+ type: 'function'
7354
+ };
7355
+ }
7356
+ // symbols, DOM elements: name only
7357
+ return null;
7358
+ }
7359
+ /**
7360
+ * Turns a `widgetParams`-style record into the serialized `WidgetTreeParam[]`
7361
+ * shape used throughout the usage events. Shared between the widget tree and
7362
+ * the root `ais.instantSearch` node so every node reports params identically.
7363
+ */ function serializeWidgetParams(widgetParams) {
7364
+ var params = [];
7365
+ Object.keys(widgetParams).forEach(function(key) {
7366
+ var raw = widgetParams[key];
7367
+ if (raw === undefined) {
7368
+ return;
7369
+ }
7370
+ var serialized = serializeParamValue(raw);
7371
+ if (serialized) {
7372
+ params.push(_object_spread({
7373
+ name: key
7374
+ }, serialized));
7375
+ } else {
7376
+ params.push({
7377
+ name: key
7378
+ });
7379
+ }
7380
+ });
7381
+ return params;
7382
+ }
7383
+ function buildWidgetTree(widgets, instantSearchInstance) {
7384
+ var parent = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : instantSearchInstance.mainIndex;
7385
+ var initOptions = createInitArgs(instantSearchInstance, parent, instantSearchInstance._initialUiState);
7386
+ return widgets.map(function(widget) {
7387
+ var widgetParams = {};
7388
+ if (widget.getWidgetRenderState) {
7389
+ var renderState = widget.getWidgetRenderState(initOptions);
7390
+ if (renderState && renderState.widgetParams) {
7391
+ widgetParams = renderState.widgetParams;
7392
+ }
7393
+ }
7394
+ var params = serializeWidgetParams(widgetParams);
7395
+ var children = isIndexWidget(widget) ? buildWidgetTree(widget.getWidgets(), instantSearchInstance, widget) : [];
7396
+ return {
7397
+ type: widget.$$widgetType || widget.$$type || 'unknown',
7398
+ params: params,
7399
+ children: children
7400
+ };
7401
+ });
7402
+ }
7403
+
7404
+ function extractWidgetPayload(widgets, instantSearchInstance, payload) {
7405
+ var parent = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : instantSearchInstance.mainIndex;
7406
+ var initOptions = createInitArgs(instantSearchInstance, parent, instantSearchInstance._initialUiState);
7407
+ widgets.forEach(function(widget) {
7408
+ var widgetParams = {};
7409
+ if (widget.getWidgetRenderState) {
7410
+ var renderState = widget.getWidgetRenderState(initOptions);
7411
+ if (renderState && renderState.widgetParams) {
7412
+ // casting, as we just earlier checked widgetParams exists, and thus an object
7413
+ widgetParams = renderState.widgetParams;
7414
+ }
7415
+ }
7416
+ // since we destructure in all widgets, the parameters with defaults are set to "undefined"
7417
+ var params = Object.keys(widgetParams).filter(function(key) {
7418
+ return widgetParams[key] !== undefined;
7419
+ });
7420
+ payload.widgets.push({
7421
+ type: widget.$$type,
7422
+ widgetType: widget.$$widgetType,
7423
+ params: params
7424
+ });
7425
+ if (isIndexWidget(widget)) {
7426
+ extractWidgetPayload(widget.getWidgets(), instantSearchInstance, payload, widget);
7427
+ }
7428
+ });
7429
+ }
7430
+
7431
+ var now = typeof performance !== 'undefined' ? function() {
7432
+ return performance.now();
7433
+ } : function() {
7434
+ return Date.now();
7435
+ };
7436
+
7437
+ function range(param) {
7438
+ var _param_start = param.start, start = _param_start === void 0 ? 0 : _param_start, end = param.end, _param_step = param.step, step = _param_step === void 0 ? 1 : _param_step;
7439
+ // We can't divide by 0 so we re-assign the step to 1 if it happens.
7440
+ var limitStep = step === 0 ? 1 : step;
7441
+ // In some cases the array to create has a decimal length.
7442
+ // We therefore need to round the value.
7443
+ // Example:
7444
+ // { start: 1, end: 5000, step: 500 }
7445
+ // => Array length = (5000 - 1) / 500 = 9.998
7446
+ var arrayLength = Math.round((end - start) / limitStep);
7447
+ return _to_consumable_array(Array(arrayLength)).map(function(_, current) {
7448
+ return start + current * limitStep;
7449
+ });
7450
+ }
7451
+
7322
7452
  function resolveSearchParameters(current) {
7323
7453
  var parent = current.getParent();
7324
7454
  var states = [
@@ -9030,6 +9160,8 @@
9030
9160
  });
9031
9161
  }
9032
9162
 
9163
+ var version = '4.106.0';
9164
+
9033
9165
  var ANONYMOUS_TOKEN_COOKIE_KEY = '_ALGOLIA';
9034
9166
  function getCookie(name) {
9035
9167
  if ((typeof document === "undefined" ? "undefined" : _type_of(document)) !== 'object' || typeof document.cookie !== 'string') {
@@ -9052,8 +9184,61 @@
9052
9184
  return getCookie(ANONYMOUS_TOKEN_COOKIE_KEY);
9053
9185
  }
9054
9186
 
9187
+ var USAGE_SESSION_KEY = 'ais.usage.sessionId';
9188
+ // Cache the id for the lifetime of the runtime so repeated calls don't hit
9189
+ // `sessionStorage` again, and so we always return the same id even when
9190
+ // storage is unavailable (SSR, privacy mode) and we fall back to a fresh UUID.
9191
+ var usageSessionId = null;
9192
+ function getUsageSessionId() {
9193
+ if (usageSessionId) {
9194
+ return usageSessionId;
9195
+ }
9196
+ try {
9197
+ var existing = sessionStorage.getItem(USAGE_SESSION_KEY);
9198
+ if (existing) {
9199
+ usageSessionId = existing;
9200
+ return usageSessionId;
9201
+ }
9202
+ usageSessionId = createUUID();
9203
+ sessionStorage.setItem(USAGE_SESSION_KEY, usageSessionId);
9204
+ return usageSessionId;
9205
+ } catch (unused) {
9206
+ // sessionStorage unavailable (SSR, privacy mode, etc.)
9207
+ usageSessionId = createUUID();
9208
+ return usageSessionId;
9209
+ }
9210
+ }
9211
+ /** @deprecated use bindEvent instead */ function writeDataAttributes(param) {
9212
+ var method = param.method, payload = param.payload;
9213
+ if ((typeof payload === "undefined" ? "undefined" : _type_of(payload)) !== 'object') {
9214
+ throw new Error("The insights helper expects the payload to be an object.");
9215
+ }
9216
+ var serializedPayload;
9217
+ try {
9218
+ serializedPayload = serializePayload(payload);
9219
+ } catch (error) {
9220
+ throw new Error("Could not JSON serialize the payload object.");
9221
+ }
9222
+ return 'data-insights-method="'.concat(method, '" data-insights-payload="').concat(serializedPayload, '"');
9223
+ }
9224
+ /**
9225
+ * @deprecated This function will be still supported in 4.x releases, but not further. It is replaced by the `insights` middleware. For more information, visit https://www.algolia.com/doc/guides/getting-insights-and-analytics/search-analytics/click-through-and-conversions/how-to/send-click-and-conversion-events-with-instantsearch/js/
9226
+ */ function insights(method, payload) {
9227
+ return writeDataAttributes({
9228
+ method: method,
9229
+ payload: payload
9230
+ });
9231
+ }
9232
+
9055
9233
  var ALGOLIA_INSIGHTS_VERSION = '2.17.2';
9056
9234
  var ALGOLIA_INSIGHTS_SRC = "https://cdn.jsdelivr.net/npm/search-insights@".concat(ALGOLIA_INSIGHTS_VERSION, "/dist/search-insights.min.js");
9235
+ // InstantSearch options that must never be sent in usage events because
9236
+ // they carry credentials or end-user data. Everything else is reported as-is.
9237
+ var SENSITIVE_OPTIONS = [
9238
+ 'searchClient',
9239
+ 'insightsClient',
9240
+ 'initialUiState'
9241
+ ];
9057
9242
  function createInsightsMiddleware() {
9058
9243
  var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
9059
9244
  var _insightsClient = props.insightsClient, insightsInitParams = props.insightsInitParams, onEvent = props.onEvent, _props_$$internal = props.$$internal, $$internal = _props_$$internal === void 0 ? false : _props_$$internal, _props_$$automatic = props.$$automatic, $$automatic = _props_$$automatic === void 0 ? false : _props_$$automatic;
@@ -9143,6 +9328,7 @@
9143
9328
  }
9144
9329
  var initialParameters;
9145
9330
  var helper;
9331
+ var removeStartEventListener = null;
9146
9332
  return {
9147
9333
  $$type: 'ais.insights',
9148
9334
  $$internal: $$internal,
@@ -9317,8 +9503,65 @@
9317
9503
  insightsClientWithLocalCredentials(event.insightsMethod, event.payload);
9318
9504
  } else ;
9319
9505
  };
9506
+ // usage tracking (browser-only)
9507
+ safelyRunOnBrowser(function() {
9508
+ var usageSessionId = getUsageSessionId();
9509
+ function sendUsageEvent(event) {
9510
+ var _helper_state;
9511
+ var userToken = (_helper_state = helper.state) === null || _helper_state === void 0 ? void 0 : _helper_state.userToken;
9512
+ insightsClientWithLocalCredentials('sendEvents', [
9513
+ _object_spread({
9514
+ eventType: 'instantsearch',
9515
+ timestamp: Date.now(),
9516
+ sessionID: usageSessionId,
9517
+ userToken: userToken ? String(userToken) : undefined
9518
+ }, event)
9519
+ ]);
9520
+ }
9521
+ // Send the start event on the first `render`, by which point every
9522
+ // flavor has registered its widgets. `bootstrapMs` then measures the
9523
+ // time between the constructor running and that point, so for flavors
9524
+ // that register widgets right at start (e.g. React) it captures the
9525
+ // cost of adding them.
9526
+ var sendStartEvent = function sendStartEvent() {
9527
+ try {
9528
+ var bootstrapMs = Math.round(now() - instantSearchInstance._createdAt);
9529
+ sendUsageEvent({
9530
+ eventName: '__start__',
9531
+ algoliaAgent: getAlgoliaAgent(instantSearchInstance.client),
9532
+ version: version,
9533
+ applicationId: appId,
9534
+ performance: {
9535
+ bootstrapMs: bootstrapMs
9536
+ },
9537
+ widgets: [
9538
+ {
9539
+ type: 'ais.instantSearch',
9540
+ // The options the instance was created with, serialized the
9541
+ // same way every widget's params are. Derived dynamically from
9542
+ // `_initialOptions` so new options are reported automatically,
9543
+ // minus the keys that carry credentials or user data. Functions
9544
+ // (`onStateChange`, `searchFunction`) report their `fn.name`
9545
+ // when present, tagged `type: 'function'`.
9546
+ params: instantSearchInstance._initialOptions ? serializeWidgetParams(omit(instantSearchInstance._initialOptions, _to_consumable_array(SENSITIVE_OPTIONS))) : [],
9547
+ children: buildWidgetTree(instantSearchInstance.mainIndex.getWidgets(), instantSearchInstance)
9548
+ }
9549
+ ]
9550
+ });
9551
+ } catch (unused) {
9552
+ // usage tracking must never crash the host app
9553
+ }
9554
+ };
9555
+ instantSearchInstance.once('render', sendStartEvent);
9556
+ removeStartEventListener = function removeStartEventListener() {
9557
+ return instantSearchInstance.removeListener('render', sendStartEvent);
9558
+ };
9559
+ });
9320
9560
  },
9321
9561
  unsubscribe: function unsubscribe() {
9562
+ if (removeStartEventListener) {
9563
+ removeStartEventListener();
9564
+ }
9322
9565
  insightsClient('onUserTokenChange', undefined);
9323
9566
  instantSearchInstance.sendEventToInsights = noop;
9324
9567
  if (helper && initialParameters) {
@@ -9366,31 +9609,6 @@
9366
9609
  return typeof userToken === 'number' ? userToken.toString() : userToken;
9367
9610
  }
9368
9611
 
9369
- function extractWidgetPayload(widgets, instantSearchInstance, payload) {
9370
- var initOptions = createInitArgs(instantSearchInstance, instantSearchInstance.mainIndex, instantSearchInstance._initialUiState);
9371
- widgets.forEach(function(widget) {
9372
- var widgetParams = {};
9373
- if (widget.getWidgetRenderState) {
9374
- var renderState = widget.getWidgetRenderState(initOptions);
9375
- if (renderState && renderState.widgetParams) {
9376
- // casting, as we just earlier checked widgetParams exists, and thus an object
9377
- widgetParams = renderState.widgetParams;
9378
- }
9379
- }
9380
- // since we destructure in all widgets, the parameters with defaults are set to "undefined"
9381
- var params = Object.keys(widgetParams).filter(function(key) {
9382
- return widgetParams[key] !== undefined;
9383
- });
9384
- payload.widgets.push({
9385
- type: widget.$$type,
9386
- widgetType: widget.$$widgetType,
9387
- params: params
9388
- });
9389
- if (isIndexWidget(widget)) {
9390
- extractWidgetPayload(widget.getWidgets(), instantSearchInstance, payload);
9391
- }
9392
- });
9393
- }
9394
9612
  function isMetadataEnabled() {
9395
9613
  return safelyRunOnBrowser(function(param) {
9396
9614
  var window = param.window;
@@ -10739,28 +10957,6 @@
10739
10957
  return reverseHighlightedValue.replace(new RegExp(TAG_REPLACEMENT.highlightPreTag, 'g'), "<".concat(highlightedTagName, ' class="').concat(className, '">')).replace(new RegExp(TAG_REPLACEMENT.highlightPostTag, 'g'), "</".concat(highlightedTagName, ">"));
10740
10958
  }
10741
10959
 
10742
- /** @deprecated use bindEvent instead */ function writeDataAttributes(param) {
10743
- var method = param.method, payload = param.payload;
10744
- if ((typeof payload === "undefined" ? "undefined" : _type_of(payload)) !== 'object') {
10745
- throw new Error("The insights helper expects the payload to be an object.");
10746
- }
10747
- var serializedPayload;
10748
- try {
10749
- serializedPayload = serializePayload(payload);
10750
- } catch (error) {
10751
- throw new Error("Could not JSON serialize the payload object.");
10752
- }
10753
- return 'data-insights-method="'.concat(method, '" data-insights-payload="').concat(serializedPayload, '"');
10754
- }
10755
- /**
10756
- * @deprecated This function will be still supported in 4.x releases, but not further. It is replaced by the `insights` middleware. For more information, visit https://www.algolia.com/doc/guides/getting-insights-and-analytics/search-analytics/click-through-and-conversions/how-to/send-click-and-conversion-events-with-instantsearch/js/
10757
- */ function insights(method, payload) {
10758
- return writeDataAttributes({
10759
- method: method,
10760
- payload: payload
10761
- });
10762
- }
10763
-
10764
10960
  function hoganHelpers(param) {
10765
10961
  var numberLocale = param.numberLocale;
10766
10962
  return {
@@ -10822,8 +11018,6 @@
10822
11018
  };
10823
11019
  }
10824
11020
 
10825
- var version = '4.104.0';
10826
-
10827
11021
  var withUsage$r = createDocumentationMessageGenerator({
10828
11022
  name: 'instantsearch'
10829
11023
  });
@@ -10843,7 +11037,14 @@
10843
11037
  function InstantSearch(options) {
10844
11038
  _class_call_check(this, InstantSearch);
10845
11039
  var _this;
10846
- _this = _call_super(this, InstantSearch), _define_property(_this, "client", void 0), _define_property(_this, "indexName", void 0), _define_property(_this, "compositionID", void 0), _define_property(_this, "insightsClient", void 0), _define_property(_this, "onStateChange", null), _define_property(_this, "future", void 0), _define_property(_this, "helper", void 0), _define_property(_this, "mainHelper", void 0), _define_property(_this, "mainIndex", void 0), _define_property(_this, "started", void 0), _define_property(_this, "templatesConfig", void 0), _define_property(_this, "renderState", {}), _define_property(_this, "_stalledSearchDelay", void 0), _define_property(_this, "_searchStalledTimer", void 0), _define_property(_this, "_initialUiState", void 0), _define_property(_this, "_initialResults", void 0), _define_property(_this, "_manuallyResetScheduleSearch", false), _define_property(_this, "_resetScheduleSearch", void 0), _define_property(_this, "_createURL", void 0), _define_property(_this, "_searchFunction", void 0), _define_property(_this, "_mainHelperSearch", void 0), _define_property(_this, "_hasSearchWidget", false), _define_property(_this, "_hasRecommendWidget", false), _define_property(_this, "_insights", void 0), _define_property(_this, "middleware", []), _define_property(_this, "sendEventToInsights", void 0), /**
11040
+ _this = _call_super(this, InstantSearch), _define_property(_this, "client", void 0), _define_property(_this, "indexName", void 0), _define_property(_this, "compositionID", void 0), _define_property(_this, "insightsClient", void 0), _define_property(_this, "onStateChange", null), _define_property(_this, "future", void 0), _define_property(_this, "helper", void 0), _define_property(_this, "mainHelper", void 0), _define_property(_this, "mainIndex", void 0), _define_property(_this, "started", void 0), _define_property(_this, "templatesConfig", void 0), _define_property(_this, "renderState", {}), _define_property(_this, "_stalledSearchDelay", void 0), _define_property(_this, "_searchStalledTimer", void 0), _define_property(_this, "_initialUiState", void 0), _define_property(_this, "_initialResults", void 0), _define_property(_this, "_manuallyResetScheduleSearch", false), _define_property(_this, "_resetScheduleSearch", void 0), _define_property(_this, "_createURL", void 0), _define_property(_this, "_searchFunction", void 0), _define_property(_this, "_mainHelperSearch", void 0), _define_property(_this, "_hasSearchWidget", false), _define_property(_this, "_hasRecommendWidget", false), _define_property(_this, "_insights", void 0), /**
11041
+ * The options the instance was created with, kept verbatim so consumers
11042
+ * (e.g. usage events) can introspect the configuration without the class
11043
+ * having to enumerate every option by hand. Typed without the class generics
11044
+ * on purpose: referencing `TUiState`/`TRouteState` here (they sit in
11045
+ * contravariant positions inside `InstantSearchOptions`) would break the
11046
+ * assignability of `InstantSearch<SpecificUiState>` to `InstantSearch`.
11047
+ */ _define_property(_this, "_initialOptions", void 0), _define_property(_this, "middleware", []), _define_property(_this, "sendEventToInsights", void 0), _define_property(_this, "_createdAt", now()), /**
10847
11048
  * The status of the search. Can be "idle", "loading", "stalled", or "error".
10848
11049
  */ _define_property(_this, "status", 'idle'), /**
10849
11050
  * The last returned error from the Search API.
@@ -10891,6 +11092,7 @@
10891
11092
  if (insightsClient && typeof insightsClient !== 'function') {
10892
11093
  throw new Error(withUsage$r('The `insightsClient` option should be a function.'));
10893
11094
  }
11095
+ _this._initialOptions = options;
10894
11096
  _this.client = searchClient;
10895
11097
  _this.future = future;
10896
11098
  _this.insightsClient = insightsClient;
@@ -11263,6 +11465,9 @@
11263
11465
  var instance = param.instance;
11264
11466
  instance.unsubscribe();
11265
11467
  });
11468
+ // Cleared after unsubscribe so in-flight readers (e.g. the insights
11469
+ // start-event listener) have detached before the reference goes away.
11470
+ this._initialOptions = null;
11266
11471
  }
11267
11472
  },
11268
11473
  {
@@ -12352,15 +12557,14 @@
12352
12557
  return Promise.resolve(value);
12353
12558
  }
12354
12559
  /**
12355
- * Error raised when the upstream stream emits a `data-guardrail-violation`
12356
- * chunk. The `message` carries the service-provided `fallbackResponse`, which
12357
- * is intentionally surfaced verbatim through the chat error UI (unlike
12358
- * generic cost-control / 4xx errors, where the raw API message is hidden
12359
- * behind a friendly default).
12560
+ * Error shape for custom chat implementations that still surface a
12561
+ * `data-guardrail-violation` chunk through the error UI. The `message` carries
12562
+ * the service-provided `fallbackResponse`, which is authored for end-user
12563
+ * display.
12360
12564
  *
12361
12565
  * Detection across package boundaries should rely on `error.name` rather than
12362
12566
  * `instanceof` to avoid issues with mixed module copies in bundled apps.
12363
- */ var GuardrailViolationError = /*#__PURE__*/ function(Error1) {
12567
+ */ /*#__PURE__*/ (function(Error1) {
12364
12568
  _inherits(GuardrailViolationError, Error1);
12365
12569
  function GuardrailViolationError(message) {
12366
12570
  _class_call_check(this, GuardrailViolationError);
@@ -12372,7 +12576,7 @@
12372
12576
  return _this;
12373
12577
  }
12374
12578
  return GuardrailViolationError;
12375
- }(_wrap_native_super(Error));
12579
+ })(_wrap_native_super(Error));
12376
12580
  /**
12377
12581
  * Reads a non-empty `message` field off a JSON-serialized error envelope.
12378
12582
  *
@@ -12464,6 +12668,7 @@
12464
12668
  }
12465
12669
  return fallbackInput;
12466
12670
  };
12671
+ var defaultGuardrailFallbackResponse = 'Sorry, we are not able to generate a response at the moment.';
12467
12672
  /**
12468
12673
  * Abstract base class for chat implementations.
12469
12674
  */ var AbstractChat = /*#__PURE__*/ function() {
@@ -13290,28 +13495,37 @@
13290
13495
  }
13291
13496
  break;
13292
13497
  }
13293
- // Surface guardrail violations through the error state, but
13294
- // distinct from generic cost-control / 4xx errors: throw a
13295
- // `GuardrailViolationError` so the UI can render the
13296
- // service-provided `fallbackResponse` verbatim (it's authored for
13297
- // end-user display) instead of the friendly default used for
13298
- // opaque transport errors. Also discard any in-progress assistant
13299
- // message so no partial text lingers above the fallback, and
13300
- // clear the local cursor so the `onFinish` callback doesn't
13301
- // receive a `currentMessage` that no longer exists in state.
13302
13498
  case 'data-guardrail-violation':
13303
13499
  {
13304
- isError = true;
13305
- if (currentMessageIndex >= 0) {
13306
- _this.state.messages = _this.state.messages.slice(0, currentMessageIndex);
13307
- currentMessage = undefined;
13308
- currentMessageIndex = -1;
13309
- }
13310
13500
  // `chunk.data` widens to `unknown` here: the chunk union also
13311
13501
  // carries a generic `data-${string}` member, and the literal
13312
13502
  // matches both, so narrowing can't pick the specific shape.
13313
13503
  var fallbackResponse = chunk.data.fallbackResponse;
13314
- throw new GuardrailViolationError(fallbackResponse || 'Sorry, we are not able to generate a response at the moment.');
13504
+ var fallbackText = fallbackResponse || defaultGuardrailFallbackResponse;
13505
+ // The stream closes after a guardrail violation; keep the
13506
+ // fallback as the current message so the normal finish path runs.
13507
+ currentMessage = {
13508
+ id: (currentMessage === null || currentMessage === void 0 ? void 0 : currentMessage.id) || currentMessageId || _this.generateId(),
13509
+ role: 'assistant',
13510
+ metadata: currentMessage === null || currentMessage === void 0 ? void 0 : currentMessage.metadata,
13511
+ parts: [
13512
+ {
13513
+ type: 'text',
13514
+ text: fallbackText,
13515
+ state: 'done'
13516
+ }
13517
+ ]
13518
+ };
13519
+ if (currentMessageIndex >= 0) {
13520
+ _this.state.replaceMessage(currentMessageIndex, currentMessage);
13521
+ } else {
13522
+ _this.state.pushMessage(currentMessage);
13523
+ currentMessageIndex = _this.state.messages.length - 1;
13524
+ }
13525
+ currentMessageId = currentMessage.id;
13526
+ currentTextPartId = undefined;
13527
+ currentReasoningPartId = undefined;
13528
+ break;
13315
13529
  }
13316
13530
  default:
13317
13531
  {
@@ -13446,7 +13660,7 @@
13446
13660
  var ChatState = /*#__PURE__*/ function() {
13447
13661
  function ChatState() {
13448
13662
  var _this = this;
13449
- var id = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : undefined, initialMessages = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : getDefaultInitialMessages(id);
13663
+ var id = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : undefined, initialMessages = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : undefined, persistence = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : true;
13450
13664
  _class_call_check(this, ChatState);
13451
13665
  _define_property(this, "_messages", void 0);
13452
13666
  _define_property(this, "_status", 'ready');
@@ -13506,7 +13720,16 @@
13506
13720
  return callback();
13507
13721
  });
13508
13722
  });
13509
- this._messages = initialMessages;
13723
+ if (initialMessages !== undefined) {
13724
+ this._messages = initialMessages;
13725
+ } else if (persistence) {
13726
+ this._messages = getDefaultInitialMessages(id);
13727
+ } else {
13728
+ this._messages = [];
13729
+ }
13730
+ if (!persistence) {
13731
+ return;
13732
+ }
13510
13733
  var saveMessagesInLocalStorage = function saveMessagesInLocalStorage() {
13511
13734
  if (_this.status === 'ready') {
13512
13735
  try {
@@ -13560,11 +13783,12 @@
13560
13783
  function Chat(_0) {
13561
13784
  _class_call_check(this, Chat);
13562
13785
  var _this;
13563
- var messages = _0.messages, agentId = _0.agentId, init = _object_without_properties(_0, [
13786
+ var messages = _0.messages, agentId = _0.agentId, _0_persistence = _0.persistence, persistence = _0_persistence === void 0 ? true : _0_persistence, init = _object_without_properties(_0, [
13564
13787
  "messages",
13565
- "agentId"
13788
+ "agentId",
13789
+ "persistence"
13566
13790
  ]);
13567
- var state = new ChatState(agentId, messages);
13791
+ var state = new ChatState(agentId, messages, persistence);
13568
13792
  _this = _call_super(this, Chat, [
13569
13793
  _object_spread_props(_object_spread({}, init), {
13570
13794
  state: state
@@ -23838,7 +24062,10 @@
23838
24062
  "isShowingMore",
23839
24063
  "translations"
23840
24064
  ]);
23841
- return /*#__PURE__*/ React.createElement("button", props, translations.showMoreButtonText({
24065
+ return /*#__PURE__*/ React.createElement("button", _object_spread_props(_object_spread({}, props), {
24066
+ "aria-expanded": isShowingMore,
24067
+ "aria-label": translations.showMoreButtonLabel
24068
+ }), translations.showMoreButtonText({
23842
24069
  isShowingMore: isShowingMore
23843
24070
  }));
23844
24071
  }
@@ -24368,6 +24595,7 @@
24368
24595
  currentPage: page + 1,
24369
24596
  nbPages: nbPages
24370
24597
  }),
24598
+ "aria-current": page === currentPage ? 'page' : undefined,
24371
24599
  href: createURL(page),
24372
24600
  onClick: function onClick() {
24373
24601
  return onNavigate(page);
@@ -24836,13 +25064,15 @@
24836
25064
  })), /*#__PURE__*/ React.createElement("button", {
24837
25065
  className: cx('ais-SearchBox-submit', classNames.submit),
24838
25066
  type: "submit",
24839
- title: translations.submitButtonTitle
25067
+ title: translations.submitButtonTitle,
25068
+ "aria-label": translations.submitButtonTitle
24840
25069
  }, /*#__PURE__*/ React.createElement(SubmitIcon, {
24841
25070
  classNames: classNames
24842
25071
  })), /*#__PURE__*/ React.createElement("button", {
24843
25072
  className: cx('ais-SearchBox-reset', classNames.reset),
24844
25073
  type: "reset",
24845
25074
  title: translations.resetButtonTitle,
25075
+ "aria-label": translations.resetButtonTitle,
24846
25076
  hidden: value.length === 0 || isSearchStalled
24847
25077
  }, /*#__PURE__*/ React.createElement(ResetIcon, {
24848
25078
  classNames: classNames
@@ -24954,7 +25184,8 @@
24954
25184
  onToggleShowMore: toggleShowMore,
24955
25185
  isShowingMore: isShowingMore,
24956
25186
  translations: {
24957
- showMoreButtonText: mergedTranslations.showMoreButtonText
25187
+ showMoreButtonText: mergedTranslations.showMoreButtonText,
25188
+ showMoreButtonLabel: translations === null || translations === void 0 ? void 0 : translations.showMoreButtonLabel
24958
25189
  }
24959
25190
  };
24960
25191
  return /*#__PURE__*/ React.createElement(RefinementList$1, _object_spread_props(_object_spread({}, props, uiProps), {
@@ -25178,6 +25409,21 @@
25178
25409
  return /*#__PURE__*/ React.createElement(SortBy$1, _object_spread({}, props, uiProps));
25179
25410
  }
25180
25411
 
25412
+ // Delay before announcing an update, so that rapid changes (e.g. typing in the
25413
+ // search box) settle into a single announcement instead of piling up. Mirrors
25414
+ // the debounce used by GOV.UK's accessible-autocomplete.
25415
+ var ANNOUNCEMENT_DELAY = 1400;
25416
+ var visuallyHiddenStyle = {
25417
+ position: 'absolute',
25418
+ width: 1,
25419
+ height: 1,
25420
+ padding: 0,
25421
+ margin: -1,
25422
+ overflow: 'hidden',
25423
+ clip: 'rect(0, 0, 0, 0)',
25424
+ whiteSpace: 'nowrap',
25425
+ border: 0
25426
+ };
25181
25427
  function Stats$1(_0) {
25182
25428
  var _0_classNames = _0.classNames, classNames = _0_classNames === void 0 ? {} : _0_classNames, nbHits = _0.nbHits, processingTimeMS = _0.processingTimeMS, nbSortedHits = _0.nbSortedHits, areHitsSorted = _0.areHitsSorted, translations = _0.translations, props = _object_without_properties(_0, [
25183
25429
  "classNames",
@@ -25193,11 +25439,37 @@
25193
25439
  nbSortedHits: nbSortedHits,
25194
25440
  areHitsSorted: areHitsSorted
25195
25441
  };
25442
+ var nextAnnouncement = translations.announcementText ? translations.announcementText(translationOptions) : '';
25443
+ var _useState = _sliced_to_array(React.useState(''), 2), announcement = _useState[0], setAnnouncement = _useState[1];
25444
+ var timerRef = React.useRef(undefined);
25445
+ var isInitialRef = React.useRef(true);
25446
+ React.useEffect(function() {
25447
+ // Don't announce the initial results, only subsequent changes.
25448
+ if (isInitialRef.current) {
25449
+ isInitialRef.current = false;
25450
+ return undefined;
25451
+ }
25452
+ clearTimeout(timerRef.current);
25453
+ timerRef.current = setTimeout(function() {
25454
+ setAnnouncement(nextAnnouncement);
25455
+ }, ANNOUNCEMENT_DELAY);
25456
+ return function() {
25457
+ return clearTimeout(timerRef.current);
25458
+ };
25459
+ }, [
25460
+ nextAnnouncement
25461
+ ]);
25196
25462
  return /*#__PURE__*/ React.createElement("div", _object_spread_props(_object_spread({}, props), {
25197
25463
  className: cx('ais-Stats', classNames.root, props.className)
25198
25464
  }), /*#__PURE__*/ React.createElement("span", {
25199
25465
  className: "ais-Stats-text"
25200
- }, translations.rootElementText(translationOptions)));
25466
+ }, translations.rootElementText(translationOptions)), /*#__PURE__*/ React.createElement("span", {
25467
+ className: "ais-Stats-announcement",
25468
+ role: "status",
25469
+ "aria-live": "polite",
25470
+ "aria-atomic": "true",
25471
+ style: visuallyHiddenStyle
25472
+ }, announcement));
25201
25473
  }
25202
25474
 
25203
25475
  function Stats(_0) {
@@ -25215,6 +25487,9 @@
25215
25487
  translations: _object_spread({
25216
25488
  rootElementText: function rootElementText(options) {
25217
25489
  return "".concat(options.areHitsSorted ? getSortedResultsSentence(options) : getResultsSentence(options), " found in ").concat(options.processingTimeMS.toLocaleString(), "ms");
25490
+ },
25491
+ announcementText: function announcementText(options) {
25492
+ return options.areHitsSorted ? getSortedResultsSentence(options) : getResultsSentence(options);
25218
25493
  }
25219
25494
  }, translations)
25220
25495
  };