@swell/apps-sdk 1.0.127 → 1.0.129

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/index.js CHANGED
@@ -89,10 +89,151 @@
89
89
  var import_json52 = __toESM(__require("json5"), 1);
90
90
 
91
91
  // src/resources.ts
92
- var import_lodash_es = __require("lodash-es");
92
+ var import_lodash_es2 = __require("lodash-es");
93
93
 
94
94
  // src/liquid/utils.ts
95
95
  var import_liquidjs = __require("liquidjs");
96
+
97
+ // src/compatibility/shopify-objects/resource.ts
98
+ var import_lodash_es = __require("lodash-es");
99
+ var ShopifyResource = class _ShopifyResource {
100
+ props;
101
+ stringProp;
102
+ linkProps;
103
+ constructor(props, stringProp, linkProps) {
104
+ this.props = props;
105
+ this.stringProp = stringProp;
106
+ this.linkProps = linkProps;
107
+ return new Proxy(props, {
108
+ get(target, prop, receiver) {
109
+ const instance = target;
110
+ switch (prop) {
111
+ case "toJSON":
112
+ return props;
113
+ case "clone":
114
+ return () => {
115
+ return new _ShopifyResource(
116
+ (0, import_lodash_es.cloneDeep)(props),
117
+ (0, import_lodash_es.cloneDeep)(stringProp),
118
+ (0, import_lodash_es.cloneDeep)(linkProps)
119
+ );
120
+ };
121
+ case "toString": {
122
+ if (stringProp) {
123
+ return () => {
124
+ return props[stringProp];
125
+ };
126
+ }
127
+ break;
128
+ }
129
+ case Symbol.toPrimitive: {
130
+ return () => {
131
+ let prop2 = stringProp;
132
+ if (typeof prop2 === "number") {
133
+ prop2 = prop2.toString();
134
+ }
135
+ return this.get?.(instance, prop2 || "handle", receiver);
136
+ };
137
+ }
138
+ default:
139
+ break;
140
+ }
141
+ const value = instance[prop];
142
+ if (value instanceof DeferredShopifyResource) {
143
+ const promise = value.resolve().then(
144
+ (value2) => {
145
+ instance[prop] = value2;
146
+ return value2;
147
+ },
148
+ (err) => {
149
+ console.log(err);
150
+ instance[prop] = null;
151
+ return null;
152
+ }
153
+ );
154
+ instance[prop] = promise;
155
+ return promise;
156
+ }
157
+ return value;
158
+ },
159
+ getPrototypeOf() {
160
+ return _ShopifyResource.prototype;
161
+ }
162
+ });
163
+ }
164
+ valueOf() {
165
+ if (this.stringProp) {
166
+ return this.props[this.stringProp];
167
+ }
168
+ return this;
169
+ }
170
+ // For typescript
171
+ clone() {
172
+ return new _ShopifyResource(this.props);
173
+ }
174
+ };
175
+ var DeferredShopifyResource = class {
176
+ handler;
177
+ result;
178
+ constructor(handler) {
179
+ this.result = void 0;
180
+ this.handler = handler;
181
+ }
182
+ async resolve() {
183
+ if (this.handler !== import_lodash_es.noop) {
184
+ const handler = this.handler;
185
+ this.handler = import_lodash_es.noop;
186
+ this.result = Promise.resolve().then(handler).then((value) => {
187
+ this.result = value;
188
+ return value;
189
+ });
190
+ }
191
+ return this.result;
192
+ }
193
+ };
194
+ function defer(handler) {
195
+ return new DeferredShopifyResource(handler);
196
+ }
197
+ function isResolvable(asyncProp) {
198
+ return isObject(asyncProp) && (isLikePromise(asyncProp) || typeof asyncProp._resolve === "function");
199
+ }
200
+ function isStorefrontResource(resource) {
201
+ return isObject(resource) && typeof resource._resolve === "function";
202
+ }
203
+ async function resolveAsyncProp(asyncProp) {
204
+ if (Array.isArray(asyncProp)) {
205
+ return Promise.all(
206
+ asyncProp.map(
207
+ (prop) => isStorefrontResource(prop) ? prop._resolve() : prop
208
+ )
209
+ );
210
+ }
211
+ if (isStorefrontResource(asyncProp)) {
212
+ return asyncProp._resolve();
213
+ }
214
+ return asyncProp;
215
+ }
216
+ function handleDeferredProp(asyncProp, handler) {
217
+ return resolveAsyncProp(asyncProp).then((value) => {
218
+ if (Array.isArray(asyncProp) && Array.isArray(value)) {
219
+ return handler(...value.map((prop) => prop || {}));
220
+ }
221
+ if (isResolvable(value)) {
222
+ return handleDeferredProp(value, handler);
223
+ }
224
+ return handler(value || {});
225
+ }).catch((err) => {
226
+ console.log(err);
227
+ return null;
228
+ });
229
+ }
230
+ function deferWith(asyncProp, handler) {
231
+ return new DeferredShopifyResource(
232
+ () => handleDeferredProp(asyncProp, handler)
233
+ );
234
+ }
235
+
236
+ // src/liquid/utils.ts
96
237
  var ForloopDrop = class extends import_liquidjs.Drop {
97
238
  i;
98
239
  length;
@@ -259,18 +400,24 @@
259
400
  async function resolveAllKeys(value, references = /* @__PURE__ */ new WeakSet()) {
260
401
  await forEachKeyDeep(value, async (key, value2) => {
261
402
  if (!isObject(value2)) {
262
- return;
403
+ return true;
263
404
  }
264
405
  const val = value2[key];
265
406
  if (isLikePromise(val)) {
266
407
  value2[key] = await val;
267
408
  await resolveAllKeys(value2[key], references);
268
409
  } else if (isObject(val)) {
410
+ if (val instanceof DeferredShopifyResource) {
411
+ value2[key] = await val.resolve();
412
+ await resolveAllKeys(value2[key], references);
413
+ return true;
414
+ }
269
415
  if (references.has(val)) {
270
416
  return false;
271
417
  }
272
418
  references.add(val);
273
419
  }
420
+ return true;
274
421
  });
275
422
  }
276
423
  async function forEachKeyDeep(obj, fn) {
@@ -388,12 +535,18 @@
388
535
  }
389
536
  return instance[prop];
390
537
  }
