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/README.md CHANGED
@@ -13,7 +13,7 @@ Universal JavaScript client for Swell's Frontend API, providing client-safe acce
13
13
 
14
14
  **About Swell**
15
15
 
16
- [Swell](https://www.swell.is) is a customizable, API-first platform for powering modern B2C/B2B shopping experiences and marketplaces. Build and connect anything using your favorite technologies, and provide admins with an easy to use dashboard.
16
+ [Swell](https://www.swell.is) is an ecommerce platform with subscriptions and B2B pricing built in. Run your store on a Swell theme, or [go headless](https://www.swell.is/headless-commerce) with its APIs.
17
17
 
18
18
  ## Documentation
19
19
 
package/dist/api.mjs CHANGED
@@ -1,21 +1,21 @@
1
- import methods$5 from './card.mjs';
1
+ import methods$6 from './card.mjs';
2
2
  import { getCookie, setCookie } from './cookie.mjs';
3
- import methods$4 from './cache.mjs';
4
- import methods$3 from './cart.mjs';
5
- import methods$6 from './account.mjs';
6
- import { j as isFunction, l as loadScript, e as isObject, v as vaultRequest, k as isEmpty, d as defaultMethods, x as trimEnd, y as utils, z as trimStart, A as trimBoth, b as toSnake, o as base64Encode, i as isServer, t as toCamel } from './index.3949a230.mjs';
3
+ import methods$5 from './cache.mjs';
4
+ import methods$4 from './cart.mjs';
5
+ import methods$7 from './account.mjs';
6
+ import { j as isFunction, l as loadScript, e as isObject, v as vaultRequest, k as isEmpty, d as defaultMethods, i as isServer, x as trimEnd, y as utils, z as trimStart, A as trimBoth, b as toSnake, o as base64Encode, t as toCamel } from './index.76eb52e5.mjs';
7
7
  import { Q as stringifyQuery } from './find.ba551a2e.mjs';
8
8
  import 'deepmerge';
9
9
  import 'fast-case';
10
- import methods$7 from './products.mjs';
11
- import methods$8 from './categories.mjs';
12
- import methods$9 from './attributes.mjs';
13
- import methods$a from './subscriptions.mjs';
14
- import methods$b from './content.mjs';
15
- import methods$c from './settings.mjs';
10
+ import methods$8 from './products.mjs';
11
+ import methods$9 from './categories.mjs';
12
+ import methods$a from './attributes.mjs';
13
+ import methods$b from './subscriptions.mjs';
14
+ import methods$c from './content.mjs';
15
+ import methods$d from './settings.mjs';
16
16
  import PaymentController from './payment.mjs';
17
- import methods$d from './locale.mjs';
18
- import methods$e, { isCurrencyCode } from './currency.mjs';
17
+ import methods$e from './locale.mjs';
18
+ import methods$f, { isCurrencyCode } from './currency.mjs';
19
19
  import './round.c68b8be5.mjs';
20
20
 
21
21
  class AppComponent {
@@ -81,7 +81,7 @@ class AppComponent {
81
81
  }
82
82
 
83
83
  async updateCart(data) {
84
- const cart = await methods$3(this.api, this.options).update(data);
84
+ const cart = await methods$4(this.api, this.options).update(data);
85
85
 
86
86
  this.setProps({ cart });
87
87
  }
@@ -317,7 +317,7 @@ class AppController {
317
317
  }
318
318
  }
319
319
 
320
- function methods$2(api) {
320
+ function methods$3(api) {
321
321
  const { get, list } = defaultMethods(api, '/invoices', ['list', 'get']);
322
322
  return {
323
323
  get: (id, ...args) => {
@@ -328,7 +328,7 @@ function methods$2(api) {
328
328
  };
329
329
  }
330
330
 
331
- function methods$1(api, opt) {
331
+ function methods$2(api, opt) {
332
332
  return {
333
333
  /**
334
334
  * Get the decoded session as an object of session values
@@ -355,7 +355,7 @@ function methods$1(api, opt) {
355
355
  };
356
356
  }
357
357
 
358
- function methods(api, _opt) {
358
+ function methods$1(api, _opt) {
359
359
  return {
360
360
  /**
361
361
  * Make a request to an app function and greceiveet a response
@@ -424,6 +424,85 @@ function methods(api, _opt) {
424
424
  };
425
425
  }
426
426
 
427
+ const PURPOSES = ['analytics', 'marketing', 'sale_of_data'];
428
+
429
+ /**
430
+ * The page the shopper landed on, which the consent call sends along: the
431
+ * first URL of this document and its referrer. Read when needed, so nothing
432
+ * is kept before the shopper answers.
433
+ *
434
+ * @returns {{url: string, referrer: string} | undefined}
435
+ */
436
+ function getLanding() {
437
+ if (isServer()) {
438
+ return undefined;
439
+ }
440
+
441
+ let url = window.location.href;
442
+
443
+ try {
444
+ const [navigation] = window.performance.getEntriesByType('navigation');
445
+ if (navigation?.name) {
446
+ url = navigation.name;
447
+ }
448
+ } catch {
449
+ // Navigation timing is not available
450
+ }
451
+
452
+ return { url, referrer: window.document.referrer || '' };
453
+ }
454
+
455
+ function methods(api) {
456
+ // Calls run one after another. Consent tools fire several events for one
457
+ // answer, and the first call may set the visitor cookie that the next one
458
+ // has to send: in parallel, each would start a visitor of its own.
459
+ let queue = Promise.resolve();
460
+
461
+ return {
462
+ /**
463
+ * Records the shopper's consent for attribution, from the storefront's
464
+ * consent banner. Purposes left out stay as they are.
465
+ *
466
+ * Calls the storefront's own origin, so that Swell sees the page's
467
+ * cookies and sets the visitor cookie on the storefront's domain.
468
+ *
469
+ * @param {{analytics?: boolean, marketing?: boolean, sale_of_data?: boolean}} consent
470
+ */
471
+ set(consent = {}) {
472
+ if (isServer()) {
473
+ return Promise.reject(new Error('consent.set() runs in the browser'));
474
+ }
475
+
476
+ const data = {};
477
+
478
+ for (const purpose of PURPOSES) {
479
+ // camelCase clients pass saleOfData
480
+ const camel = purpose.replace(/_(\w)/g, (_m, c) => c.toUpperCase());
481
+ const value = consent[purpose] ?? consent[camel];
482
+
483
+ if (typeof value === 'boolean') {
484
+ data[purpose] = value;
485
+ }
486
+ }
487
+
488
+ const result = queue.then(() =>
489
+ api.request(
490
+ 'put',
491
+ '/session/consent',
492
+ { ...data, landing: getLanding() },
493
+ undefined,
494
+ { fullUrl: `${window.location.origin}/api/session/consent` },
495
+ ),
496
+ );
497
+
498
+ // A failed call doesn't hold back the next one
499
+ queue = result.catch(() => undefined);
500
+
501
+ return result;
502
+ },
503
+ };
504
+ }
505
+
427
506
  /**
428
507
  * @template {'snake' | 'camel'} C
429
508
  * @typedef {import('../types').InitOptions<C>} InitOptions<C>
@@ -455,7 +534,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
455
534
  const api = {};
456
535
 
457
536
  Object.assign(api, {
458
- version: '5.9.2',
537
+ version: '5.9.4',
459
538
  options,
460
539
  request,
461
540
 
@@ -485,6 +564,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
485
564
  options.getCart = opt.getCart;
486
565
  options.updateCart = opt.updateCart;
487
566
  options.headers = opt.headers || {};
567
+ options.getCaptchaToken = opt.getCaptchaToken;
488
568
  },
489
569
 
490
570
  // Backward compatibility
@@ -508,39 +588,41 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
508
588
  return api.request('delete', url, data);
509
589
  },
510
590
 
511
- cache: methods$4(options),
591
+ cache: methods$5(options),
512
592
 
513
- card: methods$5(options),
593
+ card: methods$6(options),
514
594
 
515
- cart: methods$3(api, options),
595
+ cart: methods$4(api, options),
516
596
 
517
- account: methods$6(api),
597
+ account: methods$7(api),
518
598
 
519
599
  app: new AppController(api, options),
520
600
 
521
- products: methods$7(api, options),
601
+ products: methods$8(api, options),
522
602
 
523
- categories: methods$8(api),
603
+ categories: methods$9(api),
524
604
 
525
- attributes: methods$9(api),
605
+ attributes: methods$a(api),
526
606
 
527
- subscriptions: methods$a(api),
607
+ subscriptions: methods$b(api),
528
608
 
529
- invoices: methods$2(api),
609
+ invoices: methods$3(api),
530
610
 
531
- content: methods$b(api, options),
611
+ content: methods$c(api, options),
532
612
 
533
- settings: methods$c(api, options),
613
+ settings: methods$d(api, options),
534
614
 
535
615
  payment: new PaymentController(api, options),
536
616
 
537
- locale: methods$d(api, options),
617
+ locale: methods$e(api, options),
618
+
619
+ currency: methods$f(api, options),
538
620
 
539
- currency: methods$e(api, options),
621
+ session: methods$2(api, options),
540
622
 
541
- session: methods$1(api, options),
623
+ functions: methods$1(api),
542
624
 
543
- functions: methods(api),
625
+ consent: methods(api),
544
626
 
545
627
  utils,
546
628
 
@@ -614,6 +696,13 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
614
696
  reqHeaders['X-Session'] = session;
615
697
  }
616
698
 
699
+ // The storefront's visitor, for attribution: the cookie is on the
700
+ // storefront's domain and doesn't reach the store's API host
701
+ const visitor = allOptions.getCookie('swell-visitor');
702
+ if (visitor) {
703
+ reqHeaders['X-Visitor'] = visitor;
704
+ }
705
+
617
706
  if (locale) {
618
707
  reqHeaders['X-Locale'] = locale;
619
708
  }
@@ -1,4 +1,4 @@
1
- import { d as defaultMethods } from './index.3949a230.mjs';
1
+ import { d as defaultMethods } from './index.76eb52e5.mjs';
2
2
  import './find.ba551a2e.mjs';
3
3
  import './round.c68b8be5.mjs';
4
4
  import 'deepmerge';
package/dist/cache.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { s as set, m as merge, t as toCamel, a as toCamelPath } from './index.3949a230.mjs';
1
+ import { s as set, m as merge, t as toCamel, a as toCamelPath } from './index.76eb52e5.mjs';
2
2
  import { g as get } from './find.ba551a2e.mjs';
3
3
  import './round.c68b8be5.mjs';
4
4
  import 'deepmerge';
package/dist/card.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { b as toSnake, v as vaultRequest } from './index.3949a230.mjs';
1
+ import { b as toSnake, v as vaultRequest } from './index.76eb52e5.mjs';
2
2
  import './find.ba551a2e.mjs';
3
3
  import './round.c68b8be5.mjs';
4
4
  import 'deepmerge';
package/dist/cart.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import './find.ba551a2e.mjs';
2
- import { c as cloneDeep } from './index.3949a230.mjs';
2
+ import { c as cloneDeep } from './index.76eb52e5.mjs';
3
3
  import 'deepmerge';
4
4
  import 'fast-case';
5
5
  import { cleanProductOptions } from './products.mjs';
@@ -1,4 +1,4 @@
1
- import { d as defaultMethods } from './index.3949a230.mjs';
1
+ import { d as defaultMethods } from './index.76eb52e5.mjs';
2
2
  import './find.ba551a2e.mjs';
3
3
  import './round.c68b8be5.mjs';
4
4
  import 'deepmerge';
package/dist/cookie.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as isServer } from './index.3949a230.mjs';
1
+ import { i as isServer } from './index.76eb52e5.mjs';
2
2
  import './find.ba551a2e.mjs';
3
3
  import './round.c68b8be5.mjs';
4
4
  import 'deepmerge';
@@ -1586,8 +1586,36 @@ function defaultMethods(api, uri, methods) {
1586
1586
  };
1587
1587
  }
1588
1588
 
1589
+ function isCreateIntentRequest(method, url) {
1590
+ if (String(method).toLowerCase() !== 'post') {
1591
+ return false;
1592
+ }
1593
+
1594
+ return trimEnd(trimStart(url)) === 'intent';
1595
+ }
1596
+
1597
+ // Attach a captcha token to create-intent requests. The host supplies it via
1598
+ // the getCaptchaToken option and owns the widget and token lifecycle; here we
1599
+ // only forward it, so every intent-based payment method is covered. A rejection
1600
+ // from the host (timeout / failed challenge) propagates and aborts the request.
1601
+ async function addCaptchaToken(method, url, data, options) {
1602
+ if (
1603
+ typeof options.getCaptchaToken !== 'function' ||
1604
+ !isCreateIntentRequest(method, url)
1605
+ ) {
1606
+ return data;
1607
+ }
1608
+
1609
+ const token = await options.getCaptchaToken();
1610
+
1611
+ return token ? { ...data, captcha_token: token } : data;
1612
+ }
1613
+
1589
1614
  async function vaultRequest(method, url, data, options) {
1590
1615
  const { vaultUrl, timeout, key } = options;
1616
+
1617
+ data = await addCaptchaToken(method, url, data, options);
1618
+
1591
1619
  const requestData = {
1592
1620
  $jsonp: {
1593
1621
  method,
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  export { default } from './api.mjs';
2
2
  import './card.mjs';
3
- import './index.3949a230.mjs';
3
+ import './index.76eb52e5.mjs';
4
4
  import './find.ba551a2e.mjs';
5
5
  import './round.c68b8be5.mjs';
6
6
  import 'deepmerge';
package/dist/payment.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import methods from './cart.mjs';
2
2
  import methods$1 from './settings.mjs';
3
- import { e as isObject, j as isFunction, l as loadScript, c as cloneDeep, v as vaultRequest, b as toSnake, p as pick, k as isEmpty, n as isLiveMode, o as base64Encode, q as getLocationParams, w as removeUrlParams, t as toCamel } from './index.3949a230.mjs';
3
+ import { e as isObject, j as isFunction, l as loadScript, c as cloneDeep, v as vaultRequest, b as toSnake, p as pick, k as isEmpty, n as isLiveMode, o as base64Encode, q as getLocationParams, w as removeUrlParams, t as toCamel } from './index.76eb52e5.mjs';
4
4
  import { g as get } from './find.ba551a2e.mjs';
5
5
  import 'deepmerge';
6
6
  import 'fast-case';
package/dist/products.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { d as defaultMethods, r as reduce, b as toSnake, t as toCamel, g as snakeCase, u as uniq, h as isEqual } from './index.3949a230.mjs';
1
+ import { d as defaultMethods, r as reduce, b as toSnake, t as toCamel, g as snakeCase, u as uniq, h as isEqual } from './index.76eb52e5.mjs';
2
2
  import methods$1 from './attributes.mjs';
3
3
  import { g as get, f as find } from './find.ba551a2e.mjs';
4
4
  import './round.c68b8be5.mjs';
package/dist/settings.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { s as set, t as toCamel, m as merge, c as cloneDeep, e as isObject, f as camelCase } from './index.3949a230.mjs';
1
+ import { s as set, t as toCamel, m as merge, c as cloneDeep, e as isObject, f as camelCase } from './index.76eb52e5.mjs';
2
2
  import { g as get, f as find } from './find.ba551a2e.mjs';
3
3
  import './round.c68b8be5.mjs';
4
4
  import 'deepmerge';
@@ -1,5 +1,5 @@
1
1
  import { cleanProductOptions } from './products.mjs';
2
- import { d as defaultMethods } from './index.3949a230.mjs';
2
+ import { d as defaultMethods } from './index.76eb52e5.mjs';
3
3
  import './attributes.mjs';
4
4
  import './find.ba551a2e.mjs';
5
5
  import './round.c68b8be5.mjs';