@swell/apps-sdk 1.0.161 → 1.0.163
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 +134 -95
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +132 -95
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +133 -95
- package/dist/index.mjs.map +3 -3
- package/dist/src/api.d.ts +4 -0
- package/dist/src/cache/cache.d.ts +10 -1
- package/dist/src/cache/html-cache/html-cache-factory.d.ts +3 -2
- package/dist/src/cache/html-cache/html-cache.d.ts +41 -5
- package/dist/src/cache/html-cache/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7199,6 +7199,7 @@
|
|
|
7199
7199
|
});
|
|
7200
7200
|
var NULL_VALUE = "__NULL__";
|
|
7201
7201
|
var SWR_PROMISE_MAP = /* @__PURE__ */ new Map();
|
|
7202
|
+
var FETCH_PROMISE_MAP = /* @__PURE__ */ new Map();
|
|
7202
7203
|
var Cache = class {
|
|
7203
7204
|
client;
|
|
7204
7205
|
workerCtx;
|
|
@@ -7211,8 +7212,30 @@
|
|
|
7211
7212
|
...options
|
|
7212
7213
|
});
|
|
7213
7214
|
}
|
|
7214
|
-
|
|
7215
|
-
|
|
7215
|
+
/**
|
|
7216
|
+
* Always fetches fresh data and updates cache
|
|
7217
|
+
* Deduplicates concurrent requests with the same key
|
|
7218
|
+
*
|
|
7219
|
+
* @param key Cache key
|
|
7220
|
+
* @param fetchFn Function to fetch fresh data
|
|
7221
|
+
* @param ttl Time to live in milliseconds (default: DEFAULT_SWR_TTL)
|
|
7222
|
+
* @param isCacheable Whether to store result in cache (default: true)
|
|
7223
|
+
*/
|
|
7224
|
+
async fetch(key, fetchFn, ttl = DEFAULT_SWR_TTL, isCacheable = true) {
|
|
7225
|
+
let promise = FETCH_PROMISE_MAP.get(key);
|
|
7226
|
+
if (!promise) {
|
|
7227
|
+
promise = Promise.resolve().then(fetchFn).then(resolveAsyncResources).then(async (value) => {
|
|
7228
|
+
const isNull = value === null || value === void 0;
|
|
7229
|
+
if (isCacheable) {
|
|
7230
|
+
await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
|
|
7231
|
+
}
|
|
7232
|
+
return value;
|
|
7233
|
+
}).finally(() => {
|
|
7234
|
+
FETCH_PROMISE_MAP.delete(key);
|
|
7235
|
+
});
|
|
7236
|
+
FETCH_PROMISE_MAP.set(key, promise);
|
|
7237
|
+
}
|
|
7238
|
+
return await promise;
|
|
7216
7239
|
}
|
|
7217
7240
|
/**
|
|
7218
7241
|
* Fetch cache using SWR (stale-while-revalidate)
|
|
@@ -8320,18 +8343,24 @@
|
|
|
8320
8343
|
}
|
|
8321
8344
|
return params;
|
|
8322
8345
|
}
|
|
8346
|
+
/**
|
|
8347
|
+
* Checks if cache bypass is requested via X-Cache-Bypass header
|
|
8348
|
+
*/
|
|
8349
|
+
shouldBypassCache() {
|
|
8350
|
+
return this.headers?.["x-cache-bypass"] === "revalidation";
|
|
8351
|
+
}
|
|
8323
8352
|
/**
|
|
8324
8353
|
* Fetches a resource.
|
|
8325
8354
|
* First attempts to fetch from cache.
|
|
8326
8355
|
*/
|
|
8327
8356
|
async getCachedResource(key, args, handler, isCacheble = true) {
|
|
8328
8357
|
const cacheKey = getCacheKey(key, [this.instanceId, args]);
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
handler,
|
|
8332
|
-
|
|
8333
|
-
isCacheble
|
|
8334
|
-
|
|
8358
|
+
const cache = this.getResourceCache();
|
|
8359
|
+
if (this.shouldBypassCache()) {
|
|
8360
|
+
return cache.fetch(cacheKey, handler, void 0, isCacheble);
|
|
8361
|
+
} else {
|
|
8362
|
+
return cache.fetchSWR(cacheKey, handler, void 0, isCacheble);
|
|
8363
|
+
}
|
|
8335
8364
|
}
|
|
8336
8365
|
async getAppSettings() {
|
|
8337
8366
|
const settings = await this.get(
|
|
@@ -8498,11 +8527,17 @@
|
|
|
8498
8527
|
data,
|
|
8499
8528
|
opt
|
|
8500
8529
|
]);
|
|
8501
|
-
|
|
8530
|
+
const cache = this.getRequestCache();
|
|
8531
|
+
const fetchFn = () => {
|
|
8502
8532
|
const requestUrl = id ? `${url}/${id}` : url;
|
|
8503
8533
|
logger.debug("[SDK] Cacheable API request", { url: requestUrl, key });
|
|
8504
8534
|
return storefrontRequest(method, url, id, data, opt);
|
|
8505
|
-
}
|
|
8535
|
+
};
|
|
8536
|
+
if (this.shouldBypassCache()) {
|
|
8537
|
+
return cache.fetch(key, fetchFn);
|
|
8538
|
+
} else {
|
|
8539
|
+
return cache.fetchSWR(key, fetchFn);
|
|
8540
|
+
}
|
|
8506
8541
|
}
|
|
8507
8542
|
switch (method) {
|
|
8508
8543
|
case "delete":
|
|
@@ -15901,7 +15936,7 @@ ${formattedMessage}`;
|
|
|
15901
15936
|
function joinAddressLines(...props) {
|
|
15902
15937
|
return props.filter(Boolean).join("\n");
|
|
15903
15938
|
}
|
|
15904
|
-
function ShopifyCountry(
|
|
15939
|
+
function ShopifyCountry(_instance, countryCode) {
|
|
15905
15940
|
const currencyCode = getCurrencyByCountry(countryCode) || "USD";
|
|
15906
15941
|
return new ShopifyResource(
|
|
15907
15942
|
{
|
|
@@ -16234,7 +16269,7 @@ ${formattedMessage}`;
|
|
|
16234
16269
|
}
|
|
16235
16270
|
|
|
16236
16271
|
// src/compatibility/shopify-objects/font.ts
|
|
16237
|
-
function ShopifyFont(
|
|
16272
|
+
function ShopifyFont(_instance, font) {
|
|
16238
16273
|
if (font instanceof ShopifyResource) {
|
|
16239
16274
|
return font.clone();
|
|
16240
16275
|
}
|
|
@@ -16245,7 +16280,7 @@ ${formattedMessage}`;
|
|
|
16245
16280
|
family: font.family,
|
|
16246
16281
|
style: font.style,
|
|
16247
16282
|
"system?": font.system,
|
|
16248
|
-
variants: font.variants.map((variant) => ShopifyFont(
|
|
16283
|
+
variants: font.variants.map((variant) => ShopifyFont(_instance, variant)),
|
|
16249
16284
|
weight: font.weight
|
|
16250
16285
|
});
|
|
16251
16286
|
}
|
|
@@ -16258,7 +16293,7 @@ ${formattedMessage}`;
|
|
|
16258
16293
|
})
|
|
16259
16294
|
}
|
|
16260
16295
|
};
|
|
16261
|
-
function ShopifyForm(
|
|
16296
|
+
function ShopifyForm(_instance, form) {
|
|
16262
16297
|
if (form instanceof ShopifyResource) {
|
|
16263
16298
|
return form.clone();
|
|
16264
16299
|
}
|
|
@@ -16555,7 +16590,7 @@ ${formattedMessage}`;
|
|
|
16555
16590
|
}
|
|
16556
16591
|
|
|
16557
16592
|
// src/compatibility/shopify-objects/page.ts
|
|
16558
|
-
function ShopifyPage(
|
|
16593
|
+
function ShopifyPage(_instance, page) {
|
|
16559
16594
|
if (page instanceof ShopifyResource) {
|
|
16560
16595
|
return page.clone();
|
|
16561
16596
|
}
|
|
@@ -17767,7 +17802,7 @@ ${injects.join("\n")}<\/script>`;
|
|
|
17767
17802
|
};
|
|
17768
17803
|
|
|
17769
17804
|
// src/compatibility/shopify-objects/template.ts
|
|
17770
|
-
function ShopifyTemplate(
|
|
17805
|
+
function ShopifyTemplate(_instance, template) {
|
|
17771
17806
|
return new ShopifyResource(
|
|
17772
17807
|
{
|
|
17773
17808
|
directory: template.path,
|
|
@@ -20699,12 +20734,7 @@ ${injects.join("\n")}<\/script>`;
|
|
|
20699
20734
|
// Default value (always StorefrontResource)
|
|
20700
20735
|
() => this.fetchCart()
|
|
20701
20736
|
),
|
|
20702
|
-
this.
|
|
20703
|
-
"account",
|
|
20704
|
-
() => this.fetchAccount(),
|
|
20705
|
-
() => null,
|
|
20706
|
-
false
|
|
20707
|
-
)
|
|
20737
|
+
this.fetchAccount()
|
|
20708
20738
|
]);
|
|
20709
20739
|
if (!cart) {
|
|
20710
20740
|
throw new Error("Failed to fetch cart");
|
|
@@ -22342,42 +22372,27 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22342
22372
|
|
|
22343
22373
|
// src/cache/html-cache/html-cache.ts
|
|
22344
22374
|
var CACHE_KEY_ORIGIN = "https://cache.swell.store";
|
|
22345
|
-
var
|
|
22346
|
-
|
|
22347
|
-
|
|
22348
|
-
|
|
22349
|
-
|
|
22350
|
-
|
|
22351
|
-
|
|
22352
|
-
|
|
22353
|
-
SWR: 60 * 60 * 24 * 7
|
|
22354
|
-
// 1 week
|
|
22355
|
-
},
|
|
22356
|
-
PREVIEW: {
|
|
22357
|
-
DEFAULT: 10,
|
|
22358
|
-
HOME: 10,
|
|
22359
|
-
PRODUCT: 10,
|
|
22360
|
-
COLLECTION: 10,
|
|
22361
|
-
PAGE: 10,
|
|
22362
|
-
BLOG: 10,
|
|
22363
|
-
SWR: 60 * 60 * 24 * 7
|
|
22364
|
-
// 1 week
|
|
22365
|
-
}
|
|
22375
|
+
var DEFAULT_CACHE_RULES = {
|
|
22376
|
+
defaults: {
|
|
22377
|
+
live: { ttl: 20, swr: 60 * 60 * 24 * 7 },
|
|
22378
|
+
// 20s TTL, 1 week SWR
|
|
22379
|
+
preview: { ttl: 10, swr: 60 * 60 * 24 * 7 }
|
|
22380
|
+
// 10s TTL, 1 week SWR
|
|
22381
|
+
},
|
|
22382
|
+
pathRules: [{ path: "/checkout/*", skip: true }]
|
|
22366
22383
|
};
|
|
22367
22384
|
var HtmlCache = class {
|
|
22368
22385
|
epoch;
|
|
22369
22386
|
backend;
|
|
22370
|
-
|
|
22387
|
+
cacheRules;
|
|
22388
|
+
constructor(epoch, backend, cacheRules = DEFAULT_CACHE_RULES) {
|
|
22371
22389
|
this.epoch = epoch;
|
|
22372
22390
|
this.backend = backend;
|
|
22391
|
+
this.cacheRules = cacheRules;
|
|
22373
22392
|
}
|
|
22374
22393
|
async get(request) {
|
|
22375
22394
|
const trace = createTraceId();
|
|
22376
|
-
if (request
|
|
22377
|
-
logger.debug("[SDK Html-cache] non-cacheable method", { trace });
|
|
22378
|
-
return { found: false, cacheable: false };
|
|
22379
|
-
}
|
|
22380
|
-
if (!this.isCacheable(request)) {
|
|
22395
|
+
if (!this.canReadFromCache(request)) {
|
|
22381
22396
|
logger.debug("[SDK Html-cache] non-cacheable request", { trace });
|
|
22382
22397
|
return { found: false, cacheable: false };
|
|
22383
22398
|
}
|
|
@@ -22445,31 +22460,27 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22445
22460
|
}
|
|
22446
22461
|
async put(request, response) {
|
|
22447
22462
|
const trace = createTraceId();
|
|
22448
|
-
if (request
|
|
22449
|
-
logger.debug("[SDK Html-cache] put skipped, invalid method or response", {
|
|
22450
|
-
trace
|
|
22451
|
-
});
|
|
22452
|
-
return;
|
|
22453
|
-
}
|
|
22454
|
-
if (!this.isCacheable(request) || !this.isResponseCacheable(response)) {
|
|
22463
|
+
if (!this.canWriteToCache(request, response)) {
|
|
22455
22464
|
logger.debug("[SDK Html-cache] put skipped, non-cacheable", { trace });
|
|
22456
22465
|
return;
|
|
22457
22466
|
}
|
|
22458
22467
|
try {
|
|
22459
|
-
let lowercaseHeaders2 = function(headers2) {
|
|
22460
|
-
const out = {};
|
|
22461
|
-
headers2.forEach((value, key) => {
|
|
22462
|
-
out[key.toLowerCase()] = value;
|
|
22463
|
-
});
|
|
22464
|
-
return out;
|
|
22465
|
-
};
|
|
22466
|
-
var lowercaseHeaders = lowercaseHeaders2;
|
|
22467
22468
|
const cacheKey = this.buildCacheKey(request);
|
|
22468
22469
|
const ttl = this.getTTLForRequest(request);
|
|
22469
22470
|
const swr = this.getSWRForRequest(request);
|
|
22470
22471
|
const body = await response.text();
|
|
22472
|
+
if (!body || body.trim().length === 0) {
|
|
22473
|
+
logger.warn(
|
|
22474
|
+
"[SDK Html-cache] put skipped, empty or minimal response body",
|
|
22475
|
+
{
|
|
22476
|
+
trace,
|
|
22477
|
+
bodyLength: body.length
|
|
22478
|
+
}
|
|
22479
|
+
);
|
|
22480
|
+
return;
|
|
22481
|
+
}
|
|
22471
22482
|
const cacheTimeISO = (/* @__PURE__ */ new Date()).toISOString();
|
|
22472
|
-
const headers =
|
|
22483
|
+
const headers = this.normalizeHeaders(response.headers);
|
|
22473
22484
|
const entry = {
|
|
22474
22485
|
status: response.status,
|
|
22475
22486
|
statusText: response.statusText,
|
|
@@ -22503,14 +22514,13 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22503
22514
|
});
|
|
22504
22515
|
}
|
|
22505
22516
|
}
|
|
22506
|
-
|
|
22507
|
-
const
|
|
22508
|
-
return (
|
|
22517
|
+
canReadFromCache(request) {
|
|
22518
|
+
const method = request.method.toUpperCase();
|
|
22519
|
+
return (method === "GET" || method === "HEAD") && this.isRequestCacheable(request);
|
|
22509
22520
|
}
|
|
22510
|
-
|
|
22511
|
-
|
|
22512
|
-
|
|
22513
|
-
return this.isResponseCacheable(response);
|
|
22521
|
+
canWriteToCache(request, response) {
|
|
22522
|
+
const method = request.method.toUpperCase();
|
|
22523
|
+
return method === "GET" && response.ok && this.isRequestCacheable(request) && this.isResponseCacheable(response);
|
|
22514
22524
|
}
|
|
22515
22525
|
createRevalidationRequest(request) {
|
|
22516
22526
|
const headers = new Headers(request.headers);
|
|
@@ -22526,7 +22536,7 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22526
22536
|
}
|
|
22527
22537
|
buildClientResponse(entry, isStale, age) {
|
|
22528
22538
|
const headers = new Headers(entry.headers);
|
|
22529
|
-
headers.set("Cache-Control", "public, max-age=
|
|
22539
|
+
headers.set("Cache-Control", "public, max-age=1, must-revalidate");
|
|
22530
22540
|
headers.set(
|
|
22531
22541
|
"Cloudflare-CDN-Cache-Control",
|
|
22532
22542
|
`public, s-maxage=${entry.ttl}, stale-while-revalidate=${entry.swr}, stale-if-error=60`
|
|
@@ -22621,6 +22631,7 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22621
22631
|
const accept = headers.get("accept") || "";
|
|
22622
22632
|
const versionFactors = {
|
|
22623
22633
|
store: headers.get("swell-storefront-id") || "",
|
|
22634
|
+
app: (headers.get("swell-app-id") || "") + "@" + (swellData["swell-app-version"] || ""),
|
|
22624
22635
|
auth: headers.get("swell-access-token") || "",
|
|
22625
22636
|
theme: headers.get("swell-theme-version-hash") || "",
|
|
22626
22637
|
modified: headers.get("swell-cache-modified") || "",
|
|
@@ -22643,11 +22654,16 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22643
22654
|
return {};
|
|
22644
22655
|
}
|
|
22645
22656
|
}
|
|
22646
|
-
|
|
22657
|
+
isRequestCacheable(request) {
|
|
22647
22658
|
const url = new URL(request.url);
|
|
22648
22659
|
if (request.headers.get("swell-deployment-mode") === "editor") return false;
|
|
22649
|
-
|
|
22650
|
-
|
|
22660
|
+
if (this.cacheRules.pathRules) {
|
|
22661
|
+
for (const rule of this.cacheRules.pathRules) {
|
|
22662
|
+
if (this.pathMatches(rule.path, url.pathname) && rule.skip) {
|
|
22663
|
+
return false;
|
|
22664
|
+
}
|
|
22665
|
+
}
|
|
22666
|
+
}
|
|
22651
22667
|
if (request.headers.get("cache-control")?.includes("no-cache"))
|
|
22652
22668
|
return false;
|
|
22653
22669
|
return true;
|
|
@@ -22663,24 +22679,33 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22663
22679
|
}
|
|
22664
22680
|
getDeploymentMode(headers) {
|
|
22665
22681
|
const mode = headers.get("swell-deployment-mode");
|
|
22666
|
-
return mode === "preview"
|
|
22682
|
+
return mode === "preview" ? "preview" : "live";
|
|
22667
22683
|
}
|
|
22668
22684
|
getTTLForRequest(request) {
|
|
22669
22685
|
const url = new URL(request.url);
|
|
22670
22686
|
const mode = this.getDeploymentMode(request.headers);
|
|
22671
|
-
if (
|
|
22672
|
-
|
|
22673
|
-
|
|
22674
|
-
|
|
22675
|
-
|
|
22676
|
-
|
|
22677
|
-
|
|
22678
|
-
|
|
22687
|
+
if (this.cacheRules.pathRules) {
|
|
22688
|
+
for (const rule of this.cacheRules.pathRules) {
|
|
22689
|
+
if (this.pathMatches(rule.path, url.pathname) && rule.ttl !== void 0) {
|
|
22690
|
+
return rule.ttl;
|
|
22691
|
+
}
|
|
22692
|
+
}
|
|
22693
|
+
}
|
|
22694
|
+
const defaults = this.cacheRules.defaults?.[mode];
|
|
22695
|
+
return defaults?.ttl ?? DEFAULT_CACHE_RULES.defaults[mode].ttl;
|
|
22679
22696
|
}
|
|
22680
22697
|
getSWRForRequest(request) {
|
|
22698
|
+
const url = new URL(request.url);
|
|
22681
22699
|
const mode = this.getDeploymentMode(request.headers);
|
|
22682
|
-
if (
|
|
22683
|
-
|
|
22700
|
+
if (this.cacheRules.pathRules) {
|
|
22701
|
+
for (const rule of this.cacheRules.pathRules) {
|
|
22702
|
+
if (this.pathMatches(rule.path, url.pathname) && rule.swr !== void 0) {
|
|
22703
|
+
return rule.swr;
|
|
22704
|
+
}
|
|
22705
|
+
}
|
|
22706
|
+
}
|
|
22707
|
+
const defaults = this.cacheRules.defaults?.[mode];
|
|
22708
|
+
return defaults?.swr ?? DEFAULT_CACHE_RULES.defaults[mode].swr;
|
|
22684
22709
|
}
|
|
22685
22710
|
getEntryAge(entry) {
|
|
22686
22711
|
const t = Date.parse(entry.cacheTimeISO);
|
|
@@ -22688,6 +22713,22 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22688
22713
|
const age = (Date.now() - t) / 1e3;
|
|
22689
22714
|
return age < 0 ? 0 : age;
|
|
22690
22715
|
}
|
|
22716
|
+
/**
|
|
22717
|
+
* Converts wildcard pattern to regex and tests against path.
|
|
22718
|
+
* - * matches any characters except /
|
|
22719
|
+
* - ** matches any characters including /
|
|
22720
|
+
*/
|
|
22721
|
+
pathMatches(pattern, path) {
|
|
22722
|
+
const regex = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "___DOUBLE_STAR___").replace(/\*/g, "[^/]*").replace(/___DOUBLE_STAR___/g, ".*");
|
|
22723
|
+
return new RegExp(`^${regex}$`).test(path);
|
|
22724
|
+
}
|
|
22725
|
+
normalizeHeaders(headers) {
|
|
22726
|
+
const normalized = {};
|
|
22727
|
+
headers.forEach((value, key) => {
|
|
22728
|
+
normalized[key.toLowerCase()] = value;
|
|
22729
|
+
});
|
|
22730
|
+
return normalized;
|
|
22731
|
+
}
|
|
22691
22732
|
normalizeSearchParams(searchParams) {
|
|
22692
22733
|
const ignoredParams = [
|
|
22693
22734
|
"utm_source",
|
|
@@ -22856,7 +22897,6 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22856
22897
|
statusText: entry.statusText,
|
|
22857
22898
|
headers
|
|
22858
22899
|
});
|
|
22859
|
-
await cache.delete(request);
|
|
22860
22900
|
await cache.put(request, response);
|
|
22861
22901
|
}
|
|
22862
22902
|
async delete(key) {
|
|
@@ -22867,18 +22907,15 @@ ${this.shopifyCompatibility.getContentForHeader()}`;
|
|
|
22867
22907
|
};
|
|
22868
22908
|
|
|
22869
22909
|
// src/cache/html-cache/html-cache-factory.ts
|
|
22870
|
-
|
|
22871
|
-
function getHtmlCache(env) {
|
|
22910
|
+
function getHtmlCache(env, cacheRules) {
|
|
22872
22911
|
const epoch = env?.HTML_CACHE_EPOCH;
|
|
22873
22912
|
if (typeof epoch !== "string" || !epoch) return null;
|
|
22874
|
-
if (_instance) return _instance;
|
|
22875
22913
|
const kv = env?.NAMESPACE;
|
|
22914
|
+
const rules = cacheRules || env?.HTML_CACHE_RULES;
|
|
22876
22915
|
if (env?.HTML_CACHE_BACKEND !== "worker" && kv) {
|
|
22877
|
-
|
|
22878
|
-
return _instance;
|
|
22916
|
+
return new HtmlCache(epoch, new KVCacheBackend(kv), rules);
|
|
22879
22917
|
}
|
|
22880
|
-
|
|
22881
|
-
return _instance;
|
|
22918
|
+
return new HtmlCache(epoch, new WorkerCacheBackend(epoch), rules);
|
|
22882
22919
|
}
|
|
22883
22920
|
})();
|
|
22884
22921
|
//# sourceMappingURL=index.js.map
|