@sonic-equipment/ui 0.0.21 → 0.0.22
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/algolia/algolia-active-filters.d.ts +1 -1
- package/dist/icons/arrows/right-arrow-filled-icon.d.ts +0 -1
- package/dist/index.d.ts +175 -25
- package/dist/index.js +1709 -156
- package/dist/product-listing/product-listing.d.ts +0 -18
- package/dist/product-listing/product-listing.stories.d.ts +1 -2
- package/dist/shared/providers/cart-provider.d.ts +6 -6
- package/dist/shared/types/cart.d.ts +4 -4
- package/dist/styles.css +93 -93
- package/package.json +22 -22
package/dist/index.js
CHANGED
|
@@ -1,8 +1,194 @@
|
|
|
1
|
+
import { useState, useEffect, useRef, useCallback, createContext, useContext, forwardRef, Children, cloneElement, createElement } from 'react';
|
|
1
2
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
3
|
-
import { Button as Button$1, FieldError as FieldError$1, useContextProps, InputContext, Input as Input$1, Label as Label$1, NumberField as NumberField$1, Link, Checkbox as Checkbox$1, Select as Select$1, SelectValue, Popover, ListBox, Section, Header, ListBoxItem, TextAreaContext, TextArea as TextArea$1, TextField as TextField$1 } from 'react-aria-components';
|
|
3
|
+
import { Button as Button$1, Link, FieldError as FieldError$1, useContextProps, InputContext, Input as Input$1, Label as Label$1, NumberField as NumberField$1, Checkbox as Checkbox$1, Select as Select$1, SelectValue, Popover, ListBox, Section, Header, ListBoxItem, TextAreaContext, TextArea as TextArea$1, TextField as TextField$1 } from 'react-aria-components';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
-
import { useCurrentRefinements, useClearRefinements, useRefinementList, useHits, useDynamicWidgets, usePagination, useSortBy } from 'react-instantsearch';
|
|
5
|
+
import { useCurrentRefinements, useClearRefinements, useRefinementList, useHits, useDynamicWidgets, usePagination, useSortBy, InstantSearch, Configure } from 'react-instantsearch';
|
|
6
|
+
import require$$5 from '@algolia/client-search';
|
|
7
|
+
import * as http from 'http';
|
|
8
|
+
import { Agent } from 'http';
|
|
9
|
+
import * as https from 'https';
|
|
10
|
+
import { Agent as Agent$1 } from 'https';
|
|
11
|
+
import { parse } from 'url';
|
|
12
|
+
|
|
13
|
+
const useBreakpoint = () => {
|
|
14
|
+
const [device, setDevice] = useState({
|
|
15
|
+
isDesktop: false,
|
|
16
|
+
isMobile: true,
|
|
17
|
+
isTablet: false,
|
|
18
|
+
});
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const handleResize = () => {
|
|
21
|
+
setDevice({
|
|
22
|
+
isDesktop: window.innerWidth >= 1024,
|
|
23
|
+
isMobile: window.innerWidth < 768,
|
|
24
|
+
isTablet: window.innerWidth >= 768 && window.innerWidth < 1024,
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
handleResize();
|
|
28
|
+
window.addEventListener('resize', handleResize);
|
|
29
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
30
|
+
}, []);
|
|
31
|
+
return device;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
function useDebouncedCallback(func, delay) {
|
|
36
|
+
const timeoutId = useRef();
|
|
37
|
+
return function debounced(...args) {
|
|
38
|
+
clearTimeout(timeoutId.current);
|
|
39
|
+
timeoutId.current = setTimeout(() => {
|
|
40
|
+
func(...args);
|
|
41
|
+
}, delay);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const useDisclosure = () => {
|
|
46
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
47
|
+
const open = useCallback(() => {
|
|
48
|
+
setIsOpen(true);
|
|
49
|
+
}, []);
|
|
50
|
+
const close = useCallback(() => {
|
|
51
|
+
setIsOpen(false);
|
|
52
|
+
}, []);
|
|
53
|
+
const toggle = useCallback(() => {
|
|
54
|
+
setIsOpen(prevIsOpen => !prevIsOpen);
|
|
55
|
+
}, []);
|
|
56
|
+
return {
|
|
57
|
+
close,
|
|
58
|
+
isClosed: !isOpen,
|
|
59
|
+
isOpen,
|
|
60
|
+
open,
|
|
61
|
+
toggle,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const useScrollLock = (lock) => {
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (lock) {
|
|
68
|
+
document.body.style.overflow = 'hidden';
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
document.body.style.overflow = 'auto';
|
|
72
|
+
}
|
|
73
|
+
}, [lock]);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
class EventEmitter {
|
|
77
|
+
constructor() {
|
|
78
|
+
Object.defineProperty(this, "listeners", {
|
|
79
|
+
enumerable: true,
|
|
80
|
+
configurable: true,
|
|
81
|
+
writable: true,
|
|
82
|
+
value: void 0
|
|
83
|
+
});
|
|
84
|
+
this.listeners = new Map();
|
|
85
|
+
}
|
|
86
|
+
addEventListener(event, listener) {
|
|
87
|
+
if (!this.listeners.has(event)) {
|
|
88
|
+
this.listeners.set(event, []);
|
|
89
|
+
}
|
|
90
|
+
this.listeners.get(event).push(listener);
|
|
91
|
+
}
|
|
92
|
+
removeEventListener(event, listener) {
|
|
93
|
+
const listeners = this.listeners.get(event);
|
|
94
|
+
if (!listeners)
|
|
95
|
+
return;
|
|
96
|
+
const index = listeners.indexOf(listener);
|
|
97
|
+
if (index !== -1) {
|
|
98
|
+
listeners.splice(index, 1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
trigger(event, data) {
|
|
102
|
+
const listeners = this.listeners.get(event);
|
|
103
|
+
if (!listeners)
|
|
104
|
+
return;
|
|
105
|
+
listeners.forEach(listener => listener(data));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
class State extends EventEmitter {
|
|
110
|
+
constructor(state) {
|
|
111
|
+
super();
|
|
112
|
+
Object.defineProperty(this, "_state", {
|
|
113
|
+
enumerable: true,
|
|
114
|
+
configurable: true,
|
|
115
|
+
writable: true,
|
|
116
|
+
value: void 0
|
|
117
|
+
});
|
|
118
|
+
this._state = state;
|
|
119
|
+
}
|
|
120
|
+
get value() {
|
|
121
|
+
return this._state;
|
|
122
|
+
}
|
|
123
|
+
set value(newState) {
|
|
124
|
+
this._state = newState;
|
|
125
|
+
this.trigger('stateChanged', this._state);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
class GlobalState {
|
|
129
|
+
constructor(
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
131
|
+
states) {
|
|
132
|
+
Object.defineProperty(this, "states", {
|
|
133
|
+
enumerable: true,
|
|
134
|
+
configurable: true,
|
|
135
|
+
writable: true,
|
|
136
|
+
value: states
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
get(key, initialState) {
|
|
140
|
+
return (this.states.current[key] ||
|
|
141
|
+
(this.states.current[key] = new State(initialState)));
|
|
142
|
+
}
|
|
143
|
+
set(key, state) {
|
|
144
|
+
this.states.current[key] = state;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const GlobalStateProviderContext = createContext(undefined);
|
|
148
|
+
function GlobalStateProvider({ children, }) {
|
|
149
|
+
const internalState = useRef({});
|
|
150
|
+
const globalState = useRef(new GlobalState(internalState));
|
|
151
|
+
return (jsx(GlobalStateProviderContext.Provider, { value: globalState.current, children: children }));
|
|
152
|
+
}
|
|
153
|
+
function useGlobalState(key, initialState) {
|
|
154
|
+
const state = useContext(GlobalStateProviderContext).get(key, initialState);
|
|
155
|
+
const [rerenderState, setRerenderState] = useState(state.value);
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
state.addEventListener('stateChanged', setRerenderState);
|
|
158
|
+
return () => {
|
|
159
|
+
state.removeEventListener('stateChanged', setRerenderState);
|
|
160
|
+
};
|
|
161
|
+
}, [state]);
|
|
162
|
+
return [rerenderState, (value) => (state.value = value)];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function CartProvider(props) {
|
|
166
|
+
const [, updateState] = useGlobalState('cart', props);
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
updateState(props);
|
|
169
|
+
}, [props, updateState]);
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
function useCart() {
|
|
173
|
+
const [state] = useGlobalState('cart');
|
|
174
|
+
if (!state) {
|
|
175
|
+
throw new Error('useCart must be used together with the ReduxCartProvider');
|
|
176
|
+
}
|
|
177
|
+
return state;
|
|
178
|
+
}
|
|
179
|
+
function useProductCartLine(productId) {
|
|
180
|
+
const { addToCart, currentCart, isLoaded, isLoading, loadCurrentCart, removeCartLine, updateCartLine, } = useCart();
|
|
181
|
+
return {
|
|
182
|
+
addToCart,
|
|
183
|
+
cartLine: currentCart?.cartLines?.find(cl => cl.productId === productId),
|
|
184
|
+
currentCart,
|
|
185
|
+
isLoaded,
|
|
186
|
+
isLoading,
|
|
187
|
+
loadCurrentCart,
|
|
188
|
+
removeCartLine,
|
|
189
|
+
updateCartLine,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
6
192
|
|
|
7
193
|
function RightArrowFilledIcon(props) {
|
|
8
194
|
return (jsx("svg", { height: "11", viewBox: "0 0 6 11", width: "6", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M.267 11a.263.263 0 0 1-.226-.402l3.463-5.467a1.2 1.2 0 0 0-.103-1.43L.602.432A.262.262 0 0 1 .805 0h2.181c.078 0 .153.034.203.093l2.081 2.43a3 3 0 0 1 .259 3.575L2.5 10.877a.267.267 0 0 1-.225.123H.266z", fill: "currentColor", fillRule: "evenodd" }) }));
|
|
@@ -16,13 +202,44 @@ function Button({ _pseudo = 'none', children, className, color = 'primary', cond
|
|
|
16
202
|
return (jsxs(Button$1, { className: clsx(className, styles$r.button, styles$r[variant], styles$r[size], styles$r[color], { [styles$r.condensed]: condensed }, { [styles$r.icon]: icon }, styles$r[_pseudo]), isDisabled: isDisabled, onPress: onPress, type: type, children: [icon && iconPosition === 'left' && (jsx("span", { className: styles$r.icon, children: icon })), children, withArrow && (jsx(RightArrowFilledIcon, { className: styles$r['right-arrow-icon'] })), icon && iconPosition === 'right' && (jsx("span", { className: styles$r.icon, children: icon }))] }));
|
|
17
203
|
}
|
|
18
204
|
|
|
19
|
-
var styles$q = {"
|
|
205
|
+
var styles$q = {"icon-button":"icon-button-module-4PDK-","md":"icon-button-module-k3s9J","lg":"icon-button-module-agk6Y","primary":"icon-button-module-fTeP4","secondary":"icon-button-module-dM0eo"};
|
|
206
|
+
|
|
207
|
+
function IconButton({ children, className, color = 'primary', isDisabled, onPress, size = 'md', }) {
|
|
208
|
+
return (jsx(Button$1, { className: clsx(styles$q['icon-button'], styles$q[size], styles$q[color], className), isDisabled: isDisabled, onPress: onPress, children: children }));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function FavoriteFilledIcon(props) {
|
|
212
|
+
return (jsx("svg", { height: "24", viewBox: "0 0 24 24", width: "24", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M12 22a.667.667 0 0 1-.534-.267L3.227 10.72C2.411 9.599 2 8.46 2 7.327A5.336 5.336 0 0 1 7.333 2c1.892 0 3.669.982 4.667 2.468C12.998 2.982 14.775 2 16.667 2 19.607 2 22 4.39 22 7.327c0 1.133-.411 2.272-1.222 3.387l-8.244 11.019A.667.667 0 0 1 12 22", fill: "currentColor", fillRule: "evenodd" }) }));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function FavoriteOutlinedIcon(props) {
|
|
216
|
+
return (jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M7.333 3.33c-2.206 0-4 1.793-4 3.997 0 .857.316 1.71.967 2.604L12 20.223l7.705-10.299c.646-.888.962-1.74.962-2.597a4.003 4.003 0 0 0-4-3.996c-1.813 0-3.545 1.232-4.028 2.865a.666.666 0 0 1-1.278 0C10.878 4.563 9.146 3.33 7.333 3.33M12 22c-.21 0-.408-.1-.534-.267L3.227 10.72C2.411 9.599 2 8.46 2 7.327A5.336 5.336 0 0 1 7.333 2c1.892 0 3.669.982 4.667 2.468C12.998 2.982 14.775 2 16.667 2 19.607 2 22 4.39 22 7.327c0 1.133-.411 2.272-1.222 3.387l-8.245 11.019A.667.667 0 0 1 12 22", fill: "currentColor", fillRule: "evenodd" }) }));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
var styles$p = {"favorite-button":"favorite-button-module-tXSS3","is-favorite":"favorite-button-module-l557q"};
|
|
220
|
+
|
|
221
|
+
function FavoriteButton({ isFavorite, onPress }) {
|
|
222
|
+
return (jsx(IconButton, { className: clsx(styles$p['favorite-button'], {
|
|
223
|
+
[styles$p['is-favorite']]: isFavorite,
|
|
224
|
+
}), color: "secondary", onPress: onPress, children: isFavorite ? jsx(FavoriteFilledIcon, {}) : jsx(FavoriteOutlinedIcon, {}) }));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
var styles$o = {"link-button":"link-button-module-6i75g"};
|
|
228
|
+
|
|
229
|
+
function LinkButton({ children, className, href, isDisabled, onPress, target, }) {
|
|
230
|
+
if (href) {
|
|
231
|
+
return (jsx(Link, { className: clsx(styles$o['link-button'], className), href: href, isDisabled: isDisabled, onPress: onPress, target: target, children: children }));
|
|
232
|
+
}
|
|
233
|
+
return (jsx(Button$1, { className: clsx(styles$o['link-button'], className), isDisabled: isDisabled, onPress: onPress, type: "button", children: children }));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
var styles$n = {"field-error":"field-error-module-FXnIg"};
|
|
20
237
|
|
|
21
238
|
function FieldError({ children }) {
|
|
22
|
-
return (jsx(FieldError$1, { className: styles$
|
|
239
|
+
return (jsx(FieldError$1, { className: styles$n['field-error'], children: children }));
|
|
23
240
|
}
|
|
24
241
|
|
|
25
|
-
var styles$
|
|
242
|
+
var styles$m = {"input-container":"input-module-2woJR","shadow-input":"input-module-pNKEt","lg":"input-module-Dx2qC","md":"input-module-sH6e7","focus":"input-module-hEEuy","growing-input":"input-module-6HwY4"};
|
|
26
243
|
|
|
27
244
|
/**
|
|
28
245
|
* This component is used to create an input that grows as the user types.
|
|
@@ -37,33 +254,33 @@ const Input = forwardRef(({ _pseudo = 'none', autoGrow, size = 'lg', ...inputPro
|
|
|
37
254
|
const handleChange = (event) => isControlled
|
|
38
255
|
? onChange?.(event)
|
|
39
256
|
: setUncontrolledValue(event.target.value);
|
|
40
|
-
return (jsx("div", { className: clsx(styles$
|
|
257
|
+
return (jsx("div", { className: clsx(styles$m['input-container'], styles$m[size], styles$m[_pseudo]), children: jsxs("div", { className: clsx({ [styles$m['growing-input']]: autoGrow }), children: [jsx(Input$1, { size: autoGrow ? 1 : undefined, ...props, ref: ref, onChange: handleChange }), autoGrow && jsx("span", { className: styles$m['shadow-input'], children: value })] }) }));
|
|
41
258
|
});
|
|
42
259
|
Input.displayName = 'Input';
|
|
43
260
|
|
|
44
|
-
var styles$
|
|
261
|
+
var styles$l = {"label":"label-module-LGfJt","required":"label-module-oTWaS"};
|
|
45
262
|
|
|
46
263
|
function Label({ children, isRequired }) {
|
|
47
264
|
if (!children)
|
|
48
265
|
return null;
|
|
49
|
-
return (jsxs(Label$1, { className: styles$
|
|
266
|
+
return (jsxs(Label$1, { className: styles$l.label, children: [children, isRequired && jsx("span", { className: styles$l.required, children: "*" })] }));
|
|
50
267
|
}
|
|
51
268
|
|
|
52
|
-
var styles$
|
|
269
|
+
var styles$k = {"field":"number-field-module-gmnog","button-input-container":"number-field-module-8Lvgh"};
|
|
53
270
|
|
|
54
271
|
/**
|
|
55
272
|
* This component is used to create a number field.
|
|
56
273
|
* This field can also grow when a user types in text.
|
|
57
274
|
*/
|
|
58
275
|
function NumberField({ autoFocus, autoGrow, defaultValue, formatOptions = { style: 'decimal', useGrouping: false }, isDisabled, isInvalid, isReadOnly, isRequired, label, maxLength, maxValue, minValue, name, onChange, onInput, onKeyUp, placeholder, showLabel = false, size = 'lg', value, withButtons, }) {
|
|
59
|
-
return (jsxs(NumberField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles$
|
|
276
|
+
return (jsxs(NumberField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles$k.field, styles$k[size]), defaultValue: defaultValue, formatOptions: formatOptions, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxValue: maxValue, minValue: minValue, name: name, onChange: onChange, onInput: onInput, onKeyUp: e => onKeyUp?.(e), value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), jsxs("div", { className: styles$k['button-input-container'], children: [withButtons && jsx(Button$1, { slot: "decrement", children: "-" }), jsx(Input, { autoGrow: autoGrow, maxLength: maxLength, placeholder: placeholder, size: size }), withButtons && jsx(Button$1, { slot: "increment", children: "+" })] }), jsx(FieldError, {})] }));
|
|
60
277
|
}
|
|
61
278
|
|
|
62
279
|
function CartFilledIcon(props) {
|
|
63
280
|
return (jsx("svg", { height: "24", viewBox: "0 0 24 24", width: "24", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M7.896 16.666a2.603 2.603 0 1 1 0 5.207 2.603 2.603 0 0 1 0-5.207zm8.925 0a2.603 2.603 0 1 1 0 5.207 2.603 2.603 0 0 1 0-5.207zM7.896 18.1c-.645 0-1.17.524-1.17 1.169s.525 1.17 1.17 1.17a1.171 1.171 0 0 0 0-2.34zm8.925 0c-.645 0-1.17.524-1.17 1.169s.525 1.17 1.17 1.17a1.171 1.171 0 0 0 0-2.34zM4.589 3c.016 0 .032.004.048.005a.714.714 0 0 1 .146.025l.05.016a.7.7 0 0 1 .083.037l.04.021a.712.712 0 0 1 .076.053l.035.03a.699.699 0 0 1 .168.223.703.703 0 0 1 .061.209c.002.014.007.027.008.042l.207 2.646h15.776c.027.001.05.006.073.008.026.003.052.004.077.01.022.004.036.011.05.016.03.008.058.016.085.028.02.009.037.02.056.03.022.012.044.024.065.038.019.013.035.029.053.044.017.015.036.029.052.046.015.016.028.034.042.051.015.019.03.037.044.057.011.018.02.038.03.057.012.021.024.042.033.065.009.022.014.044.021.067.006.022.014.043.018.066.006.027.007.054.009.081.001.018.005.035.005.053-.001.031-.005.054-.008.077-.003.026-.004.052-.01.077l-1.39 6.054-.004.017a.698.698 0 0 1-.033.1l-.008.024a.716.716 0 0 1-.06.11l-.024.03a.707.707 0 0 1-.057.07l-.035.033a.695.695 0 0 1-.175.117l-.048.022a.723.723 0 0 1-.083.026c-.014.003-.027.008-.041.01a.707.707 0 0 1-.134.014H6.096l.112 1.427H19.41a.717.717 0 0 1 0 1.434H5.544a.714.714 0 0 1-.14-.015c-.015-.003-.03-.008-.044-.012-.03-.008-.06-.016-.087-.027-.018-.008-.034-.017-.05-.026-.024-.012-.048-.023-.07-.037-.016-.011-.03-.024-.046-.036-.02-.016-.04-.03-.058-.048-.015-.014-.027-.03-.04-.044-.017-.02-.033-.038-.048-.058-.012-.017-.021-.034-.032-.052a.678.678 0 0 1-.035-.065c-.009-.02-.016-.04-.023-.06a.715.715 0 0 1-.033-.136l-.008-.045-.904-11.571H2.717a.717.717 0 1 1 0-1.434z", fill: "currentColor", fillRule: "evenodd" }) }));
|
|
64
281
|
}
|
|
65
282
|
|
|
66
|
-
var styles$
|
|
283
|
+
var styles$j = {"manual-input-container":"add-to-cart-button-module-AWFvQ","left-button-spacer":"add-to-cart-button-module-SS7WM"};
|
|
67
284
|
|
|
68
285
|
function AddToCartButton({ initialState = 'initial', onChange, quantity, }) {
|
|
69
286
|
const [currentState, setState] = useState(initialState);
|
|
@@ -125,43 +342,59 @@ function ManualInputState({ onCancel, onConfirm, quantity, }) {
|
|
|
125
342
|
e.key === 'Enter' && onConfirm(updatedQuantity);
|
|
126
343
|
e.key === 'Escape' && onCancel();
|
|
127
344
|
};
|
|
128
|
-
return (jsxs("div", { className: styles$
|
|
345
|
+
return (jsxs("div", { className: styles$j['manual-input-container'], children: [jsx("div", { className: styles$j['left-button-spacer'] }), jsx(NumberField, { autoFocus: true, autoGrow: true, defaultValue: quantity, formatOptions: {
|
|
129
346
|
maximumFractionDigits: 0,
|
|
130
347
|
style: 'decimal',
|
|
131
348
|
useGrouping: false,
|
|
132
349
|
}, label: "Quantity", maxLength: 4, maxValue: 9999, minValue: 0, name: "quantity", onChange: setQuantity, onKeyUp: onKeyUp, showLabel: false, size: "md" }), jsx(Button, { condensed: true, onPress: () => onConfirm(updatedQuantity), size: "md", children: "OK" })] }));
|
|
133
350
|
}
|
|
134
351
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
352
|
+
const ConnectedAddToCartButton = ({ productId }) => {
|
|
353
|
+
const [quantity, setQuantity] = useState(0);
|
|
354
|
+
const { addToCart, cartLine: _cartLine, isLoaded, isLoading, loadCurrentCart, removeCartLine, updateCartLine, } = useProductCartLine(productId);
|
|
355
|
+
const [cartLine, setCartLineState] = useState(_cartLine);
|
|
356
|
+
const setCartLineStateDebounced = useDebouncedCallback(setCartLineState, 4000);
|
|
357
|
+
useEffect(() => {
|
|
358
|
+
if (isLoading || isLoaded)
|
|
359
|
+
return;
|
|
360
|
+
loadCurrentCart();
|
|
361
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
362
|
+
}, []);
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
setQuantity(cartLine?.qtyOrdered || 0);
|
|
365
|
+
}, [cartLine]);
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
/* Debounce updating the internal cart line state.
|
|
368
|
+
* This is necessary when a user mutates the cart multiple times in quick succession.
|
|
369
|
+
* A response from the server may take a while to come back, so we need to wait for it.
|
|
370
|
+
* If we don't debounce, the cart line state will be updated multiple times, causing the UI to flicker.
|
|
371
|
+
*/
|
|
372
|
+
if (!cartLine) {
|
|
373
|
+
setCartLineState(_cartLine);
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
setCartLineStateDebounced(_cartLine);
|
|
377
|
+
}
|
|
378
|
+
}, [_cartLine, cartLine, setCartLineStateDebounced]);
|
|
379
|
+
const updateCart = useDebouncedCallback((quantity) => {
|
|
380
|
+
if (cartLine) {
|
|
381
|
+
if (quantity === 0) {
|
|
382
|
+
removeCartLine({ cartLineId: cartLine.id });
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
updateCartLine({ ...cartLine, qtyOrdered: quantity });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
addToCart({ productId, quantity });
|
|
390
|
+
}
|
|
391
|
+
}, 300);
|
|
392
|
+
const handleChange = (quantity) => {
|
|
393
|
+
setQuantity(quantity);
|
|
394
|
+
updateCart(quantity);
|
|
395
|
+
};
|
|
396
|
+
return jsx(AddToCartButton, { onChange: handleChange, quantity: quantity });
|
|
397
|
+
};
|
|
165
398
|
|
|
166
399
|
var styles$i = {"tag":"tag-module-B7r15","body":"tag-module-4cfCf","shape":"tag-module-c7CRb"};
|
|
167
400
|
|
|
@@ -473,26 +706,6 @@ function AlgoliaCategories() {
|
|
|
473
706
|
return (jsx("div", { children: categories?.length > 0 && (jsxs("section", { className: styles$3['categories-section'], children: [jsx("h4", { className: styles$3['categories-header'], children: "Categories" }), jsx("div", { className: styles$3.categories, children: categories.map(({ count, href, id, name }) => (jsxs("a", { className: styles$3['category'], href: href, children: [jsx("span", { children: name }), ' ', jsxs("span", { className: styles$3.count, children: ["(", count, ")"] })] }, id))) })] })) }));
|
|
474
707
|
}
|
|
475
708
|
|
|
476
|
-
const useDisclosure = () => {
|
|
477
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
478
|
-
const open = useCallback(() => {
|
|
479
|
-
setIsOpen(true);
|
|
480
|
-
}, []);
|
|
481
|
-
const close = useCallback(() => {
|
|
482
|
-
setIsOpen(false);
|
|
483
|
-
}, []);
|
|
484
|
-
const toggle = useCallback(() => {
|
|
485
|
-
setIsOpen(prevIsOpen => !prevIsOpen);
|
|
486
|
-
}, []);
|
|
487
|
-
return {
|
|
488
|
-
close,
|
|
489
|
-
isClosed: !isOpen,
|
|
490
|
-
isOpen,
|
|
491
|
-
open,
|
|
492
|
-
toggle,
|
|
493
|
-
};
|
|
494
|
-
};
|
|
495
|
-
|
|
496
709
|
function AlgoliaMultiSelect({ attribute }) {
|
|
497
710
|
const { items, refine } = useRefinementList({
|
|
498
711
|
attribute,
|
|
@@ -560,98 +773,6 @@ function AlgoliaSortBy() {
|
|
|
560
773
|
return (jsx(Select, { label: "Sort", onChange: value => refine(String(value)), options: options, selectedOption: "dev_sonic_products_en", showLabel: false }));
|
|
561
774
|
}
|
|
562
775
|
|
|
563
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
564
|
-
function useDebouncedCallback(func, delay) {
|
|
565
|
-
const timeoutId = useRef();
|
|
566
|
-
return function debounced(...args) {
|
|
567
|
-
clearTimeout(timeoutId.current);
|
|
568
|
-
timeoutId.current = setTimeout(() => {
|
|
569
|
-
func(...args);
|
|
570
|
-
}, delay);
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
const GlobalStateProviderContext = createContext(undefined);
|
|
575
|
-
function useGlobalState(key, initialState) {
|
|
576
|
-
const state = useContext(GlobalStateProviderContext).get(key, initialState);
|
|
577
|
-
const [rerenderState, setRerenderState] = useState(state.value);
|
|
578
|
-
useEffect(() => {
|
|
579
|
-
state.addEventListener('stateChanged', setRerenderState);
|
|
580
|
-
return () => {
|
|
581
|
-
state.removeEventListener('stateChanged', setRerenderState);
|
|
582
|
-
};
|
|
583
|
-
}, [state]);
|
|
584
|
-
return [rerenderState, (value) => (state.value = value)];
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function useCart() {
|
|
588
|
-
const [state] = useGlobalState('cart');
|
|
589
|
-
if (!state) {
|
|
590
|
-
throw new Error('useCart must be used together with the ReduxCartProvider');
|
|
591
|
-
}
|
|
592
|
-
return state;
|
|
593
|
-
}
|
|
594
|
-
function useProductCartLine(productId) {
|
|
595
|
-
const { addToCart, currentCart, isLoaded, isLoading, loadCurrentCart, removeCartLine, updateCartLine, } = useCart();
|
|
596
|
-
return {
|
|
597
|
-
addToCart,
|
|
598
|
-
cartLine: currentCart?.cartLines?.find(cl => cl.productId === productId),
|
|
599
|
-
currentCart,
|
|
600
|
-
isLoaded,
|
|
601
|
-
isLoading,
|
|
602
|
-
loadCurrentCart,
|
|
603
|
-
removeCartLine,
|
|
604
|
-
updateCartLine,
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
const ConnectedAddToCartButton = ({ productId }) => {
|
|
609
|
-
const [quantity, setQuantity] = useState(0);
|
|
610
|
-
const { addToCart, cartLine: _cartLine, isLoaded, isLoading, loadCurrentCart, removeCartLine, updateCartLine, } = useProductCartLine(productId);
|
|
611
|
-
const [cartLine, setCartLineState] = useState(_cartLine);
|
|
612
|
-
const setCartLineStateDebounced = useDebouncedCallback(setCartLineState, 4000);
|
|
613
|
-
useEffect(() => {
|
|
614
|
-
if (isLoading || isLoaded)
|
|
615
|
-
return;
|
|
616
|
-
loadCurrentCart();
|
|
617
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
618
|
-
}, []);
|
|
619
|
-
useEffect(() => {
|
|
620
|
-
setQuantity(cartLine?.qtyOrdered || 0);
|
|
621
|
-
}, [cartLine]);
|
|
622
|
-
useEffect(() => {
|
|
623
|
-
/* Debounce updating the internal cart line state.
|
|
624
|
-
* This is necessary when a user mutates the cart multiple times in quick succession.
|
|
625
|
-
* A response from the server may take a while to come back, so we need to wait for it.
|
|
626
|
-
* If we don't debounce, the cart line state will be updated multiple times, causing the UI to flicker.
|
|
627
|
-
*/
|
|
628
|
-
if (!cartLine) {
|
|
629
|
-
setCartLineState(_cartLine);
|
|
630
|
-
}
|
|
631
|
-
else {
|
|
632
|
-
setCartLineStateDebounced(_cartLine);
|
|
633
|
-
}
|
|
634
|
-
}, [_cartLine, cartLine, setCartLineStateDebounced]);
|
|
635
|
-
const updateCart = useDebouncedCallback((quantity) => {
|
|
636
|
-
if (cartLine) {
|
|
637
|
-
if (quantity === 0) {
|
|
638
|
-
removeCartLine({ cartLineId: cartLine.id });
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
updateCartLine({ ...cartLine, qtyOrdered: quantity });
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
addToCart({ productId, quantity });
|
|
646
|
-
}
|
|
647
|
-
}, 300);
|
|
648
|
-
const handleChange = (quantity) => {
|
|
649
|
-
setQuantity(quantity);
|
|
650
|
-
updateCart(quantity);
|
|
651
|
-
};
|
|
652
|
-
return jsx(AddToCartButton, { onChange: handleChange, quantity: quantity });
|
|
653
|
-
};
|
|
654
|
-
|
|
655
776
|
function ConnectedProductCart({ productId, ...props }) {
|
|
656
777
|
return (jsx(ProductCard, { ...props, addToCartButton: jsx(ConnectedAddToCartButton, { productId: productId }) }));
|
|
657
778
|
}
|
|
@@ -738,4 +859,1436 @@ function parseProductListingSearchParams(params) {
|
|
|
738
859
|
};
|
|
739
860
|
}
|
|
740
861
|
|
|
741
|
-
|
|
862
|
+
function AlgoliaProductList() {
|
|
863
|
+
const r = useHits();
|
|
864
|
+
const { hits } = r;
|
|
865
|
+
r.results?.nbHits;
|
|
866
|
+
return (jsxs("div", { children: [jsx("h2", { children: "Product List" }), hits.map(hit => (jsxs("div", { children: [jsx("h3", { children: hit.name }), jsxs("div", { children: ["W x H x L: ", hit.width, " x ", hit.height, " x ", hit.length] })] }, hit.objectID)))] }));
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function getDefaultExportFromCjs (x) {
|
|
870
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
function getAugmentedNamespace(n) {
|
|
874
|
+
if (n.__esModule) return n;
|
|
875
|
+
var f = n.default;
|
|
876
|
+
if (typeof f == "function") {
|
|
877
|
+
var a = function a () {
|
|
878
|
+
if (this instanceof a) {
|
|
879
|
+
return Reflect.construct(f, arguments, this.constructor);
|
|
880
|
+
}
|
|
881
|
+
return f.apply(this, arguments);
|
|
882
|
+
};
|
|
883
|
+
a.prototype = f.prototype;
|
|
884
|
+
} else a = {};
|
|
885
|
+
Object.defineProperty(a, '__esModule', {value: true});
|
|
886
|
+
Object.keys(n).forEach(function (k) {
|
|
887
|
+
var d = Object.getOwnPropertyDescriptor(n, k);
|
|
888
|
+
Object.defineProperty(a, k, d.get ? d : {
|
|
889
|
+
enumerable: true,
|
|
890
|
+
get: function () {
|
|
891
|
+
return n[k];
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
});
|
|
895
|
+
return a;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
var algoliasearch$3 = {exports: {}};
|
|
899
|
+
|
|
900
|
+
// @todo Add logger on options to debug when caches go wrong.
|
|
901
|
+
function createFallbackableCache(options) {
|
|
902
|
+
const caches = [...options.caches];
|
|
903
|
+
const current = caches.shift(); // eslint-disable-line functional/immutable-data
|
|
904
|
+
if (current === undefined) {
|
|
905
|
+
return createNullCache();
|
|
906
|
+
}
|
|
907
|
+
return {
|
|
908
|
+
get(key, defaultValue, events = {
|
|
909
|
+
miss: () => Promise.resolve(),
|
|
910
|
+
}) {
|
|
911
|
+
return current.get(key, defaultValue, events).catch(() => {
|
|
912
|
+
return createFallbackableCache({ caches }).get(key, defaultValue, events);
|
|
913
|
+
});
|
|
914
|
+
},
|
|
915
|
+
set(key, value) {
|
|
916
|
+
return current.set(key, value).catch(() => {
|
|
917
|
+
return createFallbackableCache({ caches }).set(key, value);
|
|
918
|
+
});
|
|
919
|
+
},
|
|
920
|
+
delete(key) {
|
|
921
|
+
return current.delete(key).catch(() => {
|
|
922
|
+
return createFallbackableCache({ caches }).delete(key);
|
|
923
|
+
});
|
|
924
|
+
},
|
|
925
|
+
clear() {
|
|
926
|
+
return current.clear().catch(() => {
|
|
927
|
+
return createFallbackableCache({ caches }).clear();
|
|
928
|
+
});
|
|
929
|
+
},
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function createNullCache() {
|
|
934
|
+
return {
|
|
935
|
+
get(_key, defaultValue, events = {
|
|
936
|
+
miss: () => Promise.resolve(),
|
|
937
|
+
}) {
|
|
938
|
+
const value = defaultValue();
|
|
939
|
+
return value
|
|
940
|
+
.then(result => Promise.all([result, events.miss(result)]))
|
|
941
|
+
.then(([result]) => result);
|
|
942
|
+
},
|
|
943
|
+
set(_key, value) {
|
|
944
|
+
return Promise.resolve(value);
|
|
945
|
+
},
|
|
946
|
+
delete(_key) {
|
|
947
|
+
return Promise.resolve();
|
|
948
|
+
},
|
|
949
|
+
clear() {
|
|
950
|
+
return Promise.resolve();
|
|
951
|
+
},
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
var cacheCommon_esm = /*#__PURE__*/Object.freeze({
|
|
956
|
+
__proto__: null,
|
|
957
|
+
createFallbackableCache: createFallbackableCache,
|
|
958
|
+
createNullCache: createNullCache
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
var require$$0 = /*@__PURE__*/getAugmentedNamespace(cacheCommon_esm);
|
|
962
|
+
|
|
963
|
+
function createInMemoryCache(options = { serializable: true }) {
|
|
964
|
+
// eslint-disable-next-line functional/no-let
|
|
965
|
+
let cache = {};
|
|
966
|
+
return {
|
|
967
|
+
get(key, defaultValue, events = {
|
|
968
|
+
miss: () => Promise.resolve(),
|
|
969
|
+
}) {
|
|
970
|
+
const keyAsString = JSON.stringify(key);
|
|
971
|
+
if (keyAsString in cache) {
|
|
972
|
+
return Promise.resolve(options.serializable ? JSON.parse(cache[keyAsString]) : cache[keyAsString]);
|
|
973
|
+
}
|
|
974
|
+
const promise = defaultValue();
|
|
975
|
+
const miss = (events && events.miss) || (() => Promise.resolve());
|
|
976
|
+
return promise.then((value) => miss(value)).then(() => promise);
|
|
977
|
+
},
|
|
978
|
+
set(key, value) {
|
|
979
|
+
// eslint-disable-next-line functional/immutable-data
|
|
980
|
+
cache[JSON.stringify(key)] = options.serializable ? JSON.stringify(value) : value;
|
|
981
|
+
return Promise.resolve(value);
|
|
982
|
+
},
|
|
983
|
+
delete(key) {
|
|
984
|
+
// eslint-disable-next-line functional/immutable-data
|
|
985
|
+
delete cache[JSON.stringify(key)];
|
|
986
|
+
return Promise.resolve();
|
|
987
|
+
},
|
|
988
|
+
clear() {
|
|
989
|
+
cache = {};
|
|
990
|
+
return Promise.resolve();
|
|
991
|
+
},
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
var cacheInMemory_esm = /*#__PURE__*/Object.freeze({
|
|
996
|
+
__proto__: null,
|
|
997
|
+
createInMemoryCache: createInMemoryCache
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
var require$$1 = /*@__PURE__*/getAugmentedNamespace(cacheInMemory_esm);
|
|
1001
|
+
|
|
1002
|
+
function createAuth(authMode, appId, apiKey) {
|
|
1003
|
+
const credentials = {
|
|
1004
|
+
'x-algolia-api-key': apiKey,
|
|
1005
|
+
'x-algolia-application-id': appId,
|
|
1006
|
+
};
|
|
1007
|
+
return {
|
|
1008
|
+
headers() {
|
|
1009
|
+
return authMode === AuthMode.WithinHeaders ? credentials : {};
|
|
1010
|
+
},
|
|
1011
|
+
queryParameters() {
|
|
1012
|
+
return authMode === AuthMode.WithinQueryParameters ? credentials : {};
|
|
1013
|
+
},
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
function createRetryablePromise(callback) {
|
|
1018
|
+
let retriesCount = 0; // eslint-disable-line functional/no-let
|
|
1019
|
+
const retry = () => {
|
|
1020
|
+
retriesCount++;
|
|
1021
|
+
return new Promise((resolve) => {
|
|
1022
|
+
setTimeout(() => {
|
|
1023
|
+
resolve(callback(retry));
|
|
1024
|
+
}, Math.min(100 * retriesCount, 1000));
|
|
1025
|
+
});
|
|
1026
|
+
};
|
|
1027
|
+
return callback(retry);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
function createWaitablePromise(promise, wait = (_response, _requestOptions) => {
|
|
1031
|
+
return Promise.resolve();
|
|
1032
|
+
}) {
|
|
1033
|
+
// eslint-disable-next-line functional/immutable-data
|
|
1034
|
+
return Object.assign(promise, {
|
|
1035
|
+
wait(requestOptions) {
|
|
1036
|
+
return createWaitablePromise(promise
|
|
1037
|
+
.then(response => Promise.all([wait(response, requestOptions), response]))
|
|
1038
|
+
.then(promiseResults => promiseResults[1]));
|
|
1039
|
+
},
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// eslint-disable-next-line functional/prefer-readonly-type
|
|
1044
|
+
function shuffle(array) {
|
|
1045
|
+
let c = array.length - 1; // eslint-disable-line functional/no-let
|
|
1046
|
+
// eslint-disable-next-line functional/no-loop-statement
|
|
1047
|
+
for (c; c > 0; c--) {
|
|
1048
|
+
const b = Math.floor(Math.random() * (c + 1));
|
|
1049
|
+
const a = array[c];
|
|
1050
|
+
array[c] = array[b]; // eslint-disable-line functional/immutable-data, no-param-reassign
|
|
1051
|
+
array[b] = a; // eslint-disable-line functional/immutable-data, no-param-reassign
|
|
1052
|
+
}
|
|
1053
|
+
return array;
|
|
1054
|
+
}
|
|
1055
|
+
function addMethods(base, methods) {
|
|
1056
|
+
if (!methods) {
|
|
1057
|
+
return base;
|
|
1058
|
+
}
|
|
1059
|
+
Object.keys(methods).forEach(key => {
|
|
1060
|
+
// eslint-disable-next-line functional/immutable-data, no-param-reassign
|
|
1061
|
+
base[key] = methods[key](base);
|
|
1062
|
+
});
|
|
1063
|
+
return base;
|
|
1064
|
+
}
|
|
1065
|
+
function encode$1(format, ...args) {
|
|
1066
|
+
// eslint-disable-next-line functional/no-let
|
|
1067
|
+
let i = 0;
|
|
1068
|
+
return format.replace(/%s/g, () => encodeURIComponent(args[i++]));
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
const version = '4.23.3';
|
|
1072
|
+
|
|
1073
|
+
const destroy = (base) => {
|
|
1074
|
+
return () => {
|
|
1075
|
+
return base.transporter.requester.destroy();
|
|
1076
|
+
};
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
const AuthMode = {
|
|
1080
|
+
/**
|
|
1081
|
+
* If auth credentials should be in query parameters.
|
|
1082
|
+
*/
|
|
1083
|
+
WithinQueryParameters: 0,
|
|
1084
|
+
/**
|
|
1085
|
+
* If auth credentials should be in headers.
|
|
1086
|
+
*/
|
|
1087
|
+
WithinHeaders: 1,
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
var clientCommon_esm = /*#__PURE__*/Object.freeze({
|
|
1091
|
+
__proto__: null,
|
|
1092
|
+
AuthMode: AuthMode,
|
|
1093
|
+
addMethods: addMethods,
|
|
1094
|
+
createAuth: createAuth,
|
|
1095
|
+
createRetryablePromise: createRetryablePromise,
|
|
1096
|
+
createWaitablePromise: createWaitablePromise,
|
|
1097
|
+
destroy: destroy,
|
|
1098
|
+
encode: encode$1,
|
|
1099
|
+
shuffle: shuffle,
|
|
1100
|
+
version: version
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
const MethodEnum = {
|
|
1104
|
+
Delete: 'DELETE',
|
|
1105
|
+
Get: 'GET',
|
|
1106
|
+
Post: 'POST',
|
|
1107
|
+
Put: 'PUT',
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
var requesterCommon_esm = /*#__PURE__*/Object.freeze({
|
|
1111
|
+
__proto__: null,
|
|
1112
|
+
MethodEnum: MethodEnum
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
function createMappedRequestOptions(requestOptions, timeout) {
|
|
1116
|
+
const options = requestOptions || {};
|
|
1117
|
+
const data = options.data || {};
|
|
1118
|
+
Object.keys(options).forEach(key => {
|
|
1119
|
+
if (['timeout', 'headers', 'queryParameters', 'data', 'cacheable'].indexOf(key) === -1) {
|
|
1120
|
+
data[key] = options[key]; // eslint-disable-line functional/immutable-data
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
return {
|
|
1124
|
+
data: Object.entries(data).length > 0 ? data : undefined,
|
|
1125
|
+
timeout: options.timeout || timeout,
|
|
1126
|
+
headers: options.headers || {},
|
|
1127
|
+
queryParameters: options.queryParameters || {},
|
|
1128
|
+
cacheable: options.cacheable,
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
const CallEnum = {
|
|
1133
|
+
/**
|
|
1134
|
+
* If the host is read only.
|
|
1135
|
+
*/
|
|
1136
|
+
Read: 1,
|
|
1137
|
+
/**
|
|
1138
|
+
* If the host is write only.
|
|
1139
|
+
*/
|
|
1140
|
+
Write: 2,
|
|
1141
|
+
/**
|
|
1142
|
+
* If the host is both read and write.
|
|
1143
|
+
*/
|
|
1144
|
+
Any: 3,
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
const HostStatusEnum = {
|
|
1148
|
+
Up: 1,
|
|
1149
|
+
Down: 2,
|
|
1150
|
+
Timeouted: 3,
|
|
1151
|
+
};
|
|
1152
|
+
|
|
1153
|
+
// By default, API Clients at Algolia have expiration delay
|
|
1154
|
+
// of 5 mins. In the JavaScript client, we have 2 mins.
|
|
1155
|
+
const EXPIRATION_DELAY = 2 * 60 * 1000;
|
|
1156
|
+
function createStatefulHost(host, status = HostStatusEnum.Up) {
|
|
1157
|
+
return {
|
|
1158
|
+
...host,
|
|
1159
|
+
status,
|
|
1160
|
+
lastUpdate: Date.now(),
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
function isStatefulHostUp(host) {
|
|
1164
|
+
return host.status === HostStatusEnum.Up || Date.now() - host.lastUpdate > EXPIRATION_DELAY;
|
|
1165
|
+
}
|
|
1166
|
+
function isStatefulHostTimeouted(host) {
|
|
1167
|
+
return (host.status === HostStatusEnum.Timeouted && Date.now() - host.lastUpdate <= EXPIRATION_DELAY);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
function createStatelessHost(options) {
|
|
1171
|
+
if (typeof options === 'string') {
|
|
1172
|
+
return {
|
|
1173
|
+
protocol: 'https',
|
|
1174
|
+
url: options,
|
|
1175
|
+
accept: CallEnum.Any,
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
return {
|
|
1179
|
+
protocol: options.protocol || 'https',
|
|
1180
|
+
url: options.url,
|
|
1181
|
+
accept: options.accept || CallEnum.Any,
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
function createRetryableOptions(hostsCache, statelessHosts) {
|
|
1186
|
+
return Promise.all(statelessHosts.map(statelessHost => {
|
|
1187
|
+
return hostsCache.get(statelessHost, () => {
|
|
1188
|
+
return Promise.resolve(createStatefulHost(statelessHost));
|
|
1189
|
+
});
|
|
1190
|
+
})).then(statefulHosts => {
|
|
1191
|
+
const hostsUp = statefulHosts.filter(host => isStatefulHostUp(host));
|
|
1192
|
+
const hostsTimeouted = statefulHosts.filter(host => isStatefulHostTimeouted(host));
|
|
1193
|
+
/**
|
|
1194
|
+
* Note, we put the hosts that previously timeouted on the end of the list.
|
|
1195
|
+
*/
|
|
1196
|
+
const hostsAvailable = [...hostsUp, ...hostsTimeouted];
|
|
1197
|
+
const statelessHostsAvailable = hostsAvailable.length > 0
|
|
1198
|
+
? hostsAvailable.map(host => createStatelessHost(host))
|
|
1199
|
+
: statelessHosts;
|
|
1200
|
+
return {
|
|
1201
|
+
getTimeout(timeoutsCount, baseTimeout) {
|
|
1202
|
+
/**
|
|
1203
|
+
* Imagine that you have 4 hosts, if timeouts will increase
|
|
1204
|
+
* on the following way: 1 (timeouted) > 4 (timeouted) > 5 (200)
|
|
1205
|
+
*
|
|
1206
|
+
* Note that, the very next request, we start from the previous timeout
|
|
1207
|
+
*
|
|
1208
|
+
* 5 (timeouted) > 6 (timeouted) > 7 ...
|
|
1209
|
+
*
|
|
1210
|
+
* This strategy may need to be reviewed, but is the strategy on the our
|
|
1211
|
+
* current v3 version.
|
|
1212
|
+
*/
|
|
1213
|
+
const timeoutMultiplier = hostsTimeouted.length === 0 && timeoutsCount === 0
|
|
1214
|
+
? 1
|
|
1215
|
+
: hostsTimeouted.length + 3 + timeoutsCount;
|
|
1216
|
+
return timeoutMultiplier * baseTimeout;
|
|
1217
|
+
},
|
|
1218
|
+
statelessHosts: statelessHostsAvailable,
|
|
1219
|
+
};
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
const isNetworkError = ({ isTimedOut, status }) => {
|
|
1224
|
+
return !isTimedOut && ~~status === 0;
|
|
1225
|
+
};
|
|
1226
|
+
const isRetryable = (response) => {
|
|
1227
|
+
const status = response.status;
|
|
1228
|
+
const isTimedOut = response.isTimedOut;
|
|
1229
|
+
return (isTimedOut || isNetworkError(response) || (~~(status / 100) !== 2 && ~~(status / 100) !== 4));
|
|
1230
|
+
};
|
|
1231
|
+
const isSuccess = ({ status }) => {
|
|
1232
|
+
return ~~(status / 100) === 2;
|
|
1233
|
+
};
|
|
1234
|
+
const retryDecision = (response, outcomes) => {
|
|
1235
|
+
if (isRetryable(response)) {
|
|
1236
|
+
return outcomes.onRetry(response);
|
|
1237
|
+
}
|
|
1238
|
+
if (isSuccess(response)) {
|
|
1239
|
+
return outcomes.onSuccess(response);
|
|
1240
|
+
}
|
|
1241
|
+
return outcomes.onFail(response);
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
function retryableRequest(transporter, statelessHosts, request, requestOptions) {
|
|
1245
|
+
const stackTrace = []; // eslint-disable-line functional/prefer-readonly-type
|
|
1246
|
+
/**
|
|
1247
|
+
* First we prepare the payload that do not depend from hosts.
|
|
1248
|
+
*/
|
|
1249
|
+
const data = serializeData(request, requestOptions);
|
|
1250
|
+
const headers = serializeHeaders(transporter, requestOptions);
|
|
1251
|
+
const method = request.method;
|
|
1252
|
+
// On `GET`, the data is proxied to query parameters.
|
|
1253
|
+
const dataQueryParameters = request.method !== MethodEnum.Get
|
|
1254
|
+
? {}
|
|
1255
|
+
: {
|
|
1256
|
+
...request.data,
|
|
1257
|
+
...requestOptions.data,
|
|
1258
|
+
};
|
|
1259
|
+
const queryParameters = {
|
|
1260
|
+
'x-algolia-agent': transporter.userAgent.value,
|
|
1261
|
+
...transporter.queryParameters,
|
|
1262
|
+
...dataQueryParameters,
|
|
1263
|
+
...requestOptions.queryParameters,
|
|
1264
|
+
};
|
|
1265
|
+
let timeoutsCount = 0; // eslint-disable-line functional/no-let
|
|
1266
|
+
const retry = (hosts, // eslint-disable-line functional/prefer-readonly-type
|
|
1267
|
+
getTimeout) => {
|
|
1268
|
+
/**
|
|
1269
|
+
* We iterate on each host, until there is no host left.
|
|
1270
|
+
*/
|
|
1271
|
+
const host = hosts.pop(); // eslint-disable-line functional/immutable-data
|
|
1272
|
+
if (host === undefined) {
|
|
1273
|
+
throw createRetryError(stackTraceWithoutCredentials(stackTrace));
|
|
1274
|
+
}
|
|
1275
|
+
const payload = {
|
|
1276
|
+
data,
|
|
1277
|
+
headers,
|
|
1278
|
+
method,
|
|
1279
|
+
url: serializeUrl(host, request.path, queryParameters),
|
|
1280
|
+
connectTimeout: getTimeout(timeoutsCount, transporter.timeouts.connect),
|
|
1281
|
+
responseTimeout: getTimeout(timeoutsCount, requestOptions.timeout),
|
|
1282
|
+
};
|
|
1283
|
+
/**
|
|
1284
|
+
* The stackFrame is pushed to the stackTrace so we
|
|
1285
|
+
* can have information about onRetry and onFailure
|
|
1286
|
+
* decisions.
|
|
1287
|
+
*/
|
|
1288
|
+
const pushToStackTrace = (response) => {
|
|
1289
|
+
const stackFrame = {
|
|
1290
|
+
request: payload,
|
|
1291
|
+
response,
|
|
1292
|
+
host,
|
|
1293
|
+
triesLeft: hosts.length,
|
|
1294
|
+
};
|
|
1295
|
+
// eslint-disable-next-line functional/immutable-data
|
|
1296
|
+
stackTrace.push(stackFrame);
|
|
1297
|
+
return stackFrame;
|
|
1298
|
+
};
|
|
1299
|
+
const decisions = {
|
|
1300
|
+
onSuccess: response => deserializeSuccess(response),
|
|
1301
|
+
onRetry(response) {
|
|
1302
|
+
const stackFrame = pushToStackTrace(response);
|
|
1303
|
+
/**
|
|
1304
|
+
* If response is a timeout, we increaset the number of
|
|
1305
|
+
* timeouts so we can increase the timeout later.
|
|
1306
|
+
*/
|
|
1307
|
+
if (response.isTimedOut) {
|
|
1308
|
+
timeoutsCount++;
|
|
1309
|
+
}
|
|
1310
|
+
return Promise.all([
|
|
1311
|
+
/**
|
|
1312
|
+
* Failures are individually send the logger, allowing
|
|
1313
|
+
* the end user to debug / store stack frames even
|
|
1314
|
+
* when a retry error does not happen.
|
|
1315
|
+
*/
|
|
1316
|
+
transporter.logger.info('Retryable failure', stackFrameWithoutCredentials(stackFrame)),
|
|
1317
|
+
/**
|
|
1318
|
+
* We also store the state of the host in failure cases. If the host, is
|
|
1319
|
+
* down it will remain down for the next 2 minutes. In a timeout situation,
|
|
1320
|
+
* this host will be added end of the list of hosts on the next request.
|
|
1321
|
+
*/
|
|
1322
|
+
transporter.hostsCache.set(host, createStatefulHost(host, response.isTimedOut ? HostStatusEnum.Timeouted : HostStatusEnum.Down)),
|
|
1323
|
+
]).then(() => retry(hosts, getTimeout));
|
|
1324
|
+
},
|
|
1325
|
+
onFail(response) {
|
|
1326
|
+
pushToStackTrace(response);
|
|
1327
|
+
throw deserializeFailure(response, stackTraceWithoutCredentials(stackTrace));
|
|
1328
|
+
},
|
|
1329
|
+
};
|
|
1330
|
+
return transporter.requester.send(payload).then(response => {
|
|
1331
|
+
return retryDecision(response, decisions);
|
|
1332
|
+
});
|
|
1333
|
+
};
|
|
1334
|
+
/**
|
|
1335
|
+
* Finally, for each retryable host perform request until we got a non
|
|
1336
|
+
* retryable response. Some notes here:
|
|
1337
|
+
*
|
|
1338
|
+
* 1. The reverse here is applied so we can apply a `pop` later on => more performant.
|
|
1339
|
+
* 2. We also get from the retryable options a timeout multiplier that is tailored
|
|
1340
|
+
* for the current context.
|
|
1341
|
+
*/
|
|
1342
|
+
return createRetryableOptions(transporter.hostsCache, statelessHosts).then(options => {
|
|
1343
|
+
return retry([...options.statelessHosts].reverse(), options.getTimeout);
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
function createTransporter(options) {
|
|
1348
|
+
const { hostsCache, logger, requester, requestsCache, responsesCache, timeouts, userAgent, hosts, queryParameters, headers, } = options;
|
|
1349
|
+
const transporter = {
|
|
1350
|
+
hostsCache,
|
|
1351
|
+
logger,
|
|
1352
|
+
requester,
|
|
1353
|
+
requestsCache,
|
|
1354
|
+
responsesCache,
|
|
1355
|
+
timeouts,
|
|
1356
|
+
userAgent,
|
|
1357
|
+
headers,
|
|
1358
|
+
queryParameters,
|
|
1359
|
+
hosts: hosts.map(host => createStatelessHost(host)),
|
|
1360
|
+
read(request, requestOptions) {
|
|
1361
|
+
/**
|
|
1362
|
+
* First, we compute the user request options. Now, keep in mind,
|
|
1363
|
+
* that using request options the user is able to modified the intire
|
|
1364
|
+
* payload of the request. Such as headers, query parameters, and others.
|
|
1365
|
+
*/
|
|
1366
|
+
const mappedRequestOptions = createMappedRequestOptions(requestOptions, transporter.timeouts.read);
|
|
1367
|
+
const createRetryableRequest = () => {
|
|
1368
|
+
/**
|
|
1369
|
+
* Then, we prepare a function factory that contains the construction of
|
|
1370
|
+
* the retryable request. At this point, we may *not* perform the actual
|
|
1371
|
+
* request. But we want to have the function factory ready.
|
|
1372
|
+
*/
|
|
1373
|
+
return retryableRequest(transporter, transporter.hosts.filter(host => (host.accept & CallEnum.Read) !== 0), request, mappedRequestOptions);
|
|
1374
|
+
};
|
|
1375
|
+
/**
|
|
1376
|
+
* Once we have the function factory ready, we need to determine of the
|
|
1377
|
+
* request is "cacheable" - should be cached. Note that, once again,
|
|
1378
|
+
* the user can force this option.
|
|
1379
|
+
*/
|
|
1380
|
+
const cacheable = mappedRequestOptions.cacheable !== undefined
|
|
1381
|
+
? mappedRequestOptions.cacheable
|
|
1382
|
+
: request.cacheable;
|
|
1383
|
+
/**
|
|
1384
|
+
* If is not "cacheable", we immediatly trigger the retryable request, no
|
|
1385
|
+
* need to check cache implementations.
|
|
1386
|
+
*/
|
|
1387
|
+
if (cacheable !== true) {
|
|
1388
|
+
return createRetryableRequest();
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* If the request is "cacheable", we need to first compute the key to ask
|
|
1392
|
+
* the cache implementations if this request is on progress or if the
|
|
1393
|
+
* response already exists on the cache.
|
|
1394
|
+
*/
|
|
1395
|
+
const key = {
|
|
1396
|
+
request,
|
|
1397
|
+
mappedRequestOptions,
|
|
1398
|
+
transporter: {
|
|
1399
|
+
queryParameters: transporter.queryParameters,
|
|
1400
|
+
headers: transporter.headers,
|
|
1401
|
+
},
|
|
1402
|
+
};
|
|
1403
|
+
/**
|
|
1404
|
+
* With the computed key, we first ask the responses cache
|
|
1405
|
+
* implemention if this request was been resolved before.
|
|
1406
|
+
*/
|
|
1407
|
+
return transporter.responsesCache.get(key, () => {
|
|
1408
|
+
/**
|
|
1409
|
+
* If the request has never resolved before, we actually ask if there
|
|
1410
|
+
* is a current request with the same key on progress.
|
|
1411
|
+
*/
|
|
1412
|
+
return transporter.requestsCache.get(key, () => {
|
|
1413
|
+
return (transporter.requestsCache
|
|
1414
|
+
/**
|
|
1415
|
+
* Finally, if there is no request in progress with the same key,
|
|
1416
|
+
* this `createRetryableRequest()` will actually trigger the
|
|
1417
|
+
* retryable request.
|
|
1418
|
+
*/
|
|
1419
|
+
.set(key, createRetryableRequest())
|
|
1420
|
+
.then(response => Promise.all([transporter.requestsCache.delete(key), response]), err => Promise.all([transporter.requestsCache.delete(key), Promise.reject(err)]))
|
|
1421
|
+
.then(([_, response]) => response));
|
|
1422
|
+
});
|
|
1423
|
+
}, {
|
|
1424
|
+
/**
|
|
1425
|
+
* Of course, once we get this response back from the server, we
|
|
1426
|
+
* tell response cache to actually store the received response
|
|
1427
|
+
* to be used later.
|
|
1428
|
+
*/
|
|
1429
|
+
miss: response => transporter.responsesCache.set(key, response),
|
|
1430
|
+
});
|
|
1431
|
+
},
|
|
1432
|
+
write(request, requestOptions) {
|
|
1433
|
+
/**
|
|
1434
|
+
* On write requests, no cache mechanisms are applied, and we
|
|
1435
|
+
* proxy the request immediately to the requester.
|
|
1436
|
+
*/
|
|
1437
|
+
return retryableRequest(transporter, transporter.hosts.filter(host => (host.accept & CallEnum.Write) !== 0), request, createMappedRequestOptions(requestOptions, transporter.timeouts.write));
|
|
1438
|
+
},
|
|
1439
|
+
};
|
|
1440
|
+
return transporter;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
function createUserAgent(version) {
|
|
1444
|
+
const userAgent = {
|
|
1445
|
+
value: `Algolia for JavaScript (${version})`,
|
|
1446
|
+
add(options) {
|
|
1447
|
+
const addedUserAgent = `; ${options.segment}${options.version !== undefined ? ` (${options.version})` : ''}`;
|
|
1448
|
+
if (userAgent.value.indexOf(addedUserAgent) === -1) {
|
|
1449
|
+
// eslint-disable-next-line functional/immutable-data
|
|
1450
|
+
userAgent.value = `${userAgent.value}${addedUserAgent}`;
|
|
1451
|
+
}
|
|
1452
|
+
return userAgent;
|
|
1453
|
+
},
|
|
1454
|
+
};
|
|
1455
|
+
return userAgent;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
function deserializeSuccess(response) {
|
|
1459
|
+
// eslint-disable-next-line functional/no-try-statement
|
|
1460
|
+
try {
|
|
1461
|
+
return JSON.parse(response.content);
|
|
1462
|
+
}
|
|
1463
|
+
catch (e) {
|
|
1464
|
+
throw createDeserializationError(e.message, response);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function deserializeFailure({ content, status }, stackFrame) {
|
|
1468
|
+
// eslint-disable-next-line functional/no-let
|
|
1469
|
+
let message = content;
|
|
1470
|
+
// eslint-disable-next-line functional/no-try-statement
|
|
1471
|
+
try {
|
|
1472
|
+
message = JSON.parse(content).message;
|
|
1473
|
+
}
|
|
1474
|
+
catch (e) {
|
|
1475
|
+
// ..
|
|
1476
|
+
}
|
|
1477
|
+
return createApiError(message, status, stackFrame);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// eslint-disable-next-line functional/prefer-readonly-type
|
|
1481
|
+
function encode(format, ...args) {
|
|
1482
|
+
// eslint-disable-next-line functional/no-let
|
|
1483
|
+
let i = 0;
|
|
1484
|
+
return format.replace(/%s/g, () => encodeURIComponent(args[i++]));
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
function serializeUrl(host, path, queryParameters) {
|
|
1488
|
+
const queryParametersAsString = serializeQueryParameters(queryParameters);
|
|
1489
|
+
// eslint-disable-next-line functional/no-let
|
|
1490
|
+
let url = `${host.protocol}://${host.url}/${path.charAt(0) === '/' ? path.substr(1) : path}`;
|
|
1491
|
+
if (queryParametersAsString.length) {
|
|
1492
|
+
url += `?${queryParametersAsString}`;
|
|
1493
|
+
}
|
|
1494
|
+
return url;
|
|
1495
|
+
}
|
|
1496
|
+
function serializeQueryParameters(parameters) {
|
|
1497
|
+
const isObjectOrArray = (value) => Object.prototype.toString.call(value) === '[object Object]' ||
|
|
1498
|
+
Object.prototype.toString.call(value) === '[object Array]';
|
|
1499
|
+
return Object.keys(parameters)
|
|
1500
|
+
.map(key => encode('%s=%s', key, isObjectOrArray(parameters[key]) ? JSON.stringify(parameters[key]) : parameters[key]))
|
|
1501
|
+
.join('&');
|
|
1502
|
+
}
|
|
1503
|
+
function serializeData(request, requestOptions) {
|
|
1504
|
+
if (request.method === MethodEnum.Get ||
|
|
1505
|
+
(request.data === undefined && requestOptions.data === undefined)) {
|
|
1506
|
+
return undefined;
|
|
1507
|
+
}
|
|
1508
|
+
const data = Array.isArray(request.data)
|
|
1509
|
+
? request.data
|
|
1510
|
+
: { ...request.data, ...requestOptions.data };
|
|
1511
|
+
return JSON.stringify(data);
|
|
1512
|
+
}
|
|
1513
|
+
function serializeHeaders(transporter, requestOptions) {
|
|
1514
|
+
const headers = {
|
|
1515
|
+
...transporter.headers,
|
|
1516
|
+
...requestOptions.headers,
|
|
1517
|
+
};
|
|
1518
|
+
const serializedHeaders = {};
|
|
1519
|
+
Object.keys(headers).forEach(header => {
|
|
1520
|
+
const value = headers[header];
|
|
1521
|
+
// @ts-ignore
|
|
1522
|
+
// eslint-disable-next-line functional/immutable-data
|
|
1523
|
+
serializedHeaders[header.toLowerCase()] = value;
|
|
1524
|
+
});
|
|
1525
|
+
return serializedHeaders;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
function stackTraceWithoutCredentials(stackTrace) {
|
|
1529
|
+
return stackTrace.map(stackFrame => stackFrameWithoutCredentials(stackFrame));
|
|
1530
|
+
}
|
|
1531
|
+
function stackFrameWithoutCredentials(stackFrame) {
|
|
1532
|
+
const modifiedHeaders = stackFrame.request.headers['x-algolia-api-key']
|
|
1533
|
+
? { 'x-algolia-api-key': '*****' }
|
|
1534
|
+
: {};
|
|
1535
|
+
return {
|
|
1536
|
+
...stackFrame,
|
|
1537
|
+
request: {
|
|
1538
|
+
...stackFrame.request,
|
|
1539
|
+
headers: {
|
|
1540
|
+
...stackFrame.request.headers,
|
|
1541
|
+
...modifiedHeaders,
|
|
1542
|
+
},
|
|
1543
|
+
},
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
function createApiError(message, status, transporterStackTrace) {
|
|
1548
|
+
return {
|
|
1549
|
+
name: 'ApiError',
|
|
1550
|
+
message,
|
|
1551
|
+
status,
|
|
1552
|
+
transporterStackTrace,
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
function createDeserializationError(message, response) {
|
|
1557
|
+
return {
|
|
1558
|
+
name: 'DeserializationError',
|
|
1559
|
+
message,
|
|
1560
|
+
response,
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
function createRetryError(transporterStackTrace) {
|
|
1565
|
+
return {
|
|
1566
|
+
name: 'RetryError',
|
|
1567
|
+
message: 'Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.',
|
|
1568
|
+
transporterStackTrace,
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
var transporter_esm = /*#__PURE__*/Object.freeze({
|
|
1573
|
+
__proto__: null,
|
|
1574
|
+
CallEnum: CallEnum,
|
|
1575
|
+
HostStatusEnum: HostStatusEnum,
|
|
1576
|
+
createApiError: createApiError,
|
|
1577
|
+
createDeserializationError: createDeserializationError,
|
|
1578
|
+
createMappedRequestOptions: createMappedRequestOptions,
|
|
1579
|
+
createRetryError: createRetryError,
|
|
1580
|
+
createStatefulHost: createStatefulHost,
|
|
1581
|
+
createStatelessHost: createStatelessHost,
|
|
1582
|
+
createTransporter: createTransporter,
|
|
1583
|
+
createUserAgent: createUserAgent,
|
|
1584
|
+
deserializeFailure: deserializeFailure,
|
|
1585
|
+
deserializeSuccess: deserializeSuccess,
|
|
1586
|
+
isStatefulHostTimeouted: isStatefulHostTimeouted,
|
|
1587
|
+
isStatefulHostUp: isStatefulHostUp,
|
|
1588
|
+
serializeData: serializeData,
|
|
1589
|
+
serializeHeaders: serializeHeaders,
|
|
1590
|
+
serializeQueryParameters: serializeQueryParameters,
|
|
1591
|
+
serializeUrl: serializeUrl,
|
|
1592
|
+
stackFrameWithoutCredentials: stackFrameWithoutCredentials,
|
|
1593
|
+
stackTraceWithoutCredentials: stackTraceWithoutCredentials
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
const createAnalyticsClient = options => {
|
|
1597
|
+
const region = options.region || 'us';
|
|
1598
|
+
const auth = createAuth(AuthMode.WithinHeaders, options.appId, options.apiKey);
|
|
1599
|
+
const transporter = createTransporter({
|
|
1600
|
+
hosts: [{ url: `analytics.${region}.algolia.com` }],
|
|
1601
|
+
...options,
|
|
1602
|
+
headers: {
|
|
1603
|
+
...auth.headers(),
|
|
1604
|
+
...{ 'content-type': 'application/json' },
|
|
1605
|
+
...options.headers,
|
|
1606
|
+
},
|
|
1607
|
+
queryParameters: {
|
|
1608
|
+
...auth.queryParameters(),
|
|
1609
|
+
...options.queryParameters,
|
|
1610
|
+
},
|
|
1611
|
+
});
|
|
1612
|
+
const appId = options.appId;
|
|
1613
|
+
return addMethods({ appId, transporter }, options.methods);
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1616
|
+
const addABTest = (base) => {
|
|
1617
|
+
return (abTest, requestOptions) => {
|
|
1618
|
+
return base.transporter.write({
|
|
1619
|
+
method: MethodEnum.Post,
|
|
1620
|
+
path: '2/abtests',
|
|
1621
|
+
data: abTest,
|
|
1622
|
+
}, requestOptions);
|
|
1623
|
+
};
|
|
1624
|
+
};
|
|
1625
|
+
|
|
1626
|
+
const deleteABTest = (base) => {
|
|
1627
|
+
return (abTestID, requestOptions) => {
|
|
1628
|
+
return base.transporter.write({
|
|
1629
|
+
method: MethodEnum.Delete,
|
|
1630
|
+
path: encode$1('2/abtests/%s', abTestID),
|
|
1631
|
+
}, requestOptions);
|
|
1632
|
+
};
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1635
|
+
const getABTest = (base) => {
|
|
1636
|
+
return (abTestID, requestOptions) => {
|
|
1637
|
+
return base.transporter.read({
|
|
1638
|
+
method: MethodEnum.Get,
|
|
1639
|
+
path: encode$1('2/abtests/%s', abTestID),
|
|
1640
|
+
}, requestOptions);
|
|
1641
|
+
};
|
|
1642
|
+
};
|
|
1643
|
+
|
|
1644
|
+
const getABTests = (base) => {
|
|
1645
|
+
return (requestOptions) => {
|
|
1646
|
+
return base.transporter.read({
|
|
1647
|
+
method: MethodEnum.Get,
|
|
1648
|
+
path: '2/abtests',
|
|
1649
|
+
}, requestOptions);
|
|
1650
|
+
};
|
|
1651
|
+
};
|
|
1652
|
+
|
|
1653
|
+
const stopABTest = (base) => {
|
|
1654
|
+
return (abTestID, requestOptions) => {
|
|
1655
|
+
return base.transporter.write({
|
|
1656
|
+
method: MethodEnum.Post,
|
|
1657
|
+
path: encode$1('2/abtests/%s/stop', abTestID),
|
|
1658
|
+
}, requestOptions);
|
|
1659
|
+
};
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
var clientAnalytics_esm = /*#__PURE__*/Object.freeze({
|
|
1663
|
+
__proto__: null,
|
|
1664
|
+
addABTest: addABTest,
|
|
1665
|
+
createAnalyticsClient: createAnalyticsClient,
|
|
1666
|
+
deleteABTest: deleteABTest,
|
|
1667
|
+
getABTest: getABTest,
|
|
1668
|
+
getABTests: getABTests,
|
|
1669
|
+
stopABTest: stopABTest
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1672
|
+
var require$$2 = /*@__PURE__*/getAugmentedNamespace(clientAnalytics_esm);
|
|
1673
|
+
|
|
1674
|
+
var require$$3 = /*@__PURE__*/getAugmentedNamespace(clientCommon_esm);
|
|
1675
|
+
|
|
1676
|
+
const createPersonalizationClient = options => {
|
|
1677
|
+
const region = options.region || 'us';
|
|
1678
|
+
const auth = createAuth(AuthMode.WithinHeaders, options.appId, options.apiKey);
|
|
1679
|
+
const transporter = createTransporter({
|
|
1680
|
+
hosts: [{ url: `personalization.${region}.algolia.com` }],
|
|
1681
|
+
...options,
|
|
1682
|
+
headers: {
|
|
1683
|
+
...auth.headers(),
|
|
1684
|
+
...{ 'content-type': 'application/json' },
|
|
1685
|
+
...options.headers,
|
|
1686
|
+
},
|
|
1687
|
+
queryParameters: {
|
|
1688
|
+
...auth.queryParameters(),
|
|
1689
|
+
...options.queryParameters,
|
|
1690
|
+
},
|
|
1691
|
+
});
|
|
1692
|
+
return addMethods({ appId: options.appId, transporter }, options.methods);
|
|
1693
|
+
};
|
|
1694
|
+
|
|
1695
|
+
const getPersonalizationStrategy = (base) => {
|
|
1696
|
+
return (requestOptions) => {
|
|
1697
|
+
return base.transporter.read({
|
|
1698
|
+
method: MethodEnum.Get,
|
|
1699
|
+
path: '1/strategies/personalization',
|
|
1700
|
+
}, requestOptions);
|
|
1701
|
+
};
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
const setPersonalizationStrategy = (base) => {
|
|
1705
|
+
return (personalizationStrategy, requestOptions) => {
|
|
1706
|
+
return base.transporter.write({
|
|
1707
|
+
method: MethodEnum.Post,
|
|
1708
|
+
path: '1/strategies/personalization',
|
|
1709
|
+
data: personalizationStrategy,
|
|
1710
|
+
}, requestOptions);
|
|
1711
|
+
};
|
|
1712
|
+
};
|
|
1713
|
+
|
|
1714
|
+
var clientPersonalization_esm = /*#__PURE__*/Object.freeze({
|
|
1715
|
+
__proto__: null,
|
|
1716
|
+
createPersonalizationClient: createPersonalizationClient,
|
|
1717
|
+
getPersonalizationStrategy: getPersonalizationStrategy,
|
|
1718
|
+
setPersonalizationStrategy: setPersonalizationStrategy
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
var require$$4 = /*@__PURE__*/getAugmentedNamespace(clientPersonalization_esm);
|
|
1722
|
+
|
|
1723
|
+
function createNullLogger() {
|
|
1724
|
+
return {
|
|
1725
|
+
debug(_message, _args) {
|
|
1726
|
+
return Promise.resolve();
|
|
1727
|
+
},
|
|
1728
|
+
info(_message, _args) {
|
|
1729
|
+
return Promise.resolve();
|
|
1730
|
+
},
|
|
1731
|
+
error(_message, _args) {
|
|
1732
|
+
return Promise.resolve();
|
|
1733
|
+
},
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
const LogLevelEnum = {
|
|
1738
|
+
Debug: 1,
|
|
1739
|
+
Info: 2,
|
|
1740
|
+
Error: 3,
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
var loggerCommon_esm = /*#__PURE__*/Object.freeze({
|
|
1744
|
+
__proto__: null,
|
|
1745
|
+
LogLevelEnum: LogLevelEnum,
|
|
1746
|
+
createNullLogger: createNullLogger
|
|
1747
|
+
});
|
|
1748
|
+
|
|
1749
|
+
var require$$6$1 = /*@__PURE__*/getAugmentedNamespace(loggerCommon_esm);
|
|
1750
|
+
|
|
1751
|
+
var recommend$3 = {exports: {}};
|
|
1752
|
+
|
|
1753
|
+
/* eslint functional/prefer-readonly-type: 0 */
|
|
1754
|
+
const agentOptions = { keepAlive: true };
|
|
1755
|
+
const defaultHttpAgent = new Agent(agentOptions);
|
|
1756
|
+
const defaultHttpsAgent = new Agent$1(agentOptions);
|
|
1757
|
+
function createNodeHttpRequester({ agent: userGlobalAgent, httpAgent: userHttpAgent, httpsAgent: userHttpsAgent, requesterOptions = {}, } = {}) {
|
|
1758
|
+
const httpAgent = userHttpAgent || userGlobalAgent || defaultHttpAgent;
|
|
1759
|
+
const httpsAgent = userHttpsAgent || userGlobalAgent || defaultHttpsAgent;
|
|
1760
|
+
return {
|
|
1761
|
+
send(request) {
|
|
1762
|
+
return new Promise(resolve => {
|
|
1763
|
+
const url = parse(request.url);
|
|
1764
|
+
const path = url.query === null ? url.pathname : `${url.pathname}?${url.query}`;
|
|
1765
|
+
const options = {
|
|
1766
|
+
...requesterOptions,
|
|
1767
|
+
agent: url.protocol === 'https:' ? httpsAgent : httpAgent,
|
|
1768
|
+
hostname: url.hostname,
|
|
1769
|
+
path,
|
|
1770
|
+
method: request.method,
|
|
1771
|
+
headers: {
|
|
1772
|
+
...(requesterOptions && requesterOptions.headers ? requesterOptions.headers : {}),
|
|
1773
|
+
...request.headers,
|
|
1774
|
+
},
|
|
1775
|
+
...(url.port !== undefined ? { port: url.port || '' } : {}),
|
|
1776
|
+
};
|
|
1777
|
+
const req = (url.protocol === 'https:' ? https : http).request(options, response => {
|
|
1778
|
+
// eslint-disable-next-line functional/no-let
|
|
1779
|
+
let contentBuffers = [];
|
|
1780
|
+
response.on('data', chunk => {
|
|
1781
|
+
contentBuffers = contentBuffers.concat(chunk);
|
|
1782
|
+
});
|
|
1783
|
+
response.on('end', () => {
|
|
1784
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
1785
|
+
clearTimeout(connectTimeout);
|
|
1786
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
1787
|
+
clearTimeout(responseTimeout);
|
|
1788
|
+
resolve({
|
|
1789
|
+
status: response.statusCode || 0,
|
|
1790
|
+
content: Buffer.concat(contentBuffers).toString(),
|
|
1791
|
+
isTimedOut: false,
|
|
1792
|
+
});
|
|
1793
|
+
});
|
|
1794
|
+
});
|
|
1795
|
+
const createTimeout = (timeout, content) => {
|
|
1796
|
+
return setTimeout(() => {
|
|
1797
|
+
req.abort();
|
|
1798
|
+
resolve({
|
|
1799
|
+
status: 0,
|
|
1800
|
+
content,
|
|
1801
|
+
isTimedOut: true,
|
|
1802
|
+
});
|
|
1803
|
+
}, timeout * 1000);
|
|
1804
|
+
};
|
|
1805
|
+
const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
|
|
1806
|
+
// eslint-disable-next-line functional/no-let
|
|
1807
|
+
let responseTimeout;
|
|
1808
|
+
req.on('error', error => {
|
|
1809
|
+
clearTimeout(connectTimeout);
|
|
1810
|
+
clearTimeout(responseTimeout);
|
|
1811
|
+
resolve({ status: 0, content: error.message, isTimedOut: false });
|
|
1812
|
+
});
|
|
1813
|
+
req.once('response', () => {
|
|
1814
|
+
clearTimeout(connectTimeout);
|
|
1815
|
+
responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
|
|
1816
|
+
});
|
|
1817
|
+
if (request.data !== undefined) {
|
|
1818
|
+
req.write(request.data);
|
|
1819
|
+
}
|
|
1820
|
+
req.end();
|
|
1821
|
+
});
|
|
1822
|
+
},
|
|
1823
|
+
destroy() {
|
|
1824
|
+
httpAgent.destroy();
|
|
1825
|
+
httpsAgent.destroy();
|
|
1826
|
+
return Promise.resolve();
|
|
1827
|
+
},
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
var requesterNodeHttp_esm = /*#__PURE__*/Object.freeze({
|
|
1832
|
+
__proto__: null,
|
|
1833
|
+
createNodeHttpRequester: createNodeHttpRequester
|
|
1834
|
+
});
|
|
1835
|
+
|
|
1836
|
+
var require$$8 = /*@__PURE__*/getAugmentedNamespace(requesterNodeHttp_esm);
|
|
1837
|
+
|
|
1838
|
+
var require$$9 = /*@__PURE__*/getAugmentedNamespace(transporter_esm);
|
|
1839
|
+
|
|
1840
|
+
var require$$6 = /*@__PURE__*/getAugmentedNamespace(requesterCommon_esm);
|
|
1841
|
+
|
|
1842
|
+
var cacheCommon$1 = require$$0;
|
|
1843
|
+
var cacheInMemory$1 = require$$1;
|
|
1844
|
+
var clientCommon$1 = require$$3;
|
|
1845
|
+
var loggerCommon$1 = require$$6$1;
|
|
1846
|
+
var requesterNodeHttp$1 = require$$8;
|
|
1847
|
+
var transporter$1 = require$$9;
|
|
1848
|
+
var requesterCommon = require$$6;
|
|
1849
|
+
|
|
1850
|
+
const createRecommendClient = options => {
|
|
1851
|
+
const appId = options.appId;
|
|
1852
|
+
const auth = clientCommon$1.createAuth(options.authMode !== undefined ? options.authMode : clientCommon$1.AuthMode.WithinHeaders, appId, options.apiKey);
|
|
1853
|
+
const transporter$1$1 = transporter$1.createTransporter({
|
|
1854
|
+
hosts: [
|
|
1855
|
+
{ url: `${appId}-dsn.algolia.net`, accept: transporter$1.CallEnum.Read },
|
|
1856
|
+
{ url: `${appId}.algolia.net`, accept: transporter$1.CallEnum.Write },
|
|
1857
|
+
].concat(clientCommon$1.shuffle([
|
|
1858
|
+
{ url: `${appId}-1.algolianet.com` },
|
|
1859
|
+
{ url: `${appId}-2.algolianet.com` },
|
|
1860
|
+
{ url: `${appId}-3.algolianet.com` },
|
|
1861
|
+
])),
|
|
1862
|
+
...options,
|
|
1863
|
+
headers: {
|
|
1864
|
+
...auth.headers(),
|
|
1865
|
+
...{ 'content-type': 'application/x-www-form-urlencoded' },
|
|
1866
|
+
...options.headers,
|
|
1867
|
+
},
|
|
1868
|
+
queryParameters: {
|
|
1869
|
+
...auth.queryParameters(),
|
|
1870
|
+
...options.queryParameters,
|
|
1871
|
+
},
|
|
1872
|
+
});
|
|
1873
|
+
const base = {
|
|
1874
|
+
transporter: transporter$1$1,
|
|
1875
|
+
appId,
|
|
1876
|
+
addAlgoliaAgent(segment, version) {
|
|
1877
|
+
transporter$1$1.userAgent.add({ segment, version });
|
|
1878
|
+
},
|
|
1879
|
+
clearCache() {
|
|
1880
|
+
return Promise.all([
|
|
1881
|
+
transporter$1$1.requestsCache.clear(),
|
|
1882
|
+
transporter$1$1.responsesCache.clear(),
|
|
1883
|
+
]).then(() => undefined);
|
|
1884
|
+
},
|
|
1885
|
+
};
|
|
1886
|
+
return clientCommon$1.addMethods(base, options.methods);
|
|
1887
|
+
};
|
|
1888
|
+
|
|
1889
|
+
const getRecommendations = base => {
|
|
1890
|
+
return (queries, requestOptions) => {
|
|
1891
|
+
const requests = queries.map(query => ({
|
|
1892
|
+
...query,
|
|
1893
|
+
// The `threshold` param is required by the endpoint to make it easier
|
|
1894
|
+
// to provide a default value later, so we default it in the client
|
|
1895
|
+
// so that users don't have to provide a value.
|
|
1896
|
+
threshold: query.threshold || 0,
|
|
1897
|
+
}));
|
|
1898
|
+
return base.transporter.read({
|
|
1899
|
+
method: requesterCommon.MethodEnum.Post,
|
|
1900
|
+
path: '1/indexes/*/recommendations',
|
|
1901
|
+
data: {
|
|
1902
|
+
requests,
|
|
1903
|
+
},
|
|
1904
|
+
cacheable: true,
|
|
1905
|
+
}, requestOptions);
|
|
1906
|
+
};
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
const getFrequentlyBoughtTogether = base => {
|
|
1910
|
+
return (queries, requestOptions) => {
|
|
1911
|
+
return getRecommendations(base)(queries.map(query => ({
|
|
1912
|
+
...query,
|
|
1913
|
+
fallbackParameters: {},
|
|
1914
|
+
model: 'bought-together',
|
|
1915
|
+
})), requestOptions);
|
|
1916
|
+
};
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
const getRelatedProducts = base => {
|
|
1920
|
+
return (queries, requestOptions) => {
|
|
1921
|
+
return getRecommendations(base)(queries.map(query => ({
|
|
1922
|
+
...query,
|
|
1923
|
+
model: 'related-products',
|
|
1924
|
+
})), requestOptions);
|
|
1925
|
+
};
|
|
1926
|
+
};
|
|
1927
|
+
|
|
1928
|
+
const getTrendingFacets = base => {
|
|
1929
|
+
return (queries, requestOptions) => {
|
|
1930
|
+
const requests = queries.map(query => ({
|
|
1931
|
+
...query,
|
|
1932
|
+
model: 'trending-facets',
|
|
1933
|
+
// The `threshold` param is required by the endpoint to make it easier
|
|
1934
|
+
// to provide a default value later, so we default it in the client
|
|
1935
|
+
// so that users don't have to provide a value.
|
|
1936
|
+
threshold: query.threshold || 0,
|
|
1937
|
+
}));
|
|
1938
|
+
return base.transporter.read({
|
|
1939
|
+
method: requesterCommon.MethodEnum.Post,
|
|
1940
|
+
path: '1/indexes/*/recommendations',
|
|
1941
|
+
data: {
|
|
1942
|
+
requests,
|
|
1943
|
+
},
|
|
1944
|
+
cacheable: true,
|
|
1945
|
+
}, requestOptions);
|
|
1946
|
+
};
|
|
1947
|
+
};
|
|
1948
|
+
|
|
1949
|
+
const getTrendingItems = base => {
|
|
1950
|
+
return (queries, requestOptions) => {
|
|
1951
|
+
const requests = queries.map(query => ({
|
|
1952
|
+
...query,
|
|
1953
|
+
model: 'trending-items',
|
|
1954
|
+
// The `threshold` param is required by the endpoint to make it easier
|
|
1955
|
+
// to provide a default value later, so we default it in the client
|
|
1956
|
+
// so that users don't have to provide a value.
|
|
1957
|
+
threshold: query.threshold || 0,
|
|
1958
|
+
}));
|
|
1959
|
+
return base.transporter.read({
|
|
1960
|
+
method: requesterCommon.MethodEnum.Post,
|
|
1961
|
+
path: '1/indexes/*/recommendations',
|
|
1962
|
+
data: {
|
|
1963
|
+
requests,
|
|
1964
|
+
},
|
|
1965
|
+
cacheable: true,
|
|
1966
|
+
}, requestOptions);
|
|
1967
|
+
};
|
|
1968
|
+
};
|
|
1969
|
+
|
|
1970
|
+
const getLookingSimilar = base => {
|
|
1971
|
+
return (queries, requestOptions) => {
|
|
1972
|
+
return getRecommendations(base)(queries.map(query => ({
|
|
1973
|
+
...query,
|
|
1974
|
+
model: 'looking-similar',
|
|
1975
|
+
})), requestOptions);
|
|
1976
|
+
};
|
|
1977
|
+
};
|
|
1978
|
+
|
|
1979
|
+
const getRecommendedForYou = base => {
|
|
1980
|
+
return (queries, requestOptions) => {
|
|
1981
|
+
const requests = queries.map(query => ({
|
|
1982
|
+
...query,
|
|
1983
|
+
model: 'recommended-for-you',
|
|
1984
|
+
threshold: query.threshold || 0,
|
|
1985
|
+
}));
|
|
1986
|
+
return base.transporter.read({
|
|
1987
|
+
method: requesterCommon.MethodEnum.Post,
|
|
1988
|
+
path: '1/indexes/*/recommendations',
|
|
1989
|
+
data: {
|
|
1990
|
+
requests,
|
|
1991
|
+
},
|
|
1992
|
+
cacheable: true,
|
|
1993
|
+
}, requestOptions);
|
|
1994
|
+
};
|
|
1995
|
+
};
|
|
1996
|
+
|
|
1997
|
+
function recommend$2(appId, apiKey, options) {
|
|
1998
|
+
const commonOptions = {
|
|
1999
|
+
appId,
|
|
2000
|
+
apiKey,
|
|
2001
|
+
timeouts: {
|
|
2002
|
+
connect: 2,
|
|
2003
|
+
read: 5,
|
|
2004
|
+
write: 30,
|
|
2005
|
+
},
|
|
2006
|
+
requester: requesterNodeHttp$1.createNodeHttpRequester(),
|
|
2007
|
+
logger: loggerCommon$1.createNullLogger(),
|
|
2008
|
+
responsesCache: cacheCommon$1.createNullCache(),
|
|
2009
|
+
requestsCache: cacheCommon$1.createNullCache(),
|
|
2010
|
+
hostsCache: cacheInMemory$1.createInMemoryCache(),
|
|
2011
|
+
userAgent: transporter$1.createUserAgent(clientCommon$1.version)
|
|
2012
|
+
.add({ segment: 'Recommend', version: clientCommon$1.version })
|
|
2013
|
+
.add({ segment: 'Node.js', version: process.versions.node }),
|
|
2014
|
+
};
|
|
2015
|
+
return createRecommendClient({
|
|
2016
|
+
...commonOptions,
|
|
2017
|
+
...options,
|
|
2018
|
+
methods: {
|
|
2019
|
+
destroy: clientCommon$1.destroy,
|
|
2020
|
+
getFrequentlyBoughtTogether,
|
|
2021
|
+
getRecommendations,
|
|
2022
|
+
getRelatedProducts,
|
|
2023
|
+
getTrendingFacets,
|
|
2024
|
+
getTrendingItems,
|
|
2025
|
+
getLookingSimilar,
|
|
2026
|
+
getRecommendedForYou,
|
|
2027
|
+
},
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
/* eslint-disable functional/immutable-data */
|
|
2031
|
+
recommend$2.version = clientCommon$1.version;
|
|
2032
|
+
recommend$2.getFrequentlyBoughtTogether = getFrequentlyBoughtTogether;
|
|
2033
|
+
recommend$2.getRecommendations = getRecommendations;
|
|
2034
|
+
recommend$2.getRelatedProducts = getRelatedProducts;
|
|
2035
|
+
recommend$2.getTrendingFacets = getTrendingFacets;
|
|
2036
|
+
recommend$2.getTrendingItems = getTrendingItems;
|
|
2037
|
+
recommend$2.getLookingSimilar = getLookingSimilar;
|
|
2038
|
+
recommend$2.getRecommendedForYou = getRecommendedForYou;
|
|
2039
|
+
|
|
2040
|
+
var recommend_cjs = recommend$2;
|
|
2041
|
+
|
|
2042
|
+
/* eslint-disable functional/immutable-data, import/no-commonjs */
|
|
2043
|
+
|
|
2044
|
+
const recommend$1 = recommend_cjs;
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* The Common JS build is the default entry point for the Node environment. Keep in
|
|
2048
|
+
* in mind, that for the browser environment, we hint the bundler to use the UMD
|
|
2049
|
+
* build instead as specified on the key `browser` of our `package.json` file.
|
|
2050
|
+
*/
|
|
2051
|
+
recommend$3.exports = recommend$1;
|
|
2052
|
+
|
|
2053
|
+
/**
|
|
2054
|
+
* In addition, we also set explicitly the default export below making
|
|
2055
|
+
* this Common JS module in compliance with es6 modules specification.
|
|
2056
|
+
*/
|
|
2057
|
+
recommend$3.exports.default = recommend$1;
|
|
2058
|
+
|
|
2059
|
+
var recommendExports = recommend$3.exports;
|
|
2060
|
+
|
|
2061
|
+
var cacheCommon = require$$0;
|
|
2062
|
+
var cacheInMemory = require$$1;
|
|
2063
|
+
var clientAnalytics = require$$2;
|
|
2064
|
+
var clientCommon = require$$3;
|
|
2065
|
+
var clientPersonalization = require$$4;
|
|
2066
|
+
var clientSearch = require$$5;
|
|
2067
|
+
var loggerCommon = require$$6$1;
|
|
2068
|
+
var recommend = recommendExports;
|
|
2069
|
+
var requesterNodeHttp = require$$8;
|
|
2070
|
+
var transporter = require$$9;
|
|
2071
|
+
|
|
2072
|
+
function algoliasearch$2(appId, apiKey, options) {
|
|
2073
|
+
const commonOptions = {
|
|
2074
|
+
appId,
|
|
2075
|
+
apiKey,
|
|
2076
|
+
timeouts: {
|
|
2077
|
+
connect: 2,
|
|
2078
|
+
read: 5,
|
|
2079
|
+
write: 30,
|
|
2080
|
+
},
|
|
2081
|
+
requester: requesterNodeHttp.createNodeHttpRequester(),
|
|
2082
|
+
logger: loggerCommon.createNullLogger(),
|
|
2083
|
+
responsesCache: cacheCommon.createNullCache(),
|
|
2084
|
+
requestsCache: cacheCommon.createNullCache(),
|
|
2085
|
+
hostsCache: cacheInMemory.createInMemoryCache(),
|
|
2086
|
+
userAgent: transporter.createUserAgent(clientCommon.version).add({
|
|
2087
|
+
segment: 'Node.js',
|
|
2088
|
+
version: process.versions.node,
|
|
2089
|
+
}),
|
|
2090
|
+
};
|
|
2091
|
+
const searchClientOptions = { ...commonOptions, ...options };
|
|
2092
|
+
const initPersonalization = () => (clientOptions) => {
|
|
2093
|
+
return clientPersonalization.createPersonalizationClient({
|
|
2094
|
+
...commonOptions,
|
|
2095
|
+
...clientOptions,
|
|
2096
|
+
methods: {
|
|
2097
|
+
getPersonalizationStrategy: clientPersonalization.getPersonalizationStrategy,
|
|
2098
|
+
setPersonalizationStrategy: clientPersonalization.setPersonalizationStrategy,
|
|
2099
|
+
},
|
|
2100
|
+
});
|
|
2101
|
+
};
|
|
2102
|
+
return clientSearch.createSearchClient({
|
|
2103
|
+
...searchClientOptions,
|
|
2104
|
+
methods: {
|
|
2105
|
+
search: clientSearch.multipleQueries,
|
|
2106
|
+
searchForFacetValues: clientSearch.multipleSearchForFacetValues,
|
|
2107
|
+
multipleBatch: clientSearch.multipleBatch,
|
|
2108
|
+
multipleGetObjects: clientSearch.multipleGetObjects,
|
|
2109
|
+
multipleQueries: clientSearch.multipleQueries,
|
|
2110
|
+
copyIndex: clientSearch.copyIndex,
|
|
2111
|
+
copySettings: clientSearch.copySettings,
|
|
2112
|
+
copyRules: clientSearch.copyRules,
|
|
2113
|
+
copySynonyms: clientSearch.copySynonyms,
|
|
2114
|
+
moveIndex: clientSearch.moveIndex,
|
|
2115
|
+
listIndices: clientSearch.listIndices,
|
|
2116
|
+
getLogs: clientSearch.getLogs,
|
|
2117
|
+
listClusters: clientSearch.listClusters,
|
|
2118
|
+
multipleSearchForFacetValues: clientSearch.multipleSearchForFacetValues,
|
|
2119
|
+
getApiKey: clientSearch.getApiKey,
|
|
2120
|
+
addApiKey: clientSearch.addApiKey,
|
|
2121
|
+
listApiKeys: clientSearch.listApiKeys,
|
|
2122
|
+
updateApiKey: clientSearch.updateApiKey,
|
|
2123
|
+
deleteApiKey: clientSearch.deleteApiKey,
|
|
2124
|
+
restoreApiKey: clientSearch.restoreApiKey,
|
|
2125
|
+
assignUserID: clientSearch.assignUserID,
|
|
2126
|
+
assignUserIDs: clientSearch.assignUserIDs,
|
|
2127
|
+
getUserID: clientSearch.getUserID,
|
|
2128
|
+
searchUserIDs: clientSearch.searchUserIDs,
|
|
2129
|
+
listUserIDs: clientSearch.listUserIDs,
|
|
2130
|
+
getTopUserIDs: clientSearch.getTopUserIDs,
|
|
2131
|
+
removeUserID: clientSearch.removeUserID,
|
|
2132
|
+
hasPendingMappings: clientSearch.hasPendingMappings,
|
|
2133
|
+
generateSecuredApiKey: clientSearch.generateSecuredApiKey,
|
|
2134
|
+
getSecuredApiKeyRemainingValidity: clientSearch.getSecuredApiKeyRemainingValidity,
|
|
2135
|
+
destroy: clientCommon.destroy,
|
|
2136
|
+
clearDictionaryEntries: clientSearch.clearDictionaryEntries,
|
|
2137
|
+
deleteDictionaryEntries: clientSearch.deleteDictionaryEntries,
|
|
2138
|
+
getDictionarySettings: clientSearch.getDictionarySettings,
|
|
2139
|
+
getAppTask: clientSearch.getAppTask,
|
|
2140
|
+
replaceDictionaryEntries: clientSearch.replaceDictionaryEntries,
|
|
2141
|
+
saveDictionaryEntries: clientSearch.saveDictionaryEntries,
|
|
2142
|
+
searchDictionaryEntries: clientSearch.searchDictionaryEntries,
|
|
2143
|
+
setDictionarySettings: clientSearch.setDictionarySettings,
|
|
2144
|
+
waitAppTask: clientSearch.waitAppTask,
|
|
2145
|
+
customRequest: clientSearch.customRequest,
|
|
2146
|
+
initIndex: base => (indexName) => {
|
|
2147
|
+
return clientSearch.initIndex(base)(indexName, {
|
|
2148
|
+
methods: {
|
|
2149
|
+
batch: clientSearch.batch,
|
|
2150
|
+
delete: clientSearch.deleteIndex,
|
|
2151
|
+
findAnswers: clientSearch.findAnswers,
|
|
2152
|
+
getObject: clientSearch.getObject,
|
|
2153
|
+
getObjects: clientSearch.getObjects,
|
|
2154
|
+
saveObject: clientSearch.saveObject,
|
|
2155
|
+
saveObjects: clientSearch.saveObjects,
|
|
2156
|
+
search: clientSearch.search,
|
|
2157
|
+
searchForFacetValues: clientSearch.searchForFacetValues,
|
|
2158
|
+
waitTask: clientSearch.waitTask,
|
|
2159
|
+
setSettings: clientSearch.setSettings,
|
|
2160
|
+
getSettings: clientSearch.getSettings,
|
|
2161
|
+
partialUpdateObject: clientSearch.partialUpdateObject,
|
|
2162
|
+
partialUpdateObjects: clientSearch.partialUpdateObjects,
|
|
2163
|
+
deleteObject: clientSearch.deleteObject,
|
|
2164
|
+
deleteObjects: clientSearch.deleteObjects,
|
|
2165
|
+
deleteBy: clientSearch.deleteBy,
|
|
2166
|
+
clearObjects: clientSearch.clearObjects,
|
|
2167
|
+
browseObjects: clientSearch.browseObjects,
|
|
2168
|
+
getObjectPosition: clientSearch.getObjectPosition,
|
|
2169
|
+
findObject: clientSearch.findObject,
|
|
2170
|
+
exists: clientSearch.exists,
|
|
2171
|
+
saveSynonym: clientSearch.saveSynonym,
|
|
2172
|
+
saveSynonyms: clientSearch.saveSynonyms,
|
|
2173
|
+
getSynonym: clientSearch.getSynonym,
|
|
2174
|
+
searchSynonyms: clientSearch.searchSynonyms,
|
|
2175
|
+
browseSynonyms: clientSearch.browseSynonyms,
|
|
2176
|
+
deleteSynonym: clientSearch.deleteSynonym,
|
|
2177
|
+
clearSynonyms: clientSearch.clearSynonyms,
|
|
2178
|
+
replaceAllObjects: clientSearch.replaceAllObjects,
|
|
2179
|
+
replaceAllSynonyms: clientSearch.replaceAllSynonyms,
|
|
2180
|
+
searchRules: clientSearch.searchRules,
|
|
2181
|
+
getRule: clientSearch.getRule,
|
|
2182
|
+
deleteRule: clientSearch.deleteRule,
|
|
2183
|
+
saveRule: clientSearch.saveRule,
|
|
2184
|
+
saveRules: clientSearch.saveRules,
|
|
2185
|
+
replaceAllRules: clientSearch.replaceAllRules,
|
|
2186
|
+
browseRules: clientSearch.browseRules,
|
|
2187
|
+
clearRules: clientSearch.clearRules,
|
|
2188
|
+
},
|
|
2189
|
+
});
|
|
2190
|
+
},
|
|
2191
|
+
initAnalytics: () => (clientOptions) => {
|
|
2192
|
+
return clientAnalytics.createAnalyticsClient({
|
|
2193
|
+
...commonOptions,
|
|
2194
|
+
...clientOptions,
|
|
2195
|
+
methods: {
|
|
2196
|
+
addABTest: clientAnalytics.addABTest,
|
|
2197
|
+
getABTest: clientAnalytics.getABTest,
|
|
2198
|
+
getABTests: clientAnalytics.getABTests,
|
|
2199
|
+
stopABTest: clientAnalytics.stopABTest,
|
|
2200
|
+
deleteABTest: clientAnalytics.deleteABTest,
|
|
2201
|
+
},
|
|
2202
|
+
});
|
|
2203
|
+
},
|
|
2204
|
+
initPersonalization,
|
|
2205
|
+
initRecommendation: () => (clientOptions) => {
|
|
2206
|
+
searchClientOptions.logger.info('The `initRecommendation` method is deprecated. Use `initPersonalization` instead.');
|
|
2207
|
+
return initPersonalization()(clientOptions);
|
|
2208
|
+
},
|
|
2209
|
+
getRecommendations: recommend.getRecommendations,
|
|
2210
|
+
getFrequentlyBoughtTogether: recommend.getFrequentlyBoughtTogether,
|
|
2211
|
+
getLookingSimilar: recommend.getLookingSimilar,
|
|
2212
|
+
getRecommendedForYou: recommend.getRecommendedForYou,
|
|
2213
|
+
getRelatedProducts: recommend.getRelatedProducts,
|
|
2214
|
+
getTrendingFacets: recommend.getTrendingFacets,
|
|
2215
|
+
getTrendingItems: recommend.getTrendingItems,
|
|
2216
|
+
},
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
// eslint-disable-next-line functional/immutable-data
|
|
2220
|
+
algoliasearch$2.version = clientCommon.version;
|
|
2221
|
+
|
|
2222
|
+
var algoliasearch_cjs = algoliasearch$2;
|
|
2223
|
+
|
|
2224
|
+
/* eslint-disable functional/immutable-data, import/no-commonjs */
|
|
2225
|
+
|
|
2226
|
+
const algoliasearch$1 = algoliasearch_cjs;
|
|
2227
|
+
|
|
2228
|
+
/**
|
|
2229
|
+
* The Common JS build is the default entry point for the Node environment. Keep in
|
|
2230
|
+
* in mind, that for the browser environment, we hint the bundler to use the UMD
|
|
2231
|
+
* build instead as specified on the key `browser` of our `package.json` file.
|
|
2232
|
+
*/
|
|
2233
|
+
algoliasearch$3.exports = algoliasearch$1;
|
|
2234
|
+
|
|
2235
|
+
/**
|
|
2236
|
+
* In addition, we also set explicitly the default export below making
|
|
2237
|
+
* this Common JS module in compliance with es6 modules specification.
|
|
2238
|
+
*/
|
|
2239
|
+
algoliasearch$3.exports.default = algoliasearch$1;
|
|
2240
|
+
|
|
2241
|
+
var algoliasearchExports = algoliasearch$3.exports;
|
|
2242
|
+
|
|
2243
|
+
// eslint-disable-next-line functional/immutable-data, import/no-commonjs
|
|
2244
|
+
var lite = algoliasearchExports;
|
|
2245
|
+
|
|
2246
|
+
var algoliasearch = /*@__PURE__*/getDefaultExportFromCjs(lite);
|
|
2247
|
+
|
|
2248
|
+
const onlineSearchClient = algoliasearch('testing9VXJ0U4GSV', 'f3c57c730433f5cf7825b62545eccb05');
|
|
2249
|
+
const searchClient = ({ online }) => ({
|
|
2250
|
+
search(queries, requestOptions) {
|
|
2251
|
+
if (online)
|
|
2252
|
+
return onlineSearchClient
|
|
2253
|
+
.search(queries, requestOptions)
|
|
2254
|
+
.then(result => {
|
|
2255
|
+
// eslint-disable-next-line no-console
|
|
2256
|
+
console.log('search', result);
|
|
2257
|
+
return result;
|
|
2258
|
+
});
|
|
2259
|
+
return fetch('data/algolia.json').then(response => response.json());
|
|
2260
|
+
},
|
|
2261
|
+
async searchForFacetValues(queries, requestOptions) {
|
|
2262
|
+
if (online)
|
|
2263
|
+
return onlineSearchClient
|
|
2264
|
+
.searchForFacetValues(queries, requestOptions)
|
|
2265
|
+
.then(result => {
|
|
2266
|
+
// eslint-disable-next-line no-console
|
|
2267
|
+
console.log('searchForFacetValues', result);
|
|
2268
|
+
return result;
|
|
2269
|
+
});
|
|
2270
|
+
return [];
|
|
2271
|
+
},
|
|
2272
|
+
});
|
|
2273
|
+
|
|
2274
|
+
const AlgoliaContext = createContext({
|
|
2275
|
+
online: false,
|
|
2276
|
+
setOnline: () => { },
|
|
2277
|
+
toggleOnline: () => { },
|
|
2278
|
+
});
|
|
2279
|
+
function AlgoliaProvider({ children, online: _online = false, }) {
|
|
2280
|
+
const [online, setOnline] = useState(_online);
|
|
2281
|
+
return (jsx(AlgoliaContext.Provider, { value: {
|
|
2282
|
+
online,
|
|
2283
|
+
setOnline,
|
|
2284
|
+
toggleOnline: () => setOnline(online => !online),
|
|
2285
|
+
}, children: jsxs(InstantSearch, { future: {
|
|
2286
|
+
persistHierarchicalRootCount: true,
|
|
2287
|
+
preserveSharedStateOnUnmount: true,
|
|
2288
|
+
}, indexName: "dev_sonic_products_en", searchClient: searchClient({ online }), children: [jsx(Configure, { analytics: false, filters: "categoryPageId: Toolbox", hitsPerPage: 9, maxValuesPerFacet: 100 }), children] }) }));
|
|
2289
|
+
}
|
|
2290
|
+
function useAlgolia() {
|
|
2291
|
+
return useContext(AlgoliaContext);
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, AlgoliaMultiSelect, AlgoliaPagination, AlgoliaProductList, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Button, CartFilledIcon, CartOutlinedIcon, CartProvider, Checkbox, ColorCheckbox, ConnectedAddToCartButton, DehashedOutlinedIcon, FavoriteButton, FavoriteFilledIcon, FavoriteOutlinedIcon, FormattedMessage, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, Image, IntlProvider, LinkButton, MultiSelect, NumberField, ProductCard, ProductListing, ProductOverviewGrid, ProductPrice, ProductSku, RightArrowFilledIcon, Select, ShowAll, Sidebar, TextField, createProductListingSearchParams, parseProductListingSearchParams, useAlgolia, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
|