@teleporthq/teleport-shared 0.43.67 → 0.43.69

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.
Files changed (107) hide show
  1. package/__tests__/_helpers/embed-runtime-emitter.ts +197 -0
  2. package/__tests__/utils/discount-engine.ts +1548 -0
  3. package/__tests__/utils/product-options.ts +2458 -0
  4. package/__tests__/utils/rich-text-embeds-runtime-module.ts +34 -0
  5. package/__tests__/utils/subscription-access.ts +37 -0
  6. package/dist/cjs/index.d.ts +9 -1
  7. package/dist/cjs/index.d.ts.map +1 -1
  8. package/dist/cjs/index.js +17 -1
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  11. package/dist/cjs/utils/cart-currency.d.ts +27 -0
  12. package/dist/cjs/utils/cart-currency.d.ts.map +1 -0
  13. package/dist/cjs/utils/cart-currency.js +31 -0
  14. package/dist/cjs/utils/cart-currency.js.map +1 -0
  15. package/dist/cjs/utils/cart-line-pricing.d.ts +25 -0
  16. package/dist/cjs/utils/cart-line-pricing.d.ts.map +1 -0
  17. package/dist/cjs/utils/cart-line-pricing.js +29 -0
  18. package/dist/cjs/utils/cart-line-pricing.js.map +1 -0
  19. package/dist/cjs/utils/discount-engine.d.ts +74 -0
  20. package/dist/cjs/utils/discount-engine.d.ts.map +1 -0
  21. package/dist/cjs/utils/discount-engine.js +435 -0
  22. package/dist/cjs/utils/discount-engine.js.map +1 -0
  23. package/dist/cjs/utils/product-options.d.ts +25 -0
  24. package/dist/cjs/utils/product-options.d.ts.map +1 -0
  25. package/dist/cjs/utils/product-options.js +1155 -0
  26. package/dist/cjs/utils/product-options.js.map +1 -0
  27. package/dist/cjs/utils/rich-text-embeds-codegen.d.ts +13 -0
  28. package/dist/cjs/utils/rich-text-embeds-codegen.d.ts.map +1 -1
  29. package/dist/cjs/utils/rich-text-embeds-codegen.js +15 -104
  30. package/dist/cjs/utils/rich-text-embeds-codegen.js.map +1 -1
  31. package/dist/cjs/utils/rich-text-embeds-runtime-source.d.ts +2 -0
  32. package/dist/cjs/utils/rich-text-embeds-runtime-source.d.ts.map +1 -0
  33. package/dist/cjs/utils/rich-text-embeds-runtime-source.js +409 -0
  34. package/dist/cjs/utils/rich-text-embeds-runtime-source.js.map +1 -0
  35. package/dist/cjs/utils/session-cookie-resolver.d.ts +85 -0
  36. package/dist/cjs/utils/session-cookie-resolver.d.ts.map +1 -0
  37. package/dist/cjs/utils/session-cookie-resolver.js +108 -0
  38. package/dist/cjs/utils/session-cookie-resolver.js.map +1 -0
  39. package/dist/cjs/utils/subscription-access.d.ts +36 -0
  40. package/dist/cjs/utils/subscription-access.d.ts.map +1 -0
  41. package/dist/cjs/utils/subscription-access.js +61 -0
  42. package/dist/cjs/utils/subscription-access.js.map +1 -0
  43. package/dist/cjs/utils/table-access.d.ts +114 -0
  44. package/dist/cjs/utils/table-access.d.ts.map +1 -0
  45. package/dist/cjs/utils/table-access.js +238 -0
  46. package/dist/cjs/utils/table-access.js.map +1 -0
  47. package/dist/cjs/utils/web-push.d.ts +43 -0
  48. package/dist/cjs/utils/web-push.d.ts.map +1 -0
  49. package/dist/cjs/utils/web-push.js +62 -0
  50. package/dist/cjs/utils/web-push.js.map +1 -0
  51. package/dist/esm/index.d.ts +9 -1
  52. package/dist/esm/index.d.ts.map +1 -1
  53. package/dist/esm/index.js +9 -1
  54. package/dist/esm/index.js.map +1 -1
  55. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  56. package/dist/esm/utils/cart-currency.d.ts +27 -0
  57. package/dist/esm/utils/cart-currency.d.ts.map +1 -0
  58. package/dist/esm/utils/cart-currency.js +27 -0
  59. package/dist/esm/utils/cart-currency.js.map +1 -0
  60. package/dist/esm/utils/cart-line-pricing.d.ts +25 -0
  61. package/dist/esm/utils/cart-line-pricing.d.ts.map +1 -0
  62. package/dist/esm/utils/cart-line-pricing.js +25 -0
  63. package/dist/esm/utils/cart-line-pricing.js.map +1 -0
  64. package/dist/esm/utils/discount-engine.d.ts +74 -0
  65. package/dist/esm/utils/discount-engine.d.ts.map +1 -0
  66. package/dist/esm/utils/discount-engine.js +431 -0
  67. package/dist/esm/utils/discount-engine.js.map +1 -0
  68. package/dist/esm/utils/product-options.d.ts +25 -0
  69. package/dist/esm/utils/product-options.d.ts.map +1 -0
  70. package/dist/esm/utils/product-options.js +1151 -0
  71. package/dist/esm/utils/product-options.js.map +1 -0
  72. package/dist/esm/utils/rich-text-embeds-codegen.d.ts +13 -0
  73. package/dist/esm/utils/rich-text-embeds-codegen.d.ts.map +1 -1
  74. package/dist/esm/utils/rich-text-embeds-codegen.js +16 -105
  75. package/dist/esm/utils/rich-text-embeds-codegen.js.map +1 -1
  76. package/dist/esm/utils/rich-text-embeds-runtime-source.d.ts +2 -0
  77. package/dist/esm/utils/rich-text-embeds-runtime-source.d.ts.map +1 -0
  78. package/dist/esm/utils/rich-text-embeds-runtime-source.js +406 -0
  79. package/dist/esm/utils/rich-text-embeds-runtime-source.js.map +1 -0
  80. package/dist/esm/utils/session-cookie-resolver.d.ts +85 -0
  81. package/dist/esm/utils/session-cookie-resolver.d.ts.map +1 -0
  82. package/dist/esm/utils/session-cookie-resolver.js +103 -0
  83. package/dist/esm/utils/session-cookie-resolver.js.map +1 -0
  84. package/dist/esm/utils/subscription-access.d.ts +36 -0
  85. package/dist/esm/utils/subscription-access.d.ts.map +1 -0
  86. package/dist/esm/utils/subscription-access.js +57 -0
  87. package/dist/esm/utils/subscription-access.js.map +1 -0
  88. package/dist/esm/utils/table-access.d.ts +114 -0
  89. package/dist/esm/utils/table-access.d.ts.map +1 -0
  90. package/dist/esm/utils/table-access.js +233 -0
  91. package/dist/esm/utils/table-access.js.map +1 -0
  92. package/dist/esm/utils/web-push.d.ts +43 -0
  93. package/dist/esm/utils/web-push.d.ts.map +1 -0
  94. package/dist/esm/utils/web-push.js +59 -0
  95. package/dist/esm/utils/web-push.js.map +1 -0
  96. package/package.json +3 -3
  97. package/src/index.ts +16 -0
  98. package/src/utils/cart-currency.ts +76 -0
  99. package/src/utils/cart-line-pricing.ts +151 -0
  100. package/src/utils/discount-engine.ts +437 -0
  101. package/src/utils/product-options.ts +1150 -0
  102. package/src/utils/rich-text-embeds-codegen.ts +16 -183
  103. package/src/utils/rich-text-embeds-runtime-source.ts +405 -0
  104. package/src/utils/session-cookie-resolver.ts +305 -0
  105. package/src/utils/subscription-access.ts +59 -0
  106. package/src/utils/table-access.ts +516 -0
  107. package/src/utils/web-push.ts +61 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * The names the published app's service worker, its push routes and the
