@swell/apps-sdk 1.0.142 → 1.0.144

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2025-present Swell Commerce Corp.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to use,
6
+ copy, modify, merge, publish, distribute, sublicense, sell and/or create
7
+ derivative works of the Software or any part thereof, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The rights granted above may only be exercised to develop storefront apps that integrate
11
+ or interoperate with Swell software or services, and, if applicable, to
12
+ distribute, offer for sale or otherwise make available any such storefront apps via the Swell App Store. All other uses of the Software are strictly prohibited.
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
19
+ A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # Swell Apps SDK
2
+
3
+ The Swell Apps SDK is a TypeScript-based library designed to simplify the development of isomorphic Swell apps by providing streamlined API access, theme rendering capabilities, and comprehensive caching solutions.
4
+
5
+ ## Features
6
+
7
+ ### Core functionality
8
+ - **Unified API access** - Seamless integration with both Swell Backend API and Storefront API
9
+ - **Authentication handling** - Automatic scoped access token management based on app permissions
10
+ - **Theme rendering** - Complete Shopify-compatible theme system with Liquid templating
11
+ - **Resource management** - Deferred loading of storefront resources (products, categories, etc.)
12
+ - **Caching system** - Multi-tier caching with Cloudflare KV integration
13
+ - **Shopify compatibility** - Full compatibility layer for migrating Shopify themes and apps
14
+
15
+ ### Theme capabilities
16
+ - **Liquid templating** - Enhanced Liquid engine with Swell-specific objects and filters
17
+ - **Section rendering** - Dynamic section management with schema support
18
+ - **Settings resolution** - Automatic theme and section settings processing
19
+ - **Layout system** - Flexible layout rendering with section groups
20
+ - **Asset management** - Optimized asset loading and URL generation
21
+ - **Localization** - Multi-language support with translation rendering
22
+
23
+ ### Developer experience
24
+ - **TypeScript support** - Full type safety with comprehensive type definitions
25
+ - **Isomorphic design** - Works seamlessly in both browser and server environments
26
+ - **Error handling** - Robust error management with detailed debugging information
27
+ - **Performance optimized** - Built-in caching and resource optimization
28
+ - **Extensible architecture** - Plugin system for custom resource types
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ npm install @swell/apps-sdk
34
+ ```
35
+
36
+ ## Getting started
37
+
38
+ ### Basic setup
39
+
40
+ ```typescript
41
+ import { Swell } from '@swell/apps-sdk';
42
+
43
+ // Initialize Swell instance in your app frontend
44
+ const swell = new Swell({
45
+ serverHeaders: context.request.headers, // Headers from worker environment
46
+ });
47
+
48
+ // Make backend API calls
49
+ const products = await swell.backend.get('/products');
50
+
51
+ // Make storefront API calls
52
+ const cart = await swell.storefront.get('/cart');
53
+ ```
54
+
55
+ ### Headers and app proxying
56
+
57
+ When your Swell app is deployed, it runs behind Swell's proxy infrastructure. The proxy automatically injects essential headers that contain authentication tokens, store configuration, and storefront context. These headers are critical for the SDK to function properly:
58
+
59
+ ```typescript
60
+ // Headers passed from Swell's proxy contain:
61
+ // - swell-store-id: The store identifier
62
+ // - swell-public-key: Frontend API access key
63
+ // - swell-access-token: Backend API access token (scoped to app permissions)
64
+ // - swell-storefront-id: Current storefront instance
65
+ // - swell-environment-id: Environment (development, staging, production)
66
+ // - swell-theme-id: Active theme identifier
67
+ // - swell-storefront-context: Preloaded cart/account data
68
+
69
+ const swell = new Swell({
70
+ serverHeaders: context.request.headers, // Contains all proxy-injected headers
71
+ getCookie: (name) => getCookieValue(name),
72
+ setCookie: (name, value, options) => setCookieValue(name, value, options),
73
+ });
74
+ ```
75
+
76
+ Without these headers, the SDK cannot:
77
+ - Authenticate with Swell APIs
78
+ - Determine which store and storefront to operate on
79
+ - Access cached resources or maintain session state
80
+ - Render themes with proper configuration
81
+
82
+ The `serverHeaders` parameter should always be passed the complete headers object from your app's request context to ensure full functionality.
83
+
84
+ ### Theme rendering
85
+
86
+ ```typescript
87
+ import { Swell, SwellTheme, SwellProduct } from '@swell/apps-sdk';
88
+
89
+ const swell = new Swell({
90
+ serverHeaders: context.request.headers,
91
+ ...options,
92
+ });
93
+
94
+ // Initialize theme with optional configuration
95
+ const theme = new SwellTheme(swell, {
96
+ forms: formConfigs,
97
+ resources: customResources,
98
+ globals: additionalGlobals,
99
+ });
100
+
101
+ // Fetch settings and set global context
102
+ await theme.initGlobals('product'); // page ID
103
+
104
+ // Create page data with deferred resource loading
105
+ const data = {
106
+ product: new SwellProduct(swell, context.params.id),
107
+ };
108
+
109
+ // Render theme page
110
+ const renderedPage = await theme.renderPage(data);
111
+ ```
112
+
113
+ ## API reference
114
+
115
+ ### Swell class
116
+
117
+ The main entry point for SDK functionality:
118
+
119
+ ```typescript
120
+ class Swell {
121
+ // API access
122
+ backend: SwellBackendAPI;
123
+ storefront: typeof SwellJS;
124
+
125
+ // Configuration
126
+ config: SwellAppConfig;
127
+ url: URL;
128
+ headers: Record<string, string>;
129
+ queryParams: ParsedQs;
130
+
131
+ // State
132
+ isEditor: boolean;
133
+ isPreview: boolean;
134
+ storefrontContext: SwellData;
135
+
136
+ // Methods
137
+ get<T>(url: string, query?: SwellData): Promise<T>;
138
+ post<T>(url: string, data: SwellData): Promise<T>;
139
+ put<T>(url: string, data: SwellData): Promise<T>;
140
+ delete<T>(url: string, data?: SwellData): Promise<T>;
141
+ getCachedResource<T>(key: string, args: unknown[], handler: () => T, isCacheble = true): Promise<T>;
142
+ }
143
+ ```
144
+
145
+ ### SwellTheme class
146
+
147
+ Handles theme rendering and management:
148
+
149
+ ```typescript
150
+ class SwellTheme {
151
+ // Core properties
152
+ swell: Swell;
153
+ globals: ThemeGlobals;
154
+ liquidSwell: LiquidSwell;
155
+
156
+ // Methods
157
+ initGlobals(pageId: string, altTemplate?: string): Promise<void>;
158
+ renderPage(pageData?: SwellData, altTemplate?: string): Promise<string>;
159
+ renderSection(sectionId: string, pageData?: SwellData): Promise<string>;
160
+ renderLayout(layoutName?: string, data?: SwellData): Promise<string>;
161
+ getSectionSchema(sectionName: string): Promise<ThemeSectionSchema>;
162
+ setGlobals(globals: Partial<ThemeGlobals>): void;
163
+ }
164
+ ```
165
+
166
+ ### Resource classes
167
+
168
+ Built-in storefront resource classes for deferred loading:
169
+
170
+ #### Standard resources
171
+ - `SwellAccount` - Customer account management
172
+ - `SwellBlog` - Blog post content
173
+ - `SwellBlogCategory` - Blog categorization
174
+ - `SwellCart` - Shopping cart state
175
+ - `SwellCategory` - Product categories
176
+ - `SwellOrder` - Order information
177
+ - `SwellPage` - Static pages
178
+ - `SwellProduct` - Product details
179
+ - `SwellVariant` - Product variants
180
+
181
+ #### Primitive resources
182
+ - `SwellStorefrontCollection` - Collection results with pagination
183
+ - `SwellStorefrontRecord` - Individual records
184
+ - `SwellStorefrontSingleton` - Unique resources (cart, account)
185
+
186
+ ```typescript
187
+ // Create custom resource class
188
+ class MyAppCollection extends SwellStorefrontCollection {
189
+ constructor(swell: Swell, query: SwellData = {}) {
190
+ super(swell, 'my-app-collection', query);
191
+ return this._getProxy();
192
+ }
193
+ }
194
+
195
+ // Usage in theme data
196
+ const data = {
197
+ myCollection: new MyAppCollection(swell, { limit: 20 }),
198
+ };
199
+ ```
200
+
201
+ ## Caching
202
+
203
+ ### Memory caching
204
+ Resources are automatically cached in memory per worker instance:
205
+
206
+ ```typescript
207
+ // Cached resource with custom handler
208
+ const cachedData = await swell.getCachedResource(
209
+ 'expensive-operation',
210
+ [param1, param2],
211
+ async () => {
212
+ return await performExpensiveOperation(param1, param2);
213
+ }
214
+ );
215
+ ```
216
+
217
+ ### Cloudflare KV caching
218
+ For production scalability, enable KV caching:
219
+
220
+ ```typescript
221
+ const swell = new Swell({
222
+ serverHeaders: context.request.headers,
223
+ workerEnv: context.locals.runtime.env, // Contains THEME KV binding
224
+ workerCtx: context.locals.runtime.ctx, // Worker context
225
+ });
226
+ ```
227
+
228
+ ### Cache invalidation
229
+ Caches are automatically invalidated based on:
230
+ - Session cookies (for cart/account data)
231
+ - Theme configuration versions
232
+ - Storefront environment changes
233
+
234
+ ## Shopify compatibility
235
+
236
+ The SDK includes comprehensive Shopify compatibility for theme migration.
237
+
238
+ ### Supported Shopify features
239
+ - **Template mapping** - Direct file path compatibility
240
+ - **Liquid objects** - Full object structure compatibility
241
+ - **Form handling** - Compatible form endpoints and validation
242
+ - **Section schemas** - Shopify section configuration format
243
+ - **Settings data** - `settings_data.json` and `settings_schema.json`
244
+
245
+ ## Liquid templating
246
+
247
+ Enhanced Liquid templating with Swell-specific features. See [Swell Liquid documentation](https://developers.swell.is/storefronts/swell-liquid-reference) for details.
248
+
249
+ ## Performance optimization
250
+
251
+ ### Lazy loading
252
+ Resources are loaded only when accessed in templates:
253
+
254
+ ```liquid
255
+ <!-- Product data is fetched only when this line executes -->
256
+ {{ product.name }}
257
+
258
+ <!-- Collection is fetched only when iteration begins -->
259
+ {% for item in collection.products %}
260
+ {{ item.name }}
261
+ {% endfor %}
262
+ ```
263
+
264
+ ## Development
265
+
266
+ ### Building the SDK
267
+ ```bash
268
+ # Install dependencies
269
+ npm install
270
+
271
+ # Build for production
272
+ npm run build
273
+
274
+ # Watch for changes
275
+ npm run watch
276
+
277
+ # Run tests
278
+ npm test
279
+ ```
280
+
281
+ ### Project structure
282
+ ```
283
+ src/
284
+ ├── api.ts # Core Swell class and API handling
285
+ ├── theme.ts # SwellTheme class and rendering
286
+ ├── resources.ts # Storefront resource classes
287
+ ├── liquid/ # Liquid templating engine
288
+ ├── compatibility/ # Shopify compatibility layer
289
+ ├── cache/ # Caching implementations
290
+ ├── utils/ # Utility functions
291
+ └── index.ts # Main exports
292
+ ```
293
+
294
+ ## Resources
295
+
296
+ - [Swell Documentation](https://developers.swell.is/)
297
+ - [Apps Development Guide](https://developers.swell.is/apps/overview)
298
+ - [Proxima Example App](https://developers.swell.is/storefronts/proxima)
299
+ - [Swell Liquid Reference](https://developers.swell.is/storefronts/swell-liquid-reference)
300
+ - [GitHub Repository](https://github.com/swellstores/swell-apps-sdk)
301
+
302
+ ## 📄 License
303
+
304
+ See the [LICENSE](LICENSE) file for details.
package/dist/index.cjs CHANGED
@@ -649,6 +649,12 @@ async function forEachKeyDeep(obj, fn) {
649
649
  }
650
650
 
651
651
  // src/resources.ts
652
+ var NOT_CACHEBLE_COLLECTIONS = Object.freeze(
653
+ /* @__PURE__ */ new Set(["accounts:addresses", "accounts:orders", "accounts:subscriptions"])
654
+ );
655
+ function isResourceCacheble(name) {
656
+ return !NOT_CACHEBLE_COLLECTIONS.has(name);
657
+ }
652
658
  var MAX_QUERY_PAGE_LIMIT = 100;
653
659
  var DEFAULT_QUERY_PAGE_LIMIT = 15;
654
660
  var StorefrontResource = class {
@@ -935,7 +941,8 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
935
941
  this._swell.queryParams,
936
942
  this._getterHash
937
943
  ],
938
- getter
944
+ getter,
945
+ isResourceCacheble(this._collection)
939
946
  ).then((result) => {
940
947
  this._result = result;
941
948
  if (result) {
@@ -1049,7 +1056,8 @@ var SwellStorefrontRecord = class extends SwellStorefrontResource {
1049
1056
  this._swell.queryParams,
1050
1057
  this._getterHash
1051
1058
  ],
1052
- getter
1059
+ getter,
1060
+ isResourceCacheble(this._collection)
1053
1061
  ).then((result) => {
1054
1062
  return this._transformResult(result);
1055
1063
  }).then((result) => {
@@ -7216,16 +7224,18 @@ var Cache = class {
7216
7224
  *
7217
7225
  * This will always return the cached value immediately if exists
7218
7226
  */
7219
- async fetchSWR(key, fetchFn, ttl = DEFAULT_SWR_TTL) {
7227
+ async fetchSWR(key, fetchFn, ttl = DEFAULT_SWR_TTL, isCacheble = true) {
7220
7228
  const trace = createTraceId();
7221
7229
  logger.debug("[SDK] Cache fetch start", { key, trace });
7222
- const cacheValue = await this.client.get(key);
7230
+ const cacheValue = isCacheble ? await this.client.get(key) : void 0;
7223
7231
  let promise = SWR_PROMISE_MAP.get(key);
7224
7232
  if (promise === void 0) {
7225
7233
  promise = Promise.resolve().then(fetchFn).then(resolveAsyncResources).then(async (value) => {
7226
7234
  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 });
7235
+ if (isCacheble) {
7236
+ await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
7237
+ logger.debug("[SDK] Cache update done", { key, trace });
7238
+ }
7229
7239
  return value;
7230
7240
  }).finally(() => {
7231
7241
  SWR_PROMISE_MAP.delete(key);
@@ -7536,6 +7546,16 @@ function transformSwellVariant(params, product, variant) {
7536
7546
  }
7537
7547
 
7538
7548
  // src/resources/product.ts
7549
+ var SORT_OPTIONS = [
7550
+ { value: "", name: "Featured" },
7551
+ { value: "popularity", name: "Popularity", query: "popularity desc" },
7552
+ { value: "price_asc", name: "Price, low to high", query: "price asc" },
7553
+ { value: "price_desc", name: "Price, high to low", query: "price desc" },
7554
+ { value: "date_asc", name: "Date, old to new", query: "date asc" },
7555
+ { value: "date_desc", name: "Date, new to old", query: "date desc" },
7556
+ { value: "name_asc", name: "Product name, A-Z", query: "name asc" },
7557
+ { value: "name_desc", name: "Product name, Z-A", query: "name desc" }
7558
+ ];
7539
7559
  function transformSwellProduct(params, product) {
7540
7560
  if (!product) {
7541
7561
  return product;
@@ -7572,6 +7592,28 @@ var SwellProduct = class extends SwellStorefrontRecord {
7572
7592
  return res;
7573
7593
  }
7574
7594
  };
7595
+ function productQueryWithFilters(swell, query = {}) {
7596
+ const sortBy = swell.queryParams.sort || "";
7597
+ const filters2 = Object.entries(swell.queryParams).reduce(
7598
+ (acc, [key, value]) => {
7599
+ if (key.startsWith("filter_")) {
7600
+ const qkey = key.replace("filter_", "");
7601
+ if (value?.gte !== void 0 || value?.lte !== void 0) {
7602
+ acc[qkey] = [value.gte || 0, value.lte || void 0];
7603
+ } else {
7604
+ acc[qkey] = value;
7605
+ }
7606
+ }
7607
+ return acc;
7608
+ },
7609
+ {}
7610
+ );
7611
+ return {
7612
+ sort: SORT_OPTIONS.find((option) => option.value === sortBy)?.query || void 0,
7613
+ $filters: filters2,
7614
+ ...query
7615
+ };
7616
+ }
7575
7617
 
7576
7618
  // src/api.ts
7577
7619
  var DEFAULT_API_HOST = "https://api.schema.io";
@@ -7699,9 +7741,14 @@ var Swell = class _Swell {
7699
7741
  * Fetches a resource.
7700
7742
  * First attempts to fetch from cache.
7701
7743
  */
7702
- async getCachedResource(key, args, handler) {
7744
+ async getCachedResource(key, args, handler, isCacheble = true) {
7703
7745
  const cacheKey = getCacheKey(key, [this.instanceId, args]);
7704
- return this.getResourceCache().fetchSWR(cacheKey, handler);
7746
+ return this.getResourceCache().fetchSWR(
7747
+ cacheKey,
7748
+ handler,
7749
+ void 0,
7750
+ isCacheble
7751
+ );
7705
7752
  }
7706
7753
  async getAppSettings() {
7707
7754
  const settings = await this.get(
@@ -7713,15 +7760,16 @@ var Swell = class _Swell {
7713
7760
  return settings || {};
7714
7761
  }
7715
7762
  async getStorefrontSettings(force = false) {
7763
+ const storefrontSettings = this.storefront.settings;
7716
7764
  try {
7717
- const { settings, menus, payments, subscriptions, session } = await this.storefront.request(
7765
+ const allSettings = await this.storefront.request(
7718
7766
  "get",
7719
7767
  "/settings/all",
7720
7768
  void 0,
7721
7769
  force ? { $cache: false } : void 0,
7722
7770
  { force }
7723
7771
  );
7724
- const storefrontSettings = this.storefront.settings;
7772
+ const { settings, menus, payments, subscriptions, session } = allSettings;
7725
7773
  storefrontSettings.localizedState = {};
7726
7774
  storefrontSettings.set({
7727
7775
  value: settings
@@ -7749,7 +7797,7 @@ var Swell = class _Swell {
7749
7797
  }
7750
7798
  logger.error(err);
7751
7799
  }
7752
- return this.storefront.settings.get();
7800
+ return storefrontSettings;
7753
7801
  }
7754
7802
  getStorefrontMenus() {
7755
7803
  const menus = this.storefront.settings.getState(
@@ -15012,9 +15060,11 @@ function ShopifyCollection(instance, category) {
15012
15060
  if (category instanceof StorefrontResource) {
15013
15061
  category = cloneStorefrontResource(category);
15014
15062
  }
15063
+ const productMapper = (product) => ShopifyProduct(instance, product);
15015
15064
  const resolveProducts = makeProductsCollectionResolve(
15065
+ instance,
15016
15066
  category,
15017
- (product) => ShopifyProduct(instance, product)
15067
+ productMapper
15018
15068
  );
15019
15069
  return new ShopifyResource({
15020
15070
  all_products_count: defer(
@@ -15066,8 +15116,9 @@ function ShopifyCollection(instance, category) {
15066
15116
  category,
15067
15117
  (category2) => getFirstImage(instance, category2)
15068
15118
  ),
15069
- filters: defer(
15070
- async () => ((await resolveProducts())?.filter_options ?? []).map(
15119
+ filters: deferWith(
15120
+ category,
15121
+ (category2) => (category2?.filter_options ?? []).map(
15071
15122
  (filter) => ShopifyFilter(instance, filter)
15072
15123
  )
15073
15124
  ),
@@ -15077,9 +15128,7 @@ function ShopifyCollection(instance, category) {
15077
15128
  metafields: {},
15078
15129
  next_product: void 0,
15079
15130
  previous_product: void 0,
15080
- products: defer(async () => {
15081
- return (await resolveProducts())?.results ?? [];
15082
- }),
15131
+ products: getProducts(instance, category, productMapper),
15083
15132
  products_count: defer(
15084
15133
  async () => (await resolveProducts())?.results?.length || 0
15085
15134
  ),
@@ -15118,28 +15167,35 @@ function convertToShopifySorting(value) {
15118
15167
  return "manual";
15119
15168
  }
15120
15169
  }
15121
- function makeProductsCollectionResolve(object, mapper) {
15122
- const productResults = deferWith(object, (object2) => {
15123
- if (object2.products) {
15124
- if (object2.products instanceof SwellStorefrontCollection) {
15125
- return object2.products._cloneWithCompatibilityResult((products) => {
15126
- return {
15127
- ...products,
15128
- results: products.results.map(mapper)
15129
- };
15130
- });
15170
+ function getProducts(instance, object, mapper) {
15171
+ return deferWith(object, (object2) => {
15172
+ const { page, limit: limit2 } = instance.swell.queryParams;
15173
+ const categoryFilter = object2.id && object2.id !== "all" ? object2.id : void 0;
15174
+ const productQuery = categoryFilter ? { category: categoryFilter, $variants: true } : { $variants: true };
15175
+ const filterQuery = productQueryWithFilters(instance.swell, productQuery);
15176
+ const products = new SwellStorefrontCollection(
15177
+ instance.swell,
15178
+ "products",
15179
+ {
15180
+ page,
15181
+ limit: limit2,
15182
+ ...filterQuery
15183
+ },
15184
+ async function() {
15185
+ return this._defaultGetter().call(this);
15131
15186
  }
15132
- if (Array.isArray(object2.products?.results)) {
15133
- return {
15134
- ...object2.products,
15135
- results: object2.products.results.map(mapper)
15136
- };
15187
+ );
15188
+ return products._cloneWithCompatibilityResult(
15189
+ (products2) => {
15190
+ return { ...products2, results: products2.results.map(mapper) };
15137
15191
  }
15138
- }
15139
- return null;
15192
+ );
15140
15193
  });
15194
+ }
15195
+ function makeProductsCollectionResolve(instance, object, mapper) {
15196
+ const products = getProducts(instance, object, mapper);
15141
15197
  async function resolveProducts() {
15142
- const resolved = await productResults.resolve();
15198
+ const resolved = await products.resolve();
15143
15199
  if (resolved && "_resolve" in resolved) {
15144
15200
  return resolved._resolve();
15145
15201
  }
@@ -15173,6 +15229,9 @@ function ShopifyAddress(instance, address, account) {
15173
15229
  if (address instanceof StorefrontResource) {
15174
15230
  address = cloneStorefrontResource(address);
15175
15231
  }
15232
+ if (!address) {
15233
+ address = {};
15234
+ }
15176
15235
  return new ShopifyResource({
15177
15236
  address1: defer(() => address.address1),
15178
15237
  address2: defer(() => address.address2),
@@ -15903,11 +15962,15 @@ function ShopifySearch(instance, search) {
15903
15962
  if (search instanceof ShopifyResource) {
15904
15963
  return search.clone();
15905
15964
  }
15906
- const resolveProducts = makeProductsCollectionResolve(search, (product) => {
15907
- const shopifyProduct = ShopifyProduct(instance, product);
15908
- shopifyProduct.object_type = "product";
15909
- return shopifyProduct;
15910
- });
15965
+ const resolveProducts = makeProductsCollectionResolve(
15966
+ instance,
15967
+ search,
15968
+ (product) => {
15969
+ const shopifyProduct = ShopifyProduct(instance, product);
15970
+ shopifyProduct.object_type = "product";
15971
+ return shopifyProduct;
15972
+ }
15973
+ );
15911
15974
  return new ShopifyResource({
15912
15975
  default_sort_by: deferWith(
15913
15976
  search,
@@ -16643,6 +16706,10 @@ ${injects.join("\n")}</script>`;
16643
16706
  pageId = "account/order";
