swell-js 5.9.2 → 5.9.4

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/swell.cjs CHANGED
@@ -4726,8 +4726,36 @@ function defaultMethods(api, uri, methods) {
4726
4726
  };
4727
4727
  }
4728
4728
 
4729
+ function isCreateIntentRequest(method, url) {
4730
+ if (String(method).toLowerCase() !== 'post') {
4731
+ return false;
4732
+ }
4733
+
4734
+ return trimEnd(trimStart(url)) === 'intent';
4735
+ }
4736
+
4737
+ // Attach a captcha token to create-intent requests. The host supplies it via
4738
+ // the getCaptchaToken option and owns the widget and token lifecycle; here we
4739
+ // only forward it, so every intent-based payment method is covered. A rejection
4740
+ // from the host (timeout / failed challenge) propagates and aborts the request.
4741
+ async function addCaptchaToken(method, url, data, options) {
4742
+ if (
4743
+ typeof options.getCaptchaToken !== 'function' ||
4744
+ !isCreateIntentRequest(method, url)
4745
+ ) {
4746
+ return data;
4747
+ }
4748
+
4749
+ const token = await options.getCaptchaToken();
4750
+
4751
+ return token ? { ...data, captcha_token: token } : data;
4752
+ }
4753
+
4729
4754
  async function vaultRequest(method, url, data, options) {
4730
4755
  const { vaultUrl, timeout, key } = options;
4756
+
4757
+ data = await addCaptchaToken(method, url, data, options);
4758
+
4731
4759
  const requestData = {
4732
4760
  $jsonp: {
4733
4761
  method,
@@ -4938,7 +4966,7 @@ const utils = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
4938
4966
  vaultRequest
4939
4967
  }, Symbol.toStringTag, { value: 'Module' }));
4940
4968
 