3
+ * workflow nodes that use them have to agree on. The node handlers are
4
+ * serialized into the generated app as source text, so they interpolate these
5
+ * values at generation time rather than importing them.
6
+ */
7
+ /** The browsers that agreed to receive the app's push notifications, in the project database. */
8
+ export declare const SUBSCRIPTIONS_TABLE = "teleport_push_subscriptions";
9
+ /** Public: a browser saves (POST) or forgets (DELETE) its own subscription here. */
10
+ export declare const SUBSCRIPTIONS_ROUTE = "/api/push/subscriptions";
11
+ /** Internal: only the app's own server code may send a notification through it. */
12
+ export declare const SEND_ROUTE = "/api/push/send";
13
+ /** What a visitor-facing push step reports when the project has no push keys or no worker. */
14
+ export declare const NOT_CONFIGURED_MESSAGE = "Push notifications are not set up for this site.";
15
+ export declare const PUBLIC_KEY_ENV = "WEB_PUSH_VAPID_PUBLIC_KEY";
16
+ /** Filled at deploy from the project secret of the same name. */
17
+ export declare const PRIVATE_KEY_ENV = "WEB_PUSH_VAPID_PRIVATE_KEY";
18
+ /**
19
+ * The send route accepts a request only when this header carries an HMAC of
20
+ * `SEND_TOKEN_PURPOSE` keyed with the VAPID private key — a value only the
21
+ * app's own server holds, so no extra secret has to be provisioned.
22
+ */
23
+ export declare const SEND_TOKEN_HEADER = "x-teleport-push-token";
24
+ export declare const SEND_TOKEN_PURPOSE = "teleport-web-push-send";
25
+ /**
26
+ * The page-side API the generated service-worker module publishes on `window`.
27
+ * A workflow node handler has no module scope, so a global is the only way it
28
+ * can reach the worker registration.
29
+ */
30
+ export declare const SERVICE_WORKER_GLOBAL = "__teleportServiceWorker";
31
+ export declare const SUBSCRIBE_NODE_TYPE = "browser-subscribe-to-push";
32
+ export declare const UNSUBSCRIBE_NODE_TYPE = "browser-unsubscribe-from-push";
33
+ export declare const GET_SUBSCRIPTION_NODE_TYPE = "browser-get-push-subscription";
34
+ export declare const SHOW_NOTIFICATION_NODE_TYPE = "browser-show-notification";
35
+ export declare const SEND_NODE_TYPE = "push-send-notification";
36
+ /** Nodes that manage the visitor's push subscription and therefore need the push routes. */
37
+ export declare const PUSH_NODE_TYPES: ReadonlyArray<string>;
38
+ /**
39
+ * Nodes that need a service worker on the page: push itself, and on-page
40
+ * notifications, which Chrome on Android only shows through a worker.
41
+ */
42
+ export declare const SERVICE_WORKER_NODE_TYPES: ReadonlyArray<string>;
43
+ //# sourceMappingURL=web-push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-push.d.ts","sourceRoot":"","sources":["../../../src/utils/web-push.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iGAAiG;AACjG,eAAO,MAAM,mBAAmB,gCAAgC,CAAA;AAEhE,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,4BAA4B,CAAA;AAE5D,mFAAmF;AACnF,eAAO,MAAM,UAAU,mBAAmB,CAAA;AAE1C,8FAA8F;AAC9F,eAAO,MAAM,sBAAsB,qDAAqD,CAAA;AAExF,eAAO,MAAM,cAAc,8BAA8B,CAAA;AAEzD,iEAAiE;AACjE,eAAO,MAAM,eAAe,+BAA+B,CAAA;AAE3D;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,0BAA0B,CAAA;AACxD,eAAO,MAAM,kBAAkB,2BAA2B,CAAA;AAE1D;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,4BAA4B,CAAA;AAE9D,eAAO,MAAM,mBAAmB,8BAA8B,CAAA;AAC9D,eAAO,MAAM,qBAAqB,kCAAkC,CAAA;AACpE,eAAO,MAAM,0BAA0B,kCAAkC,CAAA;AACzE,eAAO,MAAM,2BAA2B,8BAA8B,CAAA;AACtE,eAAO,MAAM,cAAc,2BAA2B,CAAA;AAEtD,4FAA4F;AAC5F,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,MAAM,CAKjD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAG3D,CAAA"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The names the published app's service worker, its push routes and the
3
+ * workflow nodes that use them have to agree on. The node handlers are
4
+ * serialized into the generated app as source text, so they interpolate these
5
+ * values at generation time rather than importing them.
6
+ */
7
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
8
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
9
+ if (ar || !(i in from)) {
10
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
11
+ ar[i] = from[i];
12
+ }
13
+ }
14
+ return to.concat(ar || Array.prototype.slice.call(from));
15
+ };
16
+ /** The browsers that agreed to receive the app's push notifications, in the project database. */
17
+ export var SUBSCRIPTIONS_TABLE = 'teleport_push_subscriptions';
18
+ /** Public: a browser saves (POST) or forgets (DELETE) its own subscription here. */
19
+ export var SUBSCRIPTIONS_ROUTE = '/api/push/subscriptions';
20
+ /** Internal: only the app's own server code may send a notification through it. */
21
+ export var SEND_ROUTE = '/api/push/send';
22
+ /** What a visitor-facing push step reports when the project has no push keys or no worker. */
23
+ export var NOT_CONFIGURED_MESSAGE = 'Push notifications are not set up for this site.';
24
+ export var PUBLIC_KEY_ENV = 'WEB_PUSH_VAPID_PUBLIC_KEY';
25
+ /** Filled at deploy from the project secret of the same name. */
26
+ export var PRIVATE_KEY_ENV = 'WEB_PUSH_VAPID_PRIVATE_KEY';
27
+ /**
28
+ * The send route accepts a request only when this header carries an HMAC of
29
+ * `SEND_TOKEN_PURPOSE` keyed with the VAPID private key — a value only the
30
+ * app's own server holds, so no extra secret has to be provisioned.
31
+ */
32
+ export var SEND_TOKEN_HEADER = 'x-teleport-push-token';
33
+ export var SEND_TOKEN_PURPOSE = 'teleport-web-push-send';
34
+ /**
35
+ * The page-side API the generated service-worker module publishes on `window`.
36
+ * A workflow node handler has no module scope, so a global is the only way it
37
+ * can reach the worker registration.
38
+ */
39
+ export var SERVICE_WORKER_GLOBAL = '__teleportServiceWorker';
40
+ export var SUBSCRIBE_NODE_TYPE = 'browser-subscribe-to-push';
41
+ export var UNSUBSCRIBE_NODE_TYPE = 'browser-unsubscribe-from-push';
42
+ export var GET_SUBSCRIPTION_NODE_TYPE = 'browser-get-push-subscription';
43
+ export var SHOW_NOTIFICATION_NODE_TYPE = 'browser-show-notification';
44
+ export var SEND_NODE_TYPE = 'push-send-notification';
45
+ /** Nodes that manage the visitor's push subscription and therefore need the push routes. */
46
+ export var PUSH_NODE_TYPES = [
47
+ SUBSCRIBE_NODE_TYPE,
48
+ UNSUBSCRIBE_NODE_TYPE,
49
+ GET_SUBSCRIPTION_NODE_TYPE,
50
+ SEND_NODE_TYPE,
51
+ ];
52
+ /**
53
+ * Nodes that need a service worker on the page: push itself, and on-page
54
+ * notifications, which Chrome on Android only shows through a worker.
55
+ */
56
+ export var SERVICE_WORKER_NODE_TYPES = __spreadArray(__spreadArray([], PUSH_NODE_TYPES, true), [
57
+ SHOW_NOTIFICATION_NODE_TYPE,
58
+ ], false);
59
+ //# sourceMappingURL=web-push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-push.js","sourceRoot":"","sources":["../../../src/utils/web-push.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;;;;;;;;;;AAEH,iGAAiG;AACjG,MAAM,CAAC,IAAM,mBAAmB,GAAG,6BAA6B,CAAA;AAEhE,oFAAoF;AACpF,MAAM,CAAC,IAAM,mBAAmB,GAAG,yBAAyB,CAAA;AAE5D,mFAAmF;AACnF,MAAM,CAAC,IAAM,UAAU,GAAG,gBAAgB,CAAA;AAE1C,8FAA8F;AAC9F,MAAM,CAAC,IAAM,sBAAsB,GAAG,kDAAkD,CAAA;AAExF,MAAM,CAAC,IAAM,cAAc,GAAG,2BAA2B,CAAA;AAEzD,iEAAiE;AACjE,MAAM,CAAC,IAAM,eAAe,GAAG,4BAA4B,CAAA;AAE3D;;;;GAIG;AACH,MAAM,CAAC,IAAM,iBAAiB,GAAG,uBAAuB,CAAA;AACxD,MAAM,CAAC,IAAM,kBAAkB,GAAG,wBAAwB,CAAA;AAE1D;;;;GAIG;AACH,MAAM,CAAC,IAAM,qBAAqB,GAAG,yBAAyB,CAAA;AAE9D,MAAM,CAAC,IAAM,mBAAmB,GAAG,2BAA2B,CAAA;AAC9D,MAAM,CAAC,IAAM,qBAAqB,GAAG,+BAA+B,CAAA;AACpE,MAAM,CAAC,IAAM,0BAA0B,GAAG,+BAA+B,CAAA;AACzE,MAAM,CAAC,IAAM,2BAA2B,GAAG,2BAA2B,CAAA;AACtE,MAAM,CAAC,IAAM,cAAc,GAAG,wBAAwB,CAAA;AAEtD,4FAA4F;AAC5F,MAAM,CAAC,IAAM,eAAe,GAA0B;IACpD,mBAAmB;IACnB,qBAAqB;IACrB,0BAA0B;IAC1B,cAAc;CACf,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,IAAM,yBAAyB,mCACjC,eAAe;IAClB,2BAA2B;SAC5B,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teleporthq/teleport-shared",
3
- "version": "0.43.67",
3
+ "version": "0.43.69",
4
4
  "description": "A utility belt for the entire teleportHQ ecosystem",
