@swell/apps-sdk 1.0.126 → 1.0.128

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.cjs CHANGED
@@ -193,10 +193,151 @@ var import_lodash_es3 = require("lodash-es");
193
193
  var import_json52 = __toESM(require("json5"), 1);
194
194
 
195
195
  // src/resources.ts
196
- var import_lodash_es = require("lodash-es");
196
+ var import_lodash_es2 = require("lodash-es");
197
197
 
198
198
  // src/liquid/utils.ts
199
199
  var import_liquidjs = require("liquidjs");
200
+
201
+ // src/compatibility/shopify-objects/resource.ts
202
+ var import_lodash_es = require("lodash-es");
203
+ var ShopifyResource = class _ShopifyResource {
204
+ props;
205
+ stringProp;
206
+ linkProps;
207
+ constructor(props, stringProp, linkProps) {
208
+ this.props = props;
209
+ this.stringProp = stringProp;
210
+ this.linkProps = linkProps;
211
+ return new Proxy(props, {
212
+ get(target, prop, receiver) {
213
+ const instance = target;
214
+ switch (prop) {
215
+ case "toJSON":
216
+ return props;
217
+ case "clone":
218
+ return () => {
219
+ return new _ShopifyResource(
220
+ (0, import_lodash_es.cloneDeep)(props),
221
+ (0, import_lodash_es.cloneDeep)(stringProp),
222
+ (0, import_lodash_es.cloneDeep)(linkProps)
223
+ );
224
+ };
225
+ case "toString": {
226
+ if (stringProp) {
227
+ return () => {
228
+ return props[stringProp];
229
+ };
230
+ }
231
+ break;
232
+ }
233
+ case Symbol.toPrimitive: {
234
+ return () => {
235
+ let prop2 = stringProp;
236
+ if (typeof prop2 === "number") {
237
+ prop2 = prop2.toString();
238
+ }
239
+ return this.get?.(instance, prop2 || "handle", receiver);
240
+ };
241
+ }
242
+ default:
243
+ break;
244
+ }
245
+ const value = instance[prop];
246
+ if (value instanceof DeferredShopifyResource) {
247
+ const promise = value.resolve().then(
248
+ (value2) => {
249
+ instance[prop] = value2;
250
+ return value2;
251
+ },
252
+ (err) => {
253
+ console.log(err);
254
+ instance[prop] = null;
255
+ return null;
256
+ }
257
+ );
258
+ instance[prop] = promise;
259
+ return promise;
260
+ }
261
+ return value;
262
+ },
263
+ getPrototypeOf() {
264
+ return _ShopifyResource.prototype;
265
+ }
266
+ });
267
+ }
268
+ valueOf() {
269
+ if (this.stringProp) {
270
+ return this.props[this.stringProp];
271
+ }
272
+ return this;
273
+ }
274
+ // For typescript
275
+ clone() {
276
+ return new _ShopifyResource(this.props);
277
+ }
278
+ };
279
+ var DeferredShopifyResource = class {
280
+ handler;
281
+ result;
282
+ constructor(handler) {
283
+ this.result = void 0;
284
+ this.handler = handler;
285
+ }
286
+ async resolve() {
287
+ if (this.handler !== import_lodash_es.noop) {
288
+ const handler = this.handler;
289
+ this.handler = import_lodash_es.noop;
290
+ this.result = Promise.resolve().then(handler).then((value) => {
291
+ this.result = value;
292
+ return value;
293
+ });
294
+ }
295
+ return this.result;
296
+ }
297
+ };
298
+ function defer(handler) {
299
+ return new DeferredShopifyResource(handler);
300
+ }
301
+ function isResolvable(asyncProp) {
302
+ return isObject(asyncProp) && (isLikePromise(asyncProp) || typeof asyncProp._resolve === "function");
303
+ }
304
+ function isStorefrontResource(resource) {
305
+ return isObject(resource) && typeof resource._resolve === "function";
306
+ }
307
+ async function resolveAsyncProp(asyncProp) {
308
+ if (Array.isArray(asyncProp)) {
309
+ return Promise.all(
310
+ asyncProp.map(
311
+ (prop) => isStorefrontResource(prop) ? prop._resolve() : prop
312
+ )
313
+ );
314
+ }
315
+ if (isStorefrontResource(asyncProp)) {
316
+ return asyncProp._resolve();
317
+ }
318
+ return asyncProp;
319
+ }
320
+ function handleDeferredProp(asyncProp, handler) {
321
+ return resolveAsyncProp(asyncProp).then((value) => {
322
+ if (Array.isArray(asyncProp) && Array.isArray(value)) {
323
+ return handler(...value.map((prop) => prop || {}));
324
+ }
325
+ if (isResolvable(value)) {
326
+ return handleDeferredProp(value, handler);
327
+ }
328
+ return handler(value || {});
329
+ }).catch((err) => {
330
+ console.log(err);
331
+ return null;
332
+ });
333
+ }
334
+ function deferWith(asyncProp, handler) {
335
+ return new DeferredShopifyResource(
336
+ () => handleDeferredProp(asyncProp, handler)
337
+ );
338
+ }
339
+
340
+ // src/liquid/utils.ts
200
341
  var ForloopDrop = class extends import_liquidjs.Drop {
201
342
  i;
202
343
  length;
@@ -363,18 +504,24 @@ async function jsonStringifyAsync(input, space = 0) {
363
504
  async function resolveAllKeys(value, references = /* @__PURE__ */ new WeakSet()) {
364
505
  await forEachKeyDeep(value, async (key, value2) => {
365
506
  if (!isObject(value2)) {
366
- return;
507
+ return true;
367
508
  }
368
509
  const val = value2[key];
369
510
  if (isLikePromise(val)) {
370
511
  value2[key] = await val;
371
512
  await resolveAllKeys(value2[key], references);
372
513
  } else if (isObject(val)) {
514
+ if (val instanceof DeferredShopifyResource) {
515
+ value2[key] = await val.resolve();
516
+ await resolveAllKeys(value2[key], references);
517
+ return true;
518
+ }
373
519
  if (references.has(val)) {
374
520
  return false;
375
521
  }
376
522
  references.add(val);
377
523
  }
524
+ return true;
378
525
  });
379
526
  }
380
527
  async function forEachKeyDeep(obj, fn) {
@@ -700,7 +847,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
700
847
  this._getter
701
848
  );
702
849
  if (this._isResultResolved()) {
703
- cloned._result = (0, import_lodash_es.cloneDeep)(this._result);
850
+ cloned._result = (0, import_lodash_es2.cloneDeep)(this._result);
704
851
  }
705
852
  if (this._compatibilityProps) {
706
853
  cloned.setCompatibilityProps(this._compatibilityProps);
@@ -729,7 +876,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
729
876
  }
730
877
  });
731
878
  if (this._isResultResolved()) {
732
- const result = (0, import_lodash_es.cloneDeep)(this._result);
879
+ const result = (0, import_lodash_es2.cloneDeep)(this._result);
733
880
  if (result) {
734
881
  const compatibilityProps = compatibilityGetter(result);
735
882
  Object.assign(cloned, result);
@@ -893,145 +1040,6 @@ var SwellStorefrontPagination = class {
893
1040
  }
894
1041
  };
895
1042
 
896
- // src/compatibility/shopify-objects/resource.ts
897
- var import_lodash_es2 = require("lodash-es");
898
- var ShopifyResource = class _ShopifyResource {
899
- props;
900
- stringProp;
901
- linkProps;
902
- constructor(props, stringProp, linkProps) {
903
- this.props = props;
904
- this.stringProp = stringProp;
905
- this.linkProps = linkProps;
906
- return new Proxy(props, {
907
- get(target, prop, receiver) {
908
- const instance = target;
909
- switch (prop) {
910
- case "toJSON":
911
- return props;
912
- case "clone":
913
- return () => {
914
- return new _ShopifyResource(
915
- (0, import_lodash_es2.cloneDeep)(props),
916
- (0, import_lodash_es2.cloneDeep)(stringProp),
917
- (0, import_lodash_es2.cloneDeep)(linkProps)
918
- );
919
- };
920
- case "toString": {
921
- if (stringProp) {
922
- return () => {
923
- return props[stringProp];
924
- };
925
- }
926
- break;
927
- }
928
- case Symbol.toPrimitive: {
929
- return () => {
930
- let prop2 = stringProp;
931
- if (typeof prop2 === "number") {
932
- prop2 = prop2.toString();
933
- }
934
- return this.get?.(instance, prop2 || "handle", receiver);
935
- };
936
- }
937
- default:
938
- break;
939
- }
940
- const value = instance[prop];
941
- if (value instanceof DeferredShopifyResource) {
942
- const promise = value.resolve().then(
943
- (value2) => {
944
- instance[prop] = value2;
945
- return value2;
946
- },
947
- (err) => {
948
- console.log(err);
949
- instance[prop] = null;
950
- return null;
951
- }
952
- );
953
- instance[prop] = promise;
954
- return promise;
955
- }
956
- return value;
957
- },
958
- getPrototypeOf() {
959
- return _ShopifyResource.prototype;
960
- }
961
- });
962
- }
963
- valueOf() {
964
- if (this.stringProp) {
965
- return this.props[this.stringProp];
966
- }
967
- return this;
968
- }
969
- // For typescript
970
- clone() {
971
- return new _ShopifyResource(this.props);
972
- }
973
- };
974
- var DeferredShopifyResource = class {
975
- handler;
976
- result;
977
- constructor(handler) {
978
- this.result = void 0;
979
- this.handler = handler;
980
- }
981
- async resolve() {
982
- if (this.handler !== import_lodash_es2.noop) {
983
- const handler = this.handler;
984
- this.handler = import_lodash_es2.noop;
985
- this.result = Promise.resolve().then(handler).then((value) => {
986
- this.result = value;
987
- return value;
988
- });
989
- }
990
- return this.result;
991
- }
992
- };
993
- function defer(handler) {
994
- return new DeferredShopifyResource(handler);
995
- }
996
- function isResolvable(asyncProp) {
997
- return isObject(asyncProp) && (isLikePromise(asyncProp) || typeof asyncProp._resolve === "function");
998
- }
999
- function isStorefrontResource(resource) {
1000
- return isObject(resource) && typeof resource._resolve === "function";
1001
- }
1002
- async function resolveAsyncProp(asyncProp) {
1003
- if (Array.isArray(asyncProp)) {
1004
- return Promise.all(
1005
- asyncProp.map(
1006
- (prop) => isStorefrontResource(prop) ? prop._resolve() : prop
1007
- )
1008
- );
1009
- }
1010
- if (isStorefrontResource(asyncProp)) {
1011
- return asyncProp._resolve();
1012
- }
1013
- return asyncProp;
1014
- }
1015
- function handleDeferredProp(asyncProp, handler) {
1016
- return resolveAsyncProp(asyncProp).then((value) => {
1017
- if (Array.isArray(asyncProp) && Array.isArray(value)) {
1018
- return handler(...value.map((prop) => prop || {}));
1019
- }
1020
- if (isResolvable(value)) {
1021
- return handleDeferredProp(value, handler);
1022
- }
1023
- return handler(value || {});
1024
- }).catch((err) => {
1025
- console.log(err);
1026
- return null;
1027
- });
1028
- }
1029
- function deferWith(asyncProp, handler) {
1030
- return new DeferredShopifyResource(
1031
- () => handleDeferredProp(asyncProp, handler)
1032
- );
1033
- }
1034
-
1035
1043
  // src/constants.ts
1036
1044
  var FILE_DATA_INCLUDE_QUERY = {
1037
1045
  url: "/:themes:configs/{id}/file/data",
@@ -13741,6 +13749,9 @@ function ShopifyArticle(instance, blog, blogCategory) {
13741
13749
  "moderated?": false
13742
13750
  });
13743
13751
  }
13752
+ function isLikeShopifyArticle(value) {
13753
+ 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");
13754
+ }
13744
13755
 
13745
13756
  // src/compatibility/shopify-objects/blog.ts
13746
13757
  function ShopifyBlog(instance, blogCategory) {
@@ -14038,7 +14049,7 @@ function ShopifyProduct(instance, product, depth = 0) {
14038
14049
  // not used
14039
14050
  first_available_variant: deferWith(product, (product2) => {
14040
14051
  const variant = getSelectedVariant(product2, {});
14041
- return ShopifyVariant(instance, variant || product2, product2, depth + 1);
14052
+ return variant ? ShopifyVariant(instance, variant, product2, depth + 1) : void 0;
14042
14053
  }),
14043
14054
  "gift_card?": deferWith(product, (product2) => product2.type === "giftcard"),
14044
14055
  handle: defer(() => product.slug),
@@ -14151,26 +14162,32 @@ function ShopifyProduct(instance, product, depth = 0) {
14151
14162
  product,
14152
14163
  (product2) => calculateAddOptionsPrice(product2, instance.swell.queryParams)
14153
14164
  ),
14154
- price_max: deferWith(
14155
- product,
14156
- (product2) => product2.variants?.results?.reduce(
14165
+ price_max: deferWith(product, (product2) => {
14166
+ if (!Array.isArray(product2.variants?.results)) {
14167
+ return product2.price;
14168
+ }
14169
+ return product2.variants.results.reduce(
14157
14170
  (max, variant) => Math.max(max, variant.price),
14158
14171
  0
14159
- )
14160
- ),
14161
- price_min: deferWith(
14162
- product,
14163
- (product2) => product2.variants?.results?.reduce(
14172
+ );
14173
+ }),
14174
+ price_min: deferWith(product, (product2) => {
14175
+ if (!Array.isArray(product2.variants?.results)) {
14176
+ return product2.price;
14177
+ }
14178
+ return product2.variants.results.reduce(
14164
14179
  (min, variant) => Math.min(min, variant.price),
14165
14180
  Infinity
14166
- )
14167
- ),
14168
- price_varies: deferWith(
14169
- product,
14170
- (product2) => product2.variants?.results?.some(
14181
+ );
14182
+ }),
14183
+ price_varies: deferWith(product, (product2) => {
14184
+ if (!Array.isArray(product2.variants?.results)) {
14185
+ return false;
14186
+ }
14187
+ return product2.variants.results.some(
14171
14188
  (variant) => variant.price !== product2.price
14172
- )
14173
- ),
14189
+ );
14190
+ }),
14174
14191
  published_at: deferWith(
14175
14192
  product,
14176
14193
  (product2) => product2.date_updated || product2.date_created
@@ -14206,11 +14223,8 @@ function ShopifyProduct(instance, product, depth = 0) {
14206
14223
  selected_or_first_available_variant: deferWith(
14207
14224
  product,
14208
14225
  (product2) => {
14209
- let variant = getSelectedVariant(product2, instance.swell.queryParams);
14210
- if (!variant) {
14211
- variant = product2;
14212
- }
14213
- return ShopifyVariant(instance, variant, product2, depth + 1);
14226
+ const variant = getSelectedVariant(product2, instance.swell.queryParams);
14227
+ return variant ? ShopifyVariant(instance, variant, product2, depth + 1) : void 0;
14214
14228
  }
14215
14229
  ),
14216
14230
  selected_selling_plan: void 0,
@@ -14231,6 +14245,9 @@ function ShopifyProduct(instance, product, depth = 0) {
14231
14245
  ).reverse();
14232
14246
  return variants;
14233
14247
  }),
14248
+ variants_count: deferWith(product, (product2) => {
14249
+ return product2.variants?.count || 0;
14250
+ }),
14234
14251
  vendor: void 0
14235
14252
  });
14236
14253
  }
@@ -14308,6 +14325,9 @@ function getSelectedVariantOptionValues(product, variant, queryParams) {
14308
14325
  }
14309
14326
  return values;
14310
14327
  }
14328
+ function isLikeShopifyProduct(value) {
14329
+ 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");
14330
+ }
14311
14331
 
14312
14332
  // src/compatibility/shopify-objects/line_item.ts
14313
14333
  function ShopifyLineItem(instance, item, cart, options = {}) {
@@ -17376,7 +17396,7 @@ var tags = {
17376
17396
  };
17377
17397
  function bindTags(liquidSwell) {
17378
17398
  Object.entries(tags).forEach(
17379
- ([tag, bind61]) => liquidSwell.registerTag(tag, bind61(liquidSwell))
17399
+ ([tag, bind62]) => liquidSwell.registerTag(tag, bind62(liquidSwell))
17380
17400
  );
17381
17401
  }
17382
17402
 
@@ -18198,8 +18218,86 @@ function bind59(_liquidSwell) {
18198
18218
  };
18199
18219
  }
18200
18220
 
18201
- // src/liquid/filters/inline_editable.ts
18221
+ // src/liquid/filters/shopify/structured_data.ts
18202
18222
  function bind60(_liquidSwell) {
18223
+ return async function filterStructuredData(input) {
18224
+ let value = input;
18225
+ if (value instanceof StorefrontResource) {
18226
+ value = await value.resolve();
18227
+ }
18228
+ await resolveAllKeys(value);
18229
+ if (isObject2(value)) {
18230
+ if (isLikeShopifyProduct(value)) {
18231
+ return JSON.stringify(
18232
+ value.variants_count > 0 ? convertToSchemaOrgProductGroup(value) : convertToSchemaOrgProduct(
18233
+ value,
18234
+ value
18235
+ )
18236
+ );
18237
+ }
18238
+ if (isLikeShopifyArticle(value)) {
18239
+ return JSON.stringify(convertToSchemaOrgArticle(value));
18240
+ }
18241
+ }
18242
+ return value;
18243
+ };
18244
+ }
18245
+ function convertToSchemaOrgArticle(article) {
18246
+ const schemaOrgArticle = {
18247
+ "@context": "https://schema.org",
18248
+ "@type": "Article",
18249
+ "@id": article.url,
18250
+ url: article.url,
18251
+ name: article.title,
18252
+ author: article.author,
18253
+ image: article.image?.src.url || void 0,
18254
+ abstract: article.excerpt,
18255
+ keywords: article.tags,
18256
+ articleBody: article.content,
18257
+ dateCreated: article.created_at,
18258
+ dateModified: article.updated_at,
18259
+ datePublished: article.published_at
18260
+ };
18261
+ return schemaOrgArticle;
18262
+ }
18263
+ function convertToSchemaOrgProduct(variant, product) {
18264
+ const schemaOrgProduct = {
18265
+ "@context": "https://schema.org",
18266
+ "@type": "Product",
18267
+ "@id": variant.url,
18268
+ url: variant.url,
18269
+ sku: variant.sku,
18270
+ name: variant.title,
18271
+ image: variant.featured_image?.src.url || void 0,
18272
+ keywords: product.tags,
18273
+ description: product.description,
18274
+ offers: {
18275
+ "@type": "Offer",
18276
+ availability: variant.available ? "https://schema.org/InStock" : "https://schema.org/OutOfStock",
18277
+ price: variant.price,
18278
+ priceCurrency: "USD"
18279
+ }
18280
+ };
18281
+ return schemaOrgProduct;
18282
+ }
18283
+ function convertToSchemaOrgProductGroup(product) {
18284
+ const schemaOrgProductGroup = {
18285
+ "@context": "https://schema.org",
18286
+ "@type": "ProductGroup",
18287
+ productGroupID: String(product.id),
18288
+ url: product.url,
18289
+ name: product.title,
18290
+ description: product.description,
18291
+ variesBy: product.options,
18292
+ hasVariant: product.variants.map(
18293
+ (variant) => convertToSchemaOrgProduct(variant, product)
18294
+ )
18295
+ };
18296
+ return schemaOrgProductGroup;
18297
+ }
18298
+
18299
+ // src/liquid/filters/inline_editable.ts
18300
+ function bind61(_liquidSwell) {
18203
18301
  return (value, key) => {
18204
18302
  if (typeof value === "object" && "value" in value) {
18205
18303
  value = value.value;
@@ -18258,8 +18356,9 @@ var filters = {
18258
18356
  payment_terms: bind57,
18259
18357
  placeholder_svg_tag: bind58,
18260
18358
  shopify_asset_url: bind59,
18359
+ structured_data: bind60,
18261
18360
  // Swell only
18262
- inline_editable: bind60
18361
+ inline_editable: bind61
18263
18362
  };
18264
18363
  function bindFilters(liquidSwell) {
18265
18364
  for (const [tag, handler] of Object.entries(filters)) {
@@ -18273,8 +18372,8 @@ function bindFilters(liquidSwell) {
18273
18372
  }
18274
18373
  }
18275
18374
  }
18276
- function bindWithResolvedProps(liquidSwell, bind61, resolve = []) {
18277
- const handler = bind61(liquidSwell);
18375
+ function bindWithResolvedProps(liquidSwell, bind62, resolve = []) {
18376
+ const handler = bind62(liquidSwell);
18278
18377
  if (!Array.isArray(resolve)) {
18279
18378
  return handler;
18280
18379
  }
@@ -19665,14 +19764,36 @@ var SwellTheme3 = class {
19665
19764
  "layouts",
19666
19765
  name
19667
19766
  );
19668
- if (templateConfig) {
19669
- const content = await this.renderThemeTemplate(
19670
- templateConfig.file_path,
19671
- data
19672
- );
19673
- return typeof content === "string" ? content : `<!-- invalid layout: ${name}--> {{ content_for_layout }}`;
19767
+ if (!templateConfig) {
19768
+ throw new Error(`Layout template not found: ${name}`);
19769
+ }
19770
+ let content = await this.renderThemeTemplate(
19771
+ templateConfig.file_path,
19772
+ data
19773
+ );
19774
+ if (typeof content !== "string") {
19775
+ return `<!-- invalid layout: ${name}--> {{ content_for_layout }}`;
19776
+ }
19777
+ if (!this.globals.request.is_editor) {
19778
+ let customCss = this.globals.settings.custom_css || "";
19779
+ if (Array.isArray(customCss)) {
19780
+ customCss = customCss.join("\n").trim();
19781
+ }
19782
+ if (customCss) {
19783
+ let pos = -1;
19784
+ let match = null;
19785
+ const regex = /<\/body\s*?>/gi;
19786
+ while ((match = regex.exec(content)) !== null) {
19787
+ pos = match.index;
19788
+ }
19789
+ if (pos !== -1) {
19790
+ content = `${content.slice(0, pos)}
19791
+ <style>${customCss}</style>
19792
+ ${content.slice(pos)}`;
19793
+ }
19794
+ }
19674
19795
  }
19675
- throw new Error(`Layout template not found: ${name}`);
19796
+ return content;
19676
19797
  }
19677
19798
  async renderPageTemplate(name, data, altTemplateId) {
19678
19799
  let templateConfig = null;