@searchspring/snap-preact 0.59.0 → 0.60.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.
@@ -43,12 +43,23 @@ export declare class RecommendationInstantiator {
43
43
  config: RecommendationInstantiatorConfig;
44
44
  context: ContextVariables;
45
45
  targeter: DomTargeter;
46
- private uses;
47
- private plugins;
48
- private middleware;
46
+ uses: Attachments[];
47
+ plugins: {
48
+ func: (cntrlr: AbstractController, ...args: any) => Promise<void>;
49
+ args: unknown[];
50
+ }[];
51
+ middleware: {
52
+ event: string;
53
+ func: Middleware<unknown>[];
54
+ }[];
49
55
  constructor(config: RecommendationInstantiatorConfig, services?: RecommendationInstantiatorServices, context?: ContextVariables);
50
56
  plugin(func: (cntrlr: AbstractController, ...args: any) => Promise<void>, ...args: unknown[]): void;
51
57
  on(event: string, ...func: Middleware<unknown>[]): void;
52
58
  use(attachments: Attachments): void;
53
59
  }
60
+ type DefinedProps = {
61
+ [key: string]: any;
62
+ };
63
+ export declare function defined(properties: Record<string, any>): DefinedProps;
64
+ export {};
54
65
  //# sourceMappingURL=RecommendationInstantiator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAGnE,MAAM,MAAM,gCAAgC,GAAG;IAC9C,IAAI,CAAC,EAAE,MAAM,OAAO,OAAO,GAAG,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE;QACR,OAAO,EAAE,aAAa,CAAC;QACvB,MAAM,CAAC,EAAE,YAAY,CAAC;KACtB,CAAC;IACF,UAAU,EAAE;QACX,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;KACzC,CAAC;IACF,MAAM,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,aAAa,CAAC;KACzB,GAAG,WAAW,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,qBAAa,0BAA0B;IACtC,OAAO,CAAC,IAAI,CAAsB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,CAAC;KACxC,CAAM;IACA,MAAM,EAAE,gCAAgC,CAAC;IACzC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,WAAW,CAAC;IAE7B,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAAgG;IAC/G,OAAO,CAAC,UAAU,CAAwD;gBAE9D,MAAM,EAAE,gCAAgC,EAAE,QAAQ,CAAC,EAAE,kCAAkC,EAAE,OAAO,CAAC,EAAE,gBAAgB;IAyQxH,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAInG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI;IAIvD,GAAG,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;CAG1C"}
1
+ {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"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"}
@@ -82,7 +82,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
82
82
  return (mod && mod.__esModule) ? mod : { "default": mod };
83
83
  };
84
84
  Object.defineProperty(exports, "__esModule", { value: true });
85
- exports.RecommendationInstantiator = void 0;
85
+ exports.defined = exports.RecommendationInstantiator = void 0;
86
86
  var jsx_runtime_1 = require("preact/jsx-runtime");
87
87
  var preact_1 = require("preact");
88
88
  var deepmerge_1 = __importDefault(require("deepmerge"));