4941
- function methods$e(options) {
4969
+ function methods$f(options) {
4942
4970
  return {
4943
4971
  async createToken(data) {
4944
4972
  let error = null;
@@ -5155,7 +5183,7 @@ function setCookie(name, value, options = {}) {
5155
5183
 
5156
5184
  const RECORD_TIMEOUT = 5000;
5157
5185
 
5158
- function methods$d(opt) {
5186
+ function methods$e(opt) {
5159
5187
  let VALUES = {
5160
5188
  /*
5161
5189
  [model]: {
@@ -5317,7 +5345,7 @@ function methods$d(opt) {
5317
5345
  };
5318
5346
  }
5319
5347
 
5320
- function methods$c(api) {
5348
+ function methods$d(api) {
5321
5349
  const { get, list } = defaultMethods(api, '/attributes', ['list', 'get']);
5322
5350
 
5323
5351
  return {
@@ -5329,7 +5357,7 @@ function methods$c(api) {
5329
5357
  };
5330
5358
  }
5331
5359
 
5332
- function methods$b(api, opt) {
5360
+ function methods$c(api, opt) {
5333
5361
  const { get, list } = defaultMethods(api, '/products', ['list', 'get']);
5334
5362
  return {
5335
5363
  get: (id, ...args) => {
@@ -5538,7 +5566,7 @@ function findPurchaseOption(product, purchaseOption) {
5538
5566
  }
5539
5567
 
5540
5568
  async function getFilterableAttributeFilters(api, products, options) {
5541
- const { results: filterableAttributes } = await methods$c(api).list({
5569
+ const { results: filterableAttributes } = await methods$d(api).list({
5542
5570
  filterable: true,
5543
5571
  });
5544
5572
 
@@ -5722,7 +5750,7 @@ function getPriceRange(products) {
5722
5750
  };
5723
5751
  }
5724
5752
 
5725
- function methods$a(api, options) {
5753
+ function methods$b(api, options) {
5726
5754
  return {
5727
5755
  state: null,
5728
5756
  order: null,
@@ -5907,7 +5935,7 @@ function methods$a(api, options) {
5907
5935
  };
5908
5936
  }
5909
5937
 
5910
- function methods$9(api) {
5938
+ function methods$a(api) {
5911
5939
  return {
5912
5940
  state: null,
5913
5941
 
@@ -6081,7 +6109,7 @@ class AppComponent {
6081
6109
  }
6082
6110
 
6083
6111
  async updateCart(data) {
6084
- const cart = await methods$a(this.api, this.options).update(data);
6112
+ const cart = await methods$b(this.api, this.options).update(data);
6085
6113
 
6086
6114
  this.setProps({ cart });
6087
6115
  }
@@ -6317,7 +6345,7 @@ class AppController {
6317
6345
  }
6318
6346
  }
6319
6347
 
6320
- function methods$8(api) {
6348
+ function methods$9(api) {
6321
6349
  const { get, list } = defaultMethods(api, '/categories', ['list', 'get']);
6322
6350
 
6323
6351
  return {
@@ -6329,7 +6357,7 @@ function methods$8(api) {
6329
6357
  };
6330
6358
  }
6331
6359
 
6332
- function methods$7(api) {
6360
+ function methods$8(api) {
6333
6361
  const { get, list } = defaultMethods(api, '/subscriptions', ['list', 'get']);
6334
6362
  return {
6335
6363
  get: (id, ...args) => {
@@ -6394,7 +6422,7 @@ function methods$7(api) {
6394
6422
  };
6395
6423
  }
6396
6424
 
6397
- function methods$6(api) {
6425
+ function methods$7(api) {
6398
6426
  const { get, list } = defaultMethods(api, '/invoices', ['list', 'get']);
6399
6427
  return {
6400
6428
  get: (id, ...args) => {
@@ -6405,7 +6433,7 @@ function methods$6(api) {
6405
6433
  };
6406
6434
  }
6407
6435
 
6408
- function methods$5(api, opt) {
6436
+ function methods$6(api, opt) {
6409
6437
  return {
6410
6438
  get: (type, id, query) => {
6411
6439
  return api.cache.getFetch(`content_${type}`, id, () =>
@@ -6421,7 +6449,7 @@ function methods$5(api, opt) {
6421
6449
  };
6422
6450
  }
6423
6451
 
6424
- function methods$4(api, opt) {
6452
+ function methods$5(api, opt) {
6425
6453
  return {
6426
6454
  state: null,
6427
6455
  menuState: null,
@@ -6716,7 +6744,7 @@ function decodeLocaleValue(locale, values, key, configs, opt) {
6716
6744
  }
6717
6745
  }
6718
6746
 
6719
- function methods$3(api, opt) {
6747
+ function methods$4(api, opt) {
6720
6748
  return {
6721
6749
  /**
6722
6750
  * Get the decoded session as an object of session values
@@ -7104,7 +7132,7 @@ class Payment {
7104
7132
  * @returns {Promise<Cart>}
7105
7133
  */
7106
7134
  async getCart() {
7107
- const cart = await methods$a(this.api, this.options).get();
7135
+ const cart = await methods$b(this.api, this.options).get();
7108
7136
 
7109
7137
  if (!cart) {
7110
7138
  throw new Error('Cart not found');
@@ -7132,7 +7160,7 @@ class Payment {
7132
7160
  }
7133
7161
  }
7134
7162
 
7135
- const updatedCart = await methods$a(this.api, this.options).update(
7163
+ const updatedCart = await methods$b(this.api, this.options).update(
7136
7164
  updateData,
7137
7165
  );
7138
7166
 
@@ -7145,7 +7173,7 @@ class Payment {
7145
7173
  * @returns {Promise<object>}
7146
7174
  */
7147
7175
  async getSettings() {
7148
- return methods$4(this.api, this.options).get();
7176
+ return methods$5(this.api, this.options).get();
7149
7177
  }
7150
7178
 
7151
7179
  /**
@@ -12761,7 +12789,7 @@ class PaymentController {
12761
12789
  }
12762
12790
 
12763
12791
  async _getPaymentMethods() {
12764
- const paymentMethods = await methods$4(this.api, this.options).payments();
12792
+ const paymentMethods = await methods$5(this.api, this.options).payments();
12765
12793
 
12766
12794
  if (paymentMethods.error) {
12767
12795
  throw new Error(paymentMethods.error);
@@ -12991,7 +13019,7 @@ class PaymentController {
12991
13019
  }
12992
13020
  }
12993
13021
 
12994
- function methods$2(api, opt) {
13022
+ function methods$3(api, opt) {
12995
13023
  return {
12996
13024
  code: null,
12997
13025
  state: null,
@@ -13047,7 +13075,7 @@ function defaultLocale() {
13047
13075
  return typeof navigator === 'object' ? navigator.language : 'en-US';
13048
13076
  }
13049
13077
 
13050
- function methods$1(api, opt) {
13078
+ function methods$2(api, opt) {
13051
13079
  // Reads a store setting without ever returning a Promise. Until settings
13052
13080
  // load, this starts the request and reports `loaded: false`.
13053
13081
  function readSetting(path, def) {
@@ -13268,7 +13296,7 @@ function methods$1(api, opt) {
13268
13296
  };
13269
13297
  }
13270
13298
 
13271
- function methods(api, _opt) {
13299
+ function methods$1(api, _opt) {
13272
13300
  return {
13273
13301
  /**
13274
13302
  * Make a request to an app function and greceiveet a response
@@ -13337,6 +13365,85 @@ function methods(api, _opt) {
13337
13365
  };
13338
13366
  }
13339
13367
 
13368
+ const PURPOSES = ['analytics', 'marketing', 'sale_of_data'];
13369
+
13370
+ /**
13371
+ * The page the shopper landed on, which the consent call sends along: the
13372
+ * first URL of this document and its referrer. Read when needed, so nothing
13373
+ * is kept before the shopper answers.
13374
+ *
13375
+ * @returns {{url: string, referrer: string} | undefined}
13376
+ */
13377
+ function getLanding() {
13378
+ if (isServer()) {
13379
+ return undefined;
13380
+ }
13381
+
13382
+ let url = window.location.href;
13383
+
13384
+ try {
13385
+ const [navigation] = window.performance.getEntriesByType('navigation');
13386
+ if (navigation?.name) {
13387
+ url = navigation.name;
13388
+ }
13389
+ } catch {
13390
+ // Navigation timing is not available
13391
+ }
13392
+
13393
+ return { url, referrer: window.document.referrer || '' };
13394
+ }
13395
+
13396
+ function methods(api) {
13397
+ // Calls run one after another. Consent tools fire several events for one
13398
+ // answer, and the first call may set the visitor cookie that the next one
13399
+ // has to send: in parallel, each would start a visitor of its own.
13400
+ let queue = Promise.resolve();
13401
+
13402
+ return {
13403
+ /**
13404
+ * Records the shopper's consent for attribution, from the storefront's
13405
+ * consent banner. Purposes left out stay as they are.
13406
+ *
13407
+ * Calls the storefront's own origin, so that Swell sees the page's
13408
+ * cookies and sets the visitor cookie on the storefront's domain.
13409
+ *
13410
+ * @param {{analytics?: boolean, marketing?: boolean, sale_of_data?: boolean}} consent
13411
+ */
13412
+ set(consent = {}) {
13413
+ if (isServer()) {
13414
+ return Promise.reject(new Error('consent.set() runs in the browser'));
13415
+ }
13416
+
13417
+ const data = {};
13418
+
13419
+ for (const purpose of PURPOSES) {
13420
+ // camelCase clients pass saleOfData
13421
+ const camel = purpose.replace(/_(\w)/g, (_m, c) => c.toUpperCase());
13422
+ const value = consent[purpose] ?? consent[camel];
13423
+
13424
+ if (typeof value === 'boolean') {
13425
+ data[purpose] = value;
13426
+ }
13427
+ }
13428
+
13429
+ const result = queue.then(() =>
13430
+ api.request(
13431
+ 'put',
13432
+ '/session/consent',
13433
+ { ...data, landing: getLanding() },
13434
+ undefined,
13435
+ { fullUrl: `${window.location.origin}/api/session/consent` },
13436
+ ),
13437
+ );
13438
+
13439
+ // A failed call doesn't hold back the next one
13440
+ queue = result.catch(() => undefined);
13441
+
13442
+ return result;
13443
+ },
13444
+ };
13445
+ }
13446
+
13340
13447
  /**
13341
13448
  * @template {'snake' | 'camel'} C
13342
13449
  * @typedef {import('../types').InitOptions<C>} InitOptions<C>
@@ -13368,7 +13475,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
13368
13475
  const api = {};
13369
13476
 
13370
13477
  Object.assign(api, {
13371
- version: '5.9.2',
13478
+ version: '5.9.4',
13372
13479
  options,
13373
13480
  request,
13374
13481
 
@@ -13398,6 +13505,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
13398
13505
  options.getCart = opt.getCart;
13399
13506
  options.updateCart = opt.updateCart;
13400
13507
  options.headers = opt.headers || {};
13508
+ options.getCaptchaToken = opt.getCaptchaToken;
13401
13509
  },
13402
13510
 
13403
13511
  // Backward compatibility
@@ -13421,39 +13529,41 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
13421
13529
  return api.request('delete', url, data);
13422
13530
  },
13423
13531
 
13424
- cache: methods$d(options),
13532
+ cache: methods$e(options),
13425
13533
 
13426
- card: methods$e(options),
13534
+ card: methods$f(options),
13427
13535
 
13428
- cart: methods$a(api, options),
13536
+ cart: methods$b(api, options),
13429
13537
 
13430
- account: methods$9(api),
13538
+ account: methods$a(api),
13431
13539
 
13432
13540
  app: new AppController(api, options),
13433
13541
 
13434
- products: methods$b(api, options),
13542
+ products: methods$c(api, options),
13435
13543
 
13436
- categories: methods$8(api),
13544
+ categories: methods$9(api),
13437
13545
 
13438
- attributes: methods$c(api),
13546
+ attributes: methods$d(api),
13439
13547
 
13440
- subscriptions: methods$7(api),
13548
+ subscriptions: methods$8(api),
13441
13549
 
13442
- invoices: methods$6(api),
13550
+ invoices: methods$7(api),
13443
13551
 
13444
- content: methods$5(api, options),
13552
+ content: methods$6(api, options),
13445
13553
 
13446
- settings: methods$4(api, options),
13554
+ settings: methods$5(api, options),
13447
13555
 
13448
13556
  payment: new PaymentController(api, options),
13449
13557
 
13450
- locale: methods$2(api, options),
13558
+ locale: methods$3(api, options),
13559
+
13560
+ currency: methods$2(api, options),
13451
13561
 
13452
- currency: methods$1(api, options),
13562
+ session: methods$4(api, options),
13453
13563
 
13454
- session: methods$3(api, options),
13564
+ functions: methods$1(api),
13455
13565
 
13456
- functions: methods(api),
13566
+ consent: methods(api),
13457
13567
 
13458
13568
  utils,
13459
13569
 
@@ -13527,6 +13637,13 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
13527
13637
  reqHeaders['X-Session'] = session;
13528
13638
  }
13529
13639
 
13640
+ // The storefront's visitor, for attribution: the cookie is on the
13641
+ // storefront's domain and doesn't reach the store's API host
13642
+ const visitor = allOptions.getCookie('swell-visitor');
13643
+ if (visitor) {
13644
+ reqHeaders['X-Visitor'] = visitor;
13645
+ }
13646
+
13530
13647
  if (locale) {
13531
13648
  reqHeaders['X-Locale'] = locale;
13532
13649
  }