@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 +22 -0
- package/README.md +304 -0
- package/dist/index.cjs +124 -48
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +124 -48
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +124 -48
- package/dist/index.mjs.map +3 -3
- package/dist/src/api.d.ts +1 -1
- package/dist/src/cache/cache.d.ts +1 -1
- package/dist/src/compatibility/shopify-objects/collection.d.ts +1 -1
- package/dist/src/resources/product.d.ts +13 -0
- package/dist/src/theme.d.ts +2 -1
- package/dist/types/shopify.d.ts +3 -3
- package/package.json +1 -1
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
|
-
|
|
7228
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
15070
|
-
|
|
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:
|
|
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
|
|
15122
|
-
|
|
15123
|
-
|
|
15124
|
-
|
|
15125
|
-
|
|
15126
|
-
|
|
15127
|
-
|
|
15128
|
-
|
|
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
|
-
|
|
15133
|
-
|
|
15134
|
-
|
|
15135
|
-
|
|
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
|
|
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(
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
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
|
|
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:
|
|
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,
|