538
+ // add additional properties to the loaded result
539
+ _transformResult(result) {
540
+ return result;
541
+ }
391
542
  async _get(..._args) {
392
543
  if (this._getter) {
393
544
  const getter = this._getter.bind(
394
545
  this
395
546
  );
396
547
  return Promise.resolve().then(getter).then((result) => {
548
+ return this._transformResult(result);
549
+ }).then((result) => {
397
550
  this._result = result;
398
551
  if (result) {
399
552
  Object.assign(this, result);
@@ -469,6 +622,8 @@
469
622
  function cloneStorefrontResource(input) {
470
623
  const resourceName = input._resourceName;
471
624
  const clone = new StorefrontResource(input._getter);
625
+ clone._params = input._params;
626
+ clone._transformResult = input._transformResult.bind(clone);
472
627
  Object.defineProperty(clone.constructor, "name", {
473
628
  value: resourceName
474
629
  });
@@ -596,7 +751,7 @@
596
751
  this._getter
597
752
  );
598
753
  if (this._isResultResolved()) {
599
- cloned._result = (0, import_lodash_es.cloneDeep)(this._result);
754
+ cloned._result = (0, import_lodash_es2.cloneDeep)(this._result);
600
755
  }
601
756
  if (this._compatibilityProps) {
602
757
  cloned.setCompatibilityProps(this._compatibilityProps);
@@ -625,7 +780,7 @@
625
780
  }
626
781
  });
627
782
  if (this._isResultResolved()) {
628
- const result = (0, import_lodash_es.cloneDeep)(this._result);
783
+ const result = (0, import_lodash_es2.cloneDeep)(this._result);
629
784
  if (result) {
630
785
  const compatibilityProps = compatibilityGetter(result);
631
786
  Object.assign(cloned, result);
@@ -639,10 +794,12 @@
639
794
  };
640
795
  var SwellStorefrontRecord = class extends SwellStorefrontResource {
641
796
  _id;
797
+ _params;
642
798
  constructor(swell, collection, id, query = {}, getter) {
643
799
  super(swell, collection, getter);
644
800
  this._id = id;
645
801
  this._query = query;
802
+ this._params = {};
646
803
  if (!getter) {
647
804
  this._setGetter(this._defaultGetter());
648
805
  }
@@ -680,6 +837,8 @@
680
837
  ],
681
838
  getter
682
839
  ).then((result) => {
840
+ return this._transformResult(result);
841
+ }).then((result) => {
683
842
  this._result = result;
684
843
  if (result) {
685
844
  Object.assign(this, result);
@@ -789,145 +948,6 @@
789
948
  }
790
949
  };
791
950
 
792
- // src/compatibility/shopify-objects/resource.ts
793
- var import_lodash_es2 = __require("lodash-es");
794
- var ShopifyResource = class _ShopifyResource {
795
- props;
796
- stringProp;
797
- linkProps;
798
- constructor(props, stringProp, linkProps) {
799
- this.props = props;
800
- this.stringProp = stringProp;
801
- this.linkProps = linkProps;
802
- return new Proxy(props, {
803
- get(target, prop, receiver) {
804
- const instance = target;
805
- switch (prop) {
806
- case "toJSON":
807
- return props;
808
- case "clone":
809
- return () => {
810
- return new _ShopifyResource(
811
- (0, import_lodash_es2.cloneDeep)(props),
812
- (0, import_lodash_es2.cloneDeep)(stringProp),
813
- (0, import_lodash_es2.cloneDeep)(linkProps)
814
- );
815
- };
816
- case "toString": {
817
- if (stringProp) {
818
- return () => {
819
- return props[stringProp];
820
- };
821
- }
822
- break;
823
- }
824
- case Symbol.toPrimitive: {
825
- return () => {
826
- let prop2 = stringProp;
827
- if (typeof prop2 === "number") {
828
- prop2 = prop2.toString();
829
- }
830
- return this.get?.(instance, prop2 || "handle", receiver);
831
- };
832
- }
833
- default:
834
- break;
835
- }
836
- const value = instance[prop];
837
- if (value instanceof DeferredShopifyResource) {
838
- const promise = value.resolve().then(
839
- (value2) => {
840
- instance[prop] = value2;
841
- return value2;
842
- },
843
- (err) => {
844
- console.log(err);
845
- instance[prop] = null;
846
- return null;
847
- }
848
- );
849
- instance[prop] = promise;
850
- return promise;
851
- }
852
- return value;
853
- },
854
- getPrototypeOf() {
855
- return _ShopifyResource.prototype;
856
- }
857
- });
858
- }
859
- valueOf() {
860
- if (this.stringProp) {
861
- return this.props[this.stringProp];
862
- }
863
- return this;
864
- }
865
- // For typescript
866
- clone() {
867
- return new _ShopifyResource(this.props);
868
- }
869
- };
870
- var DeferredShopifyResource = class {
871
- handler;
872
- result;
873
- constructor(handler) {
874
- this.result = void 0;
875
- this.handler = handler;
876
- }
877
- async resolve() {
878
- if (this.handler !== import_lodash_es2.noop) {
879
- const handler = this.handler;
880
- this.handler = import_lodash_es2.noop;
881
- this.result = Promise.resolve().then(handler).then((value) => {
882
- this.result = value;
883
- return value;
884
- });
885
- }
886
- return this.result;
887
- }
888
- };
889
- function defer(handler) {
890
- return new DeferredShopifyResource(handler);
891
- }
892
- function isResolvable(asyncProp) {
893
- return isObject(asyncProp) && (isLikePromise(asyncProp) || typeof asyncProp._resolve === "function");
894
- }
895
- function isStorefrontResource(resource) {
896
- return isObject(resource) && typeof resource._resolve === "function";
897
- }
898
- async function resolveAsyncProp(asyncProp) {
899
- if (Array.isArray(asyncProp)) {
900
- return Promise.all(
901
- asyncProp.map(
902
- (prop) => isStorefrontResource(prop) ? prop._resolve() : prop
903
- )
904
- );
905
- }
906
- if (isStorefrontResource(asyncProp)) {
907
- return asyncProp._resolve();
908
- }
909
- return asyncProp;
910
- }
911
- function handleDeferredProp(asyncProp, handler) {
912
- return resolveAsyncProp(asyncProp).then((value) => {
913
- if (Array.isArray(asyncProp) && Array.isArray(value)) {
914
- return handler(...value.map((prop) => prop || {}));
915
- }
916
- if (isResolvable(value)) {
917
- return handleDeferredProp(value, handler);
918
- }
919
- return handler(value || {});
920
- }).catch((err) => {
921
- console.log(err);
922
- return null;
923
- });
924
- }
925
- function deferWith(asyncProp, handler) {
926
- return new DeferredShopifyResource(
927
- () => handleDeferredProp(asyncProp, handler)
928
- );
929
- }
930
-
931
951
  // src/constants.ts
932
952
  var FILE_DATA_INCLUDE_QUERY = {
933
953
  url: "/:themes:configs/{id}/file/data",
@@ -7012,50 +7032,213 @@
7012
7032
  store: new CFWorkerKVKeyvAdapter(kvStore)
7013
7033
  })
7014
7034
  );
7015
- } else {
7016
- stores.push(new import_keyv.Keyv());
7035
+ } else {
7036
+ stores.push(new import_keyv.Keyv());
7037
+ }
7038
+ return stores;
7039
+ }
7040
+
7041
+ // src/cache/request-cache.ts
7042
+ var RequestCache = class extends Cache {
7043
+ constructor(options) {
7044
+ super({
7045
+ ...options
7046
+ });
7047
+ }
7048
+ };
7049
+
7050
+ // src/cache/resource-cache.ts
7051
+ var import_keyv2 = __require("keyv");
7052
+ var ResourceCache = class extends Cache {
7053
+ constructor(options) {
7054
+ super({
7055
+ stores: buildStores2(),
7056
+ ...options
7057
+ });
7058
+ }
7059
+ };
7060
+ function buildStores2() {
7061
+ return [
7062
+ new import_keyv2.Keyv({
7063
+ // Disabling serialization allows for pure memo-ization of class instances
7064
+ // at the tradeoff of no support for compression.
7065
+ serialize: void 0,
7066
+ deserialize: void 0
7067
+ })
7068
+ ];
7069
+ }
7070
+
7071
+ // src/cache/theme-cache.ts
7072
+ var TTL = 90 * 24 * 60 * 60 * 1e3;
7073
+ var ThemeCache = class extends Cache {
7074
+ constructor(options) {
7075
+ super({
7076
+ ttl: TTL,
7077
+ ...options
7078
+ });
7079
+ }
7080
+ };
7081
+
7082
+ // src/resources/product_helpers.ts
7083
+ function calculateAddOptionsPrice(product, queryParams) {
7084
+ const { option_values = "" } = queryParams;
7085
+ const queryOptionValues = option_values;
7086
+ const optionValues = queryOptionValues.split(",");
7087
+ const addPrice = product.options?.reduce((acc, option) => {
7088
+ if (!option.active || !option.values || option.values.length <= 0) {
7089
+ return acc;
7090
+ }
7091
+ if (option.input_type !== "select") {
7092
+ return acc;
7093
+ }
7094
+ for (const value of option.values) {
7095
+ if (optionValues.includes(value.id)) {
7096
+ return acc + (value.price || 0);
7097
+ }
7098
+ }
7099
+ return acc + (option.values[0].price || 0);
7100
+ }, 0);
7101
+ return product.price + (addPrice || 0);
7102
+ }
7103
+ function calculateAddOptionsVariantPrice(product, variant, queryParams) {
7104
+ const { option_values = "" } = queryParams;
7105
+ const queryOptionValues = option_values;
7106
+ const optionValues = queryOptionValues.split(",");
7107
+ const addPrice = product.options?.reduce((acc, option) => {
7108
+ if (option.variant || // skip variant options
7109
+ !option.active || !option.values || option.values.length <= 0) {
7110
+ return acc;
7111
+ }
7112
+ if (option.input_type !== "select") {
7113
+ return acc;
7114
+ }
7115
+ for (const value of option.values) {
7116
+ if (optionValues.includes(value.id)) {
7117
+ return acc + (value.price || 0);
7118
+ }
7119
+ }
7120
+ return acc + (option.values[0].price || 0);
7121
+ }, 0);
7122
+ let price = product.price;
7123
+ if (variant.price !== null && variant.price !== void 0) {
7124
+ price = variant.price;
7125
+ }
7126
+ return price + (addPrice || 0);
7127
+ }
7128
+ function getAvailableVariants(product) {
7129
+ return (product.variants?.results?.slice()?.reverse() || []).filter(
7130
+ (variant) => variant.stock_status === "in_stock" || !variant.stock_status
7131
+ );
7132
+ }
7133
+ function getSelectedSwellVariant(product, queryParams) {
7134
+ const { variant: queryVariant, option_values } = queryParams;
7135
+ const queryOptionValues = option_values;
7136
+ const variants = getAvailableVariants(product);
7137
+ let selectedVariant = void 0;
7138
+ if (queryVariant) {
7139
+ selectedVariant = variants.find((variant) => variant.id === queryVariant);
7140
+ } else if (queryOptionValues) {
7141
+ const optionValues = queryOptionValues.split(",");
7142
+ selectedVariant = variants.find(
7143
+ (variant) => variant.option_value_ids.every(
7144
+ (optionValueId) => optionValues.includes(optionValueId)
7145
+ )
7146
+ );
7017
7147
  }
7018
- return stores;
7148
+ return selectedVariant || variants?.[0] || void 0;
7019
7149
  }
7020
-
7021
- // src/cache/request-cache.ts
7022
- var RequestCache = class extends Cache {
7023
- constructor(options) {
7024
- super({
7025
- ...options
7026
- });
7150
+ function getSelectedVariant(product, queryParams) {
7151
+ return getSelectedSwellVariant(
7152
+ product,
7153
+ queryParams
7154
+ );
7155
+ }
7156
+ function getSelectedOptionValues(product, queryParams) {
7157
+ const variant = getSelectedSwellVariant(product, queryParams);
7158
+ return getSelectedVariantOptionValues(product, variant, queryParams);
7159
+ }
7160
+ function getSelectedVariantOptionValues(product, variant, queryParams) {
7161
+ const { option_values = "" } = queryParams;
7162
+ const queryOptionValues = option_values;
7163
+ const optionValues = queryOptionValues.split(",");
7164
+ const selectedValues = variant ? [...variant.option_value_ids || []] : [];
7165
+ const values = [];
7166
+ for (const option of product.options || []) {
7167
+ if (option.active && option.values && option.values.length > 0 && option.input_type === "select") {
7168
+ let selectedByVariantId = "";
7169
+ let selectedByOptionId = "";
7170
+ for (const value of option.values) {
7171
+ if (selectedValues.includes(value.id)) {
7172
+ selectedByVariantId = value.id;
7173
+ break;
7174
+ }
7175
+ if (optionValues.includes(value.id)) {
7176
+ selectedByOptionId = value.id;
7177
+ }
7178
+ }
7179
+ values.push(
7180
+ selectedByVariantId || selectedByOptionId || option.values[0].id
7181
+ );
7182
+ }
7027
7183
  }
7028
- };
7184
+ return values;
7185
+ }
7029
7186
 
7030
- // src/cache/resource-cache.ts
7031
- var import_keyv2 = __require("keyv");
7032
- var ResourceCache = class extends Cache {
7033
- constructor(options) {
7034
- super({
7035
- stores: buildStores2(),
7036
- ...options
7037
- });
7187
+ // src/resources/variant.ts
7188
+ function transformSwellVariant(params, product, variant) {
7189
+ if (!product) {
7190
+ return product;
7038
7191
  }
7039
- };
7040
- function buildStores2() {
7041
- return [
7042
- new import_keyv2.Keyv({
7043
- // Disabling serialization allows for pure memo-ization of class instances
7044
- // at the tradeoff of no support for compression.
7045
- serialize: void 0,
7046
- deserialize: void 0
7047
- })
7048
- ];
7192
+ if (!variant) {
7193
+ return variant;
7194
+ }
7195
+ return {
7196
+ ...variant,
7197
+ // add swell properties there
7198
+ price: calculateAddOptionsVariantPrice(product, variant, params),
7199
+ selected_option_values: getSelectedVariantOptionValues(
7200
+ product,
7201
+ variant,
7202
+ params
7203
+ )
7204
+ };
7049
7205
  }
7050
7206
 
7051
- // src/cache/theme-cache.ts
7052
- var TTL = 90 * 24 * 60 * 60 * 1e3;
7053
- var ThemeCache = class extends Cache {
7054
- constructor(options) {
7055
- super({
7056
- ttl: TTL,
7057
- ...options
7058
- });
7207
+ // src/resources/product.ts
7208
+ function transformSwellProduct(params, product) {
7209
+ if (!product) {
7210
+ return product;
7211
+ }
7212
+ const newProduct = {
7213
+ ...product,
7214
+ // add swell properties there
7215
+ price: calculateAddOptionsPrice(product, params),
7216
+ selected_option_values: getSelectedOptionValues(product, params)
7217
+ };
7218
+ if (Array.isArray(newProduct.variants?.results)) {
7219
+ newProduct.variants = {
7220
+ ...newProduct.variants,
7221
+ results: newProduct.variants.results.map(
7222
+ (variant) => transformSwellVariant(params, product, variant)
7223
+ )
7224
+ };
7225
+ }
7226
+ return newProduct;
7227
+ }
7228
+ var SwellProduct = class extends SwellStorefrontRecord {
7229
+ _params;
7230
+ constructor(swell, id, query = {}, getter) {
7231
+ super(swell, "products", id, query, getter);
7232
+ this._params = swell.queryParams;
7233
+ return this._getProxy();
7234
+ }
7235
+ // add swell properties to the resolved object
7236
+ _transformResult(result) {
7237
+ const res = transformSwellProduct(
7238
+ this._params,
7239
+ result
7240
+ );
7241
+ return res;
7059
7242
  }
7060
7243
  };
7061
7244
 
@@ -7494,39 +7677,6 @@ ${formattedMessage}`;
7494
7677
  }
7495
7678
  };
7496
7679
 
7497
- // src/products.ts
7498
- function getProducts(swell, query) {
7499
- return new SwellStorefrontCollection(swell, "products", query);
7500
- }
7501
- function getProduct(swell, id, query) {
7502
- return new SwellStorefrontRecord(swell, "products", id, query);
7503
- }
7504
- function getProductsFiltered(swell, {
7505
- search,
7506
- filter,
7507
- sort
7508
- }) {
7509
- return new SwellStorefrontCollection(swell, "products", {
7510
- search,
7511
- filter,
7512
- sort
7513
- });
7514
- }
7515
-
7516
- // src/categories.ts
7517
- function getCategories(swell, query) {
7518
- return new SwellStorefrontCollection(swell, "categories", query);
7519
- }
7520
- function getCategory(swell, id, query) {
7521
- return new SwellStorefrontRecord(swell, "categories", id, query);
7522
- }
7523
- async function getCategoryWithProducts(swell, id, query) {
7524
- const category = getCategory(swell, id, query);
7525
- const categoryId = await category.id;
7526
- category.products = getProducts(swell, { category: categoryId });
7527
- return category;
7528
- }
7529
-
7530
7680
  // src/content.ts
7531
7681
  function getContentModel(swell, name) {
7532
7682
  return swell.getCachedResource(
@@ -13637,6 +13787,9 @@ ${formattedMessage}`;
13637
13787
  "moderated?": false
13638
13788
  });
13639
13789
  }
13790
+ function isLikeShopifyArticle(value) {
13791
+ return typeof value === "object" && value !== null && Object.hasOwn(value, "title") && Object.hasOwn(value, "content") && Object.hasOwn(value, "comments") && Object.hasOwn(value, "moderated?") && Object.hasOwn(value, "published_at") && Object.hasOwn(value, "excerpt_or_content");
13792
+ }
13640
13793
 
13641
13794
  // src/compatibility/shopify-objects/blog.ts
13642
13795
  function ShopifyBlog(instance, blogCategory) {
@@ -13716,11 +13869,15 @@ ${formattedMessage}`;
13716
13869
  if (variant instanceof ShopifyResource) {
13717
13870
  return variant.clone();
13718
13871
  }
13872
+ let swellVariant = {};
13719
13873
  if (variant instanceof StorefrontResource) {
13720
13874
  variant = cloneStorefrontResource(variant);
13875
+ } else {
13876
+ swellVariant = { ...variant };
13721
13877
  }
13722
13878
  const product = productIn || variant.product || {};
13723
13879
  return new ShopifyResource({
13880
+ ...swellVariant,
13724
13881
  available: deferWith(
13725
13882
  variant,
13726
13883
  (variant2) => Boolean(variant2.stock_status === "in_stock" || !variant2.stock_status)
@@ -13766,25 +13923,19 @@ ${formattedMessage}`;
13766
13923
  metafields: {},
13767
13924
  next_incoming_date: void 0,
13768
13925
  options: getOptions(product, variant),
13769
- // @ts-expect-error: move this to swell product class
13770
- selected_option_values: deferWith(
13771
- [product, variant],
13772
- (product2, variant2) => getSelectedVariantOptionValues(
13773
- product2,
13774
- variant2,
13775
- instance.swell.queryParams
13776
- )
13777
- ),
13778
13926
  option1: getOptionByIndex(product, variant, 0),
13779
13927
  // Deprecated by Shopify
13780
13928
  option2: getOptionByIndex(product, variant, 1),
13781
13929
  // Deprecated by Shopify
13782
13930
  option3: getOptionByIndex(product, variant, 2),
13783
13931
  // Deprecated by Shopify
13784
- price: deferWith(
13785
- [product, variant],
13786
- (product2, variant2) => getVariantPrice(product2, variant2, instance.swell.queryParams)
13787
- ),
13932
+ price: deferWith([product, variant], (product2, variant2) => {
13933
+ let price = product2.price;
13934
+ if (variant2.price !== null && variant2.price !== void 0) {
13935
+ price = variant2.price;
13936
+ }
13937
+ return price;
13938
+ }),
13788
13939
  product: deferWith(product, (product2) => {
13789
13940
  return ShopifyProduct(
13790
13941
  instance,
@@ -13871,30 +14022,6 @@ ${formattedMessage}`;
13871
14022
  }
13872
14023
  );
13873
14024
  }
13874
- function getVariantPrice(product, variant, queryParams) {
13875
- const { option_values: queryOptionValues = "" } = queryParams;
13876
- const optionValues = queryOptionValues.split(",");
13877
- const addPrice = product.options?.reduce((acc, option) => {
13878
- if (option.variant || // skip variant options
13879
- !option.active || !option.values || option.values.length <= 0) {
13880
- return acc;
13881
- }
13882
- if (option.input_type !== "select") {
13883
- return acc;
13884
- }
13885
- for (const value of option.values) {
13886
- if (optionValues.includes(value.id)) {
13887
- return acc + (value.price || 0);
13888
- }
13889
- }
13890
- return acc + (option.values[0].price || 0);
13891
- }, 0);
13892
- let price = product.price;
13893
- if (variant.price !== null && variant.price !== void 0) {
13894
- price = variant.price;
13895
- }
13896
- return price + (addPrice || 0);
13897
- }
13898
14025
 
13899
14026
  // src/compatibility/shopify-objects/product.ts
13900
14027
  function ShopifyProduct(instance, product, depth = 0) {
@@ -13934,7 +14061,7 @@ ${formattedMessage}`;
13934
14061
  // not used
13935
14062
  first_available_variant: deferWith(product, (product2) => {
13936
14063
  const variant = getSelectedVariant(product2, {});
13937
- return ShopifyVariant(instance, variant || product2, product2, depth + 1);
14064
+ return variant ? ShopifyVariant(instance, variant, product2, depth + 1) : void 0;
13938
14065
  }),
13939
14066
  "gift_card?": deferWith(product, (product2) => product2.type === "giftcard"),
13940
14067
  handle: defer(() => product.slug),
@@ -13970,12 +14097,6 @@ ${formattedMessage}`;
13970
14097
  }
13971
14098
  return product2.options.filter((option) => option.active && option.name).map((option) => option.name);
13972
14099
  }),
13973
- // all options values including non-variant
13974
- // @ts-expect-error: move this to swell product class
13975
- selected_option_values: deferWith(
13976
- product,
13977
- (product2) => getSelectedOptionValues(product2, instance.swell.queryParams)
13978
- ),
13979
14100
  options_by_name: deferWith(product, (product2) => {
13980
14101
  if (!Array.isArray(product2.options)) {
13981
14102
  return {};
@@ -14043,30 +14164,33 @@ ${formattedMessage}`;
14043
14164
  });
14044
14165
  }
14045
14166
  ),
14046
- price: deferWith(
14047
- product,
14048
- (product2) => calculateAddOptionsPrice(product2, instance.swell.queryParams)
14049
- ),
14050
- price_max: deferWith(
14051
- product,
14052
- (product2) => product2.variants?.results?.reduce(
14167
+ price: deferWith(product, (product2) => product2.price),
14168
+ price_max: deferWith(product, (product2) => {
14169
+ if (!Array.isArray(product2.variants?.results)) {
14170
+ return product2.price;
14171
+ }
14172
+ return product2.variants.results.reduce(
14053
14173
  (max, variant) => Math.max(max, variant.price),
14054
14174
  0
14055
- )
14056
- ),
14057
- price_min: deferWith(
14058
- product,
14059
- (product2) => product2.variants?.results?.reduce(
14175
+ );
14176
+ }),
14177
+ price_min: deferWith(product, (product2) => {
14178
+ if (!Array.isArray(product2.variants?.results)) {
14179
+ return product2.price;
14180
+ }
14181
+ return product2.variants.results.reduce(
14060
14182
  (min, variant) => Math.min(min, variant.price),
14061
14183
  Infinity
14062
- )
14063
- ),
14064
- price_varies: deferWith(
14065
- product,
14066
- (product2) => product2.variants?.results?.some(
14184
+ );
14185
+ }),
14186
+ price_varies: deferWith(product, (product2) => {
14187
+ if (!Array.isArray(product2.variants?.results)) {
14188
+ return false;
14189
+ }
14190
+ return product2.variants.results.some(
14067
14191
  (variant) => variant.price !== product2.price
14068
- )
14069
- ),
14192
+ );
14193
+ }),
14070
14194
  published_at: deferWith(
14071
14195
  product,
14072
14196
  (product2) => product2.date_updated || product2.date_created
@@ -14075,6 +14199,8 @@ ${formattedMessage}`;
14075
14199
  product,
14076
14200
  (product2) => product2.prices?.length > 0
14077
14201
  ),
14202
+ // ShopifyProduct does not have this property
14203
+ // @ts-expect-error property
14078
14204
  quantity_rule: deferWith(product, (product2) => {
14079
14205
  let inventory = product2.stock_level || 0;
14080
14206
  if (inventory < 0) {
@@ -14102,11 +14228,8 @@ ${formattedMessage}`;
14102
14228
  selected_or_first_available_variant: deferWith(
14103
14229
  product,
14104
14230
  (product2) => {
14105
- let variant = getSelectedVariant(product2, instance.swell.queryParams);
14106
- if (!variant) {
14107
- variant = product2;
14108
- }
14109
- return ShopifyVariant(instance, variant, product2, depth + 1);
14231
+ const variant = getSelectedVariant(product2, instance.swell.queryParams);
14232
+ return variant ? ShopifyVariant(instance, variant, product2, depth + 1) : void 0;
14110
14233
  }
14111
14234
  ),
14112
14235
  selected_selling_plan: void 0,
@@ -14127,82 +14250,17 @@ ${formattedMessage}`;
14127
14250
  ).reverse();
14128
14251
  return variants;
14129
14252
  }),
14253
+ variants_count: deferWith(product, (product2) => {
14254
+ return product2.variants?.count || 0;
14255
+ }),
14130
14256
  vendor: void 0
14131
14257
  });
14132
14258
  }
14133
14259
  function ShopifyProductOptionValue(values) {
14134
14260
  return new ShopifyResource(values, "name");
14135
14261
  }
14136
- function getSelectedVariant(product, queryParams) {
14137
- const { variant: queryVariant, option_values: queryOptionValues } = queryParams;
14138
- const variants = getAvailableVariants(product);
14139
- let selectedVariant = void 0;
14140
- if (queryVariant) {
14141
- selectedVariant = variants.find(
14142
- (variant) => variant.id === queryVariant
14143
- );
14144
- } else if (queryOptionValues) {
14145
- const optionValues = queryOptionValues.split(",");
14146
- selectedVariant = variants.find(
14147
- (variant) => variant.option_value_ids.every(
14148
- (optionValueId) => optionValues.includes(optionValueId)
14149
- )
14150
- );
14151
- }
14152
- return selectedVariant || variants?.[0] || void 0;
14153
- }
14154
- function getAvailableVariants(product) {
14155
- return (product.variants?.results?.slice()?.reverse() || []).filter(
14156
- (variant) => variant.stock_status === "in_stock" || !variant.stock_status
14157
- );
14158
- }
14159
- function calculateAddOptionsPrice(product, queryParams) {
14160
- const { option_values: queryOptionValues = "" } = queryParams;
14161
- const optionValues = queryOptionValues.split(",");
14162
- const addPrice = product.options?.reduce((acc, option) => {
14163
- if (!option.active || !option.values || option.values.length <= 0) {
14164
- return acc;
14165
- }
14166
- if (option.input_type !== "select") {
14167
- return acc;
14168
- }
14169
- for (const value of option.values) {
14170
- if (optionValues.includes(value.id)) {
14171
- return acc + (value.price || 0);
14172
- }
14173
- }
14174
- return acc + (option.values[0].price || 0);
14175
- }, 0);
14176
- return product.price + (addPrice || 0);
14177
- }
14178
- function getSelectedOptionValues(product, queryParams) {
14179
- const variant = getSelectedVariant(product, queryParams);
14180
- return getSelectedVariantOptionValues(product, variant, queryParams);
14181
- }
14182
- function getSelectedVariantOptionValues(product, variant, queryParams) {
14183
- const { option_values: queryOptionValues = "" } = queryParams;
14184
- const optionValues = queryOptionValues.split(",");
14185
- const selectedValues = variant ? [...variant.option_value_ids || []] : [];
14186
- const values = [];
14187
- for (const option of product.options || []) {
14188
- if (option.active && option.values?.length > 0 && option.input_type === "select") {
14189
- let selectedByVariantId = "";
14190
- let selectedByOptionId = "";
14191
- for (const value of option.values) {
14192
- if (selectedValues.includes(value.id)) {
14193
- selectedByVariantId = value.id;
14194
- break;
14195
- }
14196
- if (optionValues.includes(value.id)) {
14197
- selectedByOptionId = value.id;
14198
- }
14199
- }
14200
- values.push(
14201
- selectedByVariantId || selectedByOptionId || option.values[0].id
14202
- );
14203
- }
14204
- }
14205
- return values;
14262
+ function isLikeShopifyProduct(value) {
14263
+ return typeof value === "object" && value !== null && Object.hasOwn(value, "variants") && Object.hasOwn(value, "gift_card?") && Object.hasOwn(value, "price_varies") && Object.hasOwn(value, "has_only_default_variant");
14206
14264
  }
14207
14265
 
14208
14266
  // src/compatibility/shopify-objects/line_item.ts
@@ -17272,7 +17330,7 @@ ${injects.join("\n")}<\/script>`;
17272
17330
  };
17273
17331
  function bindTags(liquidSwell) {
17274
17332
  Object.entries(tags).forEach(
17275
- ([tag, bind61]) => liquidSwell.registerTag(tag, bind61(liquidSwell))
17333
+ ([tag, bind62]) => liquidSwell.registerTag(tag, bind62(liquidSwell))
17276
17334
  );
17277
17335
  }
17278
17336
 
@@ -18094,8 +18152,86 @@ ${injects.join("\n")}<\/script>`;
18094
18152
  };
18095
18153
  }
18096
18154
 
18097
- // src/liquid/filters/inline_editable.ts
18155
+ // src/liquid/filters/shopify/structured_data.ts
18098
18156
  function bind60(_liquidSwell) {
18157
+ return async function filterStructuredData(input) {
18158
+ let value = input;
18159
+ if (value instanceof StorefrontResource) {
18160
+ value = await value.resolve();
18161
+ }
18162
+ await resolveAllKeys(value);
18163
+ if (isObject2(value)) {
18164
+ if (isLikeShopifyProduct(value)) {
18165
+ return JSON.stringify(
18166
+ value.variants_count > 0 ? convertToSchemaOrgProductGroup(value) : convertToSchemaOrgProduct(
18167
+ value,
18168
+ value
18169
+ )
18170
+ );
18171
+ }
18172
+ if (isLikeShopifyArticle(value)) {
18173
+ return JSON.stringify(convertToSchemaOrgArticle(value));
18174
+ }
18175
+ }
18176
+ return value;
18177
+ };
18178
+ }
18179
+ function convertToSchemaOrgArticle(article) {
18180
+ const schemaOrgArticle = {
18181
+ "@context": "https://schema.org",
18182
+ "@type": "Article",
18183
+ "@id": article.url,
18184
+ url: article.url,
18185
+ name: article.title,
18186
+ author: article.author,
18187
+ image: article.image?.src.url || void 0,
18188
+ abstract: article.excerpt,
18189
+ keywords: article.tags,
18190
+ articleBody: article.content,
18191
+ dateCreated: article.created_at,
18192
+ dateModified: article.updated_at,
18193
+ datePublished: article.published_at
18194
+ };
18195
+ return schemaOrgArticle;
18196
+ }
18197
+ function convertToSchemaOrgProduct(variant, product) {
18198
+ const schemaOrgProduct = {
18199
+ "@context": "https://schema.org",
18200
+ "@type": "Product",
18201
+ "@id": variant.url,
18202
+ url: variant.url,
18203
+ sku: variant.sku,
18204
+ name: variant.title,
18205
+ image: variant.featured_image?.src.url || void 0,
18206
+ keywords: product.tags,
18207
+ description: product.description,
18208
+ offers: {
18209
+ "@type": "Offer",
18210
+ availability: variant.available ? "https://schema.org/InStock" : "https://schema.org/OutOfStock",
18211
+ price: variant.price,
18212
+ priceCurrency: "USD"
18213
+ }
18214
+ };
18215
+ return schemaOrgProduct;
18216
+ }
18217
+ function convertToSchemaOrgProductGroup(product) {
18218
+ const schemaOrgProductGroup = {
18219
+ "@context": "https://schema.org",
18220
+ "@type": "ProductGroup",
18221
+ productGroupID: String(product.id),
18222
+ url: product.url,
18223
+ name: product.title,
18224
+ description: product.description,
18225
+ variesBy: product.options,
18226
+ hasVariant: product.variants.map(
18227
+ (variant) => convertToSchemaOrgProduct(variant, product)
18228
+ )
18229
+ };
18230
+ return schemaOrgProductGroup;
18231
+ }
18232
+
18233
+ // src/liquid/filters/inline_editable.ts
18234
+ function bind61(_liquidSwell) {
18099
18235
  return (value, key) => {
18100
18236
  if (typeof value === "object" && "value" in value) {
18101
18237
  value = value.value;
@@ -18154,8 +18290,9 @@ ${injects.join("\n")}<\/script>`;
18154
18290
  payment_terms: bind57,
18155
18291
  placeholder_svg_tag: bind58,
18156
18292
  shopify_asset_url: bind59,
18293
+ structured_data: bind60,
18157
18294
  // Swell only
18158
- inline_editable: bind60
18295
+ inline_editable: bind61
18159
18296
  };
18160
18297
  function bindFilters(liquidSwell) {
18161
18298
  for (const [tag, handler] of Object.entries(filters)) {
@@ -18169,8 +18306,8 @@ ${injects.join("\n")}<\/script>`;
18169
18306
  }
18170
18307
  }
18171
18308
  }
18172
- function bindWithResolvedProps(liquidSwell, bind61, resolve = []) {
18173
- const handler = bind61(liquidSwell);
18309
+ function bindWithResolvedProps(liquidSwell, bind62, resolve = []) {
18310
+ const handler = bind62(liquidSwell);
18174
18311
  if (!Array.isArray(resolve)) {
18175
18312
  return handler;
18176
18313
  }