@swell/apps-sdk 1.0.141 → 1.0.142

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
@@ -90,6 +90,7 @@ __export(index_exports, {
90
90
  adaptShopifyMenuData: () => adaptShopifyMenuData,
91
91
  arrayToObject: () => arrayToObject,
92
92
  cloneStorefrontResource: () => cloneStorefrontResource,
93
+ configureSdkLogger: () => configureSdkLogger,
93
94
  deferMenuItemUrlAndResource: () => deferMenuItemUrlAndResource,
94
95
  dehydrateSwellRefsInStorefrontResources: () => dehydrateSwellRefsInStorefrontResources,
95
96
  extractSettingsFromForm: () => extractSettingsFromForm,
@@ -213,6 +214,97 @@ var import_json52 = __toESM(require("json5"), 1);
213
214
  // src/resources.ts
214
215
  var import_lodash_es2 = require("lodash-es");
215
216
 
217
+ // src/utils/logger.ts
218
+ var logLevels = {
219
+ error: 0,
220
+ warn: 1,
221
+ info: 2,
222
+ debug: 3
223
+ };
224
+ var currentLogLevel = "warn";
225
+ var currentTimestampFormat = "off";
226
+ var isStructured = false;
227
+ function configureSdkLogger(config = {}) {
228
+ if (config.level && logLevels[config.level] !== void 0) {
229
+ currentLogLevel = config.level;
230
+ }
231
+ if (config.timestamp) {
232
+ currentTimestampFormat = config.timestamp;
233
+ }
234
+ if (typeof config.structured === "boolean") {
235
+ isStructured = config.structured;
236
+ }
237
+ }
238
+ function getTimestamp() {
239
+ if (currentTimestampFormat === "iso") {
240
+ return (/* @__PURE__ */ new Date()).toISOString();
241
+ }
242
+ if (currentTimestampFormat === "unix") {
243
+ return Date.now();
244
+ }
245
+ return void 0;
246
+ }
247
+ function formatArgs(args) {
248
+ const timestamp = getTimestamp();
249
+ if (!isStructured) {
250
+ return timestamp !== void 0 ? [...args, `(${timestamp})`] : args;
251
+ }
252
+ let message = "";
253
+ let context = {};
254
+ const messageParts = [];
255
+ for (const arg of args) {
256
+ if (arg instanceof Error) {
257
+ context.error = {
258
+ name: arg.name,
259
+ message: arg.message,
260
+ stack: arg.stack
261
+ };
262
+ } else if (typeof arg === "object" && arg !== null && !Array.isArray(arg) && Object.getPrototypeOf(arg) === Object.prototype) {
263
+ Object.assign(context, arg);
264
+ } else {
265
+ messageParts.push(arg);
266
+ }
267
+ }
268
+ message = messageParts.map((part) => typeof part === "object" ? JSON.stringify(part) : part).join(" ");
269
+ const finalLogObject = {
270
+ message,
271
+ ...context,
272
+ ...timestamp && { timestamp }
273
+ };
274
+ return [finalLogObject];
275
+ }
276
+ var logger = {
277
+ error: (...args) => {
278
+ console.error(...formatArgs(args));
279
+ },
280
+ warn: (...args) => {
281
+ if (logLevels[currentLogLevel] >= logLevels.warn) {
282
+ console.warn(...formatArgs(args));
283
+ }
284
+ },
285
+ info: (...args) => {
286
+ if (logLevels[currentLogLevel] >= logLevels.info) {
287
+ console.info(...formatArgs(args));
288
+ }
289
+ },
290
+ debug: (...args) => {
291
+ if (logLevels[currentLogLevel] >= logLevels.debug) {
292
+ console.debug(...formatArgs(args));
293
+ }
294
+ }
295
+ };
296
+ function createTraceId(data) {
297
+ if (data === void 0) {
298
+ return Math.random().toString(36).substring(2, 10);
299
+ }
300
+ let hash = 5381;
301
+ for (let i = 0; i < data.length; i++) {
302
+ const char = data.charCodeAt(i);
303
+ hash = (hash << 5) + hash + char;
304
+ }
305
+ return (hash >>> 0).toString(16);
306
+ }
307
+
216
308
  // src/liquid/utils.ts
217
309
  var import_liquidjs = require("liquidjs");
218
310
 
@@ -608,7 +700,7 @@ var StorefrontResource = class {
608
700
  return instance[prop];
609
701
  }
610
702
  instance._result = instance._get().catch((err) => {
611
- console.log(err);
703
+ logger.error(err);
612
704
  return instance._getCollectionResultOrProp(instance, prop);
613
705
  });
614
706
  }
@@ -616,7 +708,7 @@ var StorefrontResource = class {
616
708
  return instance._result.then(() => {
617
709
  return instance._getCollectionResultOrProp(instance, prop);
618
710
  }).catch((err) => {
619
- console.log(err);
711
+ logger.error(err);
620
712
  return null;
621
713
  });
622
714
  }
@@ -675,7 +767,7 @@ var StorefrontResource = class {
675
767
  }
676
768
  return result;
677
769
  }).catch((err) => {
678
- console.log(err);
770
+ logger.error(err);
679
771
  return null;
680
772
  });
681
773
  }
@@ -853,7 +945,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
853
945
  }
854
946
  return result;
855
947
  }).catch((err) => {
856
- console.log(err);
948
+ logger.error(err);
857
949
  return null;
858
950
  });
859
951
  }
@@ -967,7 +1059,7 @@ var SwellStorefrontRecord = class extends SwellStorefrontResource {
967
1059
  }
968
1060
  return result;
969
1061
  }).catch((err) => {
970
- console.log(err);
1062
+ logger.error(err);
971
1063
  return null;
972
1064
  });
973
1065
  }
@@ -1001,15 +1093,25 @@ var SwellStorefrontSingleton = class extends SwellStorefrontResource {
1001
1093
  }
1002
1094
  async _get() {
1003
1095
  if (this._getter) {
1096
+ const trace = createTraceId();
1097
+ logger.debug("[SDK] Resource fetch start", {
1098
+ resource: this.constructor.name,
1099
+ hash: this._getterHash,
1100
+ trace
1101
+ });
1004
1102
  const getter = this._getter.bind(this);
1005
1103
  this._result = Promise.resolve().then(getter).then((result) => {
1104
+ logger.debug("[SDK] Resource fetch end", {
1105
+ hash: this._getterHash,
1106
+ trace
1107
+ });
1006
1108
  this._result = result;
1007
1109
  if (result) {
1008
1110
  Object.assign(this, result);
1009
1111
  }
1010
1112
  return result;
1011
1113
  }).catch((err) => {
1012
- console.log(err);
1114
+ logger.error(err, { trace });
1013
1115
  return null;
1014
1116
  });
1015
1117
  }
@@ -7093,6 +7195,7 @@ var DEFAULT_OPTIONS = Object.freeze({
7093
7195
  ttl: DEFAULT_TTL
7094
7196
  });
7095
7197
  var NULL_VALUE = "__NULL__";
7198
+ var SWR_PROMISE_MAP = /* @__PURE__ */ new Map();
7096
7199
  var Cache = class {
7097
7200
  client;
7098
7201
  workerCtx;
@@ -7114,19 +7217,31 @@ var Cache = class {
7114
7217
  * This will always return the cached value immediately if exists
7115
7218
  */
7116
7219
  async fetchSWR(key, fetchFn, ttl = DEFAULT_SWR_TTL) {
7220
+ const trace = createTraceId();
7221
+ logger.debug("[SDK] Cache fetch start", { key, trace });
7117
7222
  const cacheValue = await this.client.get(key);
7118
- const promiseValue = Promise.resolve().then(fetchFn).then(resolveAsyncResources).then(async (value) => {
7119
- const isNull = value === null || value === void 0;
7120
- await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
7121
- return value;
7122
- });
7123
- if (this.workerCtx?.waitUntil) {
7124
- this.workerCtx.waitUntil(promiseValue);
7223
+ let promise = SWR_PROMISE_MAP.get(key);
7224
+ if (promise === void 0) {
7225
+ promise = Promise.resolve().then(fetchFn).then(resolveAsyncResources).then(async (value) => {
7226
+ const isNull = value === null || value === void 0;
7227
+ await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
7228
+ logger.debug("[SDK] Cache update done", { key, trace });
7229
+ return value;
7230
+ }).finally(() => {
7231
+ SWR_PROMISE_MAP.delete(key);
7232
+ });
7233
+ SWR_PROMISE_MAP.set(key, promise);
7234
+ }
7235
+ if (typeof this.workerCtx?.waitUntil === "function") {
7236
+ this.workerCtx.waitUntil(promise);
7125
7237
  }
7126
7238
  if (cacheValue !== void 0) {
7239
+ logger.debug("[SDK] Cache check done", { status: "HIT", key, trace });
7127
7240
  return cacheValue === NULL_VALUE ? null : cacheValue;
7128
7241
  }
7129
- const result = await promiseValue;
7242
+ logger.debug("[SDK] Cache check done", { status: "MISS", key, trace });
7243
+ const result = await promise;
7244
+ logger.debug("[SDK] Cache fetch end", { key, trace });
7130
7245
  return result;
7131
7246
  }
7132
7247
  async get(key) {
@@ -7501,8 +7616,12 @@ var Swell = class _Swell {
7501
7616
  queryParams,
7502
7617
  workerEnv,
7503
7618
  workerCtx,
7619
+ logger: loggerConfig,
7504
7620
  ...clientProps
7505
7621
  } = params;
7622
+ if (loggerConfig) {
7623
+ configureSdkLogger(loggerConfig);
7624
+ }
7506
7625
  this.url = url instanceof URL ? url : new URL(url || "");
7507
7626
  this.config = config;
7508
7627
  this.shopifyCompatibilityConfig = shopifyCompatibilityConfig;
@@ -7512,7 +7631,9 @@ var Swell = class _Swell {
7512
7631
  this.workerCtx = workerCtx;
7513
7632
  this.workerEnv = workerEnv;
7514
7633
  this.resourceLoadingIndicator = params.resourceLoadingIndicator;
7515
- console.log(`KV cache: ${this.workerEnv?.THEME ? "enabled" : "disabled"}`);
7634
+ logger.info(
7635
+ `[SDK] KV cache: ${this.workerEnv?.THEME ? "enabled" : "disabled"}`
7636
+ );
7516
7637
  if (serverHeaders) {
7517
7638
  const { headers: headers2, swellHeaders: swellHeaders2 } = _Swell.formatHeaders(serverHeaders);
7518
7639
  this.headers = headers2;
@@ -7626,7 +7747,7 @@ var Swell = class _Swell {
7626
7747
  if (err instanceof Error) {
7627
7748
  err.message = `Swell: unable to load settings (${err.message})`;
7628
7749
  }
7629
- console.error(err);
7750
+ logger.error(err);
7630
7751
  }
7631
7752
  return this.storefront.settings.get();
7632
7753
  }
@@ -7709,7 +7830,9 @@ var Swell = class _Swell {
7709
7830
  decodeURIComponent(this.swellHeaders["storefront-context"])
7710
7831
  );
7711
7832
  } catch (error) {
7712
- console.error("Failed to parse swell-storefront-context. Ignoring...");
7833
+ logger.error(
7834
+ "[SDK] Failed to parse swell-storefront-context. Ignoring..."
7835
+ );
7713
7836
  }
7714
7837
  }
7715
7838
  return storefrontContext;
@@ -7739,7 +7862,7 @@ var Swell = class _Swell {
7739
7862
  return this.getRequestCache().fetchSWR(
7740
7863
  getCacheKey("request", [this.instanceId, method, url, id, data, opt]),
7741
7864
  () => {
7742
- console.log("Storefront request", { method, url, id, data });
7865
+ logger.info("[SDK] Storefront request", { method, url, id, data });
7743
7866
  return storefrontRequest(method, url, id, data, opt);
7744
7867
  }
7745
7868
  );
@@ -7763,7 +7886,7 @@ var Swell = class _Swell {
7763
7886
  */
7764
7887
  getResourceCache() {
7765
7888
  let cache = resourceCaches.get(this.instanceId);
7766
- if (!cache) {
7889
+ if (cache === void 0) {
7767
7890
  cache = new ResourceCache({
7768
7891
  kvStore: this.workerEnv?.THEME,
7769
7892
  workerCtx: this.workerCtx
@@ -7777,7 +7900,7 @@ var Swell = class _Swell {
7777
7900
  */
7778
7901
  getRequestCache() {
7779
7902
  let cache = requestCaches.get(this.instanceId);
7780
- if (!cache) {
7903
+ if (cache === void 0) {
7781
7904
  cache = new RequestCache({
7782
7905
  kvStore: this.workerEnv?.THEME,
7783
7906
  workerCtx: this.workerCtx
@@ -7830,6 +7953,11 @@ var SwellBackendAPI = class {
7830
7953
  }
7831
7954
  const endpointUrl = String(url).startsWith("/") ? url.substring(1) : url;
7832
7955
  const requestUrl = `${this.apiHost}/${endpointUrl}${query}`;
7956
+ const trace = createTraceId();
7957
+ logger.debug("[SDK] Backend request start", {
7958
+ query: `/${endpointUrl}${query}`,
7959
+ trace
7960
+ });
7833
7961
  const response = await fetch(requestUrl, requestOptions);
7834
7962
  const responseText = await response.text();
7835
7963
  let result;
@@ -7838,6 +7966,10 @@ var SwellBackendAPI = class {
7838
7966
  } catch {
7839
7967
  result = String(responseText || "").trim();
7840
7968
  }
7969
+ logger.debug("[SDK] Backend request end", {
7970
+ status: response.status,
7971
+ trace
7972
+ });
7841
7973
  if (response.status > 299) {
7842
7974
  throw new SwellError(result, {
7843
7975
  status: response.status,
@@ -19254,9 +19386,14 @@ var SwellTheme3 = class {
19254
19386
  }
19255
19387
  async initGlobals(pageId, altTemplate) {
19256
19388
  this.pageId = pageId;
19389
+ const trace = createTraceId();
19390
+ logger.debug("[SDK] Theme init start", { page: pageId, trace });
19257
19391
  await this.themeLoader.init(this.themeConfigs || void 0);
19392
+ logger.debug("[SDK] ThemeLoader init done", { page: pageId, trace });
19258
19393
  const { store, session, menus, geo, configs } = await this.getSettingsAndConfigs();
19394
+ logger.debug("[SDK] Theme settings load done", { page: pageId, trace });
19259
19395
  const { settings, request, page, cart, account, customer } = await this.resolvePageData(store, configs, pageId, altTemplate);
19396
+ logger.debug("[SDK] Theme page data load done", { page: pageId, trace });
19260
19397
  this.page = page;
19261
19398
  const globals = {
19262
19399
  ...this.globalData,
@@ -19283,6 +19420,7 @@ var SwellTheme3 = class {
19283
19420
  if (this.shopifyCompatibility) {
19284
19421
  this.shopifyCompatibility.adaptQueryParams();
19285
19422
  }
19423
+ logger.debug("[SDK] Theme init end", { page: pageId, trace });
19286
19424
  }
19287
19425
  setGlobals(globals) {
19288
19426
  if (this.shopifyCompatibility) {
@@ -19315,7 +19453,7 @@ var SwellTheme3 = class {
19315
19453
  try {
19316
19454
  configValue = import_json56.default.parse(config.file_data);
19317
19455
  } catch (err) {
19318
- console.error(`Error parsing ${configName} config: ${err}`);
19456
+ logger.error(`Error parsing config`, err, { configName });
19319
19457
  configValue = {};
19320
19458
  }
19321
19459
  acc[configName] = configValue;
@@ -19402,7 +19540,7 @@ var SwellTheme3 = class {
19402
19540
  templateConfig?.file_data || "{}"
19403
19541
  );
19404
19542
  } catch (err) {
19405
- console.warn(err);
19543
+ logger.warn(err);
19406
19544
  }
19407
19545
  if (pageSchema?.page) {
19408
19546
  const {
@@ -19707,7 +19845,7 @@ var SwellTheme3 = class {
19707
19845
  try {
19708
19846
  return import_json56.default.parse(localeConfig?.file_data || "{}");
19709
19847
  } catch (err) {
19710
- console.warn(err);
19848
+ logger.warn(err);
19711
19849
  }
19712
19850
  }
19713
19851
  return {};
@@ -19876,10 +20014,20 @@ var SwellTheme3 = class {
19876
20014
  return "";
19877
20015
  }
19878
20016
  template = unescapeLiquidSyntax(template);
20017
+ const trace = createTraceId();
19879
20018
  try {
19880
- return await this.liquidSwell.parseAndRender(template, data);
20019
+ logger.debug("[SDK] Render template start", {
20020
+ config: config.name,
20021
+ trace
20022
+ });
20023
+ const result = await this.liquidSwell.parseAndRender(template, data);
20024
+ logger.debug("[SDK] Render template end", {
20025
+ config: config.name,
20026
+ trace
20027
+ });
20028
+ return result;
19881
20029
  } catch (err) {
19882
- console.error(err);
20030
+ logger.error(err);
19883
20031
  return `<!-- template render error: ${err.message} -->`;
19884
20032
  }
19885
20033
  }
@@ -19887,7 +20035,7 @@ var SwellTheme3 = class {
19887
20035
  try {
19888
20036
  return await this.liquidSwell.parseAndRender(templateString, data);
19889
20037
  } catch (err) {
19890
- console.error(err);
20038
+ logger.error(err);
19891
20039
  return "";
19892
20040
  }
19893
20041
  }
@@ -19911,7 +20059,7 @@ var SwellTheme3 = class {
19911
20059
  );
19912
20060
  }
19913
20061
  } catch (err) {
19914
- console.warn(err);
20062
+ logger.warn(err);
19915
20063
  return void 0;
19916
20064
  }
19917
20065
  } else if (config?.file_path?.endsWith(".liquid")) {
@@ -19964,11 +20112,10 @@ var SwellTheme3 = class {
19964
20112
  try {
19965
20113
  return import_json56.default.parse(content);
19966
20114
  } catch (err) {
19967
- console.log(
19968
- "Unable to render theme template",
19969
- config.file_path,
20115
+ logger.error("[SDK] Unable to render theme template", {
20116
+ file: config.file_path,
19970
20117
  content
19971
- );
20118
+ });
19972
20119
  throw new PageError(err);
19973
20120
  }
19974
20121
  }
@@ -20225,7 +20372,7 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
20225
20372
  try {
20226
20373
  schema = import_json56.default.parse(resolvedConfig?.file_data) || void 0;
20227
20374
  } catch (err) {
20228
- console.warn(err);
20375
+ logger.warn(err);
20229
20376
  }
20230
20377
  }
20231
20378
  return schema;
@@ -20615,7 +20762,7 @@ function parseJsonConfig(config) {
20615
20762
  try {
20616
20763
  return import_json56.default.parse(config?.file_data || "{}");
20617
20764
  } catch (err) {
20618
- console.warn(err);
20765
+ logger.warn(err);
20619
20766
  return {};
20620
20767
  }
20621
20768
  }
@@ -21092,6 +21239,7 @@ function getResourceQuery(slug, query) {
21092
21239
  adaptShopifyMenuData,
21093
21240
  arrayToObject,
21094
21241
  cloneStorefrontResource,
21242
+ configureSdkLogger,
21095
21243
  deferMenuItemUrlAndResource,
21096
21244
  dehydrateSwellRefsInStorefrontResources,
21097
21245
  extractSettingsFromForm,