@@ -127,7 +127,7 @@ var RecommendationInstantiator = /** @class */ (function () {
127
127
  var profileCount = {};
128
128
  this.targeter = new snap_toolbox_1.DomTargeter([
129
129
  {
130
- selector: this.config.selector || 'script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]',
130
+ selector: "".concat(this.config.selector || 'script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]', ", script[type=\"searchspring/recommend\"][profile=\"email\"]"),
131
131
  autoRetarget: true,
132
132
  clickRetarget: true,
133
133
  inject: {
@@ -140,180 +140,85 @@ var RecommendationInstantiator = /** @class */ (function () {
140
140
  },
141
141
  },
142
142
  },
143
- ], function (target, injectedElem, elem) { return __awaiter(_this, void 0, void 0, function () {
144
- var tag, contextGlobals, elemContext, context, shopper, shopperId, product, products, seed, cart, options, cartContents, cartFuncContents, defaultGlobals, globals, controllerConfig, controller, createRecommendationController, profileVars, component, RecommendationsComponent, _a;
143
+ {
144
+ selector: 'script[type="searchspring/recommendations"]',
145
+ autoRetarget: true,
146
+ clickRetarget: true,
147
+ emptyTarget: false,
148
+ },
149
+ ], function (target, elem, originalElem) { return __awaiter(_this, void 0, void 0, function () {
150
+ var elemContext, scriptContextProfiles, scriptContextGlobals_1, requestGlobals_1, targetsArr_1, profile, products, product, seed, filters, blockedItems, options, shopper, shopperId, profileRequestGlobals;
145
151
  var _this = this;
146
- var _b, _c, _d, _e;
147
- return __generator(this, function (_f) {
148
- switch (_f.label) {
149
- case 0:
150
- tag = injectedElem === null || injectedElem === void 0 ? void 0 : injectedElem.getAttribute('searchspring-recommend');
151
- if (!tag) {
152
- this.logger.warn("'profile' attribute is missing from <script> tag, skipping this profile", elem);
153
- return [2 /*return*/];
152
+ var _a;
153
+ return __generator(this, function (_b) {
154
+ elemContext = (0, snap_toolbox_1.getContext)([
155
+ 'shopperId',
156
+ 'shopper',
157
+ 'product',
158
+ 'products',
159
+ 'seed',
160
+ 'cart',
161
+ 'filters',
162
+ 'blockedItems',
163
+ 'options',
164
+ 'profile',
165
+ 'custom',
166
+ 'profiles',
167
+ 'globals',
168
+ ], (originalElem || elem));
169
+ if (elemContext.profiles && elemContext.profiles.length) {
170
+ scriptContextProfiles = elemContext.profiles;
171
+ scriptContextGlobals_1 = elemContext.globals;
172
+ requestGlobals_1 = __assign({}, defined({
173
+ blockedItems: scriptContextGlobals_1.blockedItems,
174
+ filters: scriptContextGlobals_1.filters,
175
+ cart: scriptContextGlobals_1.cart && getArrayFunc(scriptContextGlobals_1.cart),
176
+ products: scriptContextGlobals_1.products,
177
+ shopper: (_a = scriptContextGlobals_1.shopper) === null || _a === void 0 ? void 0 : _a.id,
178
+ batchId: Math.random(),
179
+ }));
180
+ targetsArr_1 = [];
181
+ // build out the targets array for each profile
182
+ scriptContextProfiles.forEach(function (profile) {
183
+ if (profile.selector) {
184
+ var targetObj = {
185
+ selector: profile.selector,
186
+ autoRetarget: true,
187
+ clickRetarget: true,
188
+ profile: profile,
189
+ };
190
+ targetsArr_1.push(targetObj);
154
191
  }
155
- contextGlobals = {};
156
- elemContext = (0, snap_toolbox_1.getContext)(['shopperId', 'shopper', 'product', 'products', 'seed', 'cart', 'options', 'profile', 'custom'], elem);
157
- context = (0, deepmerge_1.default)(this.context, elemContext);
158
- shopper = context.shopper, shopperId = context.shopperId, product = context.product, products = context.products, seed = context.seed, cart = context.cart, options = context.options;
159
- /*
160
- type instantiatorContext = {
161
- shopper?: {
162
- id: string;
163
- };
164
- shopperId?: string;
165
- product?: string;
166
- products?: string[];
167
- seed?: string;
168
- cart?: string[] | () => string[];
169
- options?: {
170
- siteId?: string;
171
- branch?: string;
172
- batched?: boolean;
173
- realtime?: boolean;
174
- categories?: string[];
175
- blockedItems?: string[];
176
- brands?: string[];
177
- limit?: number;
192
+ });
193
+ new snap_toolbox_1.DomTargeter(targetsArr_1, function (target, elem, originalElem) { return __awaiter(_this, void 0, void 0, function () {
194
+ var profileRequestGlobals, profileContext;
195
+ var _a, _b;
196
+ return __generator(this, function (_c) {
197
+ if ((_a = target.profile) === null || _a === void 0 ? void 0 : _a.profile) {
198
+ profileRequestGlobals = __assign(__assign({}, requestGlobals_1), { profile: (_b = target.profile) === null || _b === void 0 ? void 0 : _b.options, tag: target.profile.profile });
199
+ profileContext = (0, deepmerge_1.default)(this.context, { globals: scriptContextGlobals_1, profile: target.profile });
200
+ if (elemContext.custom) {
201
+ profileContext.custom = elemContext.custom;
178
202
  }
203
+ readyTheController(this, elem, profileContext, profileCount, originalElem, profileRequestGlobals);
179
204
  }
180
- */
181
- if (shopper || shopperId) {
182
- contextGlobals.shopper = (shopper === null || shopper === void 0 ? void 0 : shopper.id) || shopperId;
183
- }
184
- if (product || seed) {
185
- contextGlobals.product = product || seed;
186
- }
187
- if (products) {
188
- contextGlobals.products = products;
189
- }
190
- // options
191
- if (options === null || options === void 0 ? void 0 : options.branch) {
192
- contextGlobals.branch = options.branch;
193
- }
194
- if (options === null || options === void 0 ? void 0 : options.siteId) {
195
- contextGlobals.siteId = options.siteId;
196
- }
197
- if (options === null || options === void 0 ? void 0 : options.categories) {
198
- contextGlobals.categories = options.categories;
199
- }
200
- if (options === null || options === void 0 ? void 0 : options.filters) {
201
- contextGlobals.filters = options.filters;
202
- }
203
- if (options === null || options === void 0 ? void 0 : options.brands) {
204
- contextGlobals.brands = options.brands;
205
- }
206
- if ((options === null || options === void 0 ? void 0 : options.limit) && Number.isInteger(Number(options === null || options === void 0 ? void 0 : options.limit))) {
207
- contextGlobals.limits = Number(options === null || options === void 0 ? void 0 : options.limit);
208
- }
209
- if ((options === null || options === void 0 ? void 0 : options.blockedItems) && Array.isArray(options.blockedItems)) {
210
- contextGlobals.blockedItems = options.blockedItems;
211
- }
212
- if (typeof cart === 'function') {
213
- try {
214
- cartFuncContents = cart();
215
- if (Array.isArray(cartFuncContents)) {
216
- cartContents = cartFuncContents;
217
- }
218
- }
219
- catch (e) {
220
- this.logger.warn("Error getting cart contents from function", e);
221
- }
222
- }
223
- else if (Array.isArray(cart)) {
224
- cartContents = cart;
225
- }
226
- if (Array.isArray(cartContents)) {
227
- this.tracker.cookies.cart.set(cartContents);
228
- contextGlobals.cart = this.tracker.cookies.cart.get();
229
- }
230
- profileCount[tag] = profileCount[tag] + 1 || 1;
231
- defaultGlobals = {
232
- limits: 20,
233
- };
234
- globals = (0, deepmerge_1.default)((0, deepmerge_1.default)((0, deepmerge_1.default)(defaultGlobals, ((_b = this.config.client) === null || _b === void 0 ? void 0 : _b.globals) || {}), ((_c = this.config.config) === null || _c === void 0 ? void 0 : _c.globals) || {}), contextGlobals);
235
- controllerConfig = __assign(__assign({ id: "recommend_".concat(tag, "_").concat(profileCount[tag] - 1), tag: tag, batched: (_d = options === null || options === void 0 ? void 0 : options.batched) !== null && _d !== void 0 ? _d : true, realtime: Boolean(options === null || options === void 0 ? void 0 : options.realtime) }, this.config.config), { globals: globals });
236
- controller = Object.keys(this.controller)
237
- .map(function (id) { return _this.controller[id]; })
238
- .filter(function (controller) {
239
- return (JSON.stringify({
240
- batched: controller.config.batched,
241
- branch: controller.config.branch,
242
- globals: controller.config.globals,
243
- tag: controller.config.tag,
244
- realtime: controller.config.realtime,
245
- }) ==
246
- JSON.stringify({
247
- batched: controllerConfig.batched,
248
- branch: controllerConfig.branch,
249
- globals: controllerConfig.globals,
250
- tag: controllerConfig.tag,
251
- realtime: controllerConfig.realtime,
252
- }));
253
- })[0];
254
- if (!!controller) return [3 /*break*/, 2];
255
- return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require('../create/createRecommendationController')); })];
256
- case 1:
257
- createRecommendationController = (_f.sent()).default;
258
- controller = createRecommendationController({
259
- url: this.config.url,
260
- controller: controllerConfig,
261
- context: context,
262
- mode: this.config.mode,
263
- }, { client: this.client, tracker: this.tracker });
264
- _f.label = 2;
265
- case 2:
266
- this.uses.forEach(function (attachements) { return controller.use(attachements); });
267
- this.plugins.forEach(function (plugin) { return controller.plugin.apply(controller, __spreadArray([plugin.func], plugin.args, false)); });
268
- this.middleware.forEach(function (middleware) { return controller.on.apply(controller, __spreadArray([middleware.event], middleware.func, false)); });
269
- if (!(!controller.store.loaded && !controller.store.loading)) return [3 /*break*/, 4];
270
- return [4 /*yield*/, controller.search()];
271
- case 3:
272
- _f.sent();
273
- _f.label = 4;
274
- case 4:
275
- controller.addTargeter(this.targeter);
276
- this.controller[controller.config.id] = controller;
277
- window.searchspring.controller = window.searchspring.controller || {};
278
- window.searchspring.controller[controller.config.id] = controller;
279
- profileVars = controller.store.profile.display.templateParameters;
280
- component = (_e = controller.store.profile.display.template) === null || _e === void 0 ? void 0 : _e.component;
281
- if (controller.store.error) {
282
- //something went wrong
283
- //err was already logged - nothing to do.
284
- return [2 /*return*/];
285
- }
286
- if (!controller.store.profile.display.template) {
287
- this.logger.error("profile '".concat(tag, "' found on the following element is missing a template!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
288
- return [2 /*return*/];
289
- }
290
- if (!profileVars) {
291
- this.logger.error("profile '".concat(tag, "' found on the following element is missing templateParameters!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
292
205
  return [2 /*return*/];
293
- }
294
- if (!component) {
295
- this.logger.error("profile '".concat(tag, "' found on the following element is missing a component!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
296
- return [2 /*return*/];
297
- }
298
- _a = this.config.components[component];
299
- if (!_a) return [3 /*break*/, 6];
300
- return [4 /*yield*/, this.config.components[component]()];
301
- case 5:
302
- _a = (_f.sent());
303
- _f.label = 6;
304
- case 6:
305
- RecommendationsComponent = _a;
306
- if (!RecommendationsComponent) {
307
- this.logger.error("profile '".concat(tag, "' found on the following element is expecting component mapping for '").concat(component, "' - verify instantiator config.\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
308
- return [2 /*return*/];
309
- }
310
- setTimeout(function () {
311
- if (injectedElem) {
312
- (0, preact_1.render)((0, jsx_runtime_1.jsx)(RecommendationsComponent, { controller: controller }), injectedElem);
313
- }
314
206
  });
315
- return [2 /*return*/];
207
+ }); });
208
+ }
209
+ else {
210
+ profile = elemContext.profile, products = elemContext.products, product = elemContext.product, seed = elemContext.seed, filters = elemContext.filters, blockedItems = elemContext.blockedItems, options = elemContext.options, shopper = elemContext.shopper, shopperId = elemContext.shopperId;
211
+ profileRequestGlobals = __assign({ tag: profile }, defined({
212
+ products: products || (product && [product]) || (seed && [seed]),
213
+ cart: elemContext.cart && getArrayFunc(elemContext.cart),
214
+ shopper: (shopper === null || shopper === void 0 ? void 0 : shopper.id) || shopperId,
215
+ filters: filters,
216
+ blockedItems: blockedItems,
217
+ profile: options,
218
+ }));
219
+ readyTheController(this, elem, elemContext, profileCount, originalElem, profileRequestGlobals);
316
220
  }
221
+ return [2 /*return*/];
317
222
  });
318
223
  }); });
319
224
  }
@@ -337,3 +242,141 @@ var RecommendationInstantiator = /** @class */ (function () {
337
242
  return RecommendationInstantiator;
338
243
  }());
339
244
  exports.RecommendationInstantiator = RecommendationInstantiator;
245
+ function readyTheController(instance, injectedElem, context, profileCount, elem, controllerGlobals) {
246
+ var _a, _b, _c, _d, _e, _f, _g, _h;
247
+ return __awaiter(this, void 0, void 0, function () {
248
+ var profile, batchId, cart, tag, batched, globals, controllerConfig, controller, createRecommendationController, profileVars, component, RecommendationsComponent, _j;
249
+ return __generator(this, function (_k) {
250
+ switch (_k.label) {
251
+ case 0:
252
+ profile = controllerGlobals.profile, batchId = controllerGlobals.batchId, cart = controllerGlobals.cart, tag = controllerGlobals.tag;
253
+ batched = (_a = ((profile === null || profile === void 0 ? void 0 : profile.batched) || controllerGlobals.batched)) !== null && _a !== void 0 ? _a : true;
254
+ if (!tag) {
255
+ // FEEDBACK: change message depending on script integration type (profile vs. legacy)
256
+ instance.logger.warn("'profile' is missing from <script> tag, skipping this profile", elem);
257
+ return [2 /*return*/];
258
+ }
259
+ if (Array.isArray(cart)) {
260
+ instance.tracker.cookies.cart.set(cart);
261
+ }
262
+ profileCount[tag] = profileCount[tag] + 1 || 1;
263
+ globals = deepmerge_1.default.all([
264
+ ((_b = instance.config.client) === null || _b === void 0 ? void 0 : _b.globals) || {},
265
+ ((_c = instance.config.config) === null || _c === void 0 ? void 0 : _c.globals) || {},
266
+ controllerGlobals,
267
+ ]);
268
+ controllerConfig = __assign(__assign({ id: "recommend_".concat(tag, "_").concat(profileCount[tag] - 1), tag: tag, batched: batched !== null && batched !== void 0 ? batched : true, realtime: Boolean((_e = (_d = context.options) === null || _d === void 0 ? void 0 : _d.realtime) !== null && _e !== void 0 ? _e : (_g = (_f = context.profile) === null || _f === void 0 ? void 0 : _f.options) === null || _g === void 0 ? void 0 : _g.realtime), batchId: batchId }, instance.config.config), { globals: globals });
269
+ if (profile === null || profile === void 0 ? void 0 : profile.branch) {
270
+ controllerConfig.branch = profile === null || profile === void 0 ? void 0 : profile.branch;
271
+ }
272
+ controller = Object.keys(instance.controller)
273
+ .map(function (id) { return instance.controller[id]; })
274
+ .filter(function (controller) {
275
+ return (JSON.stringify({
276
+ batched: controller.config.batched,
277
+ branch: controller.config.branch,
278
+ globals: controller.config.globals,
279
+ tag: controller.config.tag,
280
+ realtime: controller.config.realtime,
281
+ }) ==
282
+ JSON.stringify({
283
+ batched: controllerConfig.batched,
284
+ branch: controllerConfig.branch,
285
+ globals: controllerConfig.globals,
286
+ tag: controllerConfig.tag,
287
+ realtime: controllerConfig.realtime,
288
+ }));
289
+ })[0];
290
+ if (!!controller) return [3 /*break*/, 2];
291
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require('../create/createRecommendationController')); })];
292
+ case 1:
293
+ createRecommendationController = (_k.sent()).default;
294
+ controller = createRecommendationController({
295
+ url: instance.config.url,
296
+ controller: controllerConfig,
297
+ context: context,
298
+ mode: instance.config.mode,
299
+ }, { client: instance.client, tracker: instance.tracker });
300
+ instance.uses.forEach(function (attachements) { return controller.use(attachements); });
301
+ instance.plugins.forEach(function (plugin) { return controller.plugin.apply(controller, __spreadArray([plugin.func], plugin.args, false)); });
302
+ instance.middleware.forEach(function (middleware) { return controller.on.apply(controller, __spreadArray([middleware.event], middleware.func, false)); });
303
+ _k.label = 2;
304
+ case 2:
305
+ if (!(!controller.store.loaded && !controller.store.loading)) return [3 /*break*/, 4];
306
+ return [4 /*yield*/, controller.search()];
307
+ case 3:
308
+ _k.sent();
309
+ _k.label = 4;
310
+ case 4:
311
+ controller.addTargeter(instance.targeter);
312
+ instance.controller[controller.config.id] = controller;
313
+ window.searchspring.controller = window.searchspring.controller || {};
314
+ window.searchspring.controller[controller.config.id] = controller;
315
+ profileVars = controller.store.profile.display.templateParameters;
316
+ component = (_h = controller.store.profile.display.template) === null || _h === void 0 ? void 0 : _h.component;
317
+ if (controller.store.error) {
318
+ //something went wrong
319
+ //err was already logged - nothing to do.
320
+ return [2 /*return*/];
321
+ }
322
+ if (!controller.store.profile.display.template) {
323
+ instance.logger.error("profile '".concat(tag, "' found on the following element is missing a template!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
324
+ return [2 /*return*/];
325
+ }
326
+ if (!profileVars) {
327
+ instance.logger.error("profile '".concat(tag, "' found on the following element is missing templateParameters!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
328
+ return [2 /*return*/];
329
+ }
330
+ if (!component) {
331
+ instance.logger.error("profile '".concat(tag, "' found on the following element is missing a component!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
332
+ return [2 /*return*/];
333
+ }
334
+ _j = instance.config.components[component];
335
+ if (!_j) return [3 /*break*/, 6];
336
+ return [4 /*yield*/, instance.config.components[component]()];
337
+ case 5:
338
+ _j = (_k.sent());
339
+ _k.label = 6;
340
+ case 6:
341
+ RecommendationsComponent = _j;
342
+ if (!RecommendationsComponent) {
343
+ instance.logger.error("profile '".concat(tag, "' found on the following element is expecting component mapping for '").concat(component, "' - verify instantiator config.\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
344
+ return [2 /*return*/];
345
+ }
346
+ setTimeout(function () {
347
+ if (injectedElem) {
348
+ (0, preact_1.render)((0, jsx_runtime_1.jsx)(RecommendationsComponent, { controller: controller }), injectedElem);
349
+ }
350
+ });
351
+ return [2 /*return*/];
352
+ }
353
+ });
354
+ });
355
+ }
356
+ function getArrayFunc(arrayOrFunc) {
357
+ if (typeof arrayOrFunc === 'function') {
358
+ try {
359
+ var funcContents = arrayOrFunc();
360
+ if (Array.isArray(funcContents)) {
361
+ return funcContents;
362
+ }
363
+ }
364
+ catch (e) {
365
+ // function didn't return an array
366
+ }
367
+ }
368
+ else if (Array.isArray(arrayOrFunc)) {
369
+ return arrayOrFunc;
370
+ }
371
+ return [];
372
+ }
373
+ function defined(properties) {
374
+ var definedProps = {};
375
+ Object.keys(properties).map(function (key) {
376
+ if (properties[key] !== undefined) {
377
+ definedProps[key] = properties[key];
378
+ }
379
+ });
380
+ return definedProps;
381
+ }
382
+ exports.defined = defined;
@@ -43,12 +43,23 @@ export declare class RecommendationInstantiator {
43
43
  config: RecommendationInstantiatorConfig;
44
44
  context: ContextVariables;
45
45
  targeter: DomTargeter;
46
- private uses;
47
- private plugins;
48
- private middleware;
46
+ uses: Attachments[];
47
+ plugins: {
48
+ func: (cntrlr: AbstractController, ...args: any) => Promise<void>;
49
+ args: unknown[];
50
+ }[];
51
+ middleware: {
52
+ event: string;
53
+ func: Middleware<unknown>[];
54
+ }[];
49
55
  constructor(config: RecommendationInstantiatorConfig, services?: RecommendationInstantiatorServices, context?: ContextVariables);
50
56
  plugin(func: (cntrlr: AbstractController, ...args: any) => Promise<void>, ...args: unknown[]): void;
51
57
  on(event: string, ...func: Middleware<unknown>[]): void;
52
58
  use(attachments: Attachments): void;
53
59
  }
60
+ type DefinedProps = {
61
+ [key: string]: any;
62
+ };
63
+ export declare function defined(properties: Record<string, any>): DefinedProps;
64
+ export {};
54
65
  //# sourceMappingURL=RecommendationInstantiator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAGnE,MAAM,MAAM,gCAAgC,GAAG;IAC9C,IAAI,CAAC,EAAE,MAAM,OAAO,OAAO,GAAG,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE;QACR,OAAO,EAAE,aAAa,CAAC;QACvB,MAAM,CAAC,EAAE,YAAY,CAAC;KACtB,CAAC;IACF,UAAU,EAAE;QACX,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;KACzC,CAAC;IACF,MAAM,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,aAAa,CAAC;KACzB,GAAG,WAAW,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,qBAAa,0BAA0B;IACtC,OAAO,CAAC,IAAI,CAAsB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,CAAC;KACxC,CAAM;IACA,MAAM,EAAE,gCAAgC,CAAC;IACzC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,WAAW,CAAC;IAE7B,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAAgG;IAC/G,OAAO,CAAC,UAAU,CAAwD;gBAE9D,MAAM,EAAE,gCAAgC,EAAE,QAAQ,CAAC,EAAE,kCAAkC,EAAE,OAAO,CAAC,EAAE,gBAAgB;IAyQxH,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAInG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI;IAIvD,GAAG,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;CAG1C"}
1
+ {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"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"}
@@ -40,7 +40,7 @@ export class RecommendationInstantiator {
40
40
  const profileCount = {};
41
41
  this.targeter = new DomTargeter([
42
42
  {
43
- selector: this.config.selector || 'script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]',
43
+ selector: `${this.config.selector || 'script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]'}, script[type="searchspring/recommend"][profile="email"]`,
44
44
  autoRetarget: true,
45
45
  clickRetarget: true,
46
46
  inject: {
@@ -53,171 +53,88 @@ export class RecommendationInstantiator {
53
53
  },
54
54
  },
55
55
  },
56
- ], async (target, injectedElem, elem) => {
57
- const tag = injectedElem?.getAttribute('searchspring-recommend');
58
- if (!tag) {
59
- this.logger.warn(`'profile' attribute is missing from <script> tag, skipping this profile`, elem);
60
- return;
61
- }
62
- const contextGlobals = {};
63
- const elemContext = getContext(['shopperId', 'shopper', 'product', 'products', 'seed', 'cart', 'options', 'profile', 'custom'], elem);
64
- const context = deepmerge(this.context, elemContext);
65
- const { shopper, shopperId, product, products, seed, cart, options } = context;
66
- /*
67
- type instantiatorContext = {
68
- shopper?: {
69
- id: string;
70
- };
71
- shopperId?: string;
72
- product?: string;
73
- products?: string[];
74
- seed?: string;
75
- cart?: string[] | () => string[];
76
- options?: {
77
- siteId?: string;
78
- branch?: string;
79
- batched?: boolean;
80
- realtime?: boolean;
81
- categories?: string[];
82
- blockedItems?: string[];
83
- brands?: string[];
84
- limit?: number;
56
+ {
57
+ selector: 'script[type="searchspring/recommendations"]',
58
+ autoRetarget: true,
59
+ clickRetarget: true,
60
+ emptyTarget: false,
61
+ },
62
+ ], async (target, elem, originalElem) => {
63
+ const elemContext = getContext([
64
+ 'shopperId',
65
+ 'shopper',
66
+ 'product',
67
+ 'products',
68
+ 'seed',
69
+ 'cart',
70
+ 'filters',
71
+ 'blockedItems',
72
+ 'options',
73
+ 'profile',
74
+ 'custom',
75
+ 'profiles',
76
+ 'globals',
77
+ ], (originalElem || elem));
78
+ if (elemContext.profiles && elemContext.profiles.length) {
79
+ // using the "grouped block" integration structure
80
+ // type the new profile specific integration context variables
81
+ const scriptContextProfiles = elemContext.profiles;
82
+ const scriptContextGlobals = elemContext.globals;
83
+ // grab from globals
84
+ const requestGlobals = {
85
+ ...defined({
86
+ blockedItems: scriptContextGlobals.blockedItems,
87
+ filters: scriptContextGlobals.filters,
88
+ cart: scriptContextGlobals.cart && getArrayFunc(scriptContextGlobals.cart),
89
+ products: scriptContextGlobals.products,
90
+ shopper: scriptContextGlobals.shopper?.id,
91
+ batchId: Math.random(),
92
+ }),
93
+ };
94
+ const targetsArr = [];
95
+ // build out the targets array for each profile
96
+ scriptContextProfiles.forEach((profile) => {
97
+ if (profile.selector) {
98
+ const targetObj = {
99
+ selector: profile.selector,
100
+ autoRetarget: true,
101
+ clickRetarget: true,
102
+ profile,
103
+ };
104
+ targetsArr.push(targetObj);
85
105
  }
86
- }
87
- */
88
- if (shopper || shopperId) {
89
- contextGlobals.shopper = shopper?.id || shopperId;
90
- }
91
- if (product || seed) {
92
- contextGlobals.product = product || seed;
93
- }
94
- if (products) {
95
- contextGlobals.products = products;
96
- }
97
- // options
98
- if (options?.branch) {
99
- contextGlobals.branch = options.branch;
100
- }
101
- if (options?.siteId) {
102
- contextGlobals.siteId = options.siteId;
103
- }
104
- if (options?.categories) {
105
- contextGlobals.categories = options.categories;
106
- }
107
- if (options?.filters) {
108
- contextGlobals.filters = options.filters;
109
- }
110
- if (options?.brands) {
111
- contextGlobals.brands = options.brands;
112
- }
113
- if (options?.limit && Number.isInteger(Number(options?.limit))) {
114
- contextGlobals.limits = Number(options?.limit);
115
- }
116
- if (options?.blockedItems && Array.isArray(options.blockedItems)) {
117
- contextGlobals.blockedItems = options.blockedItems;
118
- }
119
- let cartContents;
120
- if (typeof cart === 'function') {
121
- try {
122
- const cartFuncContents = cart();
123
- if (Array.isArray(cartFuncContents)) {
124
- cartContents = cartFuncContents;
106
+ });
107
+ new DomTargeter(targetsArr, async (target, elem, originalElem) => {
108
+ if (target.profile?.profile) {
109
+ const profileRequestGlobals = {
110
+ ...requestGlobals,
111
+ profile: target.profile?.options,
112
+ tag: target.profile.profile,
113
+ };
114
+ const profileContext = deepmerge(this.context, { globals: scriptContextGlobals, profile: target.profile });
115
+ if (elemContext.custom) {
116
+ profileContext.custom = elemContext.custom;
117
+ }
118
+ readyTheController(this, elem, profileContext, profileCount, originalElem, profileRequestGlobals);
125
119
  }
126
- }
127
- catch (e) {
128
- this.logger.warn(`Error getting cart contents from function`, e);
129
- }
130
- }
131
- else if (Array.isArray(cart)) {
132
- cartContents = cart;
133
- }
134
- if (Array.isArray(cartContents)) {
135
- this.tracker.cookies.cart.set(cartContents);
136
- contextGlobals.cart = this.tracker.cookies.cart.get();
137
- }
138
- profileCount[tag] = profileCount[tag] + 1 || 1;
139
- const defaultGlobals = {
140
- limits: 20,
141
- };
142
- const globals = deepmerge(deepmerge(deepmerge(defaultGlobals, this.config.client?.globals || {}), this.config.config?.globals || {}), contextGlobals);
143
- const controllerConfig = {
144
- id: `recommend_${tag}_${profileCount[tag] - 1}`,
145
- tag,
146
- batched: options?.batched ?? true,
147
- realtime: Boolean(options?.realtime),
148
- ...this.config.config,
149
- globals,
150
- };
151
- // try to find an existing controller by similar configuration
152
- let controller = Object.keys(this.controller)
153
- .map((id) => this.controller[id])
154
- .filter((controller) => {
155
- return (JSON.stringify({
156
- batched: controller.config.batched,
157
- branch: controller.config.branch,
158
- globals: controller.config.globals,
159
- tag: controller.config.tag,
160
- realtime: controller.config.realtime,
161
- }) ==
162
- JSON.stringify({
163
- batched: controllerConfig.batched,
164
- branch: controllerConfig.branch,
165
- globals: controllerConfig.globals,
166
- tag: controllerConfig.tag,
167
- realtime: controllerConfig.realtime,
168
- }));
169
- })[0];
170
- if (!controller) {
171
- // no existing controller found of same configuration - creating a new controller
172
- const createRecommendationController = (await import('../create/createRecommendationController')).default;
173
- controller = createRecommendationController({
174
- url: this.config.url,
175
- controller: controllerConfig,
176
- context,
177
- mode: this.config.mode,
178
- }, { client: this.client, tracker: this.tracker });
179
- }
180
- this.uses.forEach((attachements) => controller.use(attachements));
181
- this.plugins.forEach((plugin) => controller.plugin(plugin.func, ...plugin.args));
182
- this.middleware.forEach((middleware) => controller.on(middleware.event, ...middleware.func));
183
- // run a search on the controller if it has not yet and it is not currently
184
- if (!controller.store.loaded && !controller.store.loading) {
185
- await controller.search();
186
- }
187
- controller.addTargeter(this.targeter);
188
- this.controller[controller.config.id] = controller;
189
- window.searchspring.controller = window.searchspring.controller || {};
190
- window.searchspring.controller[controller.config.id] = controller;
191
- const profileVars = controller.store.profile.display.templateParameters;
192
- const component = controller.store.profile.display.template?.component;
193
- if (controller.store.error) {
194
- //something went wrong
195
- //err was already logged - nothing to do.
196
- return;
197
- }
198
- if (!controller.store.profile.display.template) {
199
- this.logger.error(`profile '${tag}' found on the following element is missing a template!\n${elem?.outerHTML}`);
200
- return;
201
- }
202
- if (!profileVars) {
203
- this.logger.error(`profile '${tag}' found on the following element is missing templateParameters!\n${elem?.outerHTML}`);
204
- return;
120
+ });
205
121
  }
206
- if (!component) {
207
- this.logger.error(`profile '${tag}' found on the following element is missing a component!\n${elem?.outerHTML}`);
208
- return;
122
+ else {
123
+ // using the "legacy" integration structure
124
+ const { profile, products, product, seed, filters, blockedItems, options, shopper, shopperId } = elemContext;
125
+ const profileRequestGlobals = {
126
+ tag: profile,
127
+ ...defined({
128
+ products: products || (product && [product]) || (seed && [seed]),
129
+ cart: elemContext.cart && getArrayFunc(elemContext.cart),
130
+ shopper: shopper?.id || shopperId,
131
+ filters,
132
+ blockedItems,
133
+ profile: options,
134
+ }),
135
+ };
136
+ readyTheController(this, elem, elemContext, profileCount, originalElem, profileRequestGlobals);
209
137
  }
210
- const RecommendationsComponent = this.config.components[component] &&
211
- (await this.config.components[component]());
212
- if (!RecommendationsComponent) {
213
- this.logger.error(`profile '${tag}' found on the following element is expecting component mapping for '${component}' - verify instantiator config.\n${elem?.outerHTML}`);
214
- return;
215
- }
216
- setTimeout(() => {
217
- if (injectedElem) {
218
- render(_jsx(RecommendationsComponent, { controller: controller }), injectedElem);
219
- }
220
- });
221
138
  });
222
139
  }
223
140
  plugin(func, ...args) {
@@ -230,3 +147,129 @@ export class RecommendationInstantiator {
230
147
  this.uses.push(attachments);
231
148
  }
232
149
  }
150
+ async function readyTheController(instance, injectedElem, context, profileCount, elem, controllerGlobals) {
151
+ const { profile, batchId, cart, tag } = controllerGlobals;
152
+ const batched = (profile?.batched || controllerGlobals.batched) ?? true;
153
+ if (!tag) {
154
+ // FEEDBACK: change message depending on script integration type (profile vs. legacy)
155
+ instance.logger.warn(`'profile' is missing from <script> tag, skipping this profile`, elem);
156
+ return;
157
+ }
158
+ if (Array.isArray(cart)) {
159
+ instance.tracker.cookies.cart.set(cart);
160
+ }
161
+ profileCount[tag] = profileCount[tag] + 1 || 1;
162
+ const globals = deepmerge.all([
163
+ instance.config.client?.globals || {},
164
+ instance.config.config?.globals || {},
165
+ controllerGlobals,
166
+ ]);
167
+ const controllerConfig = {
168
+ id: `recommend_${tag}_${profileCount[tag] - 1}`,
169
+ tag,
170
+ batched: batched ?? true,
171
+ realtime: Boolean(context.options?.realtime ?? context.profile?.options?.realtime),
172
+ batchId: batchId,
173
+ ...instance.config.config,
174
+ globals,
175
+ };
176
+ if (profile?.branch) {
177
+ controllerConfig.branch = profile?.branch;
178
+ }
179
+ // try to find an existing controller by similar configuration
180
+ let controller = Object.keys(instance.controller)
181
+ .map((id) => instance.controller[id])
182
+ .filter((controller) => {
183
+ return (JSON.stringify({
184
+ batched: controller.config.batched,
185
+ branch: controller.config.branch,
186
+ globals: controller.config.globals,
187
+ tag: controller.config.tag,
188
+ realtime: controller.config.realtime,
189
+ }) ==
190
+ JSON.stringify({
191
+ batched: controllerConfig.batched,
192
+ branch: controllerConfig.branch,
193
+ globals: controllerConfig.globals,
194
+ tag: controllerConfig.tag,
195
+ realtime: controllerConfig.realtime,
196
+ }));
197
+ })[0];
198
+ if (!controller) {
199
+ // no existing controller found of same configuration - creating a new controller
200
+ const createRecommendationController = (await import('../create/createRecommendationController')).default;
201
+ controller = createRecommendationController({
202
+ url: instance.config.url,
203
+ controller: controllerConfig,
204
+ context,
205
+ mode: instance.config.mode,
206
+ }, { client: instance.client, tracker: instance.tracker });
207
+ instance.uses.forEach((attachements) => controller.use(attachements));
208
+ instance.plugins.forEach((plugin) => controller.plugin(plugin.func, ...plugin.args));
209
+ instance.middleware.forEach((middleware) => controller.on(middleware.event, ...middleware.func));
210
+ }
211
+ // run a search on the controller if it has not yet and it is not currently
212
+ if (!controller.store.loaded && !controller.store.loading) {
213
+ await controller.search();
214
+ }
215
+ controller.addTargeter(instance.targeter);
216
+ instance.controller[controller.config.id] = controller;
217
+ window.searchspring.controller = window.searchspring.controller || {};
218
+ window.searchspring.controller[controller.config.id] = controller;
219
+ const profileVars = controller.store.profile.display.templateParameters;
220
+ const component = controller.store.profile.display.template?.component;
221
+ if (controller.store.error) {
222
+ //something went wrong
223
+ //err was already logged - nothing to do.
224
+ return;
225
+ }
226
+ if (!controller.store.profile.display.template) {
227
+ instance.logger.error(`profile '${tag}' found on the following element is missing a template!\n${elem?.outerHTML}`);
228
+ return;
229
+ }
230
+ if (!profileVars) {
231
+ instance.logger.error(`profile '${tag}' found on the following element is missing templateParameters!\n${elem?.outerHTML}`);
232
+ return;
233
+ }
234
+ if (!component) {
235
+ instance.logger.error(`profile '${tag}' found on the following element is missing a component!\n${elem?.outerHTML}`);
236
+ return;
237
+ }
238
+ const RecommendationsComponent = instance.config.components[component] &&
239
+ (await instance.config.components[component]());
240
+ if (!RecommendationsComponent) {
241
+ instance.logger.error(`profile '${tag}' found on the following element is expecting component mapping for '${component}' - verify instantiator config.\n${elem?.outerHTML}`);
242
+ return;
243
+ }
244
+ setTimeout(() => {
245
+ if (injectedElem) {
246
+ render(_jsx(RecommendationsComponent, { controller: controller }), injectedElem);
247
+ }
248
+ });
249
+ }
250
+ function getArrayFunc(arrayOrFunc) {
251
+ if (typeof arrayOrFunc === 'function') {
252
+ try {
253
+ const funcContents = arrayOrFunc();
254
+ if (Array.isArray(funcContents)) {
255
+ return funcContents;
256
+ }
257
+ }
258
+ catch (e) {
259
+ // function didn't return an array
260
+ }
261
+ }
262
+ else if (Array.isArray(arrayOrFunc)) {
263
+ return arrayOrFunc;
264
+ }
265
+ return [];
266
+ }
267
+ export function defined(properties) {
268
+ const definedProps = {};
269
+ Object.keys(properties).map((key) => {
270
+ if (properties[key] !== undefined) {
271
+ definedProps[key] = properties[key];
272
+ }
273
+ });
274
+ return definedProps;
275
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@searchspring/snap-preact",
3
- "version": "0.59.0",
3
+ "version": "0.60.1",
4
4
  "description": "Snap Preact",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -20,17 +20,17 @@
20
20
  "test:watch": "jest --watch"
21
21
  },
22
22
  "dependencies": {
23
- "@searchspring/snap-client": "^0.59.0",
24
- "@searchspring/snap-controller": "^0.59.0",
25
- "@searchspring/snap-event-manager": "^0.59.0",
26
- "@searchspring/snap-logger": "^0.59.0",
27
- "@searchspring/snap-platforms": "^0.59.0",
28
- "@searchspring/snap-preact-components": "^0.59.0",
29
- "@searchspring/snap-profiler": "^0.59.0",
30
- "@searchspring/snap-store-mobx": "^0.59.0",
31
- "@searchspring/snap-toolbox": "^0.59.0",
32
- "@searchspring/snap-tracker": "^0.59.0",
33
- "@searchspring/snap-url-manager": "^0.59.0",
23
+ "@searchspring/snap-client": "^0.60.1",
24
+ "@searchspring/snap-controller": "^0.60.1",
25
+ "@searchspring/snap-event-manager": "^0.60.1",
26
+ "@searchspring/snap-logger": "^0.60.1",
27
+ "@searchspring/snap-platforms": "^0.60.1",
28
+ "@searchspring/snap-preact-components": "^0.60.1",
29
+ "@searchspring/snap-profiler": "^0.60.1",
30
+ "@searchspring/snap-store-mobx": "^0.60.1",
31
+ "@searchspring/snap-toolbox": "^0.60.1",
32
+ "@searchspring/snap-tracker": "^0.60.1",
33
+ "@searchspring/snap-url-manager": "^0.60.1",
34
34
  "deepmerge": "4.3.1",
35
35
  "intersection-observer": "0.12.0",
36
36
  "is-plain-object": "5.0.0"
@@ -43,5 +43,5 @@
43
43
  "files": [
44
44
  "dist/**/*"
45
45
  ],
46
- "gitHead": "3106e08ab0114c0bb0de8f7d7beb6f65968f9c75"
46
+ "gitHead": "94761345dd36b121494c165d9844a27086085dc9"
47
47
  }