5
5
  "author": "teleportHQ",
6
6
  "license": "MIT",
@@ -25,9 +25,9 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@babel/types": "^7.5.5",
28
- "@teleporthq/teleport-types": "^0.43.67",
28
+ "@teleporthq/teleport-types": "^0.43.68",
29
29
  "jss": "^10.0.0",
30
30
  "jss-preset-default": "^10.0.0"
31
31
  },
32
- "gitHead": "692355951ec33ee4b89018177e7ec4d58a66c073"
32
+ "gitHead": "ff9293d65ac3dd46ac196c5575c65d59e2006a28"
33
33
  }
package/src/index.ts CHANGED
@@ -15,12 +15,20 @@ import * as StorefrontTax from './utils/storefront-tax'
15
15
  import * as ProductDiscounts from './utils/product-discounts'
16
16
  import * as ProductRatings from './utils/product-ratings'
17
17
  import * as RegionalPricing from './utils/regional-pricing'
18
+ import * as DiscountEngine from './utils/discount-engine'
19
+ import * as ProductOptions from './utils/product-options'
20
+ import * as CartLinePricing from './utils/cart-line-pricing'
21
+ import * as CartCurrency from './utils/cart-currency'
22
+ import * as TableAccess from './utils/table-access'
23
+ import * as SessionCookieResolver from './utils/session-cookie-resolver'
24
+ import * as SubscriptionAccess from './utils/subscription-access'
18
25
  import * as FontPreconnect from './utils/font-preconnect'
19
26
  import * as EmailDate from './utils/email-date'
20
27
  import * as RichTextEmbeds from './utils/rich-text-embeds'
21
28
  import * as RichTextEmbedsCodegen from './utils/rich-text-embeds-codegen'
22
29
  import * as DataCache from './cache'
23
30
  import * as PageRevalidate from './page-revalidate'
31
+ import * as WebPush from './utils/web-push'
24
32
 
25
33
  export {
26
34
  Constants,
@@ -40,10 +48,18 @@ export {
40
48
  ProductDiscounts,
41
49
  ProductRatings,
42
50
  RegionalPricing,
51
+ DiscountEngine,
52
+ ProductOptions,
53
+ CartLinePricing,
54
+ CartCurrency,
55
+ TableAccess,
56
+ SessionCookieResolver,
57
+ SubscriptionAccess,
43
58
  FontPreconnect,
44
59
  EmailDate,
45
60
  RichTextEmbeds,
46
61
  RichTextEmbedsCodegen,
47
62
  DataCache,
48
63
  PageRevalidate,
64
+ WebPush,
49
65
  }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The currency a cart is priced in, as ES5 source for generated runtime code
3
+ * (the add-to-cart node, the storefront cart provider, the cart total and the
4
+ * checkout's server pricing step) that cannot import from this package.
5
+ *
6
+ * Every product carries its own currency, and nothing converts between them:
7
+ * an order is recorded and charged in ONE currency, so a cart holds products
8
+ * of one currency only — the same way it holds one kind of line (see the kind
9
+ * rule beside it in `cart-add-item`). The cart's currency is the currency of
10
+ * its lines; a line that names none (a cart saved before lines carried it)
11
+ * takes no part in the rule.
12
+ *
13
+ * ⚠️ PAIRED with teleport-gui's cart simulator
14
+ * (`features/e-commerce/utils/cart-kinds.ts`): the refusal reason and message
15
+ * must stay byte-identical to what the published store toasts.
16
+ *
17
+ * ⛔ Every helper takes ONE parameter. The block is appended to a serialized
18
+ * handler whose entry point a minified build finds by arity (a 2-param
19
+ * declaration wins — see `resolveHandlerEntryName`), so a 2-param helper would
20
+ * be called in place of the handler. Everything is prefixed `__cc` so the block
21
+ * can be concatenated into any generated module without colliding with its
22
+ * locals.
23
+ */
24
+
25
+ /** The reason an add-to-cart refusal answers for a line of another currency. */
26
+ export const MIXED_CURRENCY_REASON = 'mixed-currency'
27
+
28
+ export const generateCartCurrencyHelperCode = (): string => `
29
+ // ── Cart currency ────────────────────────────────────────────────────────────
30
+ // A three-letter ISO code, upper-cased, or '' for anything else.
31
+ function __ccCode(value) {
32
+ var code = String(value == null ? '' : value).trim().toUpperCase();
33
+ return /^[A-Z]{3}$/.test(code) ? code : '';
34
+ }
35
+
36
+ // The currency of the cart: the first line that names one, or ''.
37
+ function __ccCartCurrency(lines) {
38
+ if (!lines || typeof lines.length !== 'number') { return ''; }
39
+ for (var i = 0; i < lines.length; i++) {
40
+ var code = __ccCode(lines[i] ? lines[i].currency : '');
41
+ if (code) { return code; }
42
+ }
43
+ return '';
44
+ }
45
+
46
+ // Every currency the lines name, in the order they first appear.
47
+ function __ccCurrencies(lines) {
48
+ var codes = [];
49
+ if (!lines || typeof lines.length !== 'number') { return codes; }
50
+ for (var i = 0; i < lines.length; i++) {
51
+ var code = __ccCode(lines[i] ? lines[i].currency : '');
52
+ if (code && codes.indexOf(code) === -1) { codes.push(code); }
53
+ }
54
+ return codes;
55
+ }
56
+
57
+ // Why a line priced in \`input.currency\` cannot join \`input.lines\` (the OTHER
58
+ // lines of the cart), or null when it can.
59
+ function __ccCurrencyRefusal(input) {
60
+ var lineCurrency = __ccCode(input ? input.currency : '');
61
+ var cartCurrency = __ccCartCurrency(input ? input.lines : null);
62
+ if (!lineCurrency || !cartCurrency || lineCurrency === cartCurrency) { return null; }
63
+ return {
64
+ added: false,
65
+ reason: '${MIXED_CURRENCY_REASON}',
66
+ message: 'Products priced in ' + lineCurrency + ' need a separate order. Complete your current order or remove the items priced in ' + cartCurrency + ' from your cart first.'
67
+ };
68
+ }
69
+
70
+ // What the checkout says when a cart still holds several currencies (a cart
71
+ // merged at sign-in, or a product whose currency changed after it was added).
72
+ function __ccMixedCartMessage(codes) {
73
+ var named = codes.length > 1 ? codes.slice(0, -1).join(', ') + ' and ' + codes[codes.length - 1] : codes.join('');
74
+ return 'Your cart holds products priced in ' + named + '. Each currency needs its own order: remove the products priced in one of them and try again.';
75
+ }
76
+ `
@@ -0,0 +1,151 @@
1
+ /**
2
+ * What one cart line costs, read off its product (and variant) row, as ES5
3
+ * source for generated runtime code that cannot import from this package.
4
+ *
5
+ * TWO READERS, ONE RULE. The storefront provider re-prices every line with it
6
+ * when it hydrates the cart (`enrichCartItems` in the e-commerce context), and
7
+ * the checkout's server step prices the order with it (`cart-price-order` in
8
+ * the workflows plugin) — so what the buyer is shown and what the order is
9
+ * charged come from the same arithmetic over the same row. A price the
10
+ * browser holds is never an input: the line keeps only what the buyer chose
11
+ * (product, variant, options, quantity).
12
+ *
13
+ * The rule: the variant's price overrides the product's; the per-product
14
+ * markdown live at `nowMs` comes off that NET price; the chosen options'
15
+ * surcharge is added on top of the charged base (options are never marked
16
+ * down). A subscription is one unit.
17
+ *
18
+ * Needs, in the same scope: the per-product discount helpers (`__pd*`,
19
+ * `ProductDiscounts.generateProductDiscountHelperCode`), the product-option
20
+ * helpers (`__po*`, `ProductOptions.generateProductOptionsHelperCode`) and the
21
+ * discount engine's row readers (`__deStringArray`, `__deBool`,
22
+ * `DiscountEngine.generateDiscountEngineHelperCode`).
23
+ */
24
+ export const generateCartLinePricingHelperCode = (): string => `
25
+ // ── Cart line pricing ────────────────────────────────────────────────────────
26
+ var __CL_BILLING_INTERVALS = ['day', 'week', 'month', 'year'];
27
+
28
+ function __clIsRecurring(product) {
29
+ return String((product && product.payment_type) || '').trim().toLowerCase() === 'recurring';
30
+ }
31
+
32
+ function __clBillingInterval(value) {
33
+ var normalized = String(value == null ? '' : value).trim().toLowerCase();
34
+ return __CL_BILLING_INTERVALS.indexOf(normalized) !== -1 ? normalized : 'month';
35
+ }
36
+
37
+ function __clBillingIntervalCount(value) {
38
+ var parsed = Math.floor(Number(value));
39
+ return isFinite(parsed) && parsed >= 1 ? parsed : 1;
40
+ }
41
+
42
+ function __clPositiveCount(value) {
43
+ if (value === null || value === undefined || value === '') { return null; }
44
+ var parsed = Math.floor(Number(value));
45
+ return isFinite(parsed) && parsed > 0 ? parsed : null;
46
+ }
47
+
48
+ // The chosen options re-priced from the product's CURRENT definitions on the
49
+ // charged base, and whether the answers still fit (\`configurationStale\`, which
50
+ // the checkout refuses). Null for a line with no answers of a product with no
51
+ // options, which is priced exactly as before; cleared fields for a line that
52
+ // carried options its product no longer has.
53
+ function __clPriceLineOptions(item, product, basePrice) {
54
+ var entries = __poParseEntries(item.configuration);
55
+ if (entries.length === 0 && __poParseGroups(product.option_groups).length === 0) {
56
+ if (item.basePrice == null && item.configurationLabel == null && item.configurationPriceDelta == null && item.configurationStale == null) { return null; }
57
+ return { basePrice: null, configurationLabel: null, configurationPriceDelta: null, configurationStale: null };
58
+ }
59
+ var resolved = __poResolveForRow(product, basePrice, entries);
60
+ return {
61
+ basePrice: basePrice,
62
+ configurationLabel: resolved.label,
63
+ configurationPriceDelta: resolved.delta,
64
+ configurationStale: !resolved.valid
65
+ };
66
+ }
67
+
68
+ // "Red / XL" — the variant's value labels along the product's (language-
69
+ // resolved) option axes.
70
+ function __clVariantLabel(variantOptionsRaw, optionsMap) {
71
+ var axes = variantOptionsRaw;
72
+ if (typeof axes === 'string') { try { axes = JSON.parse(axes); } catch (e) { axes = []; } }
73
+ if (!Array.isArray(axes)) { return ''; }
74
+ var opts = optionsMap;
75
+ if (typeof opts === 'string') { try { opts = JSON.parse(opts); } catch (e) { opts = {}; } }
76
+ if (!opts) { opts = {}; }
77
+ var parts = [];
78
+ for (var a = 0; a < axes.length; a++) {
79
+ var axis = axes[a];
80
+ if (!axis || !axis.key) { continue; }
81
+ var valueKey = opts[axis.key];
82
+ if (valueKey == null) { continue; }
83
+ var label = valueKey;
84
+ var values = Array.isArray(axis.values) ? axis.values : [];
85
+ for (var v = 0; v < values.length; v++) { if (values[v] && values[v].value === valueKey) { label = values[v].label || valueKey; break; } }
86
+ parts.push(label);
87
+ }
88
+ return parts.join(' / ');
89
+ }
90
+
91
+ // The colour(s) of the variant's value on every COLOUR axis, for the swatch
92
+ // shown beside the label.
93
+ function __clVariantSwatches(variantOptionsRaw, optionsMap) {
94
+ var axes = variantOptionsRaw;
95
+ if (typeof axes === 'string') { try { axes = JSON.parse(axes); } catch (e) { axes = []; } }
96
+ if (!Array.isArray(axes)) { return []; }
97
+ var opts = optionsMap;
98
+ if (typeof opts === 'string') { try { opts = JSON.parse(opts); } catch (e) { opts = {}; } }
99
+ if (!opts) { opts = {}; }
100
+ var swatches = [];
101
+ for (var a = 0; a < axes.length; a++) {
102
+ var axis = axes[a];
103
+ if (!axis || !axis.key || axis.type !== 'color') { continue; }
104
+ var valueKey = opts[axis.key];
105
+ if (valueKey == null) { continue; }
106
+ var values = Array.isArray(axis.values) ? axis.values : [];
107
+ for (var v = 0; v < values.length; v++) { if (values[v] && values[v].value === valueKey && values[v].color) { swatches.push({ color: values[v].color }); break; } }
108
+ }
109
+ return swatches;
110
+ }
111
+
112
+ // The line's price and everything the totals read off its product, for the
113
+ // row as it is at \`nowMs\`. \`withWeight\` adds the weight the regional
114
+ // shipping rates price by.
115
+ function __clPriceLine(item, product, variant, nowMs, withWeight) {
116
+ var price = product.price != null ? Number(product.price) : 0;
117
+ if (variant && variant.price != null) { price = Number(variant.price); }
118
+ var discount = __pdResolveActive(product.discounts, nowMs);
119
+ var listPrice = price;
120
+ price = __pdDiscountedPrice(listPrice, discount);
121
+ var options = __clPriceLineOptions(item, product, price);
122
+ var optionsDelta = options ? options.configurationPriceDelta : null;
123
+ var recurring = __clIsRecurring(product);
124
+ var priced = {
125
+ price: optionsDelta != null ? __poRound2(price + optionsDelta) : price,
126
+ originalPrice: discount ? (optionsDelta != null ? __poRound2(listPrice + optionsDelta) : listPrice) : null,
127
+ discountType: discount ? discount.type : null,
128
+ discountValue: discount ? discount.value : null,
129
+ discountAmount: discount ? __pdDiscountAmount(listPrice, discount) : 0,
130
+ categoryIds: __deStringArray(product.category_filter_ids || product.category_ids),
131
+ isGiftCard: __deBool(product.is_gift_card, false),
132
+ isRecurring: recurring,
133
+ recurringInterval: recurring ? __clBillingInterval(product.recurring_interval) : null,
134
+ recurringIntervalCount: recurring ? __clBillingIntervalCount(product.recurring_interval_count) : null,
135
+ trialDays: recurring ? __clPositiveCount(product.trial_days) : null,
136
+ isDigital: __deBool(product.is_digital, false),
137
+ quantity: recurring ? 1 : item.quantity
138
+ };
139
+ if (withWeight) {
140
+ priced.weight = product.weight != null ? Number(product.weight) : null;
141
+ priced.weightUnit = product.weight_unit || null;
142
+ }
143
+ if (options) {
144
+ priced.basePrice = options.basePrice;
145
+ priced.configurationLabel = options.configurationLabel;
146
+ priced.configurationPriceDelta = options.configurationPriceDelta;
147
+ priced.configurationStale = options.configurationStale;
148
+ }
149
+ return priced;
150
+ }
151
+ `