16644
16707
  urlParams.id = segment3;
16645
16708
  break;
16709
+ case "subscriptions":
16710
+ pageId = "account/subscription";
16711
+ urlParams.id = segment3;
16712
+ break;
16646
16713
  case "register":
16647
16714
  pageId = "account/login";
16648
16715
  break;
@@ -19390,14 +19457,15 @@ var SwellTheme3 = class {
19390
19457
  logger.debug("[SDK] Theme init start", { page: pageId, trace });
19391
19458
  await this.themeLoader.init(this.themeConfigs || void 0);
19392
19459
  logger.debug("[SDK] ThemeLoader init done", { page: pageId, trace });
19393
- const { store, session, menus, geo, configs } = await this.getSettingsAndConfigs();
19460
+ const { store, session, menus, geo, configs, storefrontSettings } = await this.getSettingsAndConfigs();
19394
19461
  logger.debug("[SDK] Theme settings load done", { page: pageId, trace });
19395
19462
  const { settings, request, page, cart, account, customer } = await this.resolvePageData(store, configs, pageId, altTemplate);
19396
19463
  logger.debug("[SDK] Theme page data load done", { page: pageId, trace });
19397
19464
  this.page = page;
19398
19465
  const globals = {
19399
19466
  ...this.globalData,
19400
- store,
19467
+ // return all storefront settings in the store
19468
+ store: { ...storefrontSettings, ...store },
19401
19469
  settings,
19402
19470
  session,
19403
19471
  request,
@@ -19463,7 +19531,10 @@ var SwellTheme3 = class {
19463
19531
  {}
19464
19532
  )
19465
19533
  };
19466
- const session = await this.swell.storefront.settings.session();
19534
+ const [session, storeSettings] = await Promise.all([
19535
+ storefrontSettings.session(),
19536
+ storefrontSettings.get()
19537
+ ]);
19467
19538
  if (configs.translations) {
19468
19539
  configs.language = configs.translations;
19469
19540
  }
@@ -19476,11 +19547,13 @@ var SwellTheme3 = class {
19476
19547
  await this.setCompatibilityConfigs(configs);
19477
19548
  const menus = await this.resolveMenuSettings();
19478
19549
  return {
19479
- store: storefrontSettings?.store,
19550
+ store: storeSettings?.store,
19480
19551
  session,
19481
19552
  menus,
19482
19553
  geo,
19483
- configs
19554
+ configs,
19555
+ // all settings
19556
+ storefrontSettings
19484
19557
  };
19485
19558
  }
19486
19559
  async resolvePageData(store, configs, pageId, altTemplate) {
@@ -19569,7 +19642,8 @@ var SwellTheme3 = class {
19569
19642
  this.fetchSingletonResourceCached(
19570
19643
  "account",
19571
19644
  () => this.fetchAccount(),
19572
- () => null
19645
+ () => null,
19646
+ false
19573
19647
  )
19574
19648
  ]);
19575
19649
  if (!cart) {
@@ -19589,7 +19663,7 @@ var SwellTheme3 = class {
19589
19663
  // Shopify only
19590
19664
  };
19591
19665
  }
19592
- async fetchSingletonResourceCached(key, handler, defaultValue) {
19666
+ async fetchSingletonResourceCached(key, handler, defaultValue, isCacheble = true) {
19593
19667
  const cacheKey = this.swell.storefront.session.getCookie();
19594
19668
  if (!cacheKey) {
19595
19669
  return defaultValue();
@@ -19597,7 +19671,8 @@ var SwellTheme3 = class {
19597
19671
  const result = await this.swell.getCachedResource(
19598
19672
  `${key}-${cacheKey}`,
19599
19673
  [],
19600
- handler
19674
+ handler,
19675
+ isCacheble
19601
19676
  );
19602
19677
  return result ?? defaultValue();
19603
19678
  }
@@ -21128,6 +21203,7 @@ function createStorefrontRecord(resource, swell, path, parent_slug, parent_query
21128
21203
  }
21129
21204
  function createCollection(resource, swell, path, parent_slug, parent_query) {
21130
21205
  const query = getResourceQuery(parent_slug, parent_query);
21206
+ query.$resource_path = path;
21131
21207
  return new SwellStorefrontCollection(
21132
21208
  swell,
21133
21209
